blob: c281415b4ece91375c34de92d9122b26e67294bd [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 {
62 void onDiagnosticsReady(
63 PathRef File, Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {}
64};
65
Sam McCallf6ae3232017-12-05 20:11:29 +000066// GMock helpers for matching completion items.
67MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
Sam McCall44fdcec22017-12-08 15:00:59 +000068MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
69MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000070MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Eric Liu76f6b442018-01-09 17:32:00 +000071MATCHER_P(Doc, D, "") { return arg.documentation == D; }
72MATCHER_P(Detail, D, "") { return arg.detail == D; }
Sam McCall44fdcec22017-12-08 15:00:59 +000073MATCHER_P(PlainText, Text, "") {
74 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
75 arg.insertText == Text;
76}
77MATCHER_P(Snippet, Text, "") {
78 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
79 arg.insertText == Text;
80}
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000081MATCHER(FilterContainsName, "") {
82 if (arg.filterText.empty())
83 return true;
84 return llvm::StringRef(arg.insertText).contains(arg.filterText);
85}
Sam McCallf6ae3232017-12-05 20:11:29 +000086// Shorthand for Contains(Named(Name)).
87Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
88 return Contains(Named(std::move(Name)));
89}
Sam McCall44fdcec22017-12-08 15:00:59 +000090Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
91 CompletionItemKind K) {
92 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000093}
Sam McCall44fdcec22017-12-08 15:00:59 +000094MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000095
Sam McCallf6ae3232017-12-05 20:11:29 +000096CompletionList completions(StringRef Text,
97 clangd::CodeCompleteOptions Opts = {}) {
Sam McCall9aad25f2017-12-05 07:20:26 +000098 MockFSProvider FS;
Sam McCall93cd9912017-12-05 07:34:35 +000099 MockCompilationDatabase CDB;
Sam McCallf6ae3232017-12-05 20:11:29 +0000100 IgnoreDiagnostics DiagConsumer;
Sam McCall9aad25f2017-12-05 07:20:26 +0000101 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000102 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000103 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000104 Annotations Test(Text);
105 Server.addDocument(Context::empty(), File, Test.code());
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000106 auto CompletionList =
107 Server.codeComplete(Context::empty(), File, Test.point(), Opts)
108 .get()
109 .second.Value;
110 // Sanity-check that filterText is valid.
111 EXPECT_THAT(CompletionList.items, Each(FilterContainsName()));
112 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000113}
114
Sam McCallf6ae3232017-12-05 20:11:29 +0000115TEST(CompletionTest, Limit) {
116 clangd::CodeCompleteOptions Opts;
117 Opts.Limit = 2;
118 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000119struct ClassWithMembers {
120 int AAA();
121 int BBB();
122 int CCC();
123}
Sam McCallf6ae3232017-12-05 20:11:29 +0000124int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000125 )cpp",
Sam McCallf6ae3232017-12-05 20:11:29 +0000126 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000127
128 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000129 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000130}
131
Sam McCallf6ae3232017-12-05 20:11:29 +0000132TEST(CompletionTest, Filter) {
133 std::string Body = R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000134 int Abracadabra;
135 int Alakazam;
136 struct S {
137 int FooBar;
138 int FooBaz;
139 int Qux;
140 };
141 )cpp";
Sam McCallf6ae3232017-12-05 20:11:29 +0000142 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
143 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000144
Sam McCallf6ae3232017-12-05 20:11:29 +0000145 EXPECT_THAT(completions(Body + "int main() { S().FR^ }").items,
146 AllOf(Has("FooBar"), Not(Has("FooBaz")), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000147
Sam McCallf6ae3232017-12-05 20:11:29 +0000148 EXPECT_THAT(completions(Body + "int main() { S().opr^ }").items,
149 Has("operator="));
Sam McCall9aad25f2017-12-05 07:20:26 +0000150
Sam McCallf6ae3232017-12-05 20:11:29 +0000151 EXPECT_THAT(completions(Body + "int main() { aaa^ }").items,
152 AllOf(Has("Abracadabra"), Has("Alakazam")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000153
Sam McCallf6ae3232017-12-05 20:11:29 +0000154 EXPECT_THAT(completions(Body + "int main() { _a^ }").items,
155 AllOf(Has("static_cast"), Not(Has("Abracadabra"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000156}
157
Sam McCallf6ae3232017-12-05 20:11:29 +0000158void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000159 auto Results = completions(
160 R"cpp(
161 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000162
Sam McCall44fdcec22017-12-08 15:00:59 +0000163 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000164
Sam McCall44fdcec22017-12-08 15:00:59 +0000165 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000166
Sam McCall44fdcec22017-12-08 15:00:59 +0000167 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000168
Sam McCall44fdcec22017-12-08 15:00:59 +0000169 struct ClassWithMembers {
170 /// Doc for method.
171 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000172
Sam McCall44fdcec22017-12-08 15:00:59 +0000173 int field;
174 private:
175 int private_field;
176 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000177
Sam McCall44fdcec22017-12-08 15:00:59 +0000178 int test() {
179 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000180
Sam McCall44fdcec22017-12-08 15:00:59 +0000181 /// Doc for local_var.
182 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000183
Sam McCall44fdcec22017-12-08 15:00:59 +0000184 ClassWithMembers().^
185 }
186 )cpp",
187 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000188
Sam McCallf6ae3232017-12-05 20:11:29 +0000189 // Class members. The only items that must be present in after-dot
190 // completion.
Sam McCall44fdcec22017-12-08 15:00:59 +0000191 EXPECT_THAT(
192 Results.items,
193 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"), Has("field")));
194 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
195 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000196 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000197 EXPECT_THAT(Results.items, Not(AnyOf(Has("global_var"), Has("global_func"),
198 Has("global_func()"), Has("GlobalClass"),
199 Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000200 // There should be no code patterns (aka snippets) in after-dot
201 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000202 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000203 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000204 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
205 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000206}
Sam McCall9aad25f2017-12-05 07:20:26 +0000207
Sam McCallf6ae3232017-12-05 20:11:29 +0000208void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000209 auto Results = completions(
210 R"cpp(
211 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000212
Sam McCall44fdcec22017-12-08 15:00:59 +0000213 int global_var;
214 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000215
Sam McCall44fdcec22017-12-08 15:00:59 +0000216 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000217
Sam McCall44fdcec22017-12-08 15:00:59 +0000218 struct ClassWithMembers {
219 /// Doc for method.
220 int method();
221 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000222
Sam McCall44fdcec22017-12-08 15:00:59 +0000223 int test() {
224 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000225
Sam McCall44fdcec22017-12-08 15:00:59 +0000226 /// Doc for local_var.
227 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000228
Sam McCall44fdcec22017-12-08 15:00:59 +0000229 ^
230 }
231 )cpp",
232 Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000233
234 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000235 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000236 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
237 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000238 EXPECT_IFF(Opts.IncludeGlobals, Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000239 AllOf(Has("global_var"),
240 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
241 Has("GlobalClass")));
242 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000243 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000244 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000245 EXPECT_THAT(Results.items,
246 AllOf(Has("local_var"), Has("LocalClass"),
247 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000248 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000249 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
250 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000251}
252
253TEST(CompletionTest, CompletionOptions) {
254 clangd::CodeCompleteOptions Opts;
Sam McCall9aad25f2017-12-05 07:20:26 +0000255 for (bool IncludeMacros : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000256 Opts.IncludeMacros = IncludeMacros;
Sam McCall9aad25f2017-12-05 07:20:26 +0000257 for (bool IncludeGlobals : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000258 Opts.IncludeGlobals = IncludeGlobals;
Sam McCall9aad25f2017-12-05 07:20:26 +0000259 for (bool IncludeBriefComments : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000260 Opts.IncludeBriefComments = IncludeBriefComments;
Sam McCall9aad25f2017-12-05 07:20:26 +0000261 for (bool EnableSnippets : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000262 Opts.EnableSnippets = EnableSnippets;
Sam McCall9aad25f2017-12-05 07:20:26 +0000263 for (bool IncludeCodePatterns : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000264 Opts.IncludeCodePatterns = IncludeCodePatterns;
Sam McCall9aad25f2017-12-05 07:20:26 +0000265 for (bool IncludeIneligibleResults : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000266 Opts.IncludeIneligibleResults = IncludeIneligibleResults;
267 TestAfterDotCompletion(Opts);
268 TestGlobalScopeCompletion(Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000269 }
270 }
271 }
272 }
273 }
274 }
275}
276
Sam McCallf6ae3232017-12-05 20:11:29 +0000277// Check code completion works when the file contents are overridden.
278TEST(CompletionTest, CheckContentsOverride) {
279 MockFSProvider FS;
280 IgnoreDiagnostics DiagConsumer;
281 MockCompilationDatabase CDB;
282 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000283 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000284 auto File = getVirtualTestFilePath("foo.cpp");
Ilya Biryukov940901e2017-12-13 12:51:22 +0000285 Server.addDocument(Context::empty(), File, "ignored text!");
Sam McCallf6ae3232017-12-05 20:11:29 +0000286
Sam McCall328cbdb2017-12-20 16:06:05 +0000287 Annotations Example("int cbc; int b = ^;");
288 auto Results = Server
289 .codeComplete(Context::empty(), File, Example.point(),
290 clangd::CodeCompleteOptions(),
291 StringRef(Example.code()))
292 .get()
293 .second.Value;
Sam McCallf6ae3232017-12-05 20:11:29 +0000294 EXPECT_THAT(Results.items, Contains(Named("cbc")));
295}
296
Sam McCall44fdcec22017-12-08 15:00:59 +0000297TEST(CompletionTest, Priorities) {
298 auto Internal = completions(R"cpp(
299 class Foo {
300 public: void pub();
301 protected: void prot();
302 private: void priv();
303 };
304 void Foo::pub() { this->^ }
305 )cpp");
306 EXPECT_THAT(Internal.items,
307 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
308
309 auto External = completions(R"cpp(
310 class Foo {
311 public: void pub();
312 protected: void prot();
313 private: void priv();
314 };
315 void test() {
316 Foo F;
317 F.^
318 }
319 )cpp");
320 EXPECT_THAT(External.items,
321 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
322}
323
324TEST(CompletionTest, Qualifiers) {
325 auto Results = completions(R"cpp(
326 class Foo {
327 public: int foo() const;
328 int bar() const;
329 };
330 class Bar : public Foo {
331 int foo() const;
332 };
333 void test() { Bar().^ }
334 )cpp");
335 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
336 Labeled("Foo::foo() const")));
337 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
338}
339
340TEST(CompletionTest, Snippets) {
341 clangd::CodeCompleteOptions Opts;
342 Opts.EnableSnippets = true;
343 auto Results = completions(
344 R"cpp(
345 struct fake {
346 int a;
347 int f(int i, const float f) const;
348 };
349 int main() {
350 fake f;
351 f.^
352 }
353 )cpp",
354 Opts);
355 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000356 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000357 Snippet("f(${1:int i}, ${2:const float f})")));
358}
359
360TEST(CompletionTest, Kinds) {
361 auto Results = completions(R"cpp(
362 #define MACRO X
363 int variable;
364 struct Struct {};
365 int function();
366 int X = ^
367 )cpp");
368 EXPECT_THAT(Results.items, Has("function", CompletionItemKind::Function));
369 EXPECT_THAT(Results.items, Has("variable", CompletionItemKind::Variable));
370 EXPECT_THAT(Results.items, Has("int", CompletionItemKind::Keyword));
371 EXPECT_THAT(Results.items, Has("Struct", CompletionItemKind::Class));
372 EXPECT_THAT(Results.items, Has("MACRO", CompletionItemKind::Text));
373
374 clangd::CodeCompleteOptions Opts;
375 Opts.EnableSnippets = true; // Needed for code patterns.
376
377 Results = completions("nam^");
378 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
379}
380
Sam McCall800d4372017-12-19 10:29:27 +0000381SignatureHelp signatures(StringRef Text) {
382 MockFSProvider FS;
383 MockCompilationDatabase CDB;
384 IgnoreDiagnostics DiagConsumer;
385 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
386 /*StorePreamblesInMemory=*/true);
387 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000388 Annotations Test(Text);
389 Server.addDocument(Context::empty(), File, Test.code());
390 auto R = Server.signatureHelp(Context::empty(), File, Test.point());
Sam McCall800d4372017-12-19 10:29:27 +0000391 assert(R);
392 return R.get().Value;
393}
394
395MATCHER_P(ParamsAre, P, "") {
396 if (P.size() != arg.parameters.size())
397 return false;
398 for (unsigned I = 0; I < P.size(); ++I)
399 if (P[I] != arg.parameters[I].label)
400 return false;
401 return true;
402}
403
404Matcher<SignatureInformation> Sig(std::string Label,
405 std::vector<std::string> Params) {
406 return AllOf(Labeled(Label), ParamsAre(Params));
407}
408
409TEST(SignatureHelpTest, Overloads) {
410 auto Results = signatures(R"cpp(
411 void foo(int x, int y);
412 void foo(int x, float y);
413 void foo(float x, int y);
414 void foo(float x, float y);
415 void bar(int x, int y = 0);
416 int main() { foo(^); }
417 )cpp");
418 EXPECT_THAT(Results.signatures,
419 UnorderedElementsAre(
420 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
421 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
422 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
423 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
424 // We always prefer the first signature.
425 EXPECT_EQ(0, Results.activeSignature);
426 EXPECT_EQ(0, Results.activeParameter);
427}
428
429TEST(SignatureHelpTest, DefaultArgs) {
430 auto Results = signatures(R"cpp(
431 void bar(int x, int y = 0);
432 void bar(float x = 0, int y = 42);
433 int main() { bar(^
434 )cpp");
435 EXPECT_THAT(Results.signatures,
436 UnorderedElementsAre(
437 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
438 Sig("bar(float x = 0, int y = 42) -> void",
439 {"float x = 0", "int y = 42"})));
440 EXPECT_EQ(0, Results.activeSignature);
441 EXPECT_EQ(0, Results.activeParameter);
442}
443
444TEST(SignatureHelpTest, ActiveArg) {
445 auto Results = signatures(R"cpp(
446 int baz(int a, int b, int c);
447 int main() { baz(baz(1,2,3), ^); }
448 )cpp");
449 EXPECT_THAT(Results.signatures,
450 ElementsAre(Sig("baz(int a, int b, int c) -> int",
451 {"int a", "int b", "int c"})));
452 EXPECT_EQ(0, Results.activeSignature);
453 EXPECT_EQ(1, Results.activeParameter);
454}
455
Eric Liu6f648df2017-12-19 16:50:37 +0000456std::unique_ptr<SymbolIndex> simpleIndexFromSymbols(
457 std::vector<std::pair<std::string, index::SymbolKind>> Symbols) {
458 auto I = llvm::make_unique<MemIndex>();
459 struct Snapshot {
460 SymbolSlab Slab;
461 std::vector<const Symbol *> Pointers;
462 };
463 auto Snap = std::make_shared<Snapshot>();
Sam McCall4b9bbb32017-12-23 19:38:03 +0000464 SymbolSlab::Builder Slab;
Eric Liu6f648df2017-12-19 16:50:37 +0000465 for (const auto &Pair : Symbols) {
466 Symbol Sym;
467 Sym.ID = SymbolID(Pair.first);
468 llvm::StringRef QName = Pair.first;
469 size_t Pos = QName.rfind("::");
470 if (Pos == llvm::StringRef::npos) {
471 Sym.Name = QName;
472 Sym.Scope = "";
473 } else {
474 Sym.Name = QName.substr(Pos + 2);
475 Sym.Scope = QName.substr(0, Pos);
476 }
Eric Liu76f6b442018-01-09 17:32:00 +0000477 Sym.CompletionPlainInsertText = Sym.Name;
Eric Liu6f648df2017-12-19 16:50:37 +0000478 Sym.SymInfo.Kind = Pair.second;
Sam McCall4b9bbb32017-12-23 19:38:03 +0000479 Slab.insert(Sym);
Eric Liu6f648df2017-12-19 16:50:37 +0000480 }
Sam McCall4b9bbb32017-12-23 19:38:03 +0000481 Snap->Slab = std::move(Slab).build();
Eric Liu6f648df2017-12-19 16:50:37 +0000482 for (auto &Iter : Snap->Slab)
Sam McCall4b9bbb32017-12-23 19:38:03 +0000483 Snap->Pointers.push_back(&Iter);
Eric Liu6f648df2017-12-19 16:50:37 +0000484 auto S = std::shared_ptr<std::vector<const Symbol *>>(std::move(Snap),
485 &Snap->Pointers);
486 I->build(std::move(S));
Sam McCalle3e15702017-12-19 17:05:00 +0000487 return std::move(I);
Eric Liu6f648df2017-12-19 16:50:37 +0000488}
489
490TEST(CompletionTest, NoIndex) {
491 clangd::CodeCompleteOptions Opts;
492 Opts.Index = nullptr;
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("No"));
500}
501
502TEST(CompletionTest, SimpleIndexBased) {
503 clangd::CodeCompleteOptions Opts;
504 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
505 {"nx::XYZ", index::SymbolKind::Class},
506 {"ns::foo", index::SymbolKind::Function}});
507 Opts.Index = I.get();
508
509 auto Results = completions(R"cpp(
510 namespace ns { class No {}; }
511 void f() { ns::^ }
512 )cpp",
513 Opts);
514 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
515 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
516 EXPECT_THAT(Results.items, Not(Has("No")));
517}
518
519TEST(CompletionTest, IndexBasedWithFilter) {
520 clangd::CodeCompleteOptions Opts;
521 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
522 {"ns::foo", index::SymbolKind::Function}});
523 Opts.Index = I.get();
524
525 auto Results = completions(R"cpp(
526 void f() { ns::x^ }
527 )cpp",
528 Opts);
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000529 EXPECT_THAT(Results.items, Contains(AllOf(Named("XYZ"), Filter("XYZ"))));
Eric Liu6f648df2017-12-19 16:50:37 +0000530 EXPECT_THAT(Results.items, Not(Has("foo")));
531}
532
533TEST(CompletionTest, GlobalQualified) {
534 clangd::CodeCompleteOptions Opts;
535 auto I = simpleIndexFromSymbols({{"XYZ", index::SymbolKind::Class}});
536 Opts.Index = I.get();
537
538 auto Results = completions(R"cpp(
539 void f() { ::^ }
540 )cpp",
541 Opts);
542 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
543}
544
545TEST(CompletionTest, FullyQualifiedScope) {
546 clangd::CodeCompleteOptions Opts;
547 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
548 Opts.Index = I.get();
549
550 auto Results = completions(R"cpp(
551 void f() { ::ns::^ }
552 )cpp",
553 Opts);
554 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
555}
556
Eric Liubfac8f72017-12-19 18:00:37 +0000557TEST(CompletionTest, ASTIndexMultiFile) {
558 MockFSProvider FS;
559 MockCompilationDatabase CDB;
560 IgnoreDiagnostics DiagConsumer;
561 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
562 /*StorePreamblesInMemory=*/true,
563 /*BuildDynamicSymbolIndex=*/true);
564
565 Server
566 .addDocument(Context::empty(), getVirtualTestFilePath("foo.cpp"), R"cpp(
Eric Liu76f6b442018-01-09 17:32:00 +0000567 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liubfac8f72017-12-19 18:00:37 +0000568 )cpp")
569 .wait();
570
571 auto File = getVirtualTestFilePath("bar.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000572 Annotations Test(R"cpp(
Eric Liu76f6b442018-01-09 17:32:00 +0000573 namespace ns {
574 class XXX {};
575 /// Doooc
576 void fooooo() {}
577 }
Eric Liubfac8f72017-12-19 18:00:37 +0000578 void f() { ns::^ }
579 )cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000580 Server.addDocument(Context::empty(), File, Test.code()).wait();
Eric Liubfac8f72017-12-19 18:00:37 +0000581
Sam McCall328cbdb2017-12-20 16:06:05 +0000582 auto Results = Server.codeComplete(Context::empty(), File, Test.point(), {})
Eric Liubfac8f72017-12-19 18:00:37 +0000583 .get()
584 .second.Value;
585 // "XYZ" and "foo" are not included in the file being completed but are still
586 // visible through the index.
587 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
588 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
589 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
Eric Liu76f6b442018-01-09 17:32:00 +0000590 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
591 Kind(CompletionItemKind::Function),
592 Doc("Doooc"), Detail("void"))));
Eric Liubfac8f72017-12-19 18:00:37 +0000593}
594
Sam McCall9aad25f2017-12-05 07:20:26 +0000595} // namespace
596} // namespace clangd
597} // namespace clang