mirror of
https://github.com/golang/go
synced 2024-11-18 16:54:43 -07:00
c42aa19e51
Tweak a few things so that unnamed, non-basic types are offered as completions in certain cases: var _ []int = make(<>) // now properly suggests "[]int" I also fixed type related keywords to not be offered if there is an expected type: var _ *int = new(<>) // don't offer "func", etc. There are still some cases that don't work properly. For example: var _ [][]int = make([]<>) // doesn't offer "[]int" This would be harder to fix given the way things currently work. Fixes golang/go#40275, golang/go#40274. Change-Id: I2577d5863d4757845ad3ff7dbb125106b649a6b6 Reviewed-on: https://go-review.googlesource.com/c/tools/+/246360 Run-TryBot: Muir Manders <muir@mnd.rs> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Rebecca Stambler <rstambler@golang.org>
124 lines
3.1 KiB
Go
124 lines
3.1 KiB
Go
// 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 source
|
|
|
|
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)
|
|
|
|
// Maintain any type name inference from our parent's context.
|
|
inf = candidateInference{typeName: parentInf.typeName}
|
|
)
|
|
|
|
switch obj.Name() {
|
|
case "append":
|
|
if parentInf.objType == nil {
|
|
break
|
|
}
|
|
|
|
inf.objType = parentInf.objType
|
|
|
|
if exprIdx > 0 {
|
|
inf.objType = deslice(inf.objType)
|
|
// Check if we are completing the variadic append() param.
|
|
inf.variadic = exprIdx == 1 && len(call.Args) <= 2
|
|
}
|
|
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
|
|
}
|