internal/lsp/source: simplify Identifier.enclosing

Receiver base types are either *Interface or *Named, never *Struct.
Absent a comment, I don't know why we had handling for *Struct, so just
delete it.

We only care about the enclosing type if it is named, so track a
*TypeName rather than an arbitrary Type.

Change-Id: I729c85b935a35da429b975327b56d81dc56773cf
Reviewed-on: https://go-review.googlesource.com/c/tools/+/384696
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
Reviewed-by: Heschi Kreinick <heschi@google.com>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Robert Findley 2022-02-09 17:07:05 -05:00
parent 59f1f2c5a8
commit cda4201ef0
3 changed files with 33 additions and 28 deletions

View File

@ -329,37 +329,37 @@ func HoverIdentifier(ctx context.Context, i *IdentifierInfo) (*HoverInformation,
if !obj.Exported() {
return h, nil
}
var rTypeName string
var recvName string // receiver type name
switch obj := obj.(type) {
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 named, ok := i.enclosing.(*types.Named); ok {
rTypeName = named.Obj().Name()
}
if obj.IsField() && i.enclosing != nil {
recvName = i.enclosing.Name()
}
case *types.Func:
typ, ok := obj.Type().(*types.Signature)
if !ok {
return h, nil
// Note: this should never happen. go/types guarantees that the type of
// *Funcs are Signatures.
//
// TODO(rfindley): given a 'debug' mode, we should panic here.
return nil, fmt.Errorf("BUG: incorrect type %T for *Func", obj.Type())
}
if r := typ.Recv(); r != nil {
switch rtyp := Deref(r.Type()).(type) {
case *types.Struct:
rTypeName = r.Name()
case *types.Named:
if rtyp, _ := Deref(r.Type()).(*types.Named); rtyp != nil {
// If we have an unexported type, see if the enclosing type is
// exported (we may have an interface or struct we can link
// to). If not, don't show any link.
if !rtyp.Obj().Exported() {
if named, ok := i.enclosing.(*types.Named); ok && named.Obj().Exported() {
rTypeName = named.Obj().Name()
if i.enclosing != nil && i.enclosing.Exported() {
recvName = i.enclosing.Name()
} else {
return h, nil
}
} else {
rTypeName = rtyp.Obj().Name()
recvName = rtyp.Obj().Name()
}
}
}
@ -373,9 +373,9 @@ func HoverIdentifier(ctx context.Context, i *IdentifierInfo) (*HoverInformation,
if mod, version, ok := moduleAtVersion(h.LinkPath, i); ok {
h.LinkPath = strings.Replace(h.LinkPath, mod, mod+"@"+version, 1)
}
if rTypeName != "" {
h.LinkAnchor = fmt.Sprintf("%s.%s", rTypeName, obj.Name())
h.symbolName = fmt.Sprintf("(%s.%s).%s", obj.Pkg().Name(), rTypeName, obj.Name())
if recvName != "" {
h.LinkAnchor = fmt.Sprintf("%s.%s", recvName, obj.Name())
h.symbolName = fmt.Sprintf("(%s.%s).%s", obj.Pkg().Name(), recvName, obj.Name())
return h, nil
}
// For most cases, the link is "package/path#symbol".

View File

@ -39,9 +39,10 @@ type IdentifierInfo struct {
ident *ast.Ident
// 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
// For struct fields or embedded interfaces, enclosing is the object
// corresponding to the outer type declaration, if it is exported, for use in
// documentation links.
enclosing *types.TypeName
pkg Package
qf types.Qualifier
@ -375,7 +376,7 @@ func inferredSignature(info *types.Info, id *ast.Ident) *types.Signature {
return sig
}
func searchForEnclosing(info *types.Info, path []ast.Node) types.Type {
func searchForEnclosing(info *types.Info, path []ast.Node) *types.TypeName {
for _, n := range path {
switch n := n.(type) {
case *ast.SelectorExpr:
@ -383,9 +384,9 @@ func searchForEnclosing(info *types.Info, path []ast.Node) types.Type {
recv := Deref(sel.Recv())
// Keep track of the last exported type seen.
var exported types.Type
var exported *types.TypeName
if named, ok := recv.(*types.Named); ok && named.Obj().Exported() {
exported = named
exported = named.Obj()
}
// We don't want the last element, as that's the field or
// method itself.
@ -393,7 +394,7 @@ func searchForEnclosing(info *types.Info, path []ast.Node) types.Type {
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
exported = named.Obj()
}
}
}
@ -401,12 +402,16 @@ func searchForEnclosing(info *types.Info, path []ast.Node) types.Type {
}
case *ast.CompositeLit:
if t, ok := info.Types[n]; ok {
return t.Type
if named, _ := t.Type.(*types.Named); named != nil {
return named.Obj()
}
}
case *ast.TypeSpec:
if _, ok := n.Type.(*ast.StructType); ok {
if t, ok := info.Defs[n.Name]; ok {
return t.Type()
if tname, _ := t.(*types.TypeName); tname != nil {
return tname
}
}
}
}

View File

@ -83,14 +83,14 @@ func TestSearchForEnclosing(t *testing.T) {
if _, err = (*types.Config)(nil).Check("p", fset, []*ast.File{file}, info); err != nil {
t.Fatal(err)
}
typ := searchForEnclosing(info, path)
if typ == nil {
obj := searchForEnclosing(info, path)
if obj == nil {
if test.wantTypeName != "" {
t.Errorf("searchForEnclosing(...) = <nil>, want %q", test.wantTypeName)
}
return
}
if got := typ.(*types.Named).Obj().Name(); got != test.wantTypeName {
if got := obj.Name(); got != test.wantTypeName {
t.Errorf("searchForEnclosing(...) = %q, want %q", got, test.wantTypeName)
}
})