mirror of
https://github.com/golang/go
synced 2024-11-18 14:14:46 -07:00
internal/lsp: fix hover link for embedded fields and methods
Our logic to generate documentation links did not account for embedded fields and methods. The types.Info.ObjectOf an embedded field returns the *types.Var created for the field, not its types.TypeName, so we have to navigate back to the actual definition of the field. This requires traversing through all of the named types in the top-level type. Fixes golang/go#40294 Change-Id: Ia6573aebe66b7f60e2d6861a381cd7b07e7d7eaa Reviewed-on: https://go-review.googlesource.com/c/tools/+/244178 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
102e7d3570
commit
eaaaedc6af
@ -98,11 +98,13 @@ func HoverIdentifier(ctx context.Context, i *IdentifierInfo) (*HoverInformation,
|
|||||||
case types.Object:
|
case types.Object:
|
||||||
// If the variable is implicitly declared in a type switch, we need to
|
// If the variable is implicitly declared in a type switch, we need to
|
||||||
// manually generate its object string.
|
// manually generate its object string.
|
||||||
if v, ok := x.(*types.Var); ok && i.Declaration.typeSwitchImplicit {
|
if typ := i.Declaration.typeSwitchImplicit; typ != nil {
|
||||||
h.Signature = fmt.Sprintf("var %s %s", v.Name(), types.TypeString(i.enclosing, i.qf))
|
if v, ok := x.(*types.Var); ok {
|
||||||
} else {
|
h.Signature = fmt.Sprintf("var %s %s", v.Name(), types.TypeString(typ, i.qf))
|
||||||
h.Signature = objectString(x, i.qf)
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
h.Signature = objectString(x, i.qf)
|
||||||
}
|
}
|
||||||
if obj := i.Declaration.obj; obj != nil {
|
if obj := i.Declaration.obj; obj != nil {
|
||||||
h.SingleLine = objectString(obj, i.qf)
|
h.SingleLine = objectString(obj, i.qf)
|
||||||
@ -143,12 +145,11 @@ func pathLinkAndSymbolName(i *IdentifierInfo) (string, string, string) {
|
|||||||
var rTypeName string
|
var rTypeName string
|
||||||
switch obj := obj.(type) {
|
switch obj := obj.(type) {
|
||||||
case *types.Var:
|
case *types.Var:
|
||||||
|
// If the object is a field, and we have an associated selector
|
||||||
|
// composite literal, or struct, we can determine the link.
|
||||||
if obj.IsField() {
|
if obj.IsField() {
|
||||||
// If the object is a field, and we have an associated selector
|
if named, ok := i.enclosing.(*types.Named); ok {
|
||||||
// composite literal, or struct, we can determine the link.
|
rTypeName = named.Obj().Name()
|
||||||
switch typ := i.enclosing.(type) {
|
|
||||||
case *types.Named:
|
|
||||||
rTypeName = typ.Obj().Name()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *types.Func:
|
case *types.Func:
|
||||||
@ -161,10 +162,15 @@ func pathLinkAndSymbolName(i *IdentifierInfo) (string, string, string) {
|
|||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
rTypeName = r.Name()
|
rTypeName = r.Name()
|
||||||
case *types.Named:
|
case *types.Named:
|
||||||
if named, ok := i.enclosing.(*types.Named); ok {
|
// If we have an unexported type, see if the enclosing type is
|
||||||
rTypeName = named.Obj().Name()
|
// exported (we may have an interface or struct we can link
|
||||||
} else if !rtyp.Obj().Exported() {
|
// to). If not, don't show any link.
|
||||||
return "", "", ""
|
if !rtyp.Obj().Exported() {
|
||||||
|
if named := i.enclosing.(*types.Named); ok && named.Obj().Exported() {
|
||||||
|
rTypeName = named.Obj().Name()
|
||||||
|
} else {
|
||||||
|
return "", "", ""
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rTypeName = rtyp.Obj().Name()
|
rTypeName = rtyp.Obj().Name()
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,8 @@ type IdentifierInfo struct {
|
|||||||
|
|
||||||
ident *ast.Ident
|
ident *ast.Ident
|
||||||
|
|
||||||
// enclosing is an expression used to determine the link anchor for an identifier.
|
// enclosing is an expression used to determine the link anchor for an
|
||||||
|
// identifier. If it's a named type, it should be exported.
|
||||||
enclosing types.Type
|
enclosing types.Type
|
||||||
|
|
||||||
pkg Package
|
pkg Package
|
||||||
@ -45,8 +46,9 @@ type Declaration struct {
|
|||||||
obj types.Object
|
obj types.Object
|
||||||
|
|
||||||
// typeSwitchImplicit indicates that the declaration is in an implicit
|
// typeSwitchImplicit indicates that the declaration is in an implicit
|
||||||
// type switch.
|
// type switch. Its type is the type of the variable on the right-hand
|
||||||
typeSwitchImplicit bool
|
// side of the type switch.
|
||||||
|
typeSwitchImplicit types.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// Identifier returns identifier information for a position
|
// Identifier returns identifier information for a position
|
||||||
@ -158,13 +160,13 @@ func findIdentifier(ctx context.Context, s Snapshot, pkg Package, file *ast.File
|
|||||||
if result.Declaration.obj == nil {
|
if result.Declaration.obj == nil {
|
||||||
// If there was no types.Object for the declaration, there might be an
|
// If there was no types.Object for the declaration, there might be an
|
||||||
// implicit local variable declaration in a type switch.
|
// implicit local variable declaration in a type switch.
|
||||||
if objs := typeSwitchImplicits(pkg, path); len(objs) > 0 {
|
if objs, typ := typeSwitchImplicits(pkg, path); len(objs) > 0 {
|
||||||
result.Declaration.typeSwitchImplicit = true
|
|
||||||
// There is no types.Object for the declaration of an implicit local variable,
|
// There is no types.Object for the declaration of an implicit local variable,
|
||||||
// but all of the types.Objects associated with the usages of this variable can be
|
// but all of the types.Objects associated with the usages of this variable can be
|
||||||
// used to connect it back to the declaration.
|
// used to connect it back to the declaration.
|
||||||
// Preserve the first of these objects and treat it as if it were the declaring object.
|
// Preserve the first of these objects and treat it as if it were the declaring object.
|
||||||
result.Declaration.obj = objs[0]
|
result.Declaration.obj = objs[0]
|
||||||
|
result.Declaration.typeSwitchImplicit = typ
|
||||||
} else {
|
} else {
|
||||||
// Probably a type error.
|
// Probably a type error.
|
||||||
return nil, errors.Errorf("no object for ident %v", result.Name)
|
return nil, errors.Errorf("no object for ident %v", result.Name)
|
||||||
@ -236,8 +238,25 @@ func searchForEnclosing(pkg Package, path []ast.Node) types.Type {
|
|||||||
for _, n := range path {
|
for _, n := range path {
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
case *ast.SelectorExpr:
|
case *ast.SelectorExpr:
|
||||||
if selection, ok := pkg.GetTypesInfo().Selections[n]; ok {
|
if sel, ok := pkg.GetTypesInfo().Selections[n]; ok {
|
||||||
return deref(selection.Recv())
|
recv := deref(sel.Recv())
|
||||||
|
|
||||||
|
// Keep track of the last exported type seen.
|
||||||
|
var exported *types.Named
|
||||||
|
if named, ok := recv.(*types.Named); ok && named.Obj().Exported() {
|
||||||
|
exported = named
|
||||||
|
}
|
||||||
|
// We don't want the last element, as that's the field or
|
||||||
|
// method itself.
|
||||||
|
for _, index := range sel.Index()[:len(sel.Index())-1] {
|
||||||
|
if r, ok := recv.Underlying().(*types.Struct); ok {
|
||||||
|
recv = deref(r.Field(index).Type())
|
||||||
|
if named, ok := recv.(*types.Named); ok && named.Obj().Exported() {
|
||||||
|
exported = named
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exported
|
||||||
}
|
}
|
||||||
case *ast.CompositeLit:
|
case *ast.CompositeLit:
|
||||||
if t, ok := pkg.GetTypesInfo().Types[n]; ok {
|
if t, ok := pkg.GetTypesInfo().Types[n]; ok {
|
||||||
@ -249,15 +268,6 @@ func searchForEnclosing(pkg Package, path []ast.Node) types.Type {
|
|||||||
return t.Type()
|
return t.Type()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case *ast.TypeSwitchStmt:
|
|
||||||
// The right-hand side of a type switch should only have one
|
|
||||||
// element, and we need to track its type in order to generate
|
|
||||||
// hover information for implicit type switch variables.
|
|
||||||
if assign, ok := n.Assign.(*ast.AssignStmt); ok && len(assign.Rhs) == 1 {
|
|
||||||
if rhs := assign.Rhs[0].(*ast.TypeAssertExpr); ok {
|
|
||||||
return pkg.GetTypesInfo().TypeOf(rhs.X)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -339,12 +349,13 @@ func importSpec(s Snapshot, pkg Package, file *ast.File, pos token.Pos) (*Identi
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// typeSwitchImplicits returns all the implicit type switch objects
|
// typeSwitchImplicits returns all the implicit type switch objects that
|
||||||
// that correspond to the leaf *ast.Ident.
|
// correspond to the leaf *ast.Ident. It also returns the original type
|
||||||
func typeSwitchImplicits(pkg Package, path []ast.Node) []types.Object {
|
// associated with the identifier (outside of a case clause).
|
||||||
|
func typeSwitchImplicits(pkg Package, path []ast.Node) ([]types.Object, types.Type) {
|
||||||
ident, _ := path[0].(*ast.Ident)
|
ident, _ := path[0].(*ast.Ident)
|
||||||
if ident == nil {
|
if ident == nil {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -376,7 +387,6 @@ Outer:
|
|||||||
case *ast.TypeSwitchStmt:
|
case *ast.TypeSwitchStmt:
|
||||||
// Look for the type switch that owns our previously found
|
// Look for the type switch that owns our previously found
|
||||||
// *ast.AssignStmt or *ast.CaseClause.
|
// *ast.AssignStmt or *ast.CaseClause.
|
||||||
|
|
||||||
if n.Assign == assign {
|
if n.Assign == assign {
|
||||||
ts = n
|
ts = n
|
||||||
break Outer
|
break Outer
|
||||||
@ -390,11 +400,9 @@ Outer:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ts == nil {
|
if ts == nil {
|
||||||
return nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our leaf ident refers to a type switch variable. Fan out to the
|
// Our leaf ident refers to a type switch variable. Fan out to the
|
||||||
// type switch's implicit case clause objects.
|
// type switch's implicit case clause objects.
|
||||||
var objs []types.Object
|
var objs []types.Object
|
||||||
@ -403,5 +411,14 @@ Outer:
|
|||||||
objs = append(objs, ccObj)
|
objs = append(objs, ccObj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return objs
|
// The right-hand side of a type switch should only have one
|
||||||
|
// element, and we need to track its type in order to generate
|
||||||
|
// hover information for implicit type switch variables.
|
||||||
|
var typ types.Type
|
||||||
|
if assign, ok := ts.Assign.(*ast.AssignStmt); ok && len(assign.Rhs) == 1 {
|
||||||
|
if rhs := assign.Rhs[0].(*ast.TypeAssertExpr); ok {
|
||||||
|
typ = pkg.GetTypesInfo().TypeOf(rhs.X)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return objs, typ
|
||||||
}
|
}
|
||||||
|
@ -230,7 +230,7 @@ func qualifiedObjsAtProtocolPos(ctx context.Context, s Snapshot, fh FileHandle,
|
|||||||
// If leaf represents an implicit type switch object or the type
|
// If leaf represents an implicit type switch object or the type
|
||||||
// switch "assign" variable, expand to all of the type switch's
|
// switch "assign" variable, expand to all of the type switch's
|
||||||
// implicit objects.
|
// implicit objects.
|
||||||
if implicits := typeSwitchImplicits(searchpkg, path); len(implicits) > 0 {
|
if implicits, _ := typeSwitchImplicits(searchpkg, path); len(implicits) > 0 {
|
||||||
objs = append(objs, implicits...)
|
objs = append(objs, implicits...)
|
||||||
} else {
|
} else {
|
||||||
obj := searchpkg.GetTypesInfo().ObjectOf(leaf)
|
obj := searchpkg.GetTypesInfo().ObjectOf(leaf)
|
||||||
|
@ -42,3 +42,33 @@ func AStuff() { //@AStuff
|
|||||||
var typ *types.Named //@mark(typesImport, "types"),hover("types", typesImport)
|
var typ *types.Named //@mark(typesImport, "types"),hover("types", typesImport)
|
||||||
typ.Obj().Name() //@Name,hover("Name", Name)
|
typ.Obj().Name() //@Name,hover("Name", Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type A struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ A) Hi() {} //@mark(AHi, "Hi")
|
||||||
|
|
||||||
|
type S struct {
|
||||||
|
Field int //@mark(AField, "Field")
|
||||||
|
R // embed a struct
|
||||||
|
H // embed an interface
|
||||||
|
}
|
||||||
|
|
||||||
|
type R struct {
|
||||||
|
Field2 int //@mark(AField2, "Field2")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (_ R) Hey() {} //@mark(AHey, "Hey")
|
||||||
|
|
||||||
|
type H interface {
|
||||||
|
Goodbye() //@mark(AGoodbye, "Goodbye")
|
||||||
|
}
|
||||||
|
|
||||||
|
type I interface {
|
||||||
|
B() //@mark(AB, "B")
|
||||||
|
J
|
||||||
|
}
|
||||||
|
|
||||||
|
type J interface {
|
||||||
|
Hello() //@mark(AHello, "Hello")
|
||||||
|
}
|
||||||
|
@ -5,9 +5,26 @@ import (
|
|||||||
"golang.org/x/tools/internal/lsp/godef/a" //@mark(AImport, re"\".*\"")
|
"golang.org/x/tools/internal/lsp/godef/a" //@mark(AImport, re"\".*\"")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Embed struct {
|
||||||
|
*a.A
|
||||||
|
a.I
|
||||||
|
a.S
|
||||||
|
}
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
e := Embed{}
|
||||||
|
e.Hi() //@hover("Hi", AHi)
|
||||||
|
e.B() //@hover("B", AB)
|
||||||
|
e.Field //@hover("Field", AField)
|
||||||
|
e.Field2 //@hover("Field2", AField2)
|
||||||
|
e.Hello() //@hover("Hello", AHello)
|
||||||
|
e.Hey() //@hover("Hey", AHey)
|
||||||
|
e.Goodbye() //@hover("Goodbye", AGoodbye)
|
||||||
|
}
|
||||||
|
|
||||||
type S1 struct { //@S1
|
type S1 struct { //@S1
|
||||||
F1 int //@mark(S1F1, "F1")
|
F1 int //@mark(S1F1, "F1")
|
||||||
S2 //@godef("S2", S2), mark(S1S2, "S2")
|
S2 //@godef("S2", S2),mark(S1S2, "S2")
|
||||||
a.A //@godef("A", AString)
|
a.A //@godef("A", AString)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,55 @@
|
|||||||
|
-- AB-hover --
|
||||||
|
```go
|
||||||
|
func (a.I).B()
|
||||||
|
```
|
||||||
|
|
||||||
|
[`(a.I).B` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#I.B)
|
||||||
|
|
||||||
|
\@mark\(AB, \"B\"\)
|
||||||
|
-- AField-hover --
|
||||||
|
```go
|
||||||
|
field Field int
|
||||||
|
```
|
||||||
|
|
||||||
|
[`(a.S).Field` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#S.Field)
|
||||||
|
|
||||||
|
\@mark\(AField, \"Field\"\)
|
||||||
|
-- AField2-hover --
|
||||||
|
```go
|
||||||
|
field Field2 int
|
||||||
|
```
|
||||||
|
|
||||||
|
[`(a.R).Field2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#R.Field2)
|
||||||
|
|
||||||
|
\@mark\(AField2, \"Field2\"\)
|
||||||
|
-- AGoodbye-hover --
|
||||||
|
```go
|
||||||
|
func (a.H).Goodbye()
|
||||||
|
```
|
||||||
|
|
||||||
|
[`(a.H).Goodbye` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#H.Goodbye)
|
||||||
|
|
||||||
|
\@mark\(AGoodbye, \"Goodbye\"\)
|
||||||
|
-- AHello-hover --
|
||||||
|
```go
|
||||||
|
func (a.J).Hello()
|
||||||
|
```
|
||||||
|
|
||||||
|
[`(a.J).Hello` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#J.Hello)
|
||||||
|
|
||||||
|
\@mark\(AHello, \"Hello\"\)
|
||||||
|
-- AHey-hover --
|
||||||
|
```go
|
||||||
|
func (a.R).Hey()
|
||||||
|
```
|
||||||
|
|
||||||
|
[`(a.R).Hey` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#R.Hey)
|
||||||
|
-- AHi-hover --
|
||||||
|
```go
|
||||||
|
func (a.A).Hi()
|
||||||
|
```
|
||||||
|
|
||||||
|
[`(a.A).Hi` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#A.Hi)
|
||||||
-- AImport-definition --
|
-- AImport-definition --
|
||||||
godef/b/b.go:5:2-43: defined here as ```go
|
godef/b/b.go:5:2-43: defined here as ```go
|
||||||
package a ("golang.org/x/tools/internal/lsp/godef/a")
|
package a ("golang.org/x/tools/internal/lsp/godef/a")
|
||||||
@ -91,10 +143,10 @@ func a.AStuff()
|
|||||||
|
|
||||||
[`a.AStuff` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#AStuff)
|
[`a.AStuff` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/a#AStuff)
|
||||||
-- S1-definition --
|
-- S1-definition --
|
||||||
godef/b/b.go:8:6-8: defined here as ```go
|
godef/b/b.go:25:6-8: defined here as ```go
|
||||||
S1 struct {
|
S1 struct {
|
||||||
F1 int //@mark(S1F1, "F1")
|
F1 int //@mark(S1F1, "F1")
|
||||||
S2 //@godef("S2", S2), mark(S1S2, "S2")
|
S2 //@godef("S2", S2),mark(S1S2, "S2")
|
||||||
a.A //@godef("A", AString)
|
a.A //@godef("A", AString)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -105,31 +157,31 @@ S1 struct {
|
|||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 8,
|
"line": 25,
|
||||||
"column": 6,
|
"column": 6,
|
||||||
"offset": 193
|
"offset": 521
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 8,
|
"line": 25,
|
||||||
"column": 8,
|
"column": 8,
|
||||||
"offset": 195
|
"offset": 523
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nS1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2), mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", AString)\n}\n```\n\n[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1)"
|
"description": "```go\nS1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2),mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", AString)\n}\n```\n\n[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1)"
|
||||||
}
|
}
|
||||||
|
|
||||||
-- S1-hover --
|
-- S1-hover --
|
||||||
```go
|
```go
|
||||||
S1 struct {
|
S1 struct {
|
||||||
F1 int //@mark(S1F1, "F1")
|
F1 int //@mark(S1F1, "F1")
|
||||||
S2 //@godef("S2", S2), mark(S1S2, "S2")
|
S2 //@godef("S2", S2),mark(S1S2, "S2")
|
||||||
a.A //@godef("A", AString)
|
a.A //@godef("A", AString)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1)
|
[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1)
|
||||||
-- S1F1-definition --
|
-- S1F1-definition --
|
||||||
godef/b/b.go:9:2-4: defined here as ```go
|
godef/b/b.go:26:2-4: defined here as ```go
|
||||||
field F1 int
|
field F1 int
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -141,14 +193,14 @@ field F1 int
|
|||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 9,
|
"line": 26,
|
||||||
"column": 2,
|
"column": 2,
|
||||||
"offset": 212
|
"offset": 540
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 9,
|
"line": 26,
|
||||||
"column": 4,
|
"column": 4,
|
||||||
"offset": 214
|
"offset": 542
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nfield F1 int\n```\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\\@mark\\(S1F1, \\\"F1\\\"\\)"
|
"description": "```go\nfield F1 int\n```\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\\@mark\\(S1F1, \\\"F1\\\"\\)"
|
||||||
@ -163,29 +215,29 @@ field F1 int
|
|||||||
|
|
||||||
\@mark\(S1F1, \"F1\"\)
|
\@mark\(S1F1, \"F1\"\)
|
||||||
-- S1S2-definition --
|
-- S1S2-definition --
|
||||||
godef/b/b.go:10:2-4: defined here as ```go
|
godef/b/b.go:27:2-4: defined here as ```go
|
||||||
field S2 S2
|
field S2 S2
|
||||||
```
|
```
|
||||||
|
|
||||||
[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.S2)
|
[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.S2)
|
||||||
|
|
||||||
\@godef\(\"S2\", S2\), mark\(S1S2, \"S2\"\)
|
\@godef\(\"S2\", S2\),mark\(S1S2, \"S2\"\)
|
||||||
-- S1S2-definition-json --
|
-- S1S2-definition-json --
|
||||||
{
|
{
|
||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 10,
|
"line": 27,
|
||||||
"column": 2,
|
"column": 2,
|
||||||
"offset": 241
|
"offset": 569
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 10,
|
"line": 27,
|
||||||
"column": 4,
|
"column": 4,
|
||||||
"offset": 243
|
"offset": 571
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nfield S2 S2\n```\n\n[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.S2)\n\n\\@godef\\(\\\"S2\\\", S2\\), mark\\(S1S2, \\\"S2\\\"\\)"
|
"description": "```go\nfield S2 S2\n```\n\n[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.S2)\n\n\\@godef\\(\\\"S2\\\", S2\\),mark\\(S1S2, \\\"S2\\\"\\)"
|
||||||
}
|
}
|
||||||
|
|
||||||
-- S1S2-hover --
|
-- S1S2-hover --
|
||||||
@ -195,9 +247,9 @@ field S2 S2
|
|||||||
|
|
||||||
[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.S2)
|
[`(b.S1).S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.S2)
|
||||||
|
|
||||||
\@godef\(\"S2\", S2\), mark\(S1S2, \"S2\"\)
|
\@godef\(\"S2\", S2\),mark\(S1S2, \"S2\"\)
|
||||||
-- S2-definition --
|
-- S2-definition --
|
||||||
godef/b/b.go:14:6-8: defined here as ```go
|
godef/b/b.go:31:6-8: defined here as ```go
|
||||||
S2 struct {
|
S2 struct {
|
||||||
F1 string //@mark(S2F1, "F1")
|
F1 string //@mark(S2F1, "F1")
|
||||||
F2 int //@mark(S2F2, "F2")
|
F2 int //@mark(S2F2, "F2")
|
||||||
@ -211,14 +263,14 @@ S2 struct {
|
|||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 14,
|
"line": 31,
|
||||||
"column": 6,
|
"column": 6,
|
||||||
"offset": 326
|
"offset": 653
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 14,
|
"line": 31,
|
||||||
"column": 8,
|
"column": 8,
|
||||||
"offset": 328
|
"offset": 655
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nS2 struct {\n\tF1 string //@mark(S2F1, \"F1\")\n\tF2 int //@mark(S2F2, \"F2\")\n\t*a.A //@godef(\"A\", AString),godef(\"a\",AImport)\n}\n```\n\n[`b.S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2)"
|
"description": "```go\nS2 struct {\n\tF1 string //@mark(S2F1, \"F1\")\n\tF2 int //@mark(S2F2, \"F2\")\n\t*a.A //@godef(\"A\", AString),godef(\"a\",AImport)\n}\n```\n\n[`b.S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2)"
|
||||||
@ -235,7 +287,7 @@ S2 struct {
|
|||||||
|
|
||||||
[`b.S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2)
|
[`b.S2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2)
|
||||||
-- S2F1-definition --
|
-- S2F1-definition --
|
||||||
godef/b/b.go:15:2-4: defined here as ```go
|
godef/b/b.go:32:2-4: defined here as ```go
|
||||||
field F1 string
|
field F1 string
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -247,14 +299,14 @@ field F1 string
|
|||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 15,
|
"line": 32,
|
||||||
"column": 2,
|
"column": 2,
|
||||||
"offset": 345
|
"offset": 672
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 15,
|
"line": 32,
|
||||||
"column": 4,
|
"column": 4,
|
||||||
"offset": 347
|
"offset": 674
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nfield F1 string\n```\n\n[`(b.S2).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2.F1)\n\n\\@mark\\(S2F1, \\\"F1\\\"\\)"
|
"description": "```go\nfield F1 string\n```\n\n[`(b.S2).F1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2.F1)\n\n\\@mark\\(S2F1, \\\"F1\\\"\\)"
|
||||||
@ -269,11 +321,11 @@ field F1 string
|
|||||||
|
|
||||||
\@mark\(S2F1, \"F1\"\)
|
\@mark\(S2F1, \"F1\"\)
|
||||||
-- S2F2-definition --
|
-- S2F2-definition --
|
||||||
godef/b/b.go:16:2-4: defined here as ```go
|
godef/b/b.go:33:2-4: defined here as ```go
|
||||||
field F2 int
|
field F2 int
|
||||||
```
|
```
|
||||||
|
|
||||||
[`(b.S1).F2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.F2)
|
[`(b.S2).F2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2.F2)
|
||||||
|
|
||||||
\@mark\(S2F2, \"F2\"\)
|
\@mark\(S2F2, \"F2\"\)
|
||||||
-- S2F2-definition-json --
|
-- S2F2-definition-json --
|
||||||
@ -281,17 +333,17 @@ field F2 int
|
|||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 16,
|
"line": 33,
|
||||||
"column": 2,
|
"column": 2,
|
||||||
"offset": 378
|
"offset": 705
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 16,
|
"line": 33,
|
||||||
"column": 4,
|
"column": 4,
|
||||||
"offset": 380
|
"offset": 707
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nfield F2 int\n```\n\n[`(b.S1).F2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.F2)\n\n\\@mark\\(S2F2, \\\"F2\\\"\\)"
|
"description": "```go\nfield F2 int\n```\n\n[`(b.S2).F2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2.F2)\n\n\\@mark\\(S2F2, \\\"F2\\\"\\)"
|
||||||
}
|
}
|
||||||
|
|
||||||
-- S2F2-hover --
|
-- S2F2-hover --
|
||||||
@ -299,11 +351,11 @@ field F2 int
|
|||||||
field F2 int
|
field F2 int
|
||||||
```
|
```
|
||||||
|
|
||||||
[`(b.S1).F2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1.F2)
|
[`(b.S2).F2` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S2.F2)
|
||||||
|
|
||||||
\@mark\(S2F2, \"F2\"\)
|
\@mark\(S2F2, \"F2\"\)
|
||||||
-- bX-definition --
|
-- bX-definition --
|
||||||
godef/b/b.go:37:7-8: defined here as ```go
|
godef/b/b.go:54:7-8: defined here as ```go
|
||||||
const X untyped int = 0
|
const X untyped int = 0
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -315,14 +367,14 @@ const X untyped int = 0
|
|||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 37,
|
"line": 54,
|
||||||
"column": 7,
|
"column": 7,
|
||||||
"offset": 813
|
"offset": 1140
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 37,
|
"line": 54,
|
||||||
"column": 8,
|
"column": 8,
|
||||||
"offset": 814
|
"offset": 1141
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nconst X untyped int = 0\n```\n\n[`b.X` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#X)\n\n\\@mark\\(bX, \\\"X\\\"\\),godef\\(\\\"X\\\", bX\\)"
|
"description": "```go\nconst X untyped int = 0\n```\n\n[`b.X` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#X)\n\n\\@mark\\(bX, \\\"X\\\"\\),godef\\(\\\"X\\\", bX\\)"
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
-- S1-definition --
|
-- S1-definition --
|
||||||
godef/b/b.go:8:6-8: defined here as ```go
|
godef/b/b.go:25:6-8: defined here as ```go
|
||||||
S1 struct {
|
S1 struct {
|
||||||
F1 int //@mark(S1F1, "F1")
|
F1 int //@mark(S1F1, "F1")
|
||||||
S2 //@godef("S2", S2), mark(S1S2, "S2")
|
S2 //@godef("S2", S2),mark(S1S2, "S2")
|
||||||
a.A //@godef("A", AString)
|
a.A //@godef("A", AString)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -13,31 +13,31 @@ S1 struct {
|
|||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 8,
|
"line": 25,
|
||||||
"column": 6,
|
"column": 6,
|
||||||
"offset": 193
|
"offset": 521
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 8,
|
"line": 25,
|
||||||
"column": 8,
|
"column": 8,
|
||||||
"offset": 195
|
"offset": 523
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nS1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2), mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", AString)\n}\n```\n\n[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1)"
|
"description": "```go\nS1 struct {\n\tF1 int //@mark(S1F1, \"F1\")\n\tS2 //@godef(\"S2\", S2),mark(S1S2, \"S2\")\n\ta.A //@godef(\"A\", AString)\n}\n```\n\n[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1)"
|
||||||
}
|
}
|
||||||
|
|
||||||
-- S1-hover --
|
-- S1-hover --
|
||||||
```go
|
```go
|
||||||
S1 struct {
|
S1 struct {
|
||||||
F1 int //@mark(S1F1, "F1")
|
F1 int //@mark(S1F1, "F1")
|
||||||
S2 //@godef("S2", S2), mark(S1S2, "S2")
|
S2 //@godef("S2", S2),mark(S1S2, "S2")
|
||||||
a.A //@godef("A", AString)
|
a.A //@godef("A", AString)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1)
|
[`b.S1` on pkg.go.dev](https://pkg.go.dev/golang.org/x/tools/internal/lsp/godef/b#S1)
|
||||||
-- S1F1-definition --
|
-- S1F1-definition --
|
||||||
godef/b/b.go:9:2-4: defined here as ```go
|
godef/b/b.go:26:2-4: defined here as ```go
|
||||||
field F1 int
|
field F1 int
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -49,14 +49,14 @@ field F1 int
|
|||||||
"span": {
|
"span": {
|
||||||
"uri": "file://godef/b/b.go",
|
"uri": "file://godef/b/b.go",
|
||||||
"start": {
|
"start": {
|
||||||
"line": 9,
|
"line": 26,
|
||||||
"column": 2,
|
"column": 2,
|
||||||
"offset": 212
|
"offset": 540
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 9,
|
"line": 26,
|
||||||
"column": 4,
|
"column": 4,
|
||||||
"offset": 214
|
"offset": 542
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"description": "```go\nfield F1 int\n```\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\\@mark\\(S1F1, \\\"F1\\\"\\)"
|
"description": "```go\nfield F1 int\n```\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\\@mark\\(S1F1, \\\"F1\\\"\\)"
|
||||||
|
2
internal/lsp/testdata/lsp/summary.txt.golden
vendored
2
internal/lsp/testdata/lsp/summary.txt.golden
vendored
@ -13,7 +13,7 @@ FormatCount = 6
|
|||||||
ImportCount = 8
|
ImportCount = 8
|
||||||
SuggestedFixCount = 31
|
SuggestedFixCount = 31
|
||||||
FunctionExtractionCount = 5
|
FunctionExtractionCount = 5
|
||||||
DefinitionsCount = 56
|
DefinitionsCount = 63
|
||||||
TypeDefinitionsCount = 2
|
TypeDefinitionsCount = 2
|
||||||
HighlightsCount = 69
|
HighlightsCount = 69
|
||||||
ReferencesCount = 11
|
ReferencesCount = 11
|
||||||
|
Loading…
Reference in New Issue
Block a user