blob: 601c2daa471ae7ab228a7b940ab77e1de8cc2f01 [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;
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000057using ::testing::Each;
Sam McCallf6ae3232017-12-05 20:11:29 +000058using ::testing::ElementsAre;
Sam McCallf6ae3232017-12-05 20:11:29 +000059using ::testing::Not;
Sam McCall9aad25f2017-12-05 07:20:26 +000060
61class IgnoreDiagnostics : public DiagnosticsConsumer {
Ilya Biryukov95558392018-01-10 17:59:27 +000062 void
63 onDiagnosticsReady(const Context &Ctx, PathRef File,
64 Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {
65 }
Sam McCall9aad25f2017-12-05 07:20:26 +000066};
67
Sam McCallf6ae3232017-12-05 20:11:29 +000068// GMock helpers for matching completion items.
69MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
Sam McCall44fdcec22017-12-08 15:00:59 +000070MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
71MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000072MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Eric Liu76f6b442018-01-09 17:32:00 +000073MATCHER_P(Doc, D, "") { return arg.documentation == D; }
74MATCHER_P(Detail, D, "") { return arg.detail == D; }
Sam McCall44fdcec22017-12-08 15:00:59 +000075MATCHER_P(PlainText, Text, "") {
76 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
77 arg.insertText == Text;
78}
79MATCHER_P(Snippet, Text, "") {
80 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
81 arg.insertText == Text;
82}
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000083MATCHER(FilterContainsName, "") {
84 if (arg.filterText.empty())
85 return true;
86 return llvm::StringRef(arg.insertText).contains(arg.filterText);
87}
Sam McCallf6ae3232017-12-05 20:11:29 +000088// Shorthand for Contains(Named(Name)).
89Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
90 return Contains(Named(std::move(Name)));
91}
Sam McCall44fdcec22017-12-08 15:00:59 +000092Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
93 CompletionItemKind K) {
94 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000095}
Sam McCall44fdcec22017-12-08 15:00:59 +000096MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000097
Sam McCallf6ae3232017-12-05 20:11:29 +000098CompletionList completions(StringRef Text,
99 clangd::CodeCompleteOptions Opts = {}) {
Sam McCall9aad25f2017-12-05 07:20:26 +0000100 MockFSProvider FS;
Sam McCall93cd9912017-12-05 07:34:35 +0000101 MockCompilationDatabase CDB;
Sam McCallf6ae3232017-12-05 20:11:29 +0000102 IgnoreDiagnostics DiagConsumer;
Sam McCall9aad25f2017-12-05 07:20:26 +0000103 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000104 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000105 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000106 Annotations Test(Text);
107 Server.addDocument(Context::empty(), File, Test.code());
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000108 auto CompletionList =
109 Server.codeComplete(Context::empty(), File, Test.point(), Opts)
110 .get()
111 .second.Value;
112 // Sanity-check that filterText is valid.
113 EXPECT_THAT(CompletionList.items, Each(FilterContainsName()));
114 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000115}
116
Sam McCallf6ae3232017-12-05 20:11:29 +0000117TEST(CompletionTest, Limit) {
118 clangd::CodeCompleteOptions Opts;
119 Opts.Limit = 2;
120 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000121struct ClassWithMembers {
122 int AAA();
123 int BBB();
124 int CCC();
125}
Sam McCallf6ae3232017-12-05 20:11:29 +0000126int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000127 )cpp",
Sam McCallf6ae3232017-12-05 20:11:29 +0000128 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000129
130 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000131 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000132}
133
Sam McCallf6ae3232017-12-05 20:11:29 +0000134TEST(CompletionTest, Filter) {
135 std::string Body = R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000136 int Abracadabra;
137 int Alakazam;
138 struct S {
139 int FooBar;
140 int FooBaz;
141 int Qux;
142 };
143 )cpp";
Sam McCallf6ae3232017-12-05 20:11:29 +0000144 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
145 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000146
Sam McCallf6ae3232017-12-05 20:11:29 +0000147 EXPECT_THAT(completions(Body + "int main() { S().FR^ }").items,
148 AllOf(Has("FooBar"), Not(Has("FooBaz")), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000149
Sam McCallf6ae3232017-12-05 20:11:29 +0000150 EXPECT_THAT(completions(Body + "int main() { S().opr^ }").items,
151 Has("operator="));
Sam McCall9aad25f2017-12-05 07:20:26 +0000152
Sam McCallf6ae3232017-12-05 20:11:29 +0000153 EXPECT_THAT(completions(Body + "int main() { aaa^ }").items,
154 AllOf(Has("Abracadabra"), Has("Alakazam")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000155
Sam McCallf6ae3232017-12-05 20:11:29 +0000156 EXPECT_THAT(completions(Body + "int main() { _a^ }").items,
157 AllOf(Has("static_cast"), Not(Has("Abracadabra"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000158}
159
Sam McCallf6ae3232017-12-05 20:11:29 +0000160void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000161 auto Results = completions(
162 R"cpp(
163 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000164
Sam McCall44fdcec22017-12-08 15:00:59 +0000165 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000166
Sam McCall44fdcec22017-12-08 15:00:59 +0000167 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000168
Sam McCall44fdcec22017-12-08 15:00:59 +0000169 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000170
Sam McCall44fdcec22017-12-08 15:00:59 +0000171 struct ClassWithMembers {
172 /// Doc for method.
173 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000174
Sam McCall44fdcec22017-12-08 15:00:59 +0000175 int field;
176 private:
177 int private_field;
178 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000179
Sam McCall44fdcec22017-12-08 15:00:59 +0000180 int test() {
181 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000182
Sam McCall44fdcec22017-12-08 15:00:59 +0000183 /// Doc for local_var.
184 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000185
Sam McCall44fdcec22017-12-08 15:00:59 +0000186 ClassWithMembers().^
187 }
188 )cpp",
189 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000190
Sam McCallf6ae3232017-12-05 20:11:29 +0000191 // Class members. The only items that must be present in after-dot
192 // completion.
Sam McCall44fdcec22017-12-08 15:00:59 +0000193 EXPECT_THAT(
194 Results.items,
195 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"), Has("field")));
196 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
197 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000198 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000199 EXPECT_THAT(Results.items, Not(AnyOf(Has("global_var"), Has("global_func"),
200 Has("global_func()"), Has("GlobalClass"),
201 Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000202 // There should be no code patterns (aka snippets) in after-dot
203 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000204 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000205 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000206 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
207 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000208}
Sam McCall9aad25f2017-12-05 07:20:26 +0000209
Sam McCallf6ae3232017-12-05 20:11:29 +0000210void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000211 auto Results = completions(
212 R"cpp(
213 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000214
Sam McCall44fdcec22017-12-08 15:00:59 +0000215 int global_var;
216 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000217
Sam McCall44fdcec22017-12-08 15:00:59 +0000218 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000219
Sam McCall44fdcec22017-12-08 15:00:59 +0000220 struct ClassWithMembers {
221 /// Doc for method.
222 int method();
223 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000224
Sam McCall44fdcec22017-12-08 15:00:59 +0000225 int test() {
226 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000227
Sam McCall44fdcec22017-12-08 15:00:59 +0000228 /// Doc for local_var.
229 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000230
Sam McCall44fdcec22017-12-08 15:00:59 +0000231 ^
232 }
233 )cpp",
234 Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000235
236 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000237 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000238 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
239 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000240 EXPECT_IFF(Opts.IncludeGlobals, Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000241 AllOf(Has("global_var"),
242 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
243 Has("GlobalClass")));
244 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000245 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000246 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000247 EXPECT_THAT(Results.items,
248 AllOf(Has("local_var"), Has("LocalClass"),
249 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000250 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000251 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
252 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000253}
254
255TEST(CompletionTest, CompletionOptions) {
256 clangd::CodeCompleteOptions Opts;
Sam McCall9aad25f2017-12-05 07:20:26 +0000257 for (bool IncludeMacros : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000258 Opts.IncludeMacros = IncludeMacros;
Sam McCall9aad25f2017-12-05 07:20:26 +0000259 for (bool IncludeGlobals : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000260 Opts.IncludeGlobals = IncludeGlobals;
Sam McCall9aad25f2017-12-05 07:20:26 +0000261 for (bool IncludeBriefComments : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000262 Opts.IncludeBriefComments = IncludeBriefComments;
Sam McCall9aad25f2017-12-05 07:20:26 +0000263 for (bool EnableSnippets : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000264 Opts.EnableSnippets = EnableSnippets;
Sam McCall9aad25f2017-12-05 07:20:26 +0000265 for (bool IncludeCodePatterns : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000266 Opts.IncludeCodePatterns = IncludeCodePatterns;
Sam McCall9aad25f2017-12-05 07:20:26 +0000267 for (bool IncludeIneligibleResults : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000268 Opts.IncludeIneligibleResults = IncludeIneligibleResults;
269 TestAfterDotCompletion(Opts);
270 TestGlobalScopeCompletion(Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000271 }
272 }
273 }
274 }
275 }
276 }
277}
278
Sam McCallf6ae3232017-12-05 20:11:29 +0000279// Check code completion works when the file contents are overridden.
280TEST(CompletionTest, CheckContentsOverride) {
281 MockFSProvider FS;
282 IgnoreDiagnostics DiagConsumer;
283 MockCompilationDatabase CDB;
284 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000285 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000286 auto File = getVirtualTestFilePath("foo.cpp");
Ilya Biryukov940901e2017-12-13 12:51:22 +0000287 Server.addDocument(Context::empty(), File, "ignored text!");
Sam McCallf6ae3232017-12-05 20:11:29 +0000288
Sam McCall328cbdb2017-12-20 16:06:05 +0000289 Annotations Example("int cbc; int b = ^;");
290 auto Results = Server
291 .codeComplete(Context::empty(), File, Example.point(),
292 clangd::CodeCompleteOptions(),
293 StringRef(Example.code()))
294 .get()
295 .second.Value;
Sam McCallf6ae3232017-12-05 20:11:29 +0000296 EXPECT_THAT(Results.items, Contains(Named("cbc")));
297}
298
Sam McCall44fdcec22017-12-08 15:00:59 +0000299TEST(CompletionTest, Priorities) {
300 auto Internal = completions(R"cpp(
301 class Foo {
302 public: void pub();
303 protected: void prot();
304 private: void priv();
305 };
306 void Foo::pub() { this->^ }
307 )cpp");
308 EXPECT_THAT(Internal.items,
309 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
310
311 auto External = completions(R"cpp(
312 class Foo {
313 public: void pub();
314 protected: void prot();
315 private: void priv();
316 };
317 void test() {
318 Foo F;
319 F.^
320 }
321 )cpp");
322 EXPECT_THAT(External.items,
323 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
324}
325
326TEST(CompletionTest, Qualifiers) {
327 auto Results = completions(R"cpp(
328 class Foo {
329 public: int foo() const;
330 int bar() const;
331 };
332 class Bar : public Foo {
333 int foo() const;
334 };
335 void test() { Bar().^ }
336 )cpp");
337 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
338 Labeled("Foo::foo() const")));
339 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
340}
341
342TEST(CompletionTest, Snippets) {
343 clangd::CodeCompleteOptions Opts;
344 Opts.EnableSnippets = true;
345 auto Results = completions(
346 R"cpp(
347 struct fake {
348 int a;
349 int f(int i, const float f) const;
350 };
351 int main() {
352 fake f;
353 f.^
354 }
355 )cpp",
356 Opts);
357 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000358 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000359 Snippet("f(${1:int i}, ${2:const float f})")));
360}
361
362TEST(CompletionTest, Kinds) {
363 auto Results = completions(R"cpp(
364 #define MACRO X
365 int variable;
366 struct Struct {};
367 int function();
368 int X = ^
369 )cpp");
370 EXPECT_THAT(Results.items, Has("function", CompletionItemKind::Function));
371 EXPECT_THAT(Results.items, Has("variable", CompletionItemKind::Variable));
372 EXPECT_THAT(Results.items, Has("int", CompletionItemKind::Keyword));
373 EXPECT_THAT(Results.items, Has("Struct", CompletionItemKind::Class));
374 EXPECT_THAT(Results.items, Has("MACRO", CompletionItemKind::Text));
375
376 clangd::CodeCompleteOptions Opts;
377 Opts.EnableSnippets = true; // Needed for code patterns.
378
379 Results = completions("nam^");
380 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
381}
382
Sam McCall800d4372017-12-19 10:29:27 +0000383SignatureHelp signatures(StringRef Text) {
384 MockFSProvider FS;
385 MockCompilationDatabase CDB;
386 IgnoreDiagnostics DiagConsumer;
387 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
388 /*StorePreamblesInMemory=*/true);
389 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000390 Annotations Test(Text);
391 Server.addDocument(Context::empty(), File, Test.code());
392 auto R = Server.signatureHelp(Context::empty(), File, Test.point());
Sam McCall800d4372017-12-19 10:29:27 +0000393 assert(R);
394 return R.get().Value;
395}
396
397MATCHER_P(ParamsAre, P, "") {
398 if (P.size() != arg.parameters.size())
399 return false;
400 for (unsigned I = 0; I < P.size(); ++I)
401 if (P[I] != arg.parameters[I].label)
402 return false;
403 return true;
404}
405
406Matcher<SignatureInformation> Sig(std::string Label,
407 std::vector<std::string> Params) {
408 return AllOf(Labeled(Label), ParamsAre(Params));
409}
410
411TEST(SignatureHelpTest, Overloads) {
412 auto Results = signatures(R"cpp(
413 void foo(int x, int y);
414 void foo(int x, float y);
415 void foo(float x, int y);
416 void foo(float x, float y);
417 void bar(int x, int y = 0);
418 int main() { foo(^); }
419 )cpp");
420 EXPECT_THAT(Results.signatures,
421 UnorderedElementsAre(
422 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
423 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
424 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
425 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
426 // We always prefer the first signature.
427 EXPECT_EQ(0, Results.activeSignature);
428 EXPECT_EQ(0, Results.activeParameter);
429}
430
431TEST(SignatureHelpTest, DefaultArgs) {
432 auto Results = signatures(R"cpp(
433 void bar(int x, int y = 0);
434 void bar(float x = 0, int y = 42);
435 int main() { bar(^
436 )cpp");
437 EXPECT_THAT(Results.signatures,
438 UnorderedElementsAre(
439 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
440 Sig("bar(float x = 0, int y = 42) -> void",
441 {"float x = 0", "int y = 42"})));
442 EXPECT_EQ(0, Results.activeSignature);
443 EXPECT_EQ(0, Results.activeParameter);
444}
445
446TEST(SignatureHelpTest, ActiveArg) {
447 auto Results = signatures(R"cpp(
448 int baz(int a, int b, int c);
449 int main() { baz(baz(1,2,3), ^); }
450 )cpp");
451 EXPECT_THAT(Results.signatures,
452 ElementsAre(Sig("baz(int a, int b, int c) -> int",
453 {"int a", "int b", "int c"})));
454 EXPECT_EQ(0, Results.activeSignature);
455 EXPECT_EQ(1, Results.activeParameter);
456}
457
Eric Liu6f648df2017-12-19 16:50:37 +0000458std::unique_ptr<SymbolIndex> simpleIndexFromSymbols(
459 std::vector<std::pair<std::string, index::SymbolKind>> Symbols) {
Sam McCall4b9bbb32017-12-23 19:38:03 +0000460 SymbolSlab::Builder Slab;
Eric Liu6f648df2017-12-19 16:50:37 +0000461 for (const auto &Pair : Symbols) {
462 Symbol Sym;
463 Sym.ID = SymbolID(Pair.first);
464 llvm::StringRef QName = Pair.first;
465 size_t Pos = QName.rfind("::");
466 if (Pos == llvm::StringRef::npos) {
467 Sym.Name = QName;
468 Sym.Scope = "";
469 } else {
470 Sym.Name = QName.substr(Pos + 2);
471 Sym.Scope = QName.substr(0, Pos);
472 }
Eric Liu76f6b442018-01-09 17:32:00 +0000473 Sym.CompletionPlainInsertText = Sym.Name;
Eric Liu6f648df2017-12-19 16:50:37 +0000474 Sym.SymInfo.Kind = Pair.second;
Sam McCall4b9bbb32017-12-23 19:38:03 +0000475 Slab.insert(Sym);
Eric Liu6f648df2017-12-19 16:50:37 +0000476 }
Haojian Wuba28e9a2018-01-10 14:44:34 +0000477 return MemIndex::build(std::move(Slab).build());
Eric Liu6f648df2017-12-19 16:50:37 +0000478}
479
480TEST(CompletionTest, NoIndex) {
481 clangd::CodeCompleteOptions Opts;
482 Opts.Index = nullptr;
483
484 auto Results = completions(R"cpp(
485 namespace ns { class No {}; }
486 void f() { ns::^ }
487 )cpp",
488 Opts);
489 EXPECT_THAT(Results.items, Has("No"));
490}
491
Haojian Wuba28e9a2018-01-10 14:44:34 +0000492TEST(CompletionTest, StaticAndDynamicIndex) {
493 clangd::CodeCompleteOptions Opts;
494 auto StaticIdx =
495 simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
496 Opts.StaticIndex = StaticIdx.get();
497 auto DynamicIdx =
498 simpleIndexFromSymbols({{"ns::foo", index::SymbolKind::Function}});
499 Opts.Index = DynamicIdx.get();
500
501 auto Results = completions(R"cpp(
502 void f() { ::ns::^ }
503 )cpp",
504 Opts);
505 EXPECT_THAT(Results.items, Contains(Labeled("[G]XYZ")));
506 EXPECT_THAT(Results.items, Contains(Labeled("foo")));
507}
508
Eric Liu6f648df2017-12-19 16:50:37 +0000509TEST(CompletionTest, SimpleIndexBased) {
510 clangd::CodeCompleteOptions Opts;
511 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
512 {"nx::XYZ", index::SymbolKind::Class},
513 {"ns::foo", index::SymbolKind::Function}});
514 Opts.Index = I.get();
515
516 auto Results = completions(R"cpp(
517 namespace ns { class No {}; }
518 void f() { ns::^ }
519 )cpp",
520 Opts);
521 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
522 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
523 EXPECT_THAT(Results.items, Not(Has("No")));
524}
525
526TEST(CompletionTest, IndexBasedWithFilter) {
527 clangd::CodeCompleteOptions Opts;
528 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
529 {"ns::foo", index::SymbolKind::Function}});
530 Opts.Index = I.get();
531
532 auto Results = completions(R"cpp(
533 void f() { ns::x^ }
534 )cpp",
535 Opts);
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000536 EXPECT_THAT(Results.items, Contains(AllOf(Named("XYZ"), Filter("XYZ"))));
Eric Liu6f648df2017-12-19 16:50:37 +0000537 EXPECT_THAT(Results.items, Not(Has("foo")));
538}
539
540TEST(CompletionTest, GlobalQualified) {
541 clangd::CodeCompleteOptions Opts;
542 auto I = simpleIndexFromSymbols({{"XYZ", index::SymbolKind::Class}});
543 Opts.Index = I.get();
544
545 auto Results = completions(R"cpp(
546 void f() { ::^ }
547 )cpp",
548 Opts);
549 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
550}
551
552TEST(CompletionTest, FullyQualifiedScope) {
553 clangd::CodeCompleteOptions Opts;
554 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
555 Opts.Index = I.get();
556
557 auto Results = completions(R"cpp(
558 void f() { ::ns::^ }
559 )cpp",
560 Opts);
561 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
562}
563
Eric Liubfac8f72017-12-19 18:00:37 +0000564TEST(CompletionTest, ASTIndexMultiFile) {
565 MockFSProvider FS;
566 MockCompilationDatabase CDB;
567 IgnoreDiagnostics DiagConsumer;
568 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
569 /*StorePreamblesInMemory=*/true,
570 /*BuildDynamicSymbolIndex=*/true);
571
572 Server
573 .addDocument(Context::empty(), getVirtualTestFilePath("foo.cpp"), R"cpp(
Eric Liu76f6b442018-01-09 17:32:00 +0000574 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liubfac8f72017-12-19 18:00:37 +0000575 )cpp")
576 .wait();
577
578 auto File = getVirtualTestFilePath("bar.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000579 Annotations Test(R"cpp(
Eric Liu76f6b442018-01-09 17:32:00 +0000580 namespace ns {
581 class XXX {};
582 /// Doooc
583 void fooooo() {}
584 }
Eric Liubfac8f72017-12-19 18:00:37 +0000585 void f() { ns::^ }
586 )cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000587 Server.addDocument(Context::empty(), File, Test.code()).wait();
Eric Liubfac8f72017-12-19 18:00:37 +0000588
Sam McCall328cbdb2017-12-20 16:06:05 +0000589 auto Results = Server.codeComplete(Context::empty(), File, Test.point(), {})
Eric Liubfac8f72017-12-19 18:00:37 +0000590 .get()
591 .second.Value;
592 // "XYZ" and "foo" are not included in the file being completed but are still
593 // visible through the index.
594 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
595 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
596 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
Eric Liu76f6b442018-01-09 17:32:00 +0000597 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
598 Kind(CompletionItemKind::Function),
599 Doc("Doooc"), Detail("void"))));
Eric Liubfac8f72017-12-19 18:00:37 +0000600}
601
Ilya Biryukovf60bf342018-01-10 13:51:09 +0000602TEST(CompletionTest, NoDuplicates) {
603 auto Items = completions(R"cpp(
604struct Adapter {
605 void method();
606};
607
608void Adapter::method() {
609 Adapter^
610}
611 )cpp")
612 .items;
613
614 // Make sure there are no duplicate entries of 'Adapter'.
615 EXPECT_THAT(Items, ElementsAre(Named("Adapter"), Named("~Adapter")));
616}
617
Sam McCall9aad25f2017-12-05 07:20:26 +0000618} // namespace
619} // namespace clangd
620} // namespace clang