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