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 func enclosingValueSpec(path []ast.Node) *ast.ValueSpec {
199 for _, n := range path {
200 if vs, ok := n.(*ast.ValueSpec); ok {
208 // exprObj returns the types.Object associated with the *ast.Ident or
209 // *ast.SelectorExpr e.
210 func exprObj(info *types.Info, e ast.Expr) types.Object {
212 switch expr := e.(type) {
215 case *ast.SelectorExpr:
221 return info.ObjectOf(ident)
224 // typeConversion returns the type being converted to if call is a type
225 // conversion expression.
226 func typeConversion(call *ast.CallExpr, info *types.Info) types.Type {
227 // Type conversion (e.g. "float64(foo)").
228 if fun, _ := exprObj(info, call.Fun).(*types.TypeName); fun != nil {
235 // fieldsAccessible returns whether s has at least one field accessible by p.
236 func fieldsAccessible(s *types.Struct, p *types.Package) bool {
237 for i := 0; i < s.NumFields(); i++ {
239 if f.Exported() || f.Pkg() == p {
246 // prevStmt returns the statement that precedes the statement containing pos.
252 // If "<>" is pos, prevStmt returns "foo := 1"
253 func prevStmt(pos token.Pos, path []ast.Node) ast.Stmt {
254 var blockLines []ast.Stmt
255 for i := 0; i < len(path) && blockLines == nil; i++ {
256 switch n := path[i].(type) {
259 case *ast.CommClause:
261 case *ast.CaseClause:
266 for i := len(blockLines) - 1; i >= 0; i-- {
267 if blockLines[i].End() < pos {
275 // formatZeroValue produces Go code representing the zero value of T. It
276 // returns the empty string if T is invalid.
277 func formatZeroValue(T types.Type, qf types.Qualifier) string {
278 switch u := T.Underlying().(type) {
281 case u.Info()&types.IsNumeric > 0:
283 case u.Info()&types.IsString > 0:
285 case u.Info()&types.IsBoolean > 0:
290 case *types.Pointer, *types.Interface, *types.Chan, *types.Map, *types.Slice, *types.Signature:
293 return types.TypeString(T, qf) + "{}"