golang.org/x/tools/gopls@v0.15.3/internal/golang/identifier.go (about) 1 // Copyright 2018 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. 4 5 package golang 6 7 import ( 8 "errors" 9 "go/ast" 10 "go/types" 11 ) 12 13 // ErrNoIdentFound is error returned when no identifier is found at a particular position 14 var ErrNoIdentFound = errors.New("no identifier found") 15 16 // inferredSignature determines the resolved non-generic signature for an 17 // identifier in an instantiation expression. 18 // 19 // If no such signature exists, it returns nil. 20 func inferredSignature(info *types.Info, id *ast.Ident) *types.Signature { 21 inst := info.Instances[id] 22 sig, _ := inst.Type.(*types.Signature) 23 return sig 24 } 25 26 func searchForEnclosing(info *types.Info, path []ast.Node) *types.TypeName { 27 for _, n := range path { 28 switch n := n.(type) { 29 case *ast.SelectorExpr: 30 if sel, ok := info.Selections[n]; ok { 31 recv := Deref(sel.Recv()) 32 33 // Keep track of the last exported type seen. 34 var exported *types.TypeName 35 if named, ok := recv.(*types.Named); ok && named.Obj().Exported() { 36 exported = named.Obj() 37 } 38 // We don't want the last element, as that's the field or 39 // method itself. 40 for _, index := range sel.Index()[:len(sel.Index())-1] { 41 if r, ok := recv.Underlying().(*types.Struct); ok { 42 recv = Deref(r.Field(index).Type()) 43 if named, ok := recv.(*types.Named); ok && named.Obj().Exported() { 44 exported = named.Obj() 45 } 46 } 47 } 48 return exported 49 } 50 } 51 } 52 return nil 53 } 54 55 // typeToObject returns the relevant type name for the given type, after 56 // unwrapping pointers, arrays, slices, channels, and function signatures with 57 // a single non-error result, and ignoring built-in named types. 58 func typeToObject(typ types.Type) *types.TypeName { 59 switch typ := typ.(type) { 60 case *types.Named: 61 // TODO(rfindley): this should use typeparams.NamedTypeOrigin. 62 return typ.Obj() 63 case *types.Pointer: 64 return typeToObject(typ.Elem()) 65 case *types.Array: 66 return typeToObject(typ.Elem()) 67 case *types.Slice: 68 return typeToObject(typ.Elem()) 69 case *types.Chan: 70 return typeToObject(typ.Elem()) 71 case *types.Signature: 72 // Try to find a return value of a named type. If there's only one 73 // such value, jump to its type definition. 74 var res *types.TypeName 75 76 results := typ.Results() 77 for i := 0; i < results.Len(); i++ { 78 obj := typeToObject(results.At(i).Type()) 79 if obj == nil || hasErrorType(obj) { 80 // Skip builtins. TODO(rfindley): should comparable be handled here as well? 81 continue 82 } 83 if res != nil { 84 // The function/method must have only one return value of a named type. 85 return nil 86 } 87 88 res = obj 89 } 90 return res 91 default: 92 return nil 93 } 94 } 95 96 func hasErrorType(obj types.Object) bool { 97 return types.IsInterface(obj.Type()) && obj.Pkg() == nil && obj.Name() == "error" 98 } 99 100 // typeSwitchImplicits returns all the implicit type switch objects that 101 // correspond to the leaf *ast.Ident. It also returns the original type 102 // associated with the identifier (outside of a case clause). 103 func typeSwitchImplicits(info *types.Info, path []ast.Node) ([]types.Object, types.Type) { 104 ident, _ := path[0].(*ast.Ident) 105 if ident == nil { 106 return nil, nil 107 } 108 109 var ( 110 ts *ast.TypeSwitchStmt 111 assign *ast.AssignStmt 112 cc *ast.CaseClause 113 obj = info.ObjectOf(ident) 114 ) 115 116 // Walk our ancestors to determine if our leaf ident refers to a 117 // type switch variable, e.g. the "a" from "switch a := b.(type)". 118 Outer: 119 for i := 1; i < len(path); i++ { 120 switch n := path[i].(type) { 121 case *ast.AssignStmt: 122 // Check if ident is the "a" in "a := foo.(type)". The "a" in 123 // this case has no types.Object, so check for ident equality. 124 if len(n.Lhs) == 1 && n.Lhs[0] == ident { 125 assign = n 126 } 127 case *ast.CaseClause: 128 // Check if ident is a use of "a" within a case clause. Each 129 // case clause implicitly maps "a" to a different types.Object, 130 // so check if ident's object is the case clause's implicit 131 // object. 132 if obj != nil && info.Implicits[n] == obj { 133 cc = n 134 } 135 case *ast.TypeSwitchStmt: 136 // Look for the type switch that owns our previously found 137 // *ast.AssignStmt or *ast.CaseClause. 138 if n.Assign == assign { 139 ts = n 140 break Outer 141 } 142 143 for _, stmt := range n.Body.List { 144 if stmt == cc { 145 ts = n 146 break Outer 147 } 148 } 149 } 150 } 151 if ts == nil { 152 return nil, nil 153 } 154 // Our leaf ident refers to a type switch variable. Fan out to the 155 // type switch's implicit case clause objects. 156 var objs []types.Object 157 for _, cc := range ts.Body.List { 158 if ccObj := info.Implicits[cc]; ccObj != nil { 159 objs = append(objs, ccObj) 160 } 161 } 162 // The right-hand side of a type switch should only have one 163 // element, and we need to track its type in order to generate 164 // hover information for implicit type switch variables. 165 var typ types.Type 166 if assign, ok := ts.Assign.(*ast.AssignStmt); ok && len(assign.Rhs) == 1 { 167 if rhs := assign.Rhs[0].(*ast.TypeAssertExpr); ok { 168 typ = info.TypeOf(rhs.X) 169 } 170 } 171 return objs, typ 172 }