From 42268a1f04445323c504962036dc3f5fcef5b815 Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Mon, 16 Dec 2019 18:13:47 -0500 Subject: [PATCH] internal/lsp: fix link anchors for struct fields This change fixes the link anchors for fields within a struct or composite literal by getting the enclosing types.Type. Fixes golang/go#36138 Change-Id: I534a900fad6fa6fa1b1acaa5a63ca264c5d34c39 Reviewed-on: https://go-review.googlesource.com/c/tools/+/211582 Run-TryBot: Rebecca Stambler TryBot-Result: Gobot Gobot Reviewed-by: Heschi Kreinick --- internal/lsp/source/hover.go | 12 ++++---- internal/lsp/source/identifier.go | 36 ++++++++++++++++------- internal/lsp/testdata/godef/a/d.go | 6 +++- internal/lsp/testdata/godef/b/c.go.golden | 6 ++-- internal/lsp/testdata/summary.txt.golden | 2 +- 5 files changed, 39 insertions(+), 23 deletions(-) diff --git a/internal/lsp/source/hover.go b/internal/lsp/source/hover.go index f16620f78e..868c26574e 100644 --- a/internal/lsp/source/hover.go +++ b/internal/lsp/source/hover.go @@ -93,13 +93,11 @@ func (i *IdentifierInfo) linkAndSymbolName() (string, string) { switch obj := obj.(type) { case *types.Var: if obj.IsField() { - // If the object is a field, and we have an associated selector, - // we can determine the struct. - if selection, ok := i.pkg.GetTypesInfo().Selections[i.selector]; ok { - switch rtyp := deref(selection.Recv()).(type) { - case *types.Named: - rTypeName = rtyp.Obj().Name() - } + // If the object is a field, and we have an associated selector + // composite literal, or struct, we can determine the link. + switch typ := i.enclosing.(type) { + case *types.Named: + rTypeName = typ.Obj().Name() } } case *types.Func: diff --git a/internal/lsp/source/identifier.go b/internal/lsp/source/identifier.go index 2cfdf72521..0cf7955f39 100644 --- a/internal/lsp/source/identifier.go +++ b/internal/lsp/source/identifier.go @@ -33,8 +33,10 @@ type IdentifierInfo struct { Declaration Declaration - ident *ast.Ident - selector *ast.SelectorExpr + ident *ast.Ident + + // enclosing is an expression used to determine the link anchor for an identifier. + enclosing types.Type pkg Package qf types.Qualifier @@ -120,12 +122,12 @@ func identifier(s Snapshot, pkg Package, file *ast.File, pos token.Pos) (*Identi } } result := &IdentifierInfo{ - File: ph, - Snapshot: s, - qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()), - pkg: pkg, - ident: searchForIdent(path[0]), - selector: searchForSelector(path), + File: ph, + Snapshot: s, + qf: qualifier(file, pkg.GetTypes(), pkg.GetTypesInfo()), + pkg: pkg, + ident: searchForIdent(path[0]), + enclosing: searchForEnclosing(pkg, path), } // No identifier at the given position. @@ -232,11 +234,23 @@ func searchForIdent(n ast.Node) *ast.Ident { return nil } -func searchForSelector(path []ast.Node) *ast.SelectorExpr { +func searchForEnclosing(pkg Package, path []ast.Node) types.Type { for _, n := range path { - switch node := n.(type) { + switch n := n.(type) { case *ast.SelectorExpr: - return node + if selection, ok := pkg.GetTypesInfo().Selections[n]; ok { + return deref(selection.Recv()) + } + case *ast.CompositeLit: + if t, ok := pkg.GetTypesInfo().Types[n]; ok { + return t.Type + } + case *ast.TypeSpec: + if _, ok := n.Type.(*ast.StructType); ok { + if t, ok := pkg.GetTypesInfo().Defs[n.Name]; ok { + return t.Type() + } + } } } return nil diff --git a/internal/lsp/testdata/godef/a/d.go b/internal/lsp/testdata/godef/a/d.go index 4025788c8d..3b76e829da 100644 --- a/internal/lsp/testdata/godef/a/d.go +++ b/internal/lsp/testdata/godef/a/d.go @@ -17,7 +17,9 @@ func (t Thing) Method(i int) string { //@Method } func useThings() { - t := Thing{} //@mark(aStructType, "ing") + t := Thing{ //@mark(aStructType, "ing") + Member: "string", //@mark(fMember, "ember") + } fmt.Print(t.Member) //@mark(aMember, "ember") fmt.Print(Other) //@mark(aVar, "ther") Things() //@mark(aFunc, "ings") @@ -30,6 +32,8 @@ godef(aMember, Member) godef(aVar, Other) godef(aFunc, Things) godef(aMethod, Method) +godef(fMember, Member) +godef(Member, Member) //param //package name diff --git a/internal/lsp/testdata/godef/b/c.go.golden b/internal/lsp/testdata/godef/b/c.go.golden index 30fb109db2..cf7e7533a1 100644 --- a/internal/lsp/testdata/godef/b/c.go.golden +++ b/internal/lsp/testdata/godef/b/c.go.golden @@ -39,7 +39,7 @@ S1 struct { -- S1F1-definition -- godef/b/b.go:9:2-4: defined here as \@mark\(S1F1, \"F1\"\) -[`b.F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#F1) +[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.F1) ```go field F1 int @@ -59,13 +59,13 @@ field F1 int "offset": 214 } }, - "description": "\\@mark\\(S1F1, \\\"F1\\\"\\)\n\n[`b.F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#F1)\n\n```go\nfield F1 int\n```" + "description": "\\@mark\\(S1F1, \\\"F1\\\"\\)\n\n[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.F1)\n\n```go\nfield F1 int\n```" } -- S1F1-hover -- \@mark\(S1F1, \"F1\"\) -[`b.F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#F1) +[`(b.S1).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.F1) ```go field F1 int diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden index 1067353483..b96f1d6f80 100644 --- a/internal/lsp/testdata/summary.txt.golden +++ b/internal/lsp/testdata/summary.txt.golden @@ -11,7 +11,7 @@ FoldingRangesCount = 2 FormatCount = 6 ImportCount = 7 SuggestedFixCount = 1 -DefinitionsCount = 39 +DefinitionsCount = 41 TypeDefinitionsCount = 2 HighlightsCount = 44 ReferencesCount = 7