+++ /dev/null
-// Copyright 2020 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package completion
-
-import (
- "context"
- "go/ast"
- "go/types"
-)
-
-// builtinArgKind determines the expected object kind for a builtin
-// argument. It attempts to use the AST hints from builtin.go where
-// possible.
-func (c *completer) builtinArgKind(ctx context.Context, obj types.Object, call *ast.CallExpr) objKind {
- builtin, err := c.snapshot.BuiltinPackage(ctx)
- if err != nil {
- return 0
- }
- exprIdx := exprAtPos(c.pos, call.Args)
-
- builtinObj := builtin.Package.Scope.Lookup(obj.Name())
- if builtinObj == nil {
- return 0
- }
- decl, ok := builtinObj.Decl.(*ast.FuncDecl)
- if !ok || exprIdx >= len(decl.Type.Params.List) {
- return 0
- }
-
- switch ptyp := decl.Type.Params.List[exprIdx].Type.(type) {
- case *ast.ChanType:
- return kindChan
- case *ast.ArrayType:
- return kindSlice
- case *ast.MapType:
- return kindMap
- case *ast.Ident:
- switch ptyp.Name {
- case "Type":
- switch obj.Name() {
- case "make":
- return kindChan | kindSlice | kindMap
- case "len":
- return kindSlice | kindMap | kindArray | kindString | kindChan
- case "cap":
- return kindSlice | kindArray | kindChan
- }
- }
- }
-
- return 0
-}
-
-// builtinArgType infers the type of an argument to a builtin
-// function. parentInf is the inferred type info for the builtin
-// call's parent node.
-func (c *completer) builtinArgType(obj types.Object, call *ast.CallExpr, parentInf candidateInference) candidateInference {
- var (
- exprIdx = exprAtPos(c.pos, call.Args)
-
- // Propagate certain properties from our parent's inference.
- inf = candidateInference{
- typeName: parentInf.typeName,
- modifiers: parentInf.modifiers,
- }
- )
-
- switch obj.Name() {
- case "append":
- if parentInf.objType == nil {
- break
- }
-
- inf.objType = parentInf.objType
-
- if exprIdx <= 0 {
- break
- }
-
- inf.objType = deslice(inf.objType)
-
- // Check if we are completing the variadic append() param.
- inf.variadic = exprIdx == 1 && len(call.Args) <= 2
-
- // Penalize the first append() argument as a candidate. You
- // don't normally append a slice to itself.
- if sliceChain := objChain(c.pkg.GetTypesInfo(), call.Args[0]); len(sliceChain) > 0 {
- inf.penalized = append(inf.penalized, penalizedObj{objChain: sliceChain, penalty: 0.9})
- }
- case "delete":
- if exprIdx > 0 && len(call.Args) > 0 {
- // Try to fill in expected type of map key.
- firstArgType := c.pkg.GetTypesInfo().TypeOf(call.Args[0])
- if firstArgType != nil {
- if mt, ok := firstArgType.Underlying().(*types.Map); ok {
- inf.objType = mt.Key()
- }
- }
- }
- case "copy":
- var t1, t2 types.Type
- if len(call.Args) > 0 {
- t1 = c.pkg.GetTypesInfo().TypeOf(call.Args[0])
- if len(call.Args) > 1 {
- t2 = c.pkg.GetTypesInfo().TypeOf(call.Args[1])
- }
- }
-
- // Fill in expected type of either arg if the other is already present.
- if exprIdx == 1 && t1 != nil {
- inf.objType = t1
- } else if exprIdx == 0 && t2 != nil {
- inf.objType = t2
- }
- case "new":
- inf.typeName.wantTypeName = true
- if parentInf.objType != nil {
- // Expected type for "new" is the de-pointered parent type.
- if ptr, ok := parentInf.objType.Underlying().(*types.Pointer); ok {
- inf.objType = ptr.Elem()
- }
- }
- case "make":
- if exprIdx == 0 {
- inf.typeName.wantTypeName = true
- inf.objType = parentInf.objType
- } else {
- inf.objType = types.Typ[types.Int]
- }
- }
-
- return inf
-}