internal/imports: support completing import paths
Add a new autocomplete function that completes based on import path
prefix rather than package name prefix.
Updates golang/go#35877.
Change-Id: Ib768080ee99debfff1c8c870d22dc7b7459deadd
Reviewed-on: https://go-review.googlesource.com/c/tools/+/249419
Run-TryBot: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Danish Dua <danishdua@google.com>
diff --git a/internal/imports/fix.go b/internal/imports/fix.go
index 0cb09e2..62d9fe8 100644
--- a/internal/imports/fix.go
+++ b/internal/imports/fix.go
@@ -693,8 +693,8 @@
return ""
}
-// GetAllCandidates gets all of the packages starting with prefix that can be
-// imported by filename, sorted by import path.
+// GetAllCandidates calls wrapped for each package whose name starts with
+// searchPrefix, and can be imported from filename with the package name filePkg.
func GetAllCandidates(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error {
callback := &scanCallback{
rootFound: func(gopathwalk.Root) bool {
@@ -728,6 +728,35 @@
return getCandidatePkgs(ctx, callback, filename, filePkg, env)
}
+// GetImportPaths calls wrapped for each package whose import path starts with
+// searchPrefix, and can be imported from filename with the package name filePkg.
+func GetImportPaths(ctx context.Context, wrapped func(ImportFix), searchPrefix, filename, filePkg string, env *ProcessEnv) error {
+ callback := &scanCallback{
+ rootFound: func(gopathwalk.Root) bool {
+ return true
+ },
+ dirFound: func(pkg *pkg) bool {
+ if !canUse(filename, pkg.dir) {
+ return false
+ }
+ return strings.HasPrefix(pkg.importPathShort, searchPrefix)
+ },
+ packageNameLoaded: func(pkg *pkg) bool {
+ wrapped(ImportFix{
+ StmtInfo: ImportInfo{
+ ImportPath: pkg.importPathShort,
+ Name: candidateImportName(pkg),
+ },
+ IdentName: pkg.packageName,
+ FixType: AddImport,
+ Relevance: pkg.relevance,
+ })
+ return false
+ },
+ }
+ return getCandidatePkgs(ctx, callback, filename, filePkg, env)
+}
+
// A PackageExport is a package and its exports.
type PackageExport struct {
Fix *ImportFix
diff --git a/internal/imports/fix_test.go b/internal/imports/fix_test.go
index e14f1d3..0bcbb88 100644
--- a/internal/imports/fix_test.go
+++ b/internal/imports/fix_test.go
@@ -2560,7 +2560,7 @@
}.processTest(t, "foo.com/a", "a_test.go", nil, nil, want)
}
-// TestStdLibGetCandidates tests that get packages finds std library packages
+// TestGetCandidates tests that get packages finds packages
// with correct priorities.
func TestGetCandidates(t *testing.T) {
type res struct {
@@ -2613,7 +2613,57 @@
got[i].relevance = 0
}
if !reflect.DeepEqual(want, got) {
- t.Errorf("wanted stdlib results in order %v, got %v", want, got)
+ t.Errorf("wanted results in order %v, got %v", want, got)
+ }
+ })
+}
+
+func TestGetImportPaths(t *testing.T) {
+ type res struct {
+ relevance int
+ name, path string
+ }
+ want := []res{
+ {0, "http", "net/http"},
+ {0, "net", "net"},
+ {0, "neta", "neta.com/neta"},
+ }
+
+ testConfig{
+ modules: []packagestest.Module{
+ {
+ Name: "neta.com",
+ Files: fm{"neta/neta.go": "package neta\n"},
+ },
+ },
+ }.test(t, func(t *goimportTest) {
+ var mu sync.Mutex
+ var got []res
+ add := func(c ImportFix) {
+ mu.Lock()
+ defer mu.Unlock()
+ for _, w := range want {
+ if c.StmtInfo.ImportPath == w.path {
+ got = append(got, res{c.Relevance, c.IdentName, c.StmtInfo.ImportPath})
+ }
+ }
+ }
+ if err := GetImportPaths(context.Background(), add, "ne", "x.go", "x", t.env); err != nil {
+ t.Fatalf("GetImportPaths() = %v", err)
+ }
+ // Sort, then clear out relevance so it doesn't mess up the DeepEqual.
+ sort.Slice(got, func(i, j int) bool {
+ ri, rj := got[i], got[j]
+ if ri.relevance != rj.relevance {
+ return ri.relevance > rj.relevance // Highest first.
+ }
+ return ri.name < rj.name
+ })
+ for i := range got {
+ got[i].relevance = 0
+ }
+ if !reflect.DeepEqual(want, got) {
+ t.Errorf("wanted results in order %v, got %v", want, got)
}
})
}
@@ -2664,7 +2714,7 @@
got[i].relevance = 0
}
if !reflect.DeepEqual(want, got) {
- t.Errorf("wanted stdlib results in order %v, got %v", want, got)
+ t.Errorf("wanted results in order %v, got %v", want, got)
}
})
}