blob: 7411e1c3edfe7cd797b1f02227626f0dd1ffd65c [file] [log] [blame]
Sam McCall9aad25f2017-12-05 07:20:26 +00001//===-- CodeCompleteTests.cpp -----------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
Eric Liu6f648df2017-12-19 16:50:37 +00009
Sam McCall328cbdb2017-12-20 16:06:05 +000010#include "Annotations.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000011#include "ClangdServer.h"
Sam McCall328cbdb2017-12-20 16:06:05 +000012#include "CodeComplete.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000013#include "Compiler.h"
Ilya Biryukov940901e2017-12-13 12:51:22 +000014#include "Context.h"
Ilya Biryukov5a85b8e2017-12-13 12:53:16 +000015#include "Matchers.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000016#include "Protocol.h"
Sam McCallb536a2a2017-12-19 12:23:48 +000017#include "SourceCode.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000018#include "TestFS.h"
Eric Liu6f648df2017-12-19 16:50:37 +000019#include "index/MemIndex.h"
Sam McCallf6ae3232017-12-05 20:11:29 +000020#include "gmock/gmock.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000021#include "gtest/gtest.h"
22
23namespace clang {
24namespace clangd {
Sam McCall800d4372017-12-19 10:29:27 +000025// Let GMock print completion items and signature help.
Sam McCallf6ae3232017-12-05 20:11:29 +000026void PrintTo(const CompletionItem &I, std::ostream *O) {
27 llvm::raw_os_ostream OS(*O);
Sam McCall44fdcec22017-12-08 15:00:59 +000028 OS << I.label << " - " << toJSON(I);
29}
30void PrintTo(const std::vector<CompletionItem> &V, std::ostream *O) {
31 *O << "{\n";
32 for (const auto &I : V) {
33 *O << "\t";
34 PrintTo(I, O);
35 *O << "\n";
36 }
37 *O << "}";
Sam McCallf6ae3232017-12-05 20:11:29 +000038}
Sam McCall800d4372017-12-19 10:29:27 +000039void PrintTo(const SignatureInformation &I, std::ostream *O) {
40 llvm::raw_os_ostream OS(*O);
41 OS << I.label << " - " << toJSON(I);
42}
43void PrintTo(const std::vector<SignatureInformation> &V, std::ostream *O) {
44 *O << "{\n";
45 for (const auto &I : V) {
46 *O << "\t";
47 PrintTo(I, O);
48 *O << "\n";
49 }
50 *O << "}";
51}
Sam McCallf6ae3232017-12-05 20:11:29 +000052
Sam McCall9aad25f2017-12-05 07:20:26 +000053namespace {
54using namespace llvm;
Sam McCallf6ae3232017-12-05 20:11:29 +000055using ::testing::AllOf;
56using ::testing::Contains;
57using ::testing::ElementsAre;
Sam McCallf6ae3232017-12-05 20:11:29 +000058using ::testing::Not;
Sam McCall9aad25f2017-12-05 07:20:26 +000059
60class IgnoreDiagnostics : public DiagnosticsConsumer {
61 void onDiagnosticsReady(
62 PathRef File, Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {}
63};
64
Sam McCallf6ae3232017-12-05 20:11:29 +000065// GMock helpers for matching completion items.
66MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
Sam McCall44fdcec22017-12-08 15:00:59 +000067MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
68MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000069MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Sam McCall44fdcec22017-12-08 15:00:59 +000070MATCHER_P(PlainText, Text, "") {
71 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
72 arg.insertText == Text;
73}
74MATCHER_P(Snippet, Text, "") {
75 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
76 arg.insertText == Text;
77}
Sam McCallf6ae3232017-12-05 20:11:29 +000078// Shorthand for Contains(Named(Name)).
79Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
80 return Contains(Named(std::move(Name)));
81}
Sam McCall44fdcec22017-12-08 15:00:59 +000082Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
83 CompletionItemKind K) {
84 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000085}
Sam McCall44fdcec22017-12-08 15:00:59 +000086MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000087
Sam McCallf6ae3232017-12-05 20:11:29 +000088CompletionList completions(StringRef Text,
89 clangd::CodeCompleteOptions Opts = {}) {
Sam McCall9aad25f2017-12-05 07:20:26 +000090 MockFSProvider FS;
Sam McCall93cd9912017-12-05 07:34:35 +000091 MockCompilationDatabase CDB;
Sam McCallf6ae3232017-12-05 20:11:29 +000092 IgnoreDiagnostics DiagConsumer;
Sam McCall9aad25f2017-12-05 07:20:26 +000093 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +000094 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +000095 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +000096 Annotations Test(Text);
97 Server.addDocument(Context::empty(), File, Test.code());
98 return Server.codeComplete(Context::empty(), File, Test.point(), Opts)
Ilya Biryukov940901e2017-12-13 12:51:22 +000099 .get()
100 .second.Value;
Sam McCall9aad25f2017-12-05 07:20:26 +0000101}
102
Sam McCallf6ae3232017-12-05 20:11:29 +0000103TEST(CompletionTest, Limit) {
104 clangd::CodeCompleteOptions Opts;
105 Opts.Limit = 2;
106 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000107struct ClassWithMembers {
108 int AAA();
109 int BBB();
110 int CCC();
111}
Sam McCallf6ae3232017-12-05 20:11:29 +0000112int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000113 )cpp",
Sam McCallf6ae3232017-12-05 20:11:29 +0000114 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000115
116 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000117 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000118}
119
Sam McCallf6ae3232017-12-05 20:11:29 +0000120TEST(CompletionTest, Filter) {
121 std::string Body = R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000122 int Abracadabra;
123 int Alakazam;
124 struct S {
125 int FooBar;
126 int FooBaz;
127 int Qux;
128 };
129 )cpp";
Sam McCallf6ae3232017-12-05 20:11:29 +0000130 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
131 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000132
Sam McCallf6ae3232017-12-05 20:11:29 +0000133 EXPECT_THAT(completions(Body + "int main() { S().FR^ }").items,
134 AllOf(Has("FooBar"), Not(Has("FooBaz")), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000135
Sam McCallf6ae3232017-12-05 20:11:29 +0000136 EXPECT_THAT(completions(Body + "int main() { S().opr^ }").items,
137 Has("operator="));
Sam McCall9aad25f2017-12-05 07:20:26 +0000138
Sam McCallf6ae3232017-12-05 20:11:29 +0000139 EXPECT_THAT(completions(Body + "int main() { aaa^ }").items,
140 AllOf(Has("Abracadabra"), Has("Alakazam")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000141
Sam McCallf6ae3232017-12-05 20:11:29 +0000142 EXPECT_THAT(completions(Body + "int main() { _a^ }").items,
143 AllOf(Has("static_cast"), Not(Has("Abracadabra"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000144}
145
Sam McCallf6ae3232017-12-05 20:11:29 +0000146void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000147 auto Results = completions(
148 R"cpp(
149 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000150
Sam McCall44fdcec22017-12-08 15:00:59 +0000151 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000152
Sam McCall44fdcec22017-12-08 15:00:59 +0000153 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000154
Sam McCall44fdcec22017-12-08 15:00:59 +0000155 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000156
Sam McCall44fdcec22017-12-08 15:00:59 +0000157 struct ClassWithMembers {
158 /// Doc for method.
159 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000160
Sam McCall44fdcec22017-12-08 15:00:59 +0000161 int field;
162 private:
163 int private_field;
164 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000165
Sam McCall44fdcec22017-12-08 15:00:59 +0000166 int test() {
167 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000168
Sam McCall44fdcec22017-12-08 15:00:59 +0000169 /// Doc for local_var.
170 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000171
Sam McCall44fdcec22017-12-08 15:00:59 +0000172 ClassWithMembers().^
173 }
174 )cpp",
175 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000176
Sam McCallf6ae3232017-12-05 20:11:29 +0000177 // Class members. The only items that must be present in after-dot
178 // completion.
Sam McCall44fdcec22017-12-08 15:00:59 +0000179 EXPECT_THAT(
180 Results.items,
181 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"), Has("field")));
182 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
183 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000184 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000185 EXPECT_THAT(Results.items, Not(AnyOf(Has("global_var"), Has("global_func"),
186 Has("global_func()"), Has("GlobalClass"),
187 Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000188 // There should be no code patterns (aka snippets) in after-dot
189 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000190 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000191 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000192 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
193 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000194}
Sam McCall9aad25f2017-12-05 07:20:26 +0000195
Sam McCallf6ae3232017-12-05 20:11:29 +0000196void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000197 auto Results = completions(
198 R"cpp(
199 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000200
Sam McCall44fdcec22017-12-08 15:00:59 +0000201 int global_var;
202 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000203
Sam McCall44fdcec22017-12-08 15:00:59 +0000204 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000205
Sam McCall44fdcec22017-12-08 15:00:59 +0000206 struct ClassWithMembers {
207 /// Doc for method.
208 int method();
209 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000210
Sam McCall44fdcec22017-12-08 15:00:59 +0000211 int test() {
212 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000213
Sam McCall44fdcec22017-12-08 15:00:59 +0000214 /// Doc for local_var.
215 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000216
Sam McCall44fdcec22017-12-08 15:00:59 +0000217 ^
218 }
219 )cpp",
220 Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000221
222 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000223 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000224 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
225 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000226 EXPECT_IFF(Opts.IncludeGlobals, Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000227 AllOf(Has("global_var"),
228 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
229 Has("GlobalClass")));
230 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000231 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000232 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000233 EXPECT_THAT(Results.items,
234 AllOf(Has("local_var"), Has("LocalClass"),
235 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000236 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000237 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
238 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000239}
240
241TEST(CompletionTest, CompletionOptions) {
242 clangd::CodeCompleteOptions Opts;
Sam McCall9aad25f2017-12-05 07:20:26 +0000243 for (bool IncludeMacros : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000244 Opts.IncludeMacros = IncludeMacros;
Sam McCall9aad25f2017-12-05 07:20:26 +0000245 for (bool IncludeGlobals : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000246 Opts.IncludeGlobals = IncludeGlobals;
Sam McCall9aad25f2017-12-05 07:20:26 +0000247 for (bool IncludeBriefComments : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000248 Opts.IncludeBriefComments = IncludeBriefComments;
Sam McCall9aad25f2017-12-05 07:20:26 +0000249 for (bool EnableSnippets : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000250 Opts.EnableSnippets = EnableSnippets;
Sam McCall9aad25f2017-12-05 07:20:26 +0000251 for (bool IncludeCodePatterns : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000252 Opts.IncludeCodePatterns = IncludeCodePatterns;
Sam McCall9aad25f2017-12-05 07:20:26 +0000253 for (bool IncludeIneligibleResults : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000254 Opts.IncludeIneligibleResults = IncludeIneligibleResults;
255 TestAfterDotCompletion(Opts);
256 TestGlobalScopeCompletion(Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000257 }
258 }
259 }
260 }
261 }
262 }
263}
264
Sam McCallf6ae3232017-12-05 20:11:29 +0000265// Check code completion works when the file contents are overridden.
266TEST(CompletionTest, CheckContentsOverride) {
267 MockFSProvider FS;
268 IgnoreDiagnostics DiagConsumer;
269 MockCompilationDatabase CDB;
270 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000271 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000272 auto File = getVirtualTestFilePath("foo.cpp");
Ilya Biryukov940901e2017-12-13 12:51:22 +0000273 Server.addDocument(Context::empty(), File, "ignored text!");
Sam McCallf6ae3232017-12-05 20:11:29 +0000274
Sam McCall328cbdb2017-12-20 16:06:05 +0000275 Annotations Example("int cbc; int b = ^;");
276 auto Results = Server
277 .codeComplete(Context::empty(), File, Example.point(),
278 clangd::CodeCompleteOptions(),
279 StringRef(Example.code()))
280 .get()
281 .second.Value;
Sam McCallf6ae3232017-12-05 20:11:29 +0000282 EXPECT_THAT(Results.items, Contains(Named("cbc")));
283}
284
Sam McCall44fdcec22017-12-08 15:00:59 +0000285TEST(CompletionTest, Priorities) {
286 auto Internal = completions(R"cpp(
287 class Foo {
288 public: void pub();
289 protected: void prot();
290 private: void priv();
291 };
292 void Foo::pub() { this->^ }
293 )cpp");
294 EXPECT_THAT(Internal.items,
295 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
296
297 auto External = completions(R"cpp(
298 class Foo {
299 public: void pub();
300 protected: void prot();
301 private: void priv();
302 };
303 void test() {
304 Foo F;
305 F.^
306 }
307 )cpp");
308 EXPECT_THAT(External.items,
309 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
310}
311
312TEST(CompletionTest, Qualifiers) {
313 auto Results = completions(R"cpp(
314 class Foo {
315 public: int foo() const;
316 int bar() const;
317 };
318 class Bar : public Foo {
319 int foo() const;
320 };
321 void test() { Bar().^ }
322 )cpp");
323 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
324 Labeled("Foo::foo() const")));
325 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
326}
327
328TEST(CompletionTest, Snippets) {
329 clangd::CodeCompleteOptions Opts;
330 Opts.EnableSnippets = true;
331 auto Results = completions(
332 R"cpp(
333 struct fake {
334 int a;
335 int f(int i, const float f) const;
336 };
337 int main() {
338 fake f;
339 f.^
340 }
341 )cpp",
342 Opts);
343 EXPECT_THAT(Results.items,
344 HasSubsequence(PlainText("a"),
345 Snippet("f(${1:int i}, ${2:const float f})")));
346}
347
348TEST(CompletionTest, Kinds) {
349 auto Results = completions(R"cpp(
350 #define MACRO X
351 int variable;
352 struct Struct {};
353 int function();
354 int X = ^
355 )cpp");
356 EXPECT_THAT(Results.items, Has("function", CompletionItemKind::Function));
357 EXPECT_THAT(Results.items, Has("variable", CompletionItemKind::Variable));
358 EXPECT_THAT(Results.items, Has("int", CompletionItemKind::Keyword));
359 EXPECT_THAT(Results.items, Has("Struct", CompletionItemKind::Class));
360 EXPECT_THAT(Results.items, Has("MACRO", CompletionItemKind::Text));
361
362 clangd::CodeCompleteOptions Opts;
363 Opts.EnableSnippets = true; // Needed for code patterns.
364
365 Results = completions("nam^");
366 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
367}
368
Sam McCall800d4372017-12-19 10:29:27 +0000369SignatureHelp signatures(StringRef Text) {
370 MockFSProvider FS;
371 MockCompilationDatabase CDB;
372 IgnoreDiagnostics DiagConsumer;
373 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
374 /*StorePreamblesInMemory=*/true);
375 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000376 Annotations Test(Text);
377 Server.addDocument(Context::empty(), File, Test.code());
378 auto R = Server.signatureHelp(Context::empty(), File, Test.point());
Sam McCall800d4372017-12-19 10:29:27 +0000379 assert(R);
380 return R.get().Value;
381}
382
383MATCHER_P(ParamsAre, P, "") {
384 if (P.size() != arg.parameters.size())
385 return false;
386 for (unsigned I = 0; I < P.size(); ++I)
387 if (P[I] != arg.parameters[I].label)
388 return false;
389 return true;
390}
391
392Matcher<SignatureInformation> Sig(std::string Label,
393 std::vector<std::string> Params) {
394 return AllOf(Labeled(Label), ParamsAre(Params));
395}
396
397TEST(SignatureHelpTest, Overloads) {
398 auto Results = signatures(R"cpp(
399 void foo(int x, int y);
400 void foo(int x, float y);
401 void foo(float x, int y);
402 void foo(float x, float y);
403 void bar(int x, int y = 0);
404 int main() { foo(^); }
405 )cpp");
406 EXPECT_THAT(Results.signatures,
407 UnorderedElementsAre(
408 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
409 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
410 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
411 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
412 // We always prefer the first signature.
413 EXPECT_EQ(0, Results.activeSignature);
414 EXPECT_EQ(0, Results.activeParameter);
415}
416
417TEST(SignatureHelpTest, DefaultArgs) {
418 auto Results = signatures(R"cpp(
419 void bar(int x, int y = 0);
420 void bar(float x = 0, int y = 42);
421 int main() { bar(^
422 )cpp");
423 EXPECT_THAT(Results.signatures,
424 UnorderedElementsAre(
425 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
426 Sig("bar(float x = 0, int y = 42) -> void",
427 {"float x = 0", "int y = 42"})));
428 EXPECT_EQ(0, Results.activeSignature);
429 EXPECT_EQ(0, Results.activeParameter);
430}
431
432TEST(SignatureHelpTest, ActiveArg) {
433 auto Results = signatures(R"cpp(
434 int baz(int a, int b, int c);
435 int main() { baz(baz(1,2,3), ^); }
436 )cpp");
437 EXPECT_THAT(Results.signatures,
438 ElementsAre(Sig("baz(int a, int b, int c) -> int",
439 {"int a", "int b", "int c"})));
440 EXPECT_EQ(0, Results.activeSignature);
441 EXPECT_EQ(1, Results.activeParameter);
442}
443
Eric Liu6f648df2017-12-19 16:50:37 +0000444std::unique_ptr<SymbolIndex> simpleIndexFromSymbols(
445 std::vector<std::pair<std::string, index::SymbolKind>> Symbols) {
446 auto I = llvm::make_unique<MemIndex>();
447 struct Snapshot {
448 SymbolSlab Slab;
449 std::vector<const Symbol *> Pointers;
450 };
451 auto Snap = std::make_shared<Snapshot>();
452 for (const auto &Pair : Symbols) {
453 Symbol Sym;
454 Sym.ID = SymbolID(Pair.first);
455 llvm::StringRef QName = Pair.first;
456 size_t Pos = QName.rfind("::");
457 if (Pos == llvm::StringRef::npos) {
458 Sym.Name = QName;
459 Sym.Scope = "";
460 } else {
461 Sym.Name = QName.substr(Pos + 2);
462 Sym.Scope = QName.substr(0, Pos);
463 }
464 Sym.SymInfo.Kind = Pair.second;
465 Snap->Slab.insert(std::move(Sym));
466 }
467 for (auto &Iter : Snap->Slab)
468 Snap->Pointers.push_back(&Iter.second);
469 auto S = std::shared_ptr<std::vector<const Symbol *>>(std::move(Snap),
470 &Snap->Pointers);
471 I->build(std::move(S));
Sam McCalle3e15702017-12-19 17:05:00 +0000472 return std::move(I);
Eric Liu6f648df2017-12-19 16:50:37 +0000473}
474
475TEST(CompletionTest, NoIndex) {
476 clangd::CodeCompleteOptions Opts;
477 Opts.Index = nullptr;
478
479 auto Results = completions(R"cpp(
480 namespace ns { class No {}; }
481 void f() { ns::^ }
482 )cpp",
483 Opts);
484 EXPECT_THAT(Results.items, Has("No"));
485}
486
487TEST(CompletionTest, SimpleIndexBased) {
488 clangd::CodeCompleteOptions Opts;
489 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
490 {"nx::XYZ", index::SymbolKind::Class},
491 {"ns::foo", index::SymbolKind::Function}});
492 Opts.Index = I.get();
493
494 auto Results = completions(R"cpp(
495 namespace ns { class No {}; }
496 void f() { ns::^ }
497 )cpp",
498 Opts);
499 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
500 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
501 EXPECT_THAT(Results.items, Not(Has("No")));
502}
503
504TEST(CompletionTest, IndexBasedWithFilter) {
505 clangd::CodeCompleteOptions Opts;
506 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
507 {"ns::foo", index::SymbolKind::Function}});
508 Opts.Index = I.get();
509
510 auto Results = completions(R"cpp(
511 void f() { ns::x^ }
512 )cpp",
513 Opts);
514 EXPECT_THAT(Results.items, Contains(AllOf(Named("XYZ"), Filter("x"))));
515 EXPECT_THAT(Results.items, Not(Has("foo")));
516}
517
518TEST(CompletionTest, GlobalQualified) {
519 clangd::CodeCompleteOptions Opts;
520 auto I = simpleIndexFromSymbols({{"XYZ", index::SymbolKind::Class}});
521 Opts.Index = I.get();
522
523 auto Results = completions(R"cpp(
524 void f() { ::^ }
525 )cpp",
526 Opts);
527 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
528}
529
530TEST(CompletionTest, FullyQualifiedScope) {
531 clangd::CodeCompleteOptions Opts;
532 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
533 Opts.Index = I.get();
534
535 auto Results = completions(R"cpp(
536 void f() { ::ns::^ }
537 )cpp",
538 Opts);
539 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
540}
541
Eric Liubfac8f72017-12-19 18:00:37 +0000542TEST(CompletionTest, ASTIndexMultiFile) {
543 MockFSProvider FS;
544 MockCompilationDatabase CDB;
545 IgnoreDiagnostics DiagConsumer;
546 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
547 /*StorePreamblesInMemory=*/true,
548 /*BuildDynamicSymbolIndex=*/true);
549
550 Server
551 .addDocument(Context::empty(), getVirtualTestFilePath("foo.cpp"), R"cpp(
552 namespace ns { class XYZ {}; void foo() {} }
553 )cpp")
554 .wait();
555
556 auto File = getVirtualTestFilePath("bar.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000557 Annotations Test(R"cpp(
Eric Liubfac8f72017-12-19 18:00:37 +0000558 namespace ns { class XXX {}; void fooooo() {} }
559 void f() { ns::^ }
560 )cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000561 Server.addDocument(Context::empty(), File, Test.code()).wait();
Eric Liubfac8f72017-12-19 18:00:37 +0000562
Sam McCall328cbdb2017-12-20 16:06:05 +0000563 auto Results = Server.codeComplete(Context::empty(), File, Test.point(), {})
Eric Liubfac8f72017-12-19 18:00:37 +0000564 .get()
565 .second.Value;
566 // "XYZ" and "foo" are not included in the file being completed but are still
567 // visible through the index.
568 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
569 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
570 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
571 EXPECT_THAT(Results.items, Has("fooooo", CompletionItemKind::Function));
572}
573
Sam McCall9aad25f2017-12-05 07:20:26 +0000574} // namespace
575} // namespace clangd
576} // namespace clang