Skip to content

Commit e0b9cf7

Browse files
muirdmfindleyr
authored andcommitted
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>
1 parent 16e5f55 commit e0b9cf7

File tree

6 files changed

+36
-1
lines changed

6 files changed

+36
-1
lines changed

internal/lsp/source/completion/builtin.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ func (c *completer) builtinArgType(obj types.Object, call *ast.CallExpr, parentI
7373
// Infer first append() arg type as apparent return type of
7474
// append().
7575
inf.objType = parentInf.objType
76+
if parentInf.variadic {
77+
inf.objType = types.NewSlice(inf.objType)
78+
}
7679
break
7780
}
7881

internal/lsp/source/completion/completion.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1777,6 +1777,7 @@ const (
17771777
invoke // make a function call: "()" in "foo()"
17781778
takeSlice // take slice of array: "[:]" in "foo[:]"
17791779
takeDotDotDot // turn slice into variadic args: "..." in "foo..."
1780+
index // index into slice/array: "[0]" in "foo[0]"
17801781
)
17811782

17821783
type objKind int
@@ -2404,6 +2405,9 @@ func derivableTypes(t types.Type, addressable bool, f func(t types.Type, address
24042405
return true
24052406
}
24062407
case *types.Array:
2408+
if f(t.Elem(), true, index) {
2409+
return true
2410+
}
24072411
// Try converting array to slice.
24082412
if f(types.NewSlice(t.Elem()), false, takeSlice) {
24092413
return true
@@ -2412,6 +2416,18 @@ func derivableTypes(t types.Type, addressable bool, f func(t types.Type, address
24122416
if f(t.Elem(), false, dereference) {
24132417
return true
24142418
}
2419+
case *types.Slice:
2420+
if f(t.Elem(), true, index) {
2421+
return true
2422+
}
2423+
case *types.Map:
2424+
if f(t.Elem(), false, index) {
2425+
return true
2426+
}
2427+
case *types.Chan:
2428+
if f(t.Elem(), false, chanRead) {
2429+
return true
2430+
}
24152431
}
24162432

24172433
// Check if c is addressable and a pointer to c matches our type inference.

internal/lsp/source/completion/deep_completion.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,12 @@ func (c *completer) addCandidate(ctx context.Context, cand *candidate) {
260260
cand.score *= 1.1
261261
}
262262

263+
// Slight penalty for index modifier (e.g. changing "foo" to
264+
// "foo[]") to curb false positives.
265+
if cand.hasMod(index) {
266+
cand.score *= 0.9
267+
}
268+
263269
// Favor shallow matches by lowering score according to depth.
264270
cand.score -= cand.score * c.deepState.scorePenalty(cand)
265271

internal/lsp/source/completion/format.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ Suffixes:
132132
suffix += "[:]"
133133
case takeDotDotDot:
134134
suffix += "..."
135+
case index:
136+
snip.WriteText("[")
137+
snip.WritePlaceholder(nil)
138+
snip.WriteText("]")
135139
}
136140
}
137141

internal/lsp/testdata/summary.txt.golden

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
CallHierarchyCount = 2
33
CodeLensCount = 5
44
CompletionsCount = 265
5-
CompletionSnippetCount = 102
5+
CompletionSnippetCount = 103
66
UnimportedCompletionsCount = 5
77
DeepCompletionsCount = 5
88
FuzzyCompletionsCount = 8

internal/lsp/testdata/typemods/type_mods.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,9 @@ func fooPtr() *int { //@item(modFooPtr, "fooPtr", "func() *int", "func")
1313
func _() {
1414
var _ int = foo //@snippet(" //", modFooFunc, "fooFunc()()", "fooFunc()()"),snippet(" //", modFooPtr, "*fooPtr()", "*fooPtr()")
1515
}
16+
17+
func _() {
18+
var m map[int][]chan int //@item(modMapChanPtr, "m", "map[int]chan *int", "var")
19+
20+
var _ int = m //@snippet(" //", modMapChanPtr, "<-m[${1:}][${2:}]", "<-m[${1:}][${2:}]")
21+
}

0 commit comments

Comments
 (0)