1 // Copyright 2020 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.
12 "golang.org/x/tools/internal/lsp/source"
15 // exprAtPos returns the index of the expression containing pos.
16 func exprAtPos(pos token.Pos, args []ast.Expr) int {
17 for i, expr := range args {
18 if expr.Pos() <= pos && pos <= expr.End() {
25 // eachField invokes fn for each field that can be selected from a
27 func eachField(T types.Type, fn func(*types.Var)) {
28 // TODO(adonovan): this algorithm doesn't exclude ambiguous
29 // selections that match more than one field/method.
30 // types.NewSelectionSet should do that for us.
32 // for termination on recursive types
33 var seen map[*types.Struct]bool
35 var visit func(T types.Type)
36 visit = func(T types.Type) {
37 if T, ok := source.Deref(T).Underlying().(*types.Struct); ok {
42 for i := 0; i < T.NumFields(); i++ {
47 // Lazily create "seen" since it is only needed for
49 seen = make(map[*types.Struct]bool)
60 // typeIsValid reports whether typ doesn't contain any Invalid types.
61 func typeIsValid(typ types.Type) bool {
62 // Check named types separately, because we don't want
63 // to call Underlying() on them to avoid problems with recursive types.
64 if _, ok := typ.(*types.Named); ok {
68 switch typ := typ.Underlying().(type) {
70 return typ.Kind() != types.Invalid
72 return typeIsValid(typ.Elem())
74 return typeIsValid(typ.Elem())
76 return typeIsValid(typ.Elem())
78 return typeIsValid(typ.Key()) && typeIsValid(typ.Elem())
80 return typeIsValid(typ.Elem())
81 case *types.Signature:
82 return typeIsValid(typ.Params()) && typeIsValid(typ.Results())
84 for i := 0; i < typ.Len(); i++ {
85 if !typeIsValid(typ.At(i).Type()) {
90 case *types.Struct, *types.Interface:
91 // Don't bother checking structs, interfaces for validity.
98 // resolveInvalid traverses the node of the AST that defines the scope
99 // containing the declaration of obj, and attempts to find a user-friendly
100 // name for its invalid type. The resulting Object and its Type are fake.
101 func resolveInvalid(fset *token.FileSet, obj types.Object, node ast.Node, info *types.Info) types.Object {
102 var resultExpr ast.Expr
103 ast.Inspect(node, func(node ast.Node) bool {
104 switch n := node.(type) {
106 for _, name := range n.Names {
107 if info.Defs[name] == obj {
112 case *ast.Field: // This case handles parameters and results of a FuncDecl or FuncLit.
113 for _, name := range n.Names {
114 if info.Defs[name] == obj {
123 // Construct a fake type for the object and return a fake object with this type.
124 typename := source.FormatNode(fset, resultExpr)
125 typ := types.NewNamed(types.NewTypeName(token.NoPos, obj.Pkg(), typename, nil), types.Typ[types.Invalid], nil)
126 return types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), typ)
129 func isPointer(T types.Type) bool {
130 _, ok := T.(*types.Pointer)
134 func isVar(obj types.Object) bool {
135 _, ok := obj.(*types.Var)
139 func isTypeName(obj types.Object) bool {
140 _, ok := obj.(*types.TypeName)
144 func isFunc(obj types.Object) bool {
145 _, ok := obj.(*types.Func)
149 func isEmptyInterface(T types.Type) bool {
150 intf, _ := T.(*types.Interface)
151 return intf != nil && intf.NumMethods() == 0
154 func isUntyped(T types.Type) bool {
155 if basic, ok := T.(*types.Basic); ok {
156 return basic.Info()&types.IsUntyped > 0
161 func isPkgName(obj types.Object) bool {
162 _, ok := obj.(*types.PkgName)
166 func isASTFile(n ast.Node) bool {
167 _, ok := n.(*ast.File)
171 func deslice(T types.Type) types.Type {
172 if slice, ok := T.Underlying().(*types.Slice); ok {
178 // isSelector returns the enclosing *ast.SelectorExpr when pos is in the
180 func enclosingSelector(path []ast.Node, pos token.Pos) *ast.SelectorExpr {
185 if sel, ok := path[0].(*ast.SelectorExpr); ok {
189 if _, ok := path[0].(*ast.Ident); ok && len(path) > 1 {
190 if sel, ok := path[1].(*ast.SelectorExpr); ok && pos >= sel.Sel.Pos() {
198 // enclosingDeclLHS returns LHS idents from containing value spec or
200 func enclosingDeclLHS(path []ast.Node) []*ast.Ident {
201 for _, n := range path {
202 switch n := n.(type) {
205 case *ast.AssignStmt:
206 ids := make([]*ast.Ident, 0, len(n.Lhs))
207 for _, e := range n.Lhs {
208 if id, ok := e.(*ast.Ident); ok {
209 ids = append(ids, id)
219 // exprObj returns the types.Object associated with the *ast.Ident or
220 // *ast.SelectorExpr e.
221 func exprObj(info *types.Info, e ast.Expr) types.Object {
223 switch expr := e.(type) {
226 case *ast.SelectorExpr:
232 return info.ObjectOf(ident)
235 // typeConversion returns the type being converted to if call is a type
236 // conversion expression.
237 func typeConversion(call *ast.CallExpr, info *types.Info) types.Type {
238 // Type conversion (e.g. "float64(foo)").
239 if fun, _ := exprObj(info, call.Fun).(*types.TypeName); fun != nil {
246 // fieldsAccessible returns whether s has at least one field accessible by p.
247 func fieldsAccessible(s *types.Struct, p *types.Package) bool {
248 for i := 0; i < s.NumFields(); i++ {
250 if f.Exported() || f.Pkg() == p {
257 // prevStmt returns the statement that precedes the statement containing pos.
263 // If "<>" is pos, prevStmt returns "foo := 1"
264 func prevStmt(pos token.Pos, path []ast.Node) ast.Stmt {
265 var blockLines []ast.Stmt
266 for i := 0; i < len(path) && blockLines == nil; i++ {
267 switch n := path[i].(type) {
270 case *ast.CommClause:
272 case *ast.CaseClause:
277 for i := len(blockLines) - 1; i >= 0; i-- {
278 if blockLines[i].End() < pos {
286 // formatZeroValue produces Go code representing the zero value of T. It
287 // returns the empty string if T is invalid.
288 func formatZeroValue(T types.Type, qf types.Qualifier) string {
289 switch u := T.Underlying().(type) {
292 case u.Info()&types.IsNumeric > 0:
294 case u.Info()&types.IsString > 0:
296 case u.Info()&types.IsBoolean > 0:
301 case *types.Pointer, *types.Interface, *types.Chan, *types.Map, *types.Slice, *types.Signature:
304 return types.TypeString(T, qf) + "{}"
308 // isBasicKind returns whether t is a basic type of kind k.
309 func isBasicKind(t types.Type, k types.BasicInfo) bool {
310 b, _ := t.Underlying().(*types.Basic)
311 return b != nil && b.Info()&k > 0