diff --git a/gopls/internal/lsp/source/implementation_gox.go b/gopls/internal/lsp/source/implementation_gox.go index 91a8ba60b51..a00b047ff4d 100644 --- a/gopls/internal/lsp/source/implementation_gox.go +++ b/gopls/internal/lsp/source/implementation_gox.go @@ -430,6 +430,9 @@ func gopPathEnclosingObjNode(f *ast.File, pos token.Pos) []ast.Node { if pos == n.Star { pos = n.X.Pos() } + case *ast.FuncLit: + //goxls:overload anonymous function + found = n.Type.Func <= pos && pos <= n.Type.Func+token.Pos(len("func")) } return !found diff --git a/gopls/internal/lsp/source/references_gox.go b/gopls/internal/lsp/source/references_gox.go index caafe7780ac..e3ba5d0a95a 100644 --- a/gopls/internal/lsp/source/references_gox.go +++ b/gopls/internal/lsp/source/references_gox.go @@ -5,6 +5,7 @@ package source import ( + "bytes" "context" "fmt" "go/token" @@ -461,7 +462,11 @@ func gopOrdinaryReferences(ctx context.Context, snapshot Snapshot, uri span.URI, // Report the locations of the declaration(s). // TODO(adonovan): what about for corresponding methods? Add tests. for _, node := range objects { - report(gopMustLocation(pgf, node), true) + if funcLit, ok := node.(*ast.FuncLit); ok { + report(gopMustLocation(pgf, funcLit.Type), true) + } else { + report(gopMustLocation(pgf, node), true) + } } // Convert targets map to set. @@ -581,6 +586,15 @@ func gopObjectsAt(info *typesutil.Info, file *ast.File, pos token.Pos) (map[type return nil, nil, fmt.Errorf("%w for import %s", errNoObjectFound, GopUnquoteImportPath(leaf)) } targets[obj] = leaf + case *ast.FuncLit: + // Look up the implicit *types.Func (overload member) + obj := info.Implicits[leaf] + if obj == nil { + var buf bytes.Buffer + typesutil.WriteExpr(&buf, leaf) + return nil, nil, fmt.Errorf("%w for %q", errNoObjectFound, buf.String()) + } + targets[obj] = leaf } if len(targets) == 0 { diff --git a/gopls/internal/regtest/misc/references_gox_test.go b/gopls/internal/regtest/misc/references_gox_test.go new file mode 100644 index 00000000000..d3058228969 --- /dev/null +++ b/gopls/internal/regtest/misc/references_gox_test.go @@ -0,0 +1,68 @@ +package misc + +import ( + "fmt" + "strings" + "testing" + + "github.com/google/go-cmp/cmp" + . "golang.org/x/tools/gopls/internal/lsp/regtest" +) + +func TestReferencesOnOverloadMember(t *testing.T) { + const files = ` +-- go.mod -- +module mod.com + +go 1.19 +-- def.gop -- +func add = ( + func(a, b int) int { + return a + b + } + func(a, b string) string { + return a + b + } +) +-- test.gop -- +println add(1,2) +println add("Hello", "World") +println add("Bye", "World") +-- gop_autogen.go -- +package main + +import "fmt" + +const _ = true +func add__0(a int, b int) int { + return a + b +} +func add__1(a string, b string) string { + return a + b +} +func main() { + fmt.Println(add__0(1, 2)) + fmt.Println(add__1("Hello", "World")) + fmt.Println(add__1("Bye", "World")) +} +` + Run(t, files, func(t *testing.T, env *Env) { + env.OpenFile("test.gop") + loc := env.GoToDefinition(env.RegexpSearch("test.gop", `println (add)\("Hello", "World"\)`)) + refs, err := env.Editor.References(env.Ctx, loc) + if err != nil { + t.Fatalf("references on (*s).Error failed: %v", err) + } + var buf strings.Builder + for _, ref := range refs { + fmt.Fprintf(&buf, "%s %s\n", env.Sandbox.Workdir.URIToPath(ref.URI), ref.Range) + } + got := buf.String() + want := "def.gop 4:1-4:25\n" + // anonymous overload func + "test.gop 1:8-1:11\n" + + "test.gop 2:8-2:11\n" + if diff := cmp.Diff(want, got); diff != "" { + t.Errorf("unexpected references on (*s).Error (-want +got):\n%s", diff) + } + }) +}