internal/lsp: handle major versions above v0/v1 in workspace module mode
Workspace mode did not yet support major versions other than v0/v1. To
do so, we have to check the major version before creating the fake gopls
workspace pseudoversion that goes in the workspace module.
Fixes golang/go#41807
Change-Id: I108fe504fdf9e9a0ce23f7102991c9ae78f12a9f
Reviewed-on: https://go-review.googlesource.com/c/tools/+/260004
Trust: Rebecca Stambler <rstambler@golang.org>
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
diff --git a/gopls/internal/regtest/workspace_test.go b/gopls/internal/regtest/workspace_test.go
index 35027e8..4e9559d 100644
--- a/gopls/internal/regtest/workspace_test.go
+++ b/gopls/internal/regtest/workspace_test.go
@@ -455,3 +455,59 @@
env.GoToDefinition("/tmp/foo.go", env.RegexpSearch("/tmp/foo.go", `Printf`))
})
}
+
+func TestMultiModuleV2(t *testing.T) {
+ const multiModule = `
+-- moda/a/go.mod --
+module a.com
+
+require b.com/v2 v2.0.0
+-- moda/a/a.go --
+package a
+
+import (
+ "b.com/v2/b"
+)
+
+func main() {
+ var x int
+ _ = b.Hi()
+}
+-- modb/go.mod --
+module b.com
+
+-- modb/b/b.go --
+package b
+
+func Hello() int {
+ var x int
+}
+-- modb/v2/go.mod --
+module b.com/v2
+
+-- modb/v2/b/b.go --
+package b
+
+func Hi() int {
+ var x int
+}
+-- modc/go.mod --
+module gopkg.in/yaml.v1 // test gopkg.in versions
+-- modc/main.go --
+package main
+
+func main() {
+ var x int
+}
+`
+ withOptions(
+ WithModes(Experimental),
+ ).run(t, multiModule, func(t *testing.T, env *Env) {
+ env.Await(
+ env.DiagnosticAtRegexp("moda/a/a.go", "x"),
+ env.DiagnosticAtRegexp("modb/b/b.go", "x"),
+ env.DiagnosticAtRegexp("modb/v2/b/b.go", "x"),
+ env.DiagnosticAtRegexp("modc/main.go", "x"),
+ )
+ })
+}
diff --git a/internal/lsp/cache/check.go b/internal/lsp/cache/check.go
index 688d52b..709554c 100644
--- a/internal/lsp/cache/check.go
+++ b/internal/lsp/cache/check.go
@@ -278,7 +278,7 @@
// meaningless, and we don't want clients to access it.
if m.module != nil {
version := m.module.Version
- if version == source.WorkspaceModuleVersion {
+ if source.IsWorkspaceModuleVersion(version) {
version = ""
}
pkg.version = &module.Version{
diff --git a/internal/lsp/cache/snapshot.go b/internal/lsp/cache/snapshot.go
index 5e11c52..5a542a5 100644
--- a/internal/lsp/cache/snapshot.go
+++ b/internal/lsp/cache/snapshot.go
@@ -20,6 +20,7 @@
"sync"
"golang.org/x/mod/modfile"
+ "golang.org/x/mod/module"
"golang.org/x/tools/go/analysis"
"golang.org/x/tools/go/packages"
"golang.org/x/tools/internal/event"
@@ -1545,7 +1546,14 @@
}
path := parsed.File.Module.Mod.Path
paths[path] = mod
- file.AddNewRequire(path, source.WorkspaceModuleVersion, false)
+ // If the module's path includes a major version, we expect it to have
+ // a matching major version.
+ _, majorVersion, _ := module.SplitPathVersion(path)
+ if majorVersion == "" {
+ majorVersion = "/v0"
+ }
+ majorVersion = strings.TrimLeft(majorVersion, "/.") // handle gopkg.in versions
+ file.AddNewRequire(path, source.WorkspaceModuleVersion(majorVersion), false)
if err := file.AddReplace(path, "", mod.rootURI.Filename(), ""); err != nil {
return nil, err
}
diff --git a/internal/lsp/mod/diagnostics.go b/internal/lsp/mod/diagnostics.go
index d4d3cad..b834c7e 100644
--- a/internal/lsp/mod/diagnostics.go
+++ b/internal/lsp/mod/diagnostics.go
@@ -88,7 +88,7 @@
path, version := match[1], match[2]
// Any module versions that come from the workspace module should not
// be shown to the user.
- if version == source.WorkspaceModuleVersion {
+ if source.IsWorkspaceModuleVersion(version) {
continue
}
if err := module.Check(path, version); err != nil {
diff --git a/internal/lsp/source/view.go b/internal/lsp/source/view.go
index bbe95c4..b8c2153 100644
--- a/internal/lsp/source/view.go
+++ b/internal/lsp/source/view.go
@@ -548,8 +548,17 @@
PackagesLoadError = errors.New("packages.Load error")
)
-// WorkspaceModuleVersion is the nonexistent pseudoversion used in the
+// WorkspaceModuleVersion is the nonexistent pseudoversion suffix used in the
// construction of the workspace module. It is exported so that we can make
// sure not to show this version to end users in error messages, to avoid
// confusion.
-const WorkspaceModuleVersion = "v0.0.0-goplsworkspace"
+// The major version is not included, as that depends on the module path.
+const workspaceModuleVersion = ".0.0-goplsworkspace"
+
+func IsWorkspaceModuleVersion(version string) bool {
+ return strings.HasSuffix(version, workspaceModuleVersion)
+}
+
+func WorkspaceModuleVersion(majorVersion string) string {
+ return majorVersion + workspaceModuleVersion
+}