mirror of https://github.com/golang/go.git
lsp/completion: support completing to Elem() types
For array, slice, maps and chan candidates, we now support
transforming them to their element type in completions. For example:
var m map[string]int
var _ int = m<>
At <> we complete to "m[]" because we see that the map value type
matches our expected type.
Fixes golang/go#46045.
Change-Id: Ibee088550193a53744f93217cc365f67f301ae90
Reviewed-on: https://go-review.googlesource.com/c/tools/+/323451
Run-TryBot: Muir Manders <muir@mnd.rs>
gopls-CI: kokoro <noreply+kokoro@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Cherry Mui <cherryyz@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
16e5f55009
commit
e0b9cf74f6
|
|
@ -73,6 +73,9 @@ func (c *completer) builtinArgType(obj types.Object, call *ast.CallExpr, parentI
|
|||
// Infer first append() arg type as apparent return type of
|
||||
// append().
|
||||
inf.objType = parentInf.objType
|
||||
if parentInf.variadic {
|
||||
inf.objType = types.NewSlice(inf.objType)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1777,6 +1777,7 @@ const (
|
|||
invoke // make a function call: "()" in "foo()"
|
||||
takeSlice // take slice of array: "[:]" in "foo[:]"
|
||||
takeDotDotDot // turn slice into variadic args: "..." in "foo..."
|
||||
index // index into slice/array: "[0]" in "foo[0]"
|
||||
)
|
||||
|
||||
type objKind int
|
||||
|
|
@ -2404,6 +2405,9 @@ func derivableTypes(t types.Type, addressable bool, f func(t types.Type, address
|
|||
return true
|
||||
}
|
||||
case *types.Array:
|
||||
if f(t.Elem(), true, index) {
|
||||
return true
|
||||
}
|
||||
// Try converting array to slice.
|
||||
if f(types.NewSlice(t.Elem()), false, takeSlice) {
|
||||
return true
|
||||
|
|
@ -2412,6 +2416,18 @@ func derivableTypes(t types.Type, addressable bool, f func(t types.Type, address
|
|||
if f(t.Elem(), false, dereference) {
|
||||
return true
|
||||
}
|
||||
case *types.Slice:
|
||||
if f(t.Elem(), true, index) {
|
||||
return true
|
||||
}
|
||||
case *types.Map:
|
||||
if f(t.Elem(), false, index) {
|
||||
return true
|
||||
}
|
||||
case *types.Chan:
|
||||
if f(t.Elem(), false, chanRead) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Check if c is addressable and a pointer to c matches our type inference.
|
||||
|
|
|
|||
|
|
@ -260,6 +260,12 @@ func (c *completer) addCandidate(ctx context.Context, cand *candidate) {
|
|||
cand.score *= 1.1
|
||||
}
|
||||
|
||||
// Slight penalty for index modifier (e.g. changing "foo" to
|
||||
// "foo[]") to curb false positives.
|
||||
if cand.hasMod(index) {
|
||||
cand.score *= 0.9
|
||||
}
|
||||
|
||||
// Favor shallow matches by lowering score according to depth.
|
||||
cand.score -= cand.score * c.deepState.scorePenalty(cand)
|
||||
|
||||
|
|
|
|||
|
|
@ -132,6 +132,10 @@ Suffixes:
|
|||
suffix += "[:]"
|
||||
case takeDotDotDot:
|
||||
suffix += "..."
|
||||
case index:
|
||||
snip.WriteText("[")
|
||||
snip.WritePlaceholder(nil)
|
||||
snip.WriteText("]")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
CallHierarchyCount = 2
|
||||
CodeLensCount = 5
|
||||
CompletionsCount = 265
|
||||
CompletionSnippetCount = 102
|
||||
CompletionSnippetCount = 103
|
||||
UnimportedCompletionsCount = 5
|
||||
DeepCompletionsCount = 5
|
||||
FuzzyCompletionsCount = 8
|
||||
|
|
|
|||
|
|
@ -13,3 +13,9 @@ func fooPtr() *int { //@item(modFooPtr, "fooPtr", "func() *int", "func")
|
|||
func _() {
|
||||
var _ int = foo //@snippet(" //", modFooFunc, "fooFunc()()", "fooFunc()()"),snippet(" //", modFooPtr, "*fooPtr()", "*fooPtr()")
|
||||
}
|
||||
|
||||
func _() {
|
||||
var m map[int][]chan int //@item(modMapChanPtr, "m", "map[int]chan *int", "var")
|
||||
|
||||
var _ int = m //@snippet(" //", modMapChanPtr, "<-m[${1:}][${2:}]", "<-m[${1:}][${2:}]")
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue