internal/lsp: handle additional snippet cases

This change handles the case when a function that has already been
written out is being completed.

Change-Id: I0c4e9ec9bb5a8428526f00a4e62e020bcc30f0bf
Reviewed-on: https://go-review.googlesource.com/c/tools/+/176923
Run-TryBot: Rebecca Stambler <rstambler@golang.org>
Reviewed-by: Ian Cottrell <iancottrell@google.com>
This commit is contained in:
Rebecca Stambler 2019-05-14 22:02:51 -04:00
parent ce09bef8aa
commit 473d3dc1d7
6 changed files with 29 additions and 37 deletions

View File

@ -151,17 +151,7 @@ func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests
t.Errorf("%s: %s", src, diff) t.Errorf("%s: %s", src, diff)
} }
} }
// Make sure we don't crash completing the first position in file set.
firstPos, err := span.NewRange(r.data.Exported.ExpectFileSet, 1, 2).Span()
if err != nil {
t.Fatal(err)
}
_ = r.runCompletion(t, firstPos)
r.checkCompletionSnippets(t, snippets, items)
}
func (r *runner) checkCompletionSnippets(t *testing.T, data tests.CompletionSnippets, items tests.CompletionItems) {
origPlaceHolders := r.server.usePlaceholders origPlaceHolders := r.server.usePlaceholders
origTextFormat := r.server.insertTextFormat origTextFormat := r.server.insertTextFormat
defer func() { defer func() {
@ -173,31 +163,28 @@ func (r *runner) checkCompletionSnippets(t *testing.T, data tests.CompletionSnip
for _, usePlaceholders := range []bool{true, false} { for _, usePlaceholders := range []bool{true, false} {
r.server.usePlaceholders = usePlaceholders r.server.usePlaceholders = usePlaceholders
for src, want := range data { for src, want := range snippets {
list := r.runCompletion(t, src) list := r.runCompletion(t, src)
wantCompletion := items[want.CompletionItem] wantItem := items[want.CompletionItem]
var gotItem *protocol.CompletionItem var got *protocol.CompletionItem
for _, item := range list.Items { for _, item := range list.Items {
if item.Label == wantCompletion.Label { if item.Label == wantItem.Label {
gotItem = &item got = &item
break break
} }
} }
if got == nil {
if gotItem == nil { t.Fatalf("%s: couldn't find completion matching %q", src.URI(), wantItem.Label)
t.Fatalf("%s: couldn't find completion matching %q", src.URI(), wantCompletion.Label)
} }
var expected string var expected string
if usePlaceholders { if usePlaceholders {
expected = want.PlaceholderSnippet expected = want.PlaceholderSnippet
} else { } else {
expected = want.PlainSnippet expected = want.PlainSnippet
} }
if expected != got.TextEdit.NewText {
if expected != gotItem.TextEdit.NewText { t.Errorf("%s: expected snippet %q, got %q", src, expected, got.TextEdit.NewText)
t.Errorf("%s: expected snippet %q, got %q", src, expected, gotItem.TextEdit.NewText)
} }
} }
} }

View File

@ -66,6 +66,9 @@ func (c *completer) item(obj types.Object, score float64) CompletionItem {
results, writeParens := formatResults(sig.Results(), c.qf) results, writeParens := formatResults(sig.Results(), c.qf)
label, detail = formatFunction(obj.Name(), params, results, writeParens) label, detail = formatFunction(obj.Name(), params, results, writeParens)
plainSnippet, placeholderSnippet = c.functionCallSnippets(obj.Name(), params) plainSnippet, placeholderSnippet = c.functionCallSnippets(obj.Name(), params)
if plainSnippet == nil && placeholderSnippet == nil {
insert = ""
}
kind = FunctionCompletionItem kind = FunctionCompletionItem
if sig.Recv() != nil { if sig.Recv() != nil {
kind = MethodCompletionItem kind = MethodCompletionItem

View File

@ -72,7 +72,6 @@ func (c *completer) functionCallSnippets(name string, params []string) (*snippet
} }
} }
} }
plain, placeholder := &snippet.Builder{}, &snippet.Builder{} plain, placeholder := &snippet.Builder{}, &snippet.Builder{}
label := fmt.Sprintf("%s(", name) label := fmt.Sprintf("%s(", name)

View File

@ -156,11 +156,8 @@ func (r *runner) Completion(t *testing.T, data tests.Completions, snippets tests
t.Errorf("%s: %s", src, diff) t.Errorf("%s: %s", src, diff)
} }
} }
}
func (r *runner) checkCompletionSnippets(ctx context.Context, t *testing.T, data tests.CompletionSnippets, items tests.CompletionItems) {
for _, usePlaceholders := range []bool{true, false} { for _, usePlaceholders := range []bool{true, false} {
for src, want := range data { for src, want := range snippets {
f, err := r.view.GetFile(ctx, src.URI()) f, err := r.view.GetFile(ctx, src.URI())
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", src, err) t.Fatalf("failed for %v: %v", src, err)
@ -171,25 +168,23 @@ func (r *runner) checkCompletionSnippets(ctx context.Context, t *testing.T, data
if err != nil { if err != nil {
t.Fatalf("failed for %v: %v", src, err) t.Fatalf("failed for %v: %v", src, err)
} }
wantItem := items[want.CompletionItem]
wantCompletion := items[want.CompletionItem]
var got *source.CompletionItem var got *source.CompletionItem
for _, item := range list { for _, item := range list {
if item.Label == wantCompletion.Label { if item.Label == wantItem.Label {
got = &item got = &item
break break
} }
} }
if got == nil { if got == nil {
t.Fatalf("%s: couldn't find completion matching %q", src.URI(), wantCompletion.Label) t.Fatalf("%s: couldn't find completion matching %q", src.URI(), wantItem.Label)
} }
expected := want.PlainSnippet expected := want.PlainSnippet
if usePlaceholders { if usePlaceholders {
expected = want.PlaceholderSnippet expected = want.PlaceholderSnippet
} }
if insertText := got.Snippet(usePlaceholders); expected != insertText { if actual := got.Snippet(usePlaceholders); expected != actual {
t.Errorf("%s: expected snippet %q, got %q", src, expected, insertText) t.Errorf("%s: expected placeholder snippet %q, got %q", src, expected, actual)
} }
} }
} }

View File

@ -7,14 +7,15 @@ type Foo struct {
Bar int //@item(snipFieldBar, "Bar", "int", "field") Bar int //@item(snipFieldBar, "Bar", "int", "field")
} }
func (Foo) Baz() func() {} //@item(snipMethodBaz, "Baz()", "func()", "field") func (Foo) Baz() func() {} //@item(snipMethodBaz, "Baz()", "func()", "method")
func (Foo) BazBar() func() {} //@item(snipMethodBazBar, "BazBar()", "func()", "method")
func _() { func _() {
f //@snippet(" //", snipFoo, "foo(${1})", "foo(${1:i int}, ${2:b bool})") f //@snippet(" //", snipFoo, "foo(${1})", "foo(${1:i int}, ${2:b bool})")
bar //@snippet(" //", snipBar, "bar(${1})", "bar(${1:fn func()})") bar //@snippet(" //", snipBar, "bar(${1})", "bar(${1:fn func()})")
bar(nil) //@snippet("(", snipBar, "bar", "bar") bar(nil) //@snippet("(", snipBar, "", "")
bar(ba) //@snippet(")", snipBar, "bar(${1})", "bar(${1:fn func()})") bar(ba) //@snippet(")", snipBar, "bar(${1})", "bar(${1:fn func()})")
var f Foo var f Foo
bar(f.Ba) //@snippet(")", snipMethodBaz, "Baz()", "Baz()") bar(f.Ba) //@snippet(")", snipMethodBaz, "Baz()", "Baz()")
@ -29,4 +30,11 @@ func _() {
Foo{} //@snippet("}", snipFieldBar, "Bar: ${1}", "Bar: ${1:int}") Foo{} //@snippet("}", snipFieldBar, "Bar: ${1}", "Bar: ${1:int}")
Foo{Foo{}.B} //@snippet("} ", snipFieldBar, "Bar", "Bar") Foo{Foo{}.B} //@snippet("} ", snipFieldBar, "Bar", "Bar")
var err error
err.Error() //@snippet("E", Error, "", "")
f.Baz() //@snippet("B", snipMethodBaz, "", "")
// TODO(rstambler): Handle this case correctly.
f.Baz() //@fails("(", snipMethodBazBar, "Bar", "Bar")
} }

View File

@ -36,7 +36,7 @@ const (
ExpectedHighlightsCount = 2 ExpectedHighlightsCount = 2
ExpectedSymbolsCount = 1 ExpectedSymbolsCount = 1
ExpectedSignaturesCount = 20 ExpectedSignaturesCount = 20
ExpectedCompletionSnippetCount = 11 ExpectedCompletionSnippetCount = 13
ExpectedLinksCount = 2 ExpectedLinksCount = 2
) )