From 6e267b5cc78e9baebc0af24b760802105d843647 Mon Sep 17 00:00:00 2001 From: Rebecca Stambler Date: Tue, 11 Dec 2018 00:52:31 -0500 Subject: [PATCH] internal/lsp: add additional tests for completion New tests include cases for anonymous structs, composite literals, ranking of results in binary expressions, and import cycles. Change-Id: Ic02e84e09101bb9873fc1705bba2594d655bb45b Reviewed-on: https://go-review.googlesource.com/c/153443 Reviewed-by: Ian Cottrell --- internal/lsp/completion.go | 30 +++++++++---------- internal/lsp/lsp_test.go | 4 +-- internal/lsp/testdata/anon/anon.go.in | 23 ++++++++++++++ .../testdata/assign_rank/assign_rank.go.in | 19 ------------ internal/lsp/testdata/bad/{bad.go => bad0.go} | 0 .../lsp/testdata/bad/{bad_util.go => bad1.go} | 0 internal/lsp/testdata/builtins/builtins.go | 6 ++++ internal/lsp/testdata/complit/complit.go.in | 26 ++++++++++++++++ internal/lsp/testdata/errors/errors.go | 5 ++++ .../lsp/testdata/good/{good.go => good0.go} | 0 .../testdata/good/{good_util.go => good1.go} | 0 internal/lsp/testdata/rank/assign_rank.go.in | 19 ++++++++++++ internal/lsp/testdata/rank/binexpr_rank.go.in | 8 +++++ internal/lsp/testdata/self/self.go.in | 13 ++++++++ 14 files changed, 117 insertions(+), 36 deletions(-) create mode 100644 internal/lsp/testdata/anon/anon.go.in delete mode 100644 internal/lsp/testdata/assign_rank/assign_rank.go.in rename internal/lsp/testdata/bad/{bad.go => bad0.go} (100%) rename internal/lsp/testdata/bad/{bad_util.go => bad1.go} (100%) create mode 100644 internal/lsp/testdata/builtins/builtins.go create mode 100644 internal/lsp/testdata/complit/complit.go.in create mode 100644 internal/lsp/testdata/errors/errors.go rename internal/lsp/testdata/good/{good.go => good0.go} (100%) rename internal/lsp/testdata/good/{good_util.go => good1.go} (100%) create mode 100644 internal/lsp/testdata/rank/assign_rank.go.in create mode 100644 internal/lsp/testdata/rank/binexpr_rank.go.in create mode 100644 internal/lsp/testdata/self/self.go.in diff --git a/internal/lsp/completion.go b/internal/lsp/completion.go index a95f59b8..8b7f8a32 100644 --- a/internal/lsp/completion.go +++ b/internal/lsp/completion.go @@ -14,28 +14,28 @@ import ( "golang.org/x/tools/internal/lsp/source" ) -func toProtocolCompletionItems(items []source.CompletionItem, prefix string, pos protocol.Position, snippetsSupported, signatureHelpEnabled bool) []protocol.CompletionItem { - var results []protocol.CompletionItem - sort.Slice(items, func(i, j int) bool { - return items[i].Score > items[j].Score - }) +func toProtocolCompletionItems(candidates []source.CompletionItem, prefix string, pos protocol.Position, snippetsSupported, signatureHelpEnabled bool) []protocol.CompletionItem { insertTextFormat := protocol.PlainTextFormat if snippetsSupported { insertTextFormat = protocol.SnippetTextFormat } - for i, item := range items { + sort.SliceStable(candidates, func(i, j int) bool { + return candidates[i].Score > candidates[j].Score + }) + var items []protocol.CompletionItem + for i, candidate := range candidates { // Matching against the label. - if !strings.HasPrefix(item.Label, prefix) { + if !strings.HasPrefix(candidate.Label, prefix) { continue } - insertText, triggerSignatureHelp := labelToProtocolSnippets(item.Label, item.Kind, insertTextFormat, signatureHelpEnabled) + insertText, triggerSignatureHelp := labelToProtocolSnippets(candidate.Label, candidate.Kind, insertTextFormat, signatureHelpEnabled) if strings.HasPrefix(insertText, prefix) { insertText = insertText[len(prefix):] } - i := protocol.CompletionItem{ - Label: item.Label, - Detail: item.Detail, - Kind: float64(toProtocolCompletionItemKind(item.Kind)), + item := protocol.CompletionItem{ + Label: candidate.Label, + Detail: candidate.Detail, + Kind: float64(toProtocolCompletionItemKind(candidate.Kind)), InsertTextFormat: insertTextFormat, TextEdit: &protocol.TextEdit{ NewText: insertText, @@ -53,13 +53,13 @@ func toProtocolCompletionItems(items []source.CompletionItem, prefix string, pos } // If we are completing a function, we should trigger signature help if possible. if triggerSignatureHelp && signatureHelpEnabled { - i.Command = &protocol.Command{ + item.Command = &protocol.Command{ Command: "editor.action.triggerParameterHints", } } - results = append(results, i) + items = append(items, item) } - return results + return items } func toProtocolCompletionItemKind(kind source.CompletionItemKind) protocol.CompletionItemKind { diff --git a/internal/lsp/lsp_test.go b/internal/lsp/lsp_test.go index 1aaa0c68..b5b4b9d9 100644 --- a/internal/lsp/lsp_test.go +++ b/internal/lsp/lsp_test.go @@ -35,8 +35,8 @@ func testLSP(t *testing.T, exporter packagestest.Exporter) { // We hardcode the expected number of test cases to ensure that all tests // are being executed. If a test is added, this number must be changed. - const expectedCompletionsCount = 44 - const expectedDiagnosticsCount = 14 + const expectedCompletionsCount = 60 + const expectedDiagnosticsCount = 15 const expectedFormatCount = 3 const expectedDefinitionsCount = 16 const expectedTypeDefinitionsCount = 2 diff --git a/internal/lsp/testdata/anon/anon.go.in b/internal/lsp/testdata/anon/anon.go.in new file mode 100644 index 00000000..36611b26 --- /dev/null +++ b/internal/lsp/testdata/anon/anon.go.in @@ -0,0 +1,23 @@ +package anon + +func _() { + for _, _ := range []struct { + i, j int //@item(anonI, "i", "int", "field"),item(anonJ, "j", "int", "field") + }{ + { + i: 1, + //@complete("", anonJ) + }, + { + //@complete("", anonI, anonJ) + }, + } { + continue + } + + s := struct{ f int }{ } //@item(anonF, "f", "int", "field"),item(structS, "s", "struct{...}", "var"),complete(" }", anonF) + + _ = map[struct{ x int }]int{ //@item(anonX, "x", "int", "field") + struct{ x int }{ }: 1, //@complete(" }", anonX, structS) + } +} diff --git a/internal/lsp/testdata/assign_rank/assign_rank.go.in b/internal/lsp/testdata/assign_rank/assign_rank.go.in deleted file mode 100644 index be7cb3bc..00000000 --- a/internal/lsp/testdata/assign_rank/assign_rank.go.in +++ /dev/null @@ -1,19 +0,0 @@ -package assign_rank - -var ( - apple int = 3 //@item(apple, "apple", "int", "var") - pear string = "hello" //@item(pear, "pear", "string", "var") -) - -func _() { - orange := 1 //@item(orange, "orange", "int", "var") - grape := "hello" //@item(grape, "grape", "string", "var") - orange, grape = 2, "hello" //@complete(" \"", grape, pear, orange, apple) -} - -func _() { - var pineapple int //@item(pineapple, "pineapple", "int", "var") - pineapple = //@complete(" /", pineapple, apple, pear) - - y := //@complete(" /", pineapple, apple, pear) -} \ No newline at end of file diff --git a/internal/lsp/testdata/bad/bad.go b/internal/lsp/testdata/bad/bad0.go similarity index 100% rename from internal/lsp/testdata/bad/bad.go rename to internal/lsp/testdata/bad/bad0.go diff --git a/internal/lsp/testdata/bad/bad_util.go b/internal/lsp/testdata/bad/bad1.go similarity index 100% rename from internal/lsp/testdata/bad/bad_util.go rename to internal/lsp/testdata/bad/bad1.go diff --git a/internal/lsp/testdata/builtins/builtins.go b/internal/lsp/testdata/builtins/builtins.go new file mode 100644 index 00000000..75452504 --- /dev/null +++ b/internal/lsp/testdata/builtins/builtins.go @@ -0,0 +1,6 @@ +package builtins + +func _() { + // TODO(rstambler): Add testing for completion of builtin symbols. + //@complete("") +} diff --git a/internal/lsp/testdata/complit/complit.go.in b/internal/lsp/testdata/complit/complit.go.in new file mode 100644 index 00000000..9c29c52c --- /dev/null +++ b/internal/lsp/testdata/complit/complit.go.in @@ -0,0 +1,26 @@ +package complit + +type position struct { //@item(structPosition, "position", "struct{...}", "struct") + X, Y int //@item(fieldX, "X", "int", "field"),item(fieldY, "Y", "int", "field") +} + +func _() { + _ := position{ + //@complete("", fieldX, fieldY, structPosition) + } + _ := position{ + X: 1, + //@complete("", fieldY) + } + _ := position{ + //@complete("", fieldX) + Y: 1, + } +} + +func _() { + _ := position{ + X: 1, //@complete("X", fieldX),complete(" 1", structPosition) + Y: , //@complete(":", fieldY),complete(" ,", structPosition) + } +} diff --git a/internal/lsp/testdata/errors/errors.go b/internal/lsp/testdata/errors/errors.go new file mode 100644 index 00000000..3de1f632 --- /dev/null +++ b/internal/lsp/testdata/errors/errors.go @@ -0,0 +1,5 @@ +package errors + +func _() { + bob.Bob() //@complete(".") +} diff --git a/internal/lsp/testdata/good/good.go b/internal/lsp/testdata/good/good0.go similarity index 100% rename from internal/lsp/testdata/good/good.go rename to internal/lsp/testdata/good/good0.go diff --git a/internal/lsp/testdata/good/good_util.go b/internal/lsp/testdata/good/good1.go similarity index 100% rename from internal/lsp/testdata/good/good_util.go rename to internal/lsp/testdata/good/good1.go diff --git a/internal/lsp/testdata/rank/assign_rank.go.in b/internal/lsp/testdata/rank/assign_rank.go.in new file mode 100644 index 00000000..27375d94 --- /dev/null +++ b/internal/lsp/testdata/rank/assign_rank.go.in @@ -0,0 +1,19 @@ +package rank + +var ( + apple int = 3 //@item(apple, "apple", "int", "var") + pear string = "hello" //@item(pear, "pear", "string", "var") +) + +func _() { + orange := 1 //@item(orange, "orange", "int", "var") + grape := "hello" //@item(grape, "grape", "string", "var") + orange, grape = 2, "hello" //@complete(" \"", grape, pear, orange, apple) +} + +func _() { + var pineapple int //@item(pineapple, "pineapple", "int", "var") + pineapple = //@complete(" /", pineapple, apple, pear) + + y := //@complete(" /", pineapple, apple, pear) +} diff --git a/internal/lsp/testdata/rank/binexpr_rank.go.in b/internal/lsp/testdata/rank/binexpr_rank.go.in new file mode 100644 index 00000000..60b2cc1b --- /dev/null +++ b/internal/lsp/testdata/rank/binexpr_rank.go.in @@ -0,0 +1,8 @@ +package rank + +func _() { + _ = 5 + ; //@complete(" ;", apple, pear) + y := + 5; //@complete(" +", apple, pear) + + if 6 == {} //@complete(" {", apple, pear) +} diff --git a/internal/lsp/testdata/self/self.go.in b/internal/lsp/testdata/self/self.go.in new file mode 100644 index 00000000..b9c5f0d8 --- /dev/null +++ b/internal/lsp/testdata/self/self.go.in @@ -0,0 +1,13 @@ +// +build go1.11 + +package self + +import ( + "golang.org/x/tools/internal/lsp/self" //@diag("\"", "could not import golang.org/x/tools/internal/lsp/self (import cycle: [golang.org/x/tools/internal/lsp/self])") +) + +func Hello() {} + +func _() { + self.Hello() +}