github.com/v2fly/tools@v0.100.0/internal/lsp/source/completion/util.go (about)

     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.
     4  
     5  package completion
     6  
     7  import (
     8  	"go/ast"
     9  	"go/token"
    10  	"go/types"
    11  
    12  	"github.com/v2fly/tools/internal/lsp/diff"
    13  	"github.com/v2fly/tools/internal/lsp/protocol"
    14  	"github.com/v2fly/tools/internal/lsp/source"
    15  )
    16  
    17  // exprAtPos returns the index of the expression containing pos.
    18  func exprAtPos(pos token.Pos, args []ast.Expr) int {
    19  	for i, expr := range args {
    20  		if expr.Pos() <= pos && pos <= expr.End() {
    21  			return i
    22  		}
    23  	}
    24  	return len(args)
    25  }
    26  
    27  // eachField invokes fn for each field that can be selected from a
    28  // value of type T.
    29  func eachField(T types.Type, fn func(*types.Var)) {
    30  	// TODO(adonovan): this algorithm doesn't exclude ambiguous
    31  	// selections that match more than one field/method.
    32  	// types.NewSelectionSet should do that for us.
    33  
    34  	// for termination on recursive types
    35  	var seen map[*types.Struct]bool
    36  
    37  	var visit func(T types.Type)
    38  	visit = func(T types.Type) {
    39  		if T, ok := source.Deref(T).Underlying().(*types.Struct); ok {
    40  			if seen[T] {
    41  				return
    42  			}
    43  
    44  			for i := 0; i < T.NumFields(); i++ {
    45  				f := T.Field(i)
    46  				fn(f)
    47  				if f.Anonymous() {
    48  					if seen == nil {
    49  						// Lazily create "seen" since it is only needed for
    50  						// embedded structs.
    51  						seen = make(map[*types.Struct]bool)
    52  					}
    53  					seen[T] = true
    54  					visit(f.Type())
    55  				}
    56  			}
    57  		}
    58  	}
    59  	visit(T)
    60  }
    61  
    62  // typeIsValid reports whether typ doesn't contain any Invalid types.
    63  func typeIsValid(typ types.Type) bool {
    64  	// Check named types separately, because we don't want
    65  	// to call Underlying() on them to avoid problems with recursive types.
    66  	if _, ok := typ.(*types.Named); ok {
    67  		return true
    68  	}
    69  
    70  	switch typ := typ.Underlying().(type) {
    71  	case *types.Basic:
    72  		return typ.Kind() != types.Invalid
    73  	case *types.Array:
    74  		return typeIsValid(typ.Elem())
    75  	case *types.Slice:
    76  		return typeIsValid(typ.Elem())
    77  	case *types.Pointer:
    78  		return typeIsValid(typ.Elem())
    79  	case *types.Map:
    80  		return typeIsValid(typ.Key()) && typeIsValid(typ.Elem())
    81  	case *types.Chan:
    82  		return typeIsValid(typ.Elem())
    83  	case *types.Signature:
    84  		return typeIsValid(typ.Params()) && typeIsValid(typ.Results())
    85  	case *types.Tuple:
    86  		for i := 0; i < typ.Len(); i++ {
    87  			if !typeIsValid(typ.At(i).Type()) {
    88  				return false
    89  			}
    90  		}
    91  		return true
    92  	case *types.Struct, *types.Interface:
    93  		// Don't bother checking structs, interfaces for validity.
    94  		return true
    95  	default:
    96  		return false
    97  	}
    98  }
    99  
   100  // resolveInvalid traverses the node of the AST that defines the scope
   101  // containing the declaration of obj, and attempts to find a user-friendly
   102  // name for its invalid type. The resulting Object and its Type are fake.
   103  func resolveInvalid(fset *token.FileSet, obj types.Object, node ast.Node, info *types.Info) types.Object {
   104  	var resultExpr ast.Expr
   105  	ast.Inspect(node, func(node ast.Node) bool {
   106  		switch n := node.(type) {
   107  		case *ast.ValueSpec:
   108  			for _, name := range n.Names {
   109  				if info.Defs[name] == obj {
   110  					resultExpr = n.Type
   111  				}
   112  			}
   113  			return false
   114  		case *ast.Field: // This case handles parameters and results of a FuncDecl or FuncLit.
   115  			for _, name := range n.Names {
   116  				if info.Defs[name] == obj {
   117  					resultExpr = n.Type
   118  				}
   119  			}
   120  			return false
   121  		default:
   122  			return true
   123  		}
   124  	})
   125  	// Construct a fake type for the object and return a fake object with this type.
   126  	typename := source.FormatNode(fset, resultExpr)
   127  	typ := types.NewNamed(types.NewTypeName(token.NoPos, obj.Pkg(), typename, nil), types.Typ[types.Invalid], nil)
   128  	return types.NewVar(obj.Pos(), obj.Pkg(), obj.Name(), typ)
   129  }
   130  
   131  func isPointer(T types.Type) bool {
   132  	_, ok := T.(*types.Pointer)
   133  	return ok
   134  }
   135  
   136  func isVar(obj types.Object) bool {
   137  	_, ok := obj.(*types.Var)
   138  	return ok
   139  }
   140  
   141  func isTypeName(obj types.Object) bool {
   142  	_, ok := obj.(*types.TypeName)
   143  	return ok
   144  }
   145  
   146  func isFunc(obj types.Object) bool {
   147  	_, ok := obj.(*types.Func)
   148  	return ok
   149  }
   150  
   151  func isEmptyInterface(T types.Type) bool {
   152  	intf, _ := T.(*types.Interface)
   153  	return intf != nil && intf.NumMethods() == 0
   154  }
   155  
   156  func isUntyped(T types.Type) bool {
   157  	if basic, ok := T.(*types.Basic); ok {
   158  		return basic.Info()&types.IsUntyped > 0
   159  	}
   160  	return false
   161  }
   162  
   163  func isPkgName(obj types.Object) bool {
   164  	_, ok := obj.(*types.PkgName)
   165  	return ok
   166  }
   167  
   168  func isASTFile(n ast.Node) bool {
   169  	_, ok := n.(*ast.File)
   170  	return ok
   171  }
   172  
   173  func deslice(T types.Type) types.Type {
   174  	if slice, ok := T.Underlying().(*types.Slice); ok {
   175  		return slice.Elem()
   176  	}
   177  	return nil
   178  }
   179  
   180  // isSelector returns the enclosing *ast.SelectorExpr when pos is in the
   181  // selector.
   182  func enclosingSelector(path []ast.Node, pos token.Pos) *ast.SelectorExpr {
   183  	if len(path) == 0 {
   184  		return nil
   185  	}
   186  
   187  	if sel, ok := path[0].(*ast.SelectorExpr); ok {
   188  		return sel
   189  	}
   190  
   191  	if _, ok := path[0].(*ast.Ident); ok && len(path) > 1 {
   192  		if sel, ok := path[1].(*ast.SelectorExpr); ok && pos >= sel.Sel.Pos() {
   193  			return sel
   194  		}
   195  	}
   196  
   197  	return nil
   198  }
   199  
   200  // enclosingDeclLHS returns LHS idents from containing value spec or
   201  // assign statement.
   202  func enclosingDeclLHS(path []ast.Node) []*ast.Ident {
   203  	for _, n := range path {
   204  		switch n := n.(type) {
   205  		case *ast.ValueSpec:
   206  			return n.Names
   207  		case *ast.AssignStmt:
   208  			ids := make([]*ast.Ident, 0, len(n.Lhs))
   209  			for _, e := range n.Lhs {
   210  				if id, ok := e.(*ast.Ident); ok {
   211  					ids = append(ids, id)
   212  				}
   213  			}
   214  			return ids
   215  		}
   216  	}
   217  
   218  	return nil
   219  }
   220  
   221  // exprObj returns the types.Object associated with the *ast.Ident or
   222  // *ast.SelectorExpr e.
   223  func exprObj(info *types.Info, e ast.Expr) types.Object {
   224  	var ident *ast.Ident
   225  	switch expr := e.(type) {
   226  	case *ast.Ident:
   227  		ident = expr
   228  	case *ast.SelectorExpr:
   229  		ident = expr.Sel
   230  	default:
   231  		return nil
   232  	}
   233  
   234  	return info.ObjectOf(ident)
   235  }
   236  
   237  // typeConversion returns the type being converted to if call is a type
   238  // conversion expression.
   239  func typeConversion(call *ast.CallExpr, info *types.Info) types.Type {
   240  	// Type conversion (e.g. "float64(foo)").
   241  	if fun, _ := exprObj(info, call.Fun).(*types.TypeName); fun != nil {
   242  		return fun.Type()
   243  	}
   244  
   245  	return nil
   246  }
   247  
   248  // fieldsAccessible returns whether s has at least one field accessible by p.
   249  func fieldsAccessible(s *types.Struct, p *types.Package) bool {
   250  	for i := 0; i < s.NumFields(); i++ {
   251  		f := s.Field(i)
   252  		if f.Exported() || f.Pkg() == p {
   253  			return true
   254  		}
   255  	}
   256  	return false
   257  }
   258  
   259  // prevStmt returns the statement that precedes the statement containing pos.
   260  // For example:
   261  //
   262  //     foo := 1
   263  //     bar(1 + 2<>)
   264  //
   265  // If "<>" is pos, prevStmt returns "foo := 1"
   266  func prevStmt(pos token.Pos, path []ast.Node) ast.Stmt {
   267  	var blockLines []ast.Stmt
   268  	for i := 0; i < len(path) && blockLines == nil; i++ {
   269  		switch n := path[i].(type) {
   270  		case *ast.BlockStmt:
   271  			blockLines = n.List
   272  		case *ast.CommClause:
   273  			blockLines = n.Body
   274  		case *ast.CaseClause:
   275  			blockLines = n.Body
   276  		}
   277  	}
   278  
   279  	for i := len(blockLines) - 1; i >= 0; i-- {
   280  		if blockLines[i].End() < pos {
   281  			return blockLines[i]
   282  		}
   283  	}
   284  
   285  	return nil
   286  }
   287  
   288  // formatZeroValue produces Go code representing the zero value of T. It
   289  // returns the empty string if T is invalid.
   290  func formatZeroValue(T types.Type, qf types.Qualifier) string {
   291  	switch u := T.Underlying().(type) {
   292  	case *types.Basic:
   293  		switch {
   294  		case u.Info()&types.IsNumeric > 0:
   295  			return "0"
   296  		case u.Info()&types.IsString > 0:
   297  			return `""`
   298  		case u.Info()&types.IsBoolean > 0:
   299  			return "false"
   300  		default:
   301  			return ""
   302  		}
   303  	case *types.Pointer, *types.Interface, *types.Chan, *types.Map, *types.Slice, *types.Signature:
   304  		return "nil"
   305  	default:
   306  		return types.TypeString(T, qf) + "{}"
   307  	}
   308  }
   309  
   310  // isBasicKind returns whether t is a basic type of kind k.
   311  func isBasicKind(t types.Type, k types.BasicInfo) bool {
   312  	b, _ := t.Underlying().(*types.Basic)
   313  	return b != nil && b.Info()&k > 0
   314  }
   315  
   316  func (c *completer) editText(from, to token.Pos, newText string) ([]protocol.TextEdit, error) {
   317  	rng := source.NewMappedRange(c.snapshot.FileSet(), c.mapper, from, to)
   318  	spn, err := rng.Span()
   319  	if err != nil {
   320  		return nil, err
   321  	}
   322  	return source.ToProtocolEdits(c.mapper, []diff.TextEdit{{
   323  		Span:    spn,
   324  		NewText: newText,
   325  	}})
   326  }