golang.org/x/tools/gopls@v0.15.3/internal/golang/completion/builtin.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 "context" 9 "go/ast" 10 "go/types" 11 ) 12 13 // builtinArgKind determines the expected object kind for a builtin 14 // argument. It attempts to use the AST hints from builtin.go where 15 // possible. 16 func (c *completer) builtinArgKind(ctx context.Context, obj types.Object, call *ast.CallExpr) objKind { 17 builtin, err := c.snapshot.BuiltinFile(ctx) 18 if err != nil { 19 return 0 20 } 21 exprIdx := exprAtPos(c.pos, call.Args) 22 23 builtinObj := builtin.File.Scope.Lookup(obj.Name()) 24 if builtinObj == nil { 25 return 0 26 } 27 decl, ok := builtinObj.Decl.(*ast.FuncDecl) 28 if !ok || exprIdx >= len(decl.Type.Params.List) { 29 return 0 30 } 31 32 switch ptyp := decl.Type.Params.List[exprIdx].Type.(type) { 33 case *ast.ChanType: 34 return kindChan 35 case *ast.ArrayType: 36 return kindSlice 37 case *ast.MapType: 38 return kindMap 39 case *ast.Ident: 40 switch ptyp.Name { 41 case "Type": 42 switch obj.Name() { 43 case "make": 44 return kindChan | kindSlice | kindMap 45 case "len": 46 return kindSlice | kindMap | kindArray | kindString | kindChan 47 case "cap": 48 return kindSlice | kindArray | kindChan 49 } 50 } 51 } 52 53 return 0 54 } 55 56 // builtinArgType infers the type of an argument to a builtin 57 // function. parentInf is the inferred type info for the builtin 58 // call's parent node. 59 func (c *completer) builtinArgType(obj types.Object, call *ast.CallExpr, parentInf candidateInference) candidateInference { 60 var ( 61 exprIdx = exprAtPos(c.pos, call.Args) 62 63 // Propagate certain properties from our parent's inference. 64 inf = candidateInference{ 65 typeName: parentInf.typeName, 66 modifiers: parentInf.modifiers, 67 } 68 ) 69 70 switch obj.Name() { 71 case "append": 72 if exprIdx <= 0 { 73 // Infer first append() arg type as apparent return type of 74 // append(). 75 inf.objType = parentInf.objType 76 if parentInf.variadic { 77 inf.objType = types.NewSlice(inf.objType) 78 } 79 break 80 } 81 82 // For non-initial append() args, infer slice type from the first 83 // append() arg, or from parent context. 84 if len(call.Args) > 0 { 85 inf.objType = c.pkg.GetTypesInfo().TypeOf(call.Args[0]) 86 } 87 if inf.objType == nil { 88 inf.objType = parentInf.objType 89 } 90 if inf.objType == nil { 91 break 92 } 93 94 inf.objType = deslice(inf.objType) 95 96 // Check if we are completing the variadic append() param. 97 inf.variadic = exprIdx == 1 && len(call.Args) <= 2 98 99 // Penalize the first append() argument as a candidate. You 100 // don't normally append a slice to itself. 101 if sliceChain := objChain(c.pkg.GetTypesInfo(), call.Args[0]); len(sliceChain) > 0 { 102 inf.penalized = append(inf.penalized, penalizedObj{objChain: sliceChain, penalty: 0.9}) 103 } 104 case "delete": 105 if exprIdx > 0 && len(call.Args) > 0 { 106 // Try to fill in expected type of map key. 107 firstArgType := c.pkg.GetTypesInfo().TypeOf(call.Args[0]) 108 if firstArgType != nil { 109 if mt, ok := firstArgType.Underlying().(*types.Map); ok { 110 inf.objType = mt.Key() 111 } 112 } 113 } 114 case "copy": 115 var t1, t2 types.Type 116 if len(call.Args) > 0 { 117 t1 = c.pkg.GetTypesInfo().TypeOf(call.Args[0]) 118 if len(call.Args) > 1 { 119 t2 = c.pkg.GetTypesInfo().TypeOf(call.Args[1]) 120 } 121 } 122 123 // Fill in expected type of either arg if the other is already present. 124 if exprIdx == 1 && t1 != nil { 125 inf.objType = t1 126 } else if exprIdx == 0 && t2 != nil { 127 inf.objType = t2 128 } 129 case "new": 130 inf.typeName.wantTypeName = true 131 if parentInf.objType != nil { 132 // Expected type for "new" is the de-pointered parent type. 133 if ptr, ok := parentInf.objType.Underlying().(*types.Pointer); ok { 134 inf.objType = ptr.Elem() 135 } 136 } 137 case "make": 138 if exprIdx == 0 { 139 inf.typeName.wantTypeName = true 140 inf.objType = parentInf.objType 141 } else { 142 inf.objType = types.Typ[types.UntypedInt] 143 } 144 } 145 146 return inf 147 }