blob: 1cc95e9fb35f9693a4761376bc4a743c2a0154ef [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 McCall84652cc2018-01-12 16:16:09 +0000383TEST(CompletionTest, NoDuplicates) {
384 auto Items = completions(R"cpp(
385struct Adapter {
386 void method();
387};
388
389void Adapter::method() {
390 Adapter^
391}
392 )cpp")
393 .items;
394
395 // Make sure there are no duplicate entries of 'Adapter'.
396 EXPECT_THAT(Items, ElementsAre(Named("Adapter"), Named("~Adapter")));
397}
398
399TEST(CompletionTest, FuzzyRanking) {
400 auto Items = completions(R"cpp(
401 struct fake { int BigBang, Babble, Ball; };
402 int main() { fake().bb^ }")cpp").items;
403 // BigBang is a better match than Babble. Ball doesn't match at all.
404 EXPECT_THAT(Items, ElementsAre(Named("BigBang"), Named("Babble")));
405}
406
Sam McCall800d4372017-12-19 10:29:27 +0000407SignatureHelp signatures(StringRef Text) {
408 MockFSProvider FS;
409 MockCompilationDatabase CDB;
410 IgnoreDiagnostics DiagConsumer;
411 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
412 /*StorePreamblesInMemory=*/true);
413 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000414 Annotations Test(Text);
415 Server.addDocument(Context::empty(), File, Test.code());
416 auto R = Server.signatureHelp(Context::empty(), File, Test.point());
Sam McCall800d4372017-12-19 10:29:27 +0000417 assert(R);
418 return R.get().Value;
419}
420
421MATCHER_P(ParamsAre, P, "") {
422 if (P.size() != arg.parameters.size())
423 return false;
424 for (unsigned I = 0; I < P.size(); ++I)
425 if (P[I] != arg.parameters[I].label)
426 return false;
427 return true;
428}
429
430Matcher<SignatureInformation> Sig(std::string Label,
431 std::vector<std::string> Params) {
432 return AllOf(Labeled(Label), ParamsAre(Params));
433}
434
435TEST(SignatureHelpTest, Overloads) {
436 auto Results = signatures(R"cpp(
437 void foo(int x, int y);
438 void foo(int x, float y);
439 void foo(float x, int y);
440 void foo(float x, float y);
441 void bar(int x, int y = 0);
442 int main() { foo(^); }
443 )cpp");
444 EXPECT_THAT(Results.signatures,
445 UnorderedElementsAre(
446 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
447 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
448 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
449 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
450 // We always prefer the first signature.
451 EXPECT_EQ(0, Results.activeSignature);
452 EXPECT_EQ(0, Results.activeParameter);
453}
454
455TEST(SignatureHelpTest, DefaultArgs) {
456 auto Results = signatures(R"cpp(
457 void bar(int x, int y = 0);
458 void bar(float x = 0, int y = 42);
459 int main() { bar(^
460 )cpp");
461 EXPECT_THAT(Results.signatures,
462 UnorderedElementsAre(
463 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
464 Sig("bar(float x = 0, int y = 42) -> void",
465 {"float x = 0", "int y = 42"})));
466 EXPECT_EQ(0, Results.activeSignature);
467 EXPECT_EQ(0, Results.activeParameter);
468}
469
470TEST(SignatureHelpTest, ActiveArg) {
471 auto Results = signatures(R"cpp(
472 int baz(int a, int b, int c);
473 int main() { baz(baz(1,2,3), ^); }
474 )cpp");
475 EXPECT_THAT(Results.signatures,
476 ElementsAre(Sig("baz(int a, int b, int c) -> int",
477 {"int a", "int b", "int c"})));
478 EXPECT_EQ(0, Results.activeSignature);
479 EXPECT_EQ(1, Results.activeParameter);
480}
481
Eric Liu6f648df2017-12-19 16:50:37 +0000482std::unique_ptr<SymbolIndex> simpleIndexFromSymbols(
483 std::vector<std::pair<std::string, index::SymbolKind>> Symbols) {
Sam McCall4b9bbb32017-12-23 19:38:03 +0000484 SymbolSlab::Builder Slab;
Eric Liu6f648df2017-12-19 16:50:37 +0000485 for (const auto &Pair : Symbols) {
486 Symbol Sym;
487 Sym.ID = SymbolID(Pair.first);
488 llvm::StringRef QName = Pair.first;
489 size_t Pos = QName.rfind("::");
490 if (Pos == llvm::StringRef::npos) {
491 Sym.Name = QName;
492 Sym.Scope = "";
493 } else {
494 Sym.Name = QName.substr(Pos + 2);
495 Sym.Scope = QName.substr(0, Pos);
496 }
Eric Liu76f6b442018-01-09 17:32:00 +0000497 Sym.CompletionPlainInsertText = Sym.Name;
Eric Liu6f648df2017-12-19 16:50:37 +0000498 Sym.SymInfo.Kind = Pair.second;
Sam McCall4b9bbb32017-12-23 19:38:03 +0000499 Slab.insert(Sym);
Eric Liu6f648df2017-12-19 16:50:37 +0000500 }
Haojian Wuba28e9a2018-01-10 14:44:34 +0000501 return MemIndex::build(std::move(Slab).build());
Eric Liu6f648df2017-12-19 16:50:37 +0000502}
503
504TEST(CompletionTest, NoIndex) {
505 clangd::CodeCompleteOptions Opts;
506 Opts.Index = nullptr;
507
508 auto Results = completions(R"cpp(
509 namespace ns { class No {}; }
510 void f() { ns::^ }
511 )cpp",
512 Opts);
513 EXPECT_THAT(Results.items, Has("No"));
514}
515
Haojian Wuba28e9a2018-01-10 14:44:34 +0000516TEST(CompletionTest, StaticAndDynamicIndex) {
517 clangd::CodeCompleteOptions Opts;
518 auto StaticIdx =
519 simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
520 Opts.StaticIndex = StaticIdx.get();
521 auto DynamicIdx =
522 simpleIndexFromSymbols({{"ns::foo", index::SymbolKind::Function}});
523 Opts.Index = DynamicIdx.get();
524
525 auto Results = completions(R"cpp(
526 void f() { ::ns::^ }
527 )cpp",
528 Opts);
529 EXPECT_THAT(Results.items, Contains(Labeled("[G]XYZ")));
530 EXPECT_THAT(Results.items, Contains(Labeled("foo")));
531}
532
Eric Liu6f648df2017-12-19 16:50:37 +0000533TEST(CompletionTest, SimpleIndexBased) {
534 clangd::CodeCompleteOptions Opts;
535 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
536 {"nx::XYZ", index::SymbolKind::Class},
537 {"ns::foo", index::SymbolKind::Function}});
538 Opts.Index = I.get();
539
540 auto Results = completions(R"cpp(
541 namespace ns { class No {}; }
542 void f() { ns::^ }
543 )cpp",
544 Opts);
545 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
546 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
547 EXPECT_THAT(Results.items, Not(Has("No")));
548}
549
550TEST(CompletionTest, IndexBasedWithFilter) {
551 clangd::CodeCompleteOptions Opts;
552 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
553 {"ns::foo", index::SymbolKind::Function}});
554 Opts.Index = I.get();
555
556 auto Results = completions(R"cpp(
557 void f() { ns::x^ }
558 )cpp",
559 Opts);
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000560 EXPECT_THAT(Results.items, Contains(AllOf(Named("XYZ"), Filter("XYZ"))));
Eric Liu6f648df2017-12-19 16:50:37 +0000561 EXPECT_THAT(Results.items, Not(Has("foo")));
562}
563
564TEST(CompletionTest, GlobalQualified) {
565 clangd::CodeCompleteOptions Opts;
566 auto I = simpleIndexFromSymbols({{"XYZ", index::SymbolKind::Class}});
567 Opts.Index = I.get();
568
569 auto Results = completions(R"cpp(
570 void f() { ::^ }
571 )cpp",
572 Opts);
573 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
574}
575
576TEST(CompletionTest, FullyQualifiedScope) {
577 clangd::CodeCompleteOptions Opts;
578 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
579 Opts.Index = I.get();
580
581 auto Results = completions(R"cpp(
582 void f() { ::ns::^ }
583 )cpp",
584 Opts);
585 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
586}
587
Eric Liubfac8f72017-12-19 18:00:37 +0000588TEST(CompletionTest, ASTIndexMultiFile) {
589 MockFSProvider FS;
590 MockCompilationDatabase CDB;
591 IgnoreDiagnostics DiagConsumer;
592 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
593 /*StorePreamblesInMemory=*/true,
594 /*BuildDynamicSymbolIndex=*/true);
595
596 Server
597 .addDocument(Context::empty(), getVirtualTestFilePath("foo.cpp"), R"cpp(
Eric Liu76f6b442018-01-09 17:32:00 +0000598 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liubfac8f72017-12-19 18:00:37 +0000599 )cpp")
600 .wait();
601
602 auto File = getVirtualTestFilePath("bar.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000603 Annotations Test(R"cpp(
Eric Liu76f6b442018-01-09 17:32:00 +0000604 namespace ns {
605 class XXX {};
606 /// Doooc
607 void fooooo() {}
608 }
Eric Liubfac8f72017-12-19 18:00:37 +0000609 void f() { ns::^ }
610 )cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000611 Server.addDocument(Context::empty(), File, Test.code()).wait();
Eric Liubfac8f72017-12-19 18:00:37 +0000612
Sam McCall328cbdb2017-12-20 16:06:05 +0000613 auto Results = Server.codeComplete(Context::empty(), File, Test.point(), {})
Eric Liubfac8f72017-12-19 18:00:37 +0000614 .get()
615 .second.Value;
616 // "XYZ" and "foo" are not included in the file being completed but are still
617 // visible through the index.
618 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
619 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
620 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
Eric Liu76f6b442018-01-09 17:32:00 +0000621 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
622 Kind(CompletionItemKind::Function),
623 Doc("Doooc"), Detail("void"))));
Eric Liubfac8f72017-12-19 18:00:37 +0000624}
625
Sam McCall9aad25f2017-12-05 07:20:26 +0000626} // namespace
627} // namespace clangd
628} // namespace clang