From 0f69de236bb709847e215a792a40aaee1cba60d9 Mon Sep 17 00:00:00 2001 From: Muir Manders Date: Fri, 6 Dec 2019 14:29:09 -0800 Subject: [PATCH] internal/lsp: offer basic type conversion candidates When the expected type is a basic type, we will now offer a corresponding type conversion candidate. For example: var foo int64 foo = // offer "int64(<>)" as a candidate The type conversion candidate will be ranked below matching concrete candidates but above the sea of non-matching candidates. This change broke almost every completion test. I added a new completion option for literal candidates so tests can selectively ask for literal completions. Updates golang/go#36015. Change-Id: I63fbdb33436d662a666c1ffd3b2d918d840dccc7 Reviewed-on: https://go-review.googlesource.com/c/tools/+/210288 Run-TryBot: Rebecca Stambler TryBot-Result: Gobot Gobot Reviewed-by: Rebecca Stambler --- internal/lsp/completion_test.go | 3 +++ internal/lsp/source/completion.go | 6 +++++- internal/lsp/source/completion_literal.go | 9 +++++++-- internal/lsp/source/options.go | 2 ++ internal/lsp/source/source_test.go | 3 +++ .../lsp/testdata/snippets/literal_snippets.go.in | 13 +++++++++++++ internal/lsp/testdata/summary.txt.golden | 4 ++-- 7 files changed, 35 insertions(+), 5 deletions(-) diff --git a/internal/lsp/completion_test.go b/internal/lsp/completion_test.go index 664e075901..846a54b467 100644 --- a/internal/lsp/completion_test.go +++ b/internal/lsp/completion_test.go @@ -15,6 +15,7 @@ func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, Deep: false, FuzzyMatching: false, Documentation: true, + Literal: strings.Contains(string(src.URI()), "literal"), }) if !strings.Contains(string(src.URI()), "builtins") { got = tests.FilterBuiltins(got) @@ -30,6 +31,7 @@ func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.C Placeholders: placeholders, Deep: true, FuzzyMatching: true, + Literal: true, }) got := tests.FindItem(list, *items[expected.CompletionItem]) want := expected.PlainSnippet @@ -99,6 +101,7 @@ func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completi got := r.callCompletion(t, src, source.CompletionOptions{ FuzzyMatching: true, Deep: true, + Literal: true, }) want := expected(t, test, items) if msg := tests.CheckCompletionOrder(want, got, true); msg != "" { diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion.go index 342d095c64..9d948d8b7c 100644 --- a/internal/lsp/source/completion.go +++ b/internal/lsp/source/completion.go @@ -322,7 +322,11 @@ func (c *completer) found(obj types.Object, score float64, imp *importInfo) { } else if isTypeName(obj) { // If obj is a *types.TypeName that didn't otherwise match, check // if a literal object of this type makes a good candidate. - c.literal(obj.Type(), imp) + + // We only care about named types (i.e. don't want builtin types). + if _, isNamed := obj.Type().(*types.Named); isNamed { + c.literal(obj.Type(), imp) + } } // Favor shallow matches by lowering weight according to depth. diff --git a/internal/lsp/source/completion_literal.go b/internal/lsp/source/completion_literal.go index 95286718d0..7f62e57d30 100644 --- a/internal/lsp/source/completion_literal.go +++ b/internal/lsp/source/completion_literal.go @@ -20,6 +20,10 @@ import ( // literal generates composite literal, function literal, and make() // completion items. func (c *completer) literal(literalType types.Type, imp *importInfo) { + if !c.opts.Literal { + return + } + expType := c.expectedType.objType if c.expectedType.variadic { @@ -124,8 +128,9 @@ func (c *completer) literal(literalType types.Type, imp *importInfo) { case *types.Basic, *types.Signature: // Add a literal completion for basic types that implement our // expected interface (e.g. named string type http.Dir - // implements http.FileSystem). - if isInterface(expType) { + // implements http.FileSystem), or are identical to our expected + // type (i.e. yielding a type conversion such as "float64()"). + if isInterface(expType) || types.Identical(expType, literalType) { c.basicLiteral(t, typeName, float64(score), addlEdits) } } diff --git a/internal/lsp/source/options.go b/internal/lsp/source/options.go index 21ac309478..1c378ead69 100644 --- a/internal/lsp/source/options.go +++ b/internal/lsp/source/options.go @@ -64,6 +64,7 @@ var ( Documentation: true, Deep: true, FuzzyMatching: true, + Literal: true, Budget: 100 * time.Millisecond, }, ComputeEdits: myers.ComputeEdits, @@ -123,6 +124,7 @@ type CompletionOptions struct { Documentation bool FullDocumentation bool Placeholders bool + Literal bool // Budget is the soft latency goal for completion requests. Most // requests finish in a couple milliseconds, but in some cases deep diff --git a/internal/lsp/source/source_test.go b/internal/lsp/source/source_test.go index fbed335070..41bf6bcdeb 100644 --- a/internal/lsp/source/source_test.go +++ b/internal/lsp/source/source_test.go @@ -110,6 +110,7 @@ func (r *runner) Completion(t *testing.T, src span.Span, test tests.Completion, prefix, list := r.callCompletion(t, src, source.CompletionOptions{ Documentation: true, FuzzyMatching: true, + Literal: strings.Contains(string(src.URI()), "literal"), }) if !strings.Contains(string(src.URI()), "builtins") { list = tests.FilterBuiltins(list) @@ -130,6 +131,7 @@ func (r *runner) CompletionSnippet(t *testing.T, src span.Span, expected tests.C _, list := r.callCompletion(t, src, source.CompletionOptions{ Placeholders: placeholders, Deep: true, + Literal: true, }) got := tests.FindItem(list, *items[expected.CompletionItem]) want := expected.PlainSnippet @@ -234,6 +236,7 @@ func (r *runner) RankCompletion(t *testing.T, src span.Span, test tests.Completi prefix, list := r.callCompletion(t, src, source.CompletionOptions{ FuzzyMatching: true, Deep: true, + Literal: true, }) fuzzyMatcher := fuzzy.NewMatcher(prefix) var got []protocol.CompletionItem diff --git a/internal/lsp/testdata/snippets/literal_snippets.go.in b/internal/lsp/testdata/snippets/literal_snippets.go.in index 57489fb3e3..7233b07e69 100644 --- a/internal/lsp/testdata/snippets/literal_snippets.go.in +++ b/internal/lsp/testdata/snippets/literal_snippets.go.in @@ -160,3 +160,16 @@ func _() { sf = foo.Str //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}") sf = foo. //@snippet(" //", litStructFoo, "StructFoo{$0\\}", "StructFoo{$0\\}") } + +func _() { + float64() //@item(litFloat64, "float64()", "float64", "var") + + var f float64 + f = fl //@complete(" //", litFloat64),snippet(" //", litFloat64, "float64($0)", "float64($0)") + + type myInt int + myInt() //@item(litMyInt, "myInt()", "", "var") + + var mi myInt + mi = my //@snippet(" //", litMyInt, "myInt($0)", "myInt($0)") +} diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden index 31e701c6f5..14dc1bd1c2 100644 --- a/internal/lsp/testdata/summary.txt.golden +++ b/internal/lsp/testdata/summary.txt.golden @@ -1,6 +1,6 @@ -- summary -- -CompletionsCount = 221 -CompletionSnippetCount = 51 +CompletionsCount = 222 +CompletionSnippetCount = 53 UnimportedCompletionsCount = 4 DeepCompletionsCount = 5 FuzzyCompletionsCount = 7