gopls/internal/regtest: fix goimports on windows when using vendoring Add a test for goimports when using mod vendoring on windows, along with a very subtle one-line fix. Fixes golang/go#56291 Change-Id: I2e45f70fc6dfa32164d4664acad886ec811474b8 Reviewed-on: https://go-review.googlesource.com/c/tools/+/498695 Run-TryBot: Robert Findley <rfindley@google.com> Reviewed-by: Alan Donovan <adonovan@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> gopls-CI: kokoro <noreply+kokoro@google.com>
diff --git a/gopls/internal/regtest/misc/vendor_test.go b/gopls/internal/regtest/misc/vendor_test.go index 4fcf106..efed16b 100644 --- a/gopls/internal/regtest/misc/vendor_test.go +++ b/gopls/internal/regtest/misc/vendor_test.go
@@ -63,3 +63,41 @@ ) }) } + +func TestWindowsVendoring_Issue56291(t *testing.T) { + const src = ` +-- go.mod -- +module mod.com + +go 1.14 + +require golang.org/x/hello v1.2.3 +-- go.sum -- +golang.org/x/hello v1.2.3 h1:EcMp5gSkIhaTkPXp8/3+VH+IFqTpk3ZbpOhqk0Ncmho= +golang.org/x/hello v1.2.3/go.mod h1:WW7ER2MRNXWA6c8/4bDIek4Hc/+DofTrMaQQitGXcco= +-- main.go -- +package main + +import "golang.org/x/hello/hi" + +func main() { + _ = hi.Goodbye +} +` + WithOptions( + Modes(Default), + ProxyFiles(basicProxy), + ).Run(t, src, func(t *testing.T, env *Env) { + env.OpenFile("main.go") + env.AfterChange(NoDiagnostics()) + env.RunGoCommand("mod", "tidy") + env.RunGoCommand("mod", "vendor") + env.AfterChange(NoDiagnostics()) + env.RegexpReplace("main.go", `import "golang.org/x/hello/hi"`, "") + env.AfterChange( + Diagnostics(env.AtRegexp("main.go", "hi.Goodbye")), + ) + env.SaveBuffer("main.go") + env.AfterChange(NoDiagnostics()) + }) +}
diff --git a/internal/imports/mod.go b/internal/imports/mod.go index 1389d38..977d238 100644 --- a/internal/imports/mod.go +++ b/internal/imports/mod.go
@@ -38,7 +38,7 @@ mains []*gocommand.ModuleJSON mainByDir map[string]*gocommand.ModuleJSON modsByModPath []*gocommand.ModuleJSON // All modules, ordered by # of path components in module Path... - modsByDir []*gocommand.ModuleJSON // ...or Dir. + modsByDir []*gocommand.ModuleJSON // ...or number of path components in their Dir. // moduleCacheCache stores information about the module cache. moduleCacheCache *dirInfoCache @@ -124,7 +124,7 @@ }) sort.Slice(r.modsByDir, func(i, j int) bool { count := func(x int) int { - return strings.Count(r.modsByDir[x].Dir, "/") + return strings.Count(r.modsByDir[x].Dir, string(filepath.Separator)) } return count(j) < count(i) // descending order }) @@ -328,6 +328,10 @@ // - in /vendor/ in -mod=vendor mode. // - nested module? Dunno. // Rumor has it that replace targets cannot contain other replace targets. + // + // Note that it is critical here that modsByDir is sorted to have deeper dirs + // first. This ensures that findModuleByDir finds the innermost module. + // See also golang/go#56291. for _, m := range r.modsByDir { if !strings.HasPrefix(dir, m.Dir) { continue