Skip to content

Commit 78a11c2

Browse files
committed
cmd/go: detect case-insensitive import path collision
We already detect this collision when both imports are used anywhere in a single program. Also detect it when they are in different targets being processed together. Fixes #20264. Change-Id: I5d3c822aae136053fbcb5ed167e1d67f9b847a0f Reviewed-on: https://go-review.googlesource.com/46424 Run-TryBot: Russ Cox <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent e00a38c commit 78a11c2

File tree

3 files changed

+26
-16
lines changed

3 files changed

+26
-16
lines changed

src/cmd/go/go_test.go

+11-2
Original file line numberDiff line numberDiff line change
@@ -2040,8 +2040,10 @@ func TestCaseCollisions(t *testing.T) {
20402040
)`)
20412041
tg.tempFile("src/example/a/pkg/pkg.go", `package pkg`)
20422042
tg.tempFile("src/example/a/Pkg/pkg.go", `package pkg`)
2043-
tg.runFail("list", "example/a")
2044-
tg.grepStderr("case-insensitive import collision", "go list example/a did not report import collision")
2043+
tg.run("list", "-json", "example/a")
2044+
tg.grepStdout("case-insensitive import collision", "go list -json example/a did not report import collision")
2045+
tg.runFail("build", "example/a")
2046+
tg.grepStderr("case-insensitive import collision", "go build example/a did not report import collision")
20452047
tg.tempFile("src/example/b/file.go", `package b`)
20462048
tg.tempFile("src/example/b/FILE.go", `package b`)
20472049
f, err := os.Open(tg.path("src/example/b"))
@@ -2059,6 +2061,13 @@ func TestCaseCollisions(t *testing.T) {
20592061
}
20602062
tg.runFail(args...)
20612063
tg.grepStderr("case-insensitive file name collision", "go list example/b did not report file name collision")
2064+
2065+
tg.runFail("list", "example/a/pkg", "example/a/Pkg")
2066+
tg.grepStderr("case-insensitive import collision", "go list example/a/pkg example/a/Pkg did not report import collision")
2067+
tg.run("list", "-json", "-e", "example/a/pkg", "example/a/Pkg")
2068+
tg.grepStdout("case-insensitive import collision", "go list -json -e example/a/pkg example/a/Pkg did not report import collision")
2069+
tg.runFail("build", "example/a/pkg", "example/a/Pkg")
2070+
tg.grepStderr("case-insensitive import collision", "go build example/a/pkg example/a/Pkg did not report import collision")
20622071
}
20632072

20642073
// Issue 8181.

src/cmd/go/internal/load/pkg.go

+11-10
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,8 @@ var cgoSyscallExclude = map[string]bool{
828828
"runtime/msan": true,
829829
}
830830

831+
var foldPath = make(map[string]string)
832+
831833
// load populates p using information from bp, err, which should
832834
// be the result of calling build.Context.Import.
833835
func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package {
@@ -1109,17 +1111,16 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) *Package
11091111
return p
11101112
}
11111113

1112-
// In the absence of errors lower in the dependency tree,
1113-
// check for case-insensitive collisions of import paths.
1114-
if len(p.DepsErrors) == 0 {
1115-
dep1, dep2 := str.FoldDup(p.Deps)
1116-
if dep1 != "" {
1117-
p.Error = &PackageError{
1118-
ImportStack: stk.Copy(),
1119-
Err: fmt.Sprintf("case-insensitive import collision: %q and %q", dep1, dep2),
1120-
}
1121-
return p
1114+
// Check for case-insensitive collisions of import paths.
1115+
fold := str.ToFold(p.ImportPath)
1116+
if other := foldPath[fold]; other == "" {
1117+
foldPath[fold] = p.ImportPath
1118+
} else if other != p.ImportPath {
1119+
p.Error = &PackageError{
1120+
ImportStack: stk.Copy(),
1121+
Err: fmt.Sprintf("case-insensitive import collision: %q and %q", p.ImportPath, other),
11221122
}
1123+
return p
11231124
}
11241125

11251126
if p.BinaryOnly {

src/cmd/go/internal/str/str.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ func StringList(args ...interface{}) []string {
2929
return x
3030
}
3131

32-
// toFold returns a string with the property that
33-
// strings.EqualFold(s, t) iff toFold(s) == toFold(t)
32+
// ToFold returns a string with the property that
33+
// strings.EqualFold(s, t) iff ToFold(s) == ToFold(t)
3434
// This lets us test a large set of strings for fold-equivalent
3535
// duplicates without making a quadratic number of calls
3636
// to EqualFold. Note that strings.ToUpper and strings.ToLower
3737
// do not have the desired property in some corner cases.
38-
func toFold(s string) string {
38+
func ToFold(s string) string {
3939
// Fast path: all ASCII, no upper case.
4040
// Most paths look like this already.
4141
for i := 0; i < len(s); i++ {
@@ -74,7 +74,7 @@ Slow:
7474
func FoldDup(list []string) (string, string) {
7575
clash := map[string]string{}
7676
for _, s := range list {
77-
fold := toFold(s)
77+
fold := ToFold(s)
7878
if t := clash[fold]; t != "" {
7979
if s > t {
8080
s, t = t, s

0 commit comments

Comments
 (0)