diff --git a/gopls/internal/regtest/workspace/workspace_test.go b/gopls/internal/regtest/workspace/workspace_test.go index 5648dc9297..a241348cae 100644 --- a/gopls/internal/regtest/workspace/workspace_test.go +++ b/gopls/internal/regtest/workspace/workspace_test.go @@ -865,6 +865,55 @@ module example.com/bar/baz }) } +func TestExpandToGoWork(t *testing.T) { + testenv.NeedsGo1Point(t, 18) + const workspace = ` +-- moda/a/go.mod -- +module a.com + +require b.com v1.2.3 +-- moda/a/a.go -- +package a + +import ( + "b.com/b" +) + +func main() { + var x int + _ = b.Hello() +} +-- modb/go.mod -- +module b.com + +require example.com v1.2.3 +-- modb/b/b.go -- +package b + +func Hello() int { + var x int +} +-- go.work -- +go 1.17 + +use ( + ./moda/a + ./modb +) +` + WithOptions( + WorkspaceFolders("moda/a"), + ).Run(t, workspace, func(t *testing.T, env *Env) { + env.OpenFile("moda/a/a.go") + env.Await(env.DoneWithOpen()) + location, _ := env.GoToDefinition("moda/a/a.go", env.RegexpSearch("moda/a/a.go", "Hello")) + want := "modb/b/b.go" + if !strings.HasSuffix(location, want) { + t.Errorf("expected %s, got %v", want, location) + } + }) +} + func TestNonWorkspaceFileCreation(t *testing.T) { testenv.NeedsGo1Point(t, 13) diff --git a/internal/lsp/cache/view.go b/internal/lsp/cache/view.go index 6a9360a5e8..13d3db3826 100644 --- a/internal/lsp/cache/view.go +++ b/internal/lsp/cache/view.go @@ -832,7 +832,7 @@ func go111moduleForVersion(go111module string, goversion int) go111module { // TODO (rFindley): move this to workspace.go // TODO (rFindley): simplify this once workspace modules are enabled by default. func findWorkspaceRoot(ctx context.Context, folder span.URI, fs source.FileSource, excludePath func(string) bool, experimental bool) (span.URI, error) { - patterns := []string{"go.mod"} + patterns := []string{"go.work", "go.mod"} if experimental { patterns = []string{"go.work", "gopls.mod", "go.mod"} } @@ -882,7 +882,8 @@ func findRootPattern(ctx context.Context, folder span.URI, basename string, fs s if exists { return span.URIFromPath(dir), nil } - next, _ := filepath.Split(dir) + // Trailing separators must be trimmed, otherwise filepath.Split is a noop. + next, _ := filepath.Split(strings.TrimRight(dir, string(filepath.Separator))) if next == dir { break } diff --git a/internal/lsp/cache/view_test.go b/internal/lsp/cache/view_test.go index ecd7e84ed7..d76dcda8ed 100644 --- a/internal/lsp/cache/view_test.go +++ b/internal/lsp/cache/view_test.go @@ -55,6 +55,8 @@ func TestFindWorkspaceRoot(t *testing.T) { module a -- a/x/x.go package x +-- a/x/y/y.go +package x -- b/go.mod -- module b -- b/c/go.mod -- @@ -79,6 +81,7 @@ module fg {"", "", false}, // no module at root, and more than one nested module {"a", "a", false}, {"a/x", "a", false}, + {"a/x/y", "a", false}, {"b/c", "b/c", false}, {"d", "d/e", false}, {"d", "d", true},