From 89082a3841783366cb82b3dc4ce9258fb3dad1a9 Mon Sep 17 00:00:00 2001 From: Muir Manders Date: Thu, 26 Dec 2019 21:31:56 -0800 Subject: [PATCH] internal/lsp/source: fix some invalid literal candidates We were marking all literal candidates as addressable so we were getting invalid candidates like "&int()". Fix it to only mark literal struct, array, slice and map types as addressable. I also fixed the unnamed literal candidate to pass the dereferenced expected type. For example, if the expected type was "*[]int" we were passing a literal type of "*[]int" which wasn't working anymore. Now we pass "[]int" and take its address as "&[]int{}". Change-Id: I5d0ee074d3cc91c39dd881630583e31be5a05579 Reviewed-on: https://go-review.googlesource.com/c/tools/+/212677 Run-TryBot: Muir Manders TryBot-Result: Gobot Gobot Reviewed-by: Rebecca Stambler --- internal/lsp/source/completion.go | 5 +++-- internal/lsp/source/completion_literal.go | 11 +++++++++-- internal/lsp/testdata/snippets/literal_snippets.go.in | 7 +++++++ internal/lsp/testdata/summary.txt.golden | 4 ++-- 4 files changed, 21 insertions(+), 6 deletions(-) diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion.go index 9964e0ac38..30f3d6ee5e 100644 --- a/internal/lsp/source/completion.go +++ b/internal/lsp/source/completion.go @@ -917,8 +917,9 @@ func (c *completer) lexical() error { // if an object literal makes a good candidate. For example, if // our expected type is "[]int", this will add a candidate of // "[]int{}". - if _, named := deref(c.expectedType.objType).(*types.Named); !named { - c.literal(c.expectedType.objType, nil) + t := deref(c.expectedType.objType) + if _, named := t.(*types.Named); !named { + c.literal(t, nil) } } diff --git a/internal/lsp/source/completion_literal.go b/internal/lsp/source/completion_literal.go index 816e1b3148..287d43d046 100644 --- a/internal/lsp/source/completion_literal.go +++ b/internal/lsp/source/completion_literal.go @@ -65,9 +65,16 @@ func (c *completer) literal(literalType types.Type, imp *importInfo) { // Check if an object of type literalType would match our expected type. cand := candidate{ - obj: c.fakeObj(literalType), - addressable: true, + obj: c.fakeObj(literalType), } + + switch literalType.Underlying().(type) { + // These literal types are addressable (e.g. "&[]int{}"), others are + // not (e.g. can't do "&(func(){})"). + case *types.Struct, *types.Array, *types.Slice, *types.Map: + cand.addressable = true + } + if !c.matchingCandidate(&cand) { return } diff --git a/internal/lsp/testdata/snippets/literal_snippets.go.in b/internal/lsp/testdata/snippets/literal_snippets.go.in index dfb210b63c..9906a2b78a 100644 --- a/internal/lsp/testdata/snippets/literal_snippets.go.in +++ b/internal/lsp/testdata/snippets/literal_snippets.go.in @@ -10,8 +10,12 @@ import ( func _() { []int{} //@item(litIntSlice, "[]int{}", "", "var") + &[]int{} //@item(litIntSliceAddr, "&[]int{}", "", "var") make([]int, 0) //@item(makeIntSlice, "make([]int, 0)", "", "func") + var _ *[]int = in //@snippet(" //", litIntSliceAddr, "&[]int{$0\\}", "&[]int{$0\\}") + var _ **[]int = in //@complete(" //") + var slice []int slice = i //@snippet(" //", litIntSlice, "[]int{$0\\}", "[]int{$0\\}") slice = m //@snippet(" //", makeIntSlice, "make([]int, ${1:})", "make([]int, ${1:0})") @@ -164,6 +168,9 @@ func _() { func _() { float64() //@item(litFloat64, "float64()", "float64", "var") + // don't complete to "&float64()" + var _ *float64 = float64 //@complete(" //") + var f float64 f = fl //@complete(" //", litFloat64),snippet(" //", litFloat64, "float64($0)", "float64($0)") diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden index 25d58cebe2..1afb5eae2c 100644 --- a/internal/lsp/testdata/summary.txt.golden +++ b/internal/lsp/testdata/summary.txt.golden @@ -1,6 +1,6 @@ -- summary -- -CompletionsCount = 223 -CompletionSnippetCount = 61 +CompletionsCount = 225 +CompletionSnippetCount = 62 UnimportedCompletionsCount = 4 DeepCompletionsCount = 5 FuzzyCompletionsCount = 8