1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
12 . "golang.org/x/tools/gopls/internal/regtest"
14 "golang.org/x/tools/internal/lsp/fake"
15 "golang.org/x/tools/internal/lsp/tests"
18 const internalDefinition = `
34 const message = "Hello World."
37 func TestGoToInternalDefinition(t *testing.T) {
38 Run(t, internalDefinition, func(t *testing.T, env *Env) {
39 env.OpenFile("main.go")
40 name, pos := env.GoToDefinition("main.go", env.RegexpSearch("main.go", "message"))
41 if want := "const.go"; name != want {
42 t.Errorf("GoToDefinition: got file %q, want %q", name, want)
44 if want := env.RegexpSearch("const.go", "message"); pos != want {
45 t.Errorf("GoToDefinition: got position %v, want %v", pos, want)
50 const stdlibDefinition = `
64 func TestGoToStdlibDefinition_Issue37045(t *testing.T) {
65 Run(t, stdlibDefinition, func(t *testing.T, env *Env) {
66 env.OpenFile("main.go")
67 name, pos := env.GoToDefinition("main.go", env.RegexpSearch("main.go", `fmt.(Printf)`))
68 if got, want := path.Base(name), "print.go"; got != want {
69 t.Errorf("GoToDefinition: got file %q, want %q", name, want)
72 // Test that we can jump to definition from outside our workspace.
73 // See golang.org/issues/37045.
74 newName, newPos := env.GoToDefinition(name, pos)
76 t.Errorf("GoToDefinition is not idempotent: got %q, want %q", newName, name)
79 t.Errorf("GoToDefinition is not idempotent: got %v, want %v", newPos, pos)
84 func TestUnexportedStdlib_Issue40809(t *testing.T) {
85 Run(t, stdlibDefinition, func(t *testing.T, env *Env) {
86 env.OpenFile("main.go")
87 name, _ := env.GoToDefinition("main.go", env.RegexpSearch("main.go", `fmt.(Printf)`))
90 pos := env.RegexpSearch(name, `:=\s*(newPrinter)\(\)`)
92 // Check that we can find references on a reference
93 refs := env.References(name, pos)
95 t.Errorf("expected 5+ references to newPrinter, found: %#v", refs)
98 name, pos = env.GoToDefinition(name, pos)
99 content, _ := env.Hover(name, pos)
100 if !strings.Contains(content.Value, "newPrinter") {
101 t.Fatal("definition of newPrinter went to the incorrect place")
103 // And on the definition too.
104 refs = env.References(name, pos)
106 t.Errorf("expected 5+ references to newPrinter, found: %#v", refs)
111 // Test the hover on an error's Error function.
112 // This can't be done via the marker tests because Error is a builtin.
113 func TestHoverOnError(t *testing.T) {
126 Run(t, mod, func(t *testing.T, env *Env) {
127 env.OpenFile("main.go")
128 content, _ := env.Hover("main.go", env.RegexpSearch("main.go", "Error"))
130 t.Fatalf("nil hover content for Error")
132 want := "```go\nfunc (error).Error() string\n```"
133 if content.Value != want {
134 t.Fatalf("hover failed:\n%s", tests.Diff(t, want, content.Value))
139 func TestImportShortcut(t *testing.T) {
152 for _, tt := range []struct {
155 importShortcut string
158 {0, true, "Definition"},
161 t.Run(tt.importShortcut, func(t *testing.T) {
164 ImportShortcut: tt.importShortcut,
166 ).Run(t, mod, func(t *testing.T, env *Env) {
167 env.OpenFile("main.go")
168 file, pos := env.GoToDefinition("main.go", env.RegexpSearch("main.go", `"fmt"`))
169 if !tt.wantDef && (file != "" || pos != (fake.Pos{})) {
170 t.Fatalf("expected no definition, got one: %s:%v", file, pos)
171 } else if tt.wantDef && file == "" && pos == (fake.Pos{}) {
172 t.Fatalf("expected definition, got none")
174 links := env.DocumentLink("main.go")
175 if len(links) != tt.wantLinks {
176 t.Fatalf("expected %v links, got %v", tt.wantLinks, len(links))