go/ast/astutil: match prefix segments when adding imports
AddImport and AddNamedImport attempt to place new
imports in roughly the correct place--and thus the
correct group--by matching prefixes. Matching prefixes
byte-by-byte led to "regexp" being grouped with "rsc.io/p".
Instead, match prefixes by segments.
Fixes golang/go#9961.
Change-Id: I52b7c58a9a2fbe85c2b5297e50c87d409364bda3
Reviewed-on: https://go-review.googlesource.com/8090
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/go/ast/astutil/imports.go b/go/ast/astutil/imports.go
index 29f52de..2816793 100644
--- a/go/ast/astutil/imports.go
+++ b/go/ast/astutil/imports.go
@@ -308,13 +308,15 @@
return false
}
-// matchLen returns the length of the longest prefix shared by x and y.
+// matchLen returns the length of the longest path segment prefix shared by x and y.
func matchLen(x, y string) int {
- i := 0
- for i < len(x) && i < len(y) && x[i] == y[i] {
- i++
+ n := 0
+ for i := 0; i < len(x) && i < len(y) && x[i] == y[i]; i++ {
+ if x[i] == '/' {
+ n++
+ }
}
- return i
+ return n
}
// isTopName returns true if n is a top-level unresolved identifier with the given name.
diff --git a/go/ast/astutil/imports_test.go b/go/ast/astutil/imports_test.go
index 6bc940c..e956f49 100644
--- a/go/ast/astutil/imports_test.go
+++ b/go/ast/astutil/imports_test.go
@@ -315,6 +315,31 @@
type T time.Time
`,
},
+
+ // Issue 9961: Match prefixes using path segments rather than bytes
+ {
+ name: "issue 9961",
+ pkg: "regexp",
+ in: `package main
+
+import (
+ "flag"
+ "testing"
+
+ "rsc.io/p"
+)
+`,
+ out: `package main
+
+import (
+ "flag"
+ "regexp"
+ "testing"
+
+ "rsc.io/p"
+)
+`,
+ },
}
func TestAddImport(t *testing.T) {
diff --git a/imports/fix_test.go b/imports/fix_test.go
index 9382a19..6be1d57 100644
--- a/imports/fix_test.go
+++ b/imports/fix_test.go
@@ -671,19 +671,59 @@
func main() { fmt.Println("pi:", math.Pi) }
`,
},
+
+ // Too aggressive prefix matching
+ // golang.org/issue/9961
+ {
+ name: "issue 9961",
+ in: `package p
+
+import (
+ "zip"
+
+ "rsc.io/p"
+)
+
+var (
+ _ = fmt.Print
+ _ = zip.Store
+ _ p.P
+ _ = regexp.Compile
+)
+`,
+ out: `package p
+
+import (
+ "fmt"
+ "regexp"
+ "zip"
+
+ "rsc.io/p"
+)
+
+var (
+ _ = fmt.Print
+ _ = zip.Store
+ _ p.P
+ _ = regexp.Compile
+)
+`,
+ },
}
func TestFixImports(t *testing.T) {
simplePkgs := map[string]string{
- "fmt": "fmt",
- "os": "os",
- "math": "math",
"appengine": "appengine",
- "user": "appengine/user",
- "zip": "archive/zip",
"bytes": "bytes",
+ "fmt": "fmt",
+ "math": "math",
+ "os": "os",
+ "p": "rsc.io/p",
+ "regexp": "regexp",
"snappy": "code.google.com/p/snappy-go/snappy",
"str": "strings",
+ "user": "appengine/user",
+ "zip": "archive/zip",
}
findImport = func(pkgName string, symbols map[string]bool) (string, bool, error) {
return simplePkgs[pkgName], pkgName == "str", nil