forked from OSchip/llvm-project
[clangd] Add unit tests for signature help. SigHelp/CodeComplete lit tests are smoke only.
llvm-svn: 321065
This commit is contained in:
parent
efb06387b7
commit
800d4371f3
|
@ -6,13 +6,13 @@ Content-Length: 125
|
|||
|
||||
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
|
||||
|
||||
Content-Length: 246
|
||||
Content-Length: 186
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"struct fake { int a, bb, ccc; int f(int i, const float f) const; };\nint main() {\n fake f;\n f.\n}\n"}}}
|
||||
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"struct S { int a; };\nint main() {\nS().\n}"}}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":5}}}
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":4}}}
|
||||
# CHECK: "id": 1
|
||||
# CHECK-NEXT: "jsonrpc": "2.0",
|
||||
# CHECK-NEXT: "result": {
|
||||
|
@ -27,157 +27,31 @@ Content-Length: 148
|
|||
# CHECK-NEXT: "label": "a",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}a"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "detail": "int",
|
||||
# CHECK-NEXT: "filterText": "bb",
|
||||
# CHECK-NEXT: "insertText": "bb",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 5,
|
||||
# CHECK-NEXT: "label": "bb",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}bb"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "detail": "int",
|
||||
# CHECK-NEXT: "filterText": "ccc",
|
||||
# CHECK-NEXT: "insertText": "ccc",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 5,
|
||||
# CHECK-NEXT: "label": "ccc",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}ccc"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "detail": "int",
|
||||
# CHECK-NEXT: "filterText": "f",
|
||||
# CHECK-NEXT: "insertText": "f",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 2,
|
||||
# CHECK-NEXT: "label": "f(int i, const float f) const",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}f"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "filterText": "fake",
|
||||
# CHECK-NEXT: "insertText": "fake",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 7,
|
||||
# CHECK-NEXT: "label": "fake::",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}fake"
|
||||
# CHECK-NEXT: },
|
||||
# FIXME: Why do buildbots show different operator=s here?
|
||||
# CHECK: {
|
||||
# CHECK: "detail": "void",
|
||||
# CHECK-NEXT: "filterText": "~fake",
|
||||
# CHECK-NEXT: "insertText": "~fake",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 4,
|
||||
# CHECK-NEXT: "label": "~fake()",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}~fake"
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":2,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":5}}}
|
||||
# CHECK: "id": 2
|
||||
# CHECK-NEXT: "jsonrpc": "2.0",
|
||||
# CHECK-NEXT: "result": {
|
||||
# CHECK-NEXT: "isIncomplete": false,
|
||||
# CHECK-NEXT: "items": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "detail": "int",
|
||||
# CHECK-NEXT: "filterText": "a",
|
||||
# CHECK-NEXT: "insertText": "a",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 5,
|
||||
# CHECK-NEXT: "label": "a",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "detail": "int",
|
||||
# CHECK-NEXT: "filterText": "bb",
|
||||
# CHECK-NEXT: "insertText": "bb",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 5,
|
||||
# CHECK-NEXT: "label": "bb",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "detail": "int",
|
||||
# CHECK-NEXT: "filterText": "ccc",
|
||||
# CHECK-NEXT: "insertText": "ccc",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 5,
|
||||
# CHECK-NEXT: "label": "ccc",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "detail": "int",
|
||||
# CHECK-NEXT: "filterText": "f",
|
||||
# CHECK-NEXT: "insertText": "f",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 2,
|
||||
# CHECK-NEXT: "label": "f(int i, const float f) const",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "filterText": "fake",
|
||||
# CHECK-NEXT: "insertText": "fake",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 7,
|
||||
# CHECK-NEXT: "label": "fake::",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK: {
|
||||
# CHECK: "detail": "void",
|
||||
# CHECK-NEXT: "filterText": "~fake",
|
||||
# CHECK-NEXT: "insertText": "~fake",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 4,
|
||||
# CHECK-NEXT: "label": "~fake()",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK: ]
|
||||
# Update the source file and check for completions again.
|
||||
Content-Length: 226
|
||||
Content-Length: 190
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":2},"contentChanges":[{"text":"struct fancy { int (*func())(int, int); };\nint main() {\n fancy f;\n f.\n}\n"}]}}
|
||||
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"file:///main.cpp","version":2},"contentChanges":[{"text":"struct S { int b; };\nint main() {\nS().\n}"}]}}
|
||||
|
||||
Content-Length: 148
|
||||
|
||||
{"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":3,"character":5}}}
|
||||
# CHECK: "id": 3,
|
||||
{"jsonrpc":"2.0","id":3,"method":"textDocument/completion","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":4}}}
|
||||
# CHECK: "id": 3,
|
||||
# CHECK-NEXT: "jsonrpc": "2.0",
|
||||
# CHECK-NEXT: "result": {
|
||||
# CHECK-NEXT: "isIncomplete": false,
|
||||
# CHECK-NEXT: "items": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "detail": "int (*)(int, int)",
|
||||
# CHECK-NEXT: "filterText": "func",
|
||||
# CHECK-NEXT: "insertText": "func",
|
||||
# CHECK-NEXT: "detail": "int",
|
||||
# CHECK-NEXT: "filterText": "b",
|
||||
# CHECK-NEXT: "insertText": "b",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 2,
|
||||
# CHECK-NEXT: "label": "func()",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: "kind": 5,
|
||||
# CHECK-NEXT: "label": "b",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}b"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "filterText": "fancy",
|
||||
# CHECK-NEXT: "insertText": "fancy",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 7,
|
||||
# CHECK-NEXT: "label": "fancy::",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: },
|
||||
# CHECK: {
|
||||
# CHECK: "detail": "void",
|
||||
# CHECK-NEXT: "filterText": "~fancy",
|
||||
# CHECK-NEXT: "insertText": "~fancy",
|
||||
# CHECK-NEXT: "insertTextFormat": 1,
|
||||
# CHECK-NEXT: "kind": 4,
|
||||
# CHECK-NEXT: "label": "~fancy()",
|
||||
# CHECK-NEXT: "sortText": "{{.*}}"
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK: ]
|
||||
Content-Length: 44
|
||||
|
||||
{"jsonrpc":"2.0","id":4,"method":"shutdown"}
|
||||
Content-Length: 33
|
||||
|
||||
{"jsonrpc":"2.0":"method":"exit"}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# RUN: clangd -run-synchronously < %s | FileCheck %s
|
||||
# RUN: clangd -pretty -run-synchronously < %s | FileCheck -strict-whitespace %s
|
||||
# It is absolutely vital that this file has CRLF line endings.
|
||||
|
||||
# Start a session.
|
||||
|
@ -6,45 +6,32 @@ Content-Length: 125
|
|||
|
||||
{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
|
||||
|
||||
# Modify the document.
|
||||
Content-Length: 333
|
||||
Content-Length: 172
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"void foo(int x, int y);\nvoid foo(int x, float y);\nvoid foo(float x, int y);\nvoid foo(float x, float y);\nvoid bar(int x, int y = 0);\nvoid bar(float x = 0, int y = 42);\nint main() { foo("}}}
|
||||
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"void x(int);\nint main(){\nx("}}}
|
||||
|
||||
# Ask for signature help.
|
||||
Content-Length: 151
|
||||
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":8,"character":9}}}
|
||||
# CHECK: {"id":1,"jsonrpc":"2.0","result":{"activeParameter":0,"activeSignature":0,"signatures":[
|
||||
# CHECK-DAG: {"label":"foo(float x, float y) -> void","parameters":[{"label":"float x"},{"label":"float y"}]}
|
||||
# CHECK-DAG: {"label":"foo(float x, int y) -> void","parameters":[{"label":"float x"},{"label":"int y"}]}
|
||||
# CHECK-DAG: {"label":"foo(int x, float y) -> void","parameters":[{"label":"int x"},{"label":"float y"}]}
|
||||
# CHECK-DAG: {"label":"foo(int x, int y) -> void","parameters":[{"label":"int x"},{"label":"int y"}]}
|
||||
# CHECK-SAME: ]}
|
||||
|
||||
# Modify the document
|
||||
Content-Length: 333
|
||||
|
||||
{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":2,"text":"void foo(int x, int y);\nvoid foo(int x, float y);\nvoid foo(float x, int y);\nvoid foo(float x, float y);\nvoid bar(int x, int y = 0);\nvoid bar(float x = 0, int y = 42);\nint main() { bar("}}}
|
||||
|
||||
# Ask for signature help (this checks default argument handling).
|
||||
Content-Length: 151
|
||||
|
||||
{"jsonrpc":"2.0","id":2,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":8,"character":9}}}
|
||||
# CHECK: {"id":2,"jsonrpc":"2.0","result":{"activeParameter":0,"activeSignature":0,"signatures":[
|
||||
# CHECK-DAG: {"label":"bar(int x, int y = 0) -> void","parameters":[{"label":"int x"},{"label":"int y = 0"}]}
|
||||
# CHECK-DAG: {"label":"bar(float x = 0, int y = 42) -> void","parameters":[{"label":"float x = 0"},{"label":"int y = 42"}]}
|
||||
# CHECK-SAME: ]}
|
||||
|
||||
Content-Length: 159
|
||||
|
||||
{"jsonrpc":"2.0","id":3,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"file:///doesnotexist.cpp"},"position":{"line":8,"character":9}}}
|
||||
# CHECK: {"error":{"code":-32602,"message":"signatureHelp is called for non-added document"},"id":3,"jsonrpc":"2.0"}
|
||||
{"jsonrpc":"2.0","id":1,"method":"textDocument/signatureHelp","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":2,"character":2}}}
|
||||
# CHECK: "id": 1,
|
||||
# CHECK-NEXT: "jsonrpc": "2.0",
|
||||
# CHECK-NEXT: "result": {
|
||||
# CHECK-NEXT: "activeParameter": 0,
|
||||
# CHECK-NEXT: "activeSignature": 0,
|
||||
# CHECK-NEXT: "signatures": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "label": "x(int) -> void",
|
||||
# CHECK-NEXT: "parameters": [
|
||||
# CHECK-NEXT: {
|
||||
# CHECK-NEXT: "label": "int"
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
# CHECK-NEXT: ]
|
||||
# CHECK-NEXT: }
|
||||
|
||||
# Shutdown.
|
||||
Content-Length: 49
|
||||
|
||||
{"jsonrpc":"2.0","id":100000,"method":"shutdown"}
|
||||
Content-Length: 33
|
||||
|
||||
{"jsonrpc":"2.0":"method":"exit"}
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
namespace clang {
|
||||
namespace clangd {
|
||||
// Let GMock print completion items.
|
||||
// Let GMock print completion items and signature help.
|
||||
void PrintTo(const CompletionItem &I, std::ostream *O) {
|
||||
llvm::raw_os_ostream OS(*O);
|
||||
OS << I.label << " - " << toJSON(I);
|
||||
|
@ -31,6 +31,19 @@ void PrintTo(const std::vector<CompletionItem> &V, std::ostream *O) {
|
|||
}
|
||||
*O << "}";
|
||||
}
|
||||
void PrintTo(const SignatureInformation &I, std::ostream *O) {
|
||||
llvm::raw_os_ostream OS(*O);
|
||||
OS << I.label << " - " << toJSON(I);
|
||||
}
|
||||
void PrintTo(const std::vector<SignatureInformation> &V, std::ostream *O) {
|
||||
*O << "{\n";
|
||||
for (const auto &I : V) {
|
||||
*O << "\t";
|
||||
PrintTo(I, O);
|
||||
*O << "\n";
|
||||
}
|
||||
*O << "}";
|
||||
}
|
||||
|
||||
namespace {
|
||||
using namespace llvm;
|
||||
|
@ -368,6 +381,81 @@ TEST(CompletionTest, Kinds) {
|
|||
EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
|
||||
}
|
||||
|
||||
SignatureHelp signatures(StringRef Text) {
|
||||
MockFSProvider FS;
|
||||
MockCompilationDatabase CDB;
|
||||
IgnoreDiagnostics DiagConsumer;
|
||||
ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
|
||||
/*StorePreamblesInMemory=*/true);
|
||||
auto File = getVirtualTestFilePath("foo.cpp");
|
||||
auto Test = parseTextMarker(Text);
|
||||
Server.addDocument(Context::empty(), File, Test.Text);
|
||||
auto R = Server.signatureHelp(Context::empty(), File, Test.MarkerPos);
|
||||
assert(R);
|
||||
return R.get().Value;
|
||||
}
|
||||
|
||||
MATCHER_P(ParamsAre, P, "") {
|
||||
if (P.size() != arg.parameters.size())
|
||||
return false;
|
||||
for (unsigned I = 0; I < P.size(); ++I)
|
||||
if (P[I] != arg.parameters[I].label)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
Matcher<SignatureInformation> Sig(std::string Label,
|
||||
std::vector<std::string> Params) {
|
||||
return AllOf(Labeled(Label), ParamsAre(Params));
|
||||
}
|
||||
|
||||
TEST(SignatureHelpTest, Overloads) {
|
||||
auto Results = signatures(R"cpp(
|
||||
void foo(int x, int y);
|
||||
void foo(int x, float y);
|
||||
void foo(float x, int y);
|
||||
void foo(float x, float y);
|
||||
void bar(int x, int y = 0);
|
||||
int main() { foo(^); }
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures,
|
||||
UnorderedElementsAre(
|
||||
Sig("foo(float x, float y) -> void", {"float x", "float y"}),
|
||||
Sig("foo(float x, int y) -> void", {"float x", "int y"}),
|
||||
Sig("foo(int x, float y) -> void", {"int x", "float y"}),
|
||||
Sig("foo(int x, int y) -> void", {"int x", "int y"})));
|
||||
// We always prefer the first signature.
|
||||
EXPECT_EQ(0, Results.activeSignature);
|
||||
EXPECT_EQ(0, Results.activeParameter);
|
||||
}
|
||||
|
||||
TEST(SignatureHelpTest, DefaultArgs) {
|
||||
auto Results = signatures(R"cpp(
|
||||
void bar(int x, int y = 0);
|
||||
void bar(float x = 0, int y = 42);
|
||||
int main() { bar(^
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures,
|
||||
UnorderedElementsAre(
|
||||
Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
|
||||
Sig("bar(float x = 0, int y = 42) -> void",
|
||||
{"float x = 0", "int y = 42"})));
|
||||
EXPECT_EQ(0, Results.activeSignature);
|
||||
EXPECT_EQ(0, Results.activeParameter);
|
||||
}
|
||||
|
||||
TEST(SignatureHelpTest, ActiveArg) {
|
||||
auto Results = signatures(R"cpp(
|
||||
int baz(int a, int b, int c);
|
||||
int main() { baz(baz(1,2,3), ^); }
|
||||
)cpp");
|
||||
EXPECT_THAT(Results.signatures,
|
||||
ElementsAre(Sig("baz(int a, int b, int c) -> int",
|
||||
{"int a", "int b", "int c"})));
|
||||
EXPECT_EQ(0, Results.activeSignature);
|
||||
EXPECT_EQ(1, Results.activeParameter);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace clangd
|
||||
} // namespace clang
|
||||
|
|
Loading…
Reference in New Issue