From 8938cee73c2baa24cd58a044a94f5da9acfc43e1 Mon Sep 17 00:00:00 2001 From: Muir Manders Date: Tue, 2 Feb 2021 22:29:19 -0800 Subject: [PATCH] internal/lsp/completion: fix invalid struct literal field snippet In cases like: type foo struct { a int; b float64 } foo{b<>} We were completing to "foo{int(b: )}" (the problem being the nonsensical int() conversion). The expected type at "<>" is int to allow completions to match "a". When we pass the *types.Var representing "b" through the candidate matching machinery, we say "Oh, a float64! I can convert that to my expected type of int!". Fix by bailing out of candidate matching early if the candidate is a composite literal struct field name. Field names aren't really objects you can do anything to. Fixes golang/go#43789. Change-Id: Ie4dab166973dfcdcb519f864532ead1f792d25a3 Reviewed-on: https://go-review.googlesource.com/c/tools/+/289130 Run-TryBot: Muir Manders Run-TryBot: Rebecca Stambler gopls-CI: kokoro TryBot-Result: Go Bot Reviewed-by: Rebecca Stambler Trust: Rebecca Stambler Trust: Hyang-Ah Hana Kim --- internal/lsp/source/completion/completion.go | 5 +++++ internal/lsp/testdata/snippets/snippets.go.in | 8 ++++++++ internal/lsp/testdata/summary.txt.golden | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/internal/lsp/source/completion/completion.go b/internal/lsp/source/completion/completion.go index cde7b38a35..20f30dad6c 100644 --- a/internal/lsp/source/completion/completion.go +++ b/internal/lsp/source/completion/completion.go @@ -2444,6 +2444,11 @@ func (c *completer) matchingCandidate(cand *candidate) bool { return false } + // Bail out early if we are completing a field name in a composite literal. + if v, ok := cand.obj.(*types.Var); ok && v.IsField() && c.wantStructFieldCompletions() { + return true + } + if isTypeName(cand.obj) { return c.matchingTypeName(cand) } else if c.wantTypeName() { diff --git a/internal/lsp/testdata/snippets/snippets.go.in b/internal/lsp/testdata/snippets/snippets.go.in index 35a9295a9e..58150c644c 100644 --- a/internal/lsp/testdata/snippets/snippets.go.in +++ b/internal/lsp/testdata/snippets/snippets.go.in @@ -51,3 +51,11 @@ func _() { f.Baz() //@snippet("B", snipMethodBazBaz, "BazBaz(${1:})", "BazBaz(${1:at AliasType})") } + +func _() { + type bar struct { + a int + b float64 //@item(snipBarB, "b", "float64", "field") + } + bar{b} //@snippet("}", snipBarB, "b: ${1:}", "b: ${1:float64}") +} diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden index 18f2b1bfe4..1ac9c9b7a4 100644 --- a/internal/lsp/testdata/summary.txt.golden +++ b/internal/lsp/testdata/summary.txt.golden @@ -2,7 +2,7 @@ CallHierarchyCount = 2 CodeLensCount = 5 CompletionsCount = 258 -CompletionSnippetCount = 89 +CompletionSnippetCount = 90 UnimportedCompletionsCount = 5 DeepCompletionsCount = 5 FuzzyCompletionsCount = 8