blob: 312725fc90e69dfb024da37b78f871385e3d914f [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 McCall9aad25f2017-12-05 07:20:26 +000010#include "ClangdServer.h"
11#include "Compiler.h"
Ilya Biryukov940901e2017-12-13 12:51:22 +000012#include "Context.h"
Ilya Biryukov5a85b8e2017-12-13 12:53:16 +000013#include "Matchers.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000014#include "Protocol.h"
Sam McCallb536a2a2017-12-19 12:23:48 +000015#include "SourceCode.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000016#include "TestFS.h"
Eric Liu6f648df2017-12-19 16:50:37 +000017#include "index/MemIndex.h"
Sam McCallf6ae3232017-12-05 20:11:29 +000018#include "gmock/gmock.h"
Sam McCall9aad25f2017-12-05 07:20:26 +000019#include "gtest/gtest.h"
20
21namespace clang {
22namespace clangd {
Sam McCall800d4372017-12-19 10:29:27 +000023// Let GMock print completion items and signature help.
Sam McCallf6ae3232017-12-05 20:11:29 +000024void PrintTo(const CompletionItem &I, std::ostream *O) {
25 llvm::raw_os_ostream OS(*O);
Sam McCall44fdcec22017-12-08 15:00:59 +000026 OS << I.label << " - " << toJSON(I);
27}
28void PrintTo(const std::vector<CompletionItem> &V, std::ostream *O) {
29 *O << "{\n";
30 for (const auto &I : V) {
31 *O << "\t";
32 PrintTo(I, O);
33 *O << "\n";
34 }
35 *O << "}";
Sam McCallf6ae3232017-12-05 20:11:29 +000036}
Sam McCall800d4372017-12-19 10:29:27 +000037void PrintTo(const SignatureInformation &I, std::ostream *O) {
38 llvm::raw_os_ostream OS(*O);
39 OS << I.label << " - " << toJSON(I);
40}
41void PrintTo(const std::vector<SignatureInformation> &V, std::ostream *O) {
42 *O << "{\n";
43 for (const auto &I : V) {
44 *O << "\t";
45 PrintTo(I, O);
46 *O << "\n";
47 }
48 *O << "}";
49}
Sam McCallf6ae3232017-12-05 20:11:29 +000050
Sam McCall9aad25f2017-12-05 07:20:26 +000051namespace {
52using namespace llvm;
Sam McCallf6ae3232017-12-05 20:11:29 +000053using ::testing::AllOf;
54using ::testing::Contains;
55using ::testing::ElementsAre;
Sam McCallf6ae3232017-12-05 20:11:29 +000056using ::testing::Not;
Sam McCall9aad25f2017-12-05 07:20:26 +000057
58class IgnoreDiagnostics : public DiagnosticsConsumer {
59 void onDiagnosticsReady(
60 PathRef File, Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {}
61};
62
63struct StringWithPos {
64 std::string Text;
65 clangd::Position MarkerPos;
66};
67
Sam McCallf6ae3232017-12-05 20:11:29 +000068/// Accepts a source file with a cursor marker ^.
69/// Returns the source file with the marker removed, and the marker position.
70StringWithPos parseTextMarker(StringRef Text) {
71 std::size_t MarkerOffset = Text.find('^');
72 assert(MarkerOffset != StringRef::npos && "^ wasn't found in Text.");
Sam McCall9aad25f2017-12-05 07:20:26 +000073
74 std::string WithoutMarker;
75 WithoutMarker += Text.take_front(MarkerOffset);
Sam McCallf6ae3232017-12-05 20:11:29 +000076 WithoutMarker += Text.drop_front(MarkerOffset + 1);
77 assert(StringRef(WithoutMarker).find('^') == StringRef::npos &&
78 "There were multiple occurences of ^ inside Text");
Sam McCall9aad25f2017-12-05 07:20:26 +000079
Sam McCallf6ae3232017-12-05 20:11:29 +000080 auto MarkerPos = offsetToPosition(WithoutMarker, MarkerOffset);
Sam McCall9aad25f2017-12-05 07:20:26 +000081 return {std::move(WithoutMarker), MarkerPos};
82}
83
Sam McCallf6ae3232017-12-05 20:11:29 +000084// GMock helpers for matching completion items.
85MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
Sam McCall44fdcec22017-12-08 15:00:59 +000086MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
87MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000088MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Sam McCall44fdcec22017-12-08 15:00:59 +000089MATCHER_P(PlainText, Text, "") {
90 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
91 arg.insertText == Text;
92}
93MATCHER_P(Snippet, Text, "") {
94 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
95 arg.insertText == Text;
96}
Sam McCallf6ae3232017-12-05 20:11:29 +000097// Shorthand for Contains(Named(Name)).
98Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
99 return Contains(Named(std::move(Name)));
100}
Sam McCall44fdcec22017-12-08 15:00:59 +0000101Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
102 CompletionItemKind K) {
103 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +0000104}
Sam McCall44fdcec22017-12-08 15:00:59 +0000105MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +0000106
Sam McCallf6ae3232017-12-05 20:11:29 +0000107CompletionList completions(StringRef Text,
108 clangd::CodeCompleteOptions Opts = {}) {
Sam McCall9aad25f2017-12-05 07:20:26 +0000109 MockFSProvider FS;
Sam McCall93cd9912017-12-05 07:34:35 +0000110 MockCompilationDatabase CDB;
Sam McCallf6ae3232017-12-05 20:11:29 +0000111 IgnoreDiagnostics DiagConsumer;
Sam McCall9aad25f2017-12-05 07:20:26 +0000112 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000113 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000114 auto File = getVirtualTestFilePath("foo.cpp");
115 auto Test = parseTextMarker(Text);
Ilya Biryukov940901e2017-12-13 12:51:22 +0000116 Server.addDocument(Context::empty(), File, Test.Text);
117 return Server.codeComplete(Context::empty(), File, Test.MarkerPos, Opts)
118 .get()
119 .second.Value;
Sam McCall9aad25f2017-12-05 07:20:26 +0000120}
121
Sam McCallf6ae3232017-12-05 20:11:29 +0000122TEST(CompletionTest, Limit) {
123 clangd::CodeCompleteOptions Opts;
124 Opts.Limit = 2;
125 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000126struct ClassWithMembers {
127 int AAA();
128 int BBB();
129 int CCC();
130}
Sam McCallf6ae3232017-12-05 20:11:29 +0000131int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000132 )cpp",
Sam McCallf6ae3232017-12-05 20:11:29 +0000133 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000134
135 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000136 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000137}
138
Sam McCallf6ae3232017-12-05 20:11:29 +0000139TEST(CompletionTest, Filter) {
140 std::string Body = R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000141 int Abracadabra;
142 int Alakazam;
143 struct S {
144 int FooBar;
145 int FooBaz;
146 int Qux;
147 };
148 )cpp";
Sam McCallf6ae3232017-12-05 20:11:29 +0000149 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
150 AllOf(Has("FooBar"), Has("FooBaz"), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000151
Sam McCallf6ae3232017-12-05 20:11:29 +0000152 EXPECT_THAT(completions(Body + "int main() { S().FR^ }").items,
153 AllOf(Has("FooBar"), Not(Has("FooBaz")), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000154
Sam McCallf6ae3232017-12-05 20:11:29 +0000155 EXPECT_THAT(completions(Body + "int main() { S().opr^ }").items,
156 Has("operator="));
Sam McCall9aad25f2017-12-05 07:20:26 +0000157
Sam McCallf6ae3232017-12-05 20:11:29 +0000158 EXPECT_THAT(completions(Body + "int main() { aaa^ }").items,
159 AllOf(Has("Abracadabra"), Has("Alakazam")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000160
Sam McCallf6ae3232017-12-05 20:11:29 +0000161 EXPECT_THAT(completions(Body + "int main() { _a^ }").items,
162 AllOf(Has("static_cast"), Not(Has("Abracadabra"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000163}
164
Sam McCallf6ae3232017-12-05 20:11:29 +0000165void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000166 auto Results = completions(
167 R"cpp(
168 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000169
Sam McCall44fdcec22017-12-08 15:00:59 +0000170 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000171
Sam McCall44fdcec22017-12-08 15:00:59 +0000172 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000173
Sam McCall44fdcec22017-12-08 15:00:59 +0000174 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000175
Sam McCall44fdcec22017-12-08 15:00:59 +0000176 struct ClassWithMembers {
177 /// Doc for method.
178 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000179
Sam McCall44fdcec22017-12-08 15:00:59 +0000180 int field;
181 private:
182 int private_field;
183 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000184
Sam McCall44fdcec22017-12-08 15:00:59 +0000185 int test() {
186 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000187
Sam McCall44fdcec22017-12-08 15:00:59 +0000188 /// Doc for local_var.
189 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000190
Sam McCall44fdcec22017-12-08 15:00:59 +0000191 ClassWithMembers().^
192 }
193 )cpp",
194 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000195
Sam McCallf6ae3232017-12-05 20:11:29 +0000196 // Class members. The only items that must be present in after-dot
197 // completion.
Sam McCall44fdcec22017-12-08 15:00:59 +0000198 EXPECT_THAT(
199 Results.items,
200 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"), Has("field")));
201 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
202 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000203 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000204 EXPECT_THAT(Results.items, Not(AnyOf(Has("global_var"), Has("global_func"),
205 Has("global_func()"), Has("GlobalClass"),
206 Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000207 // There should be no code patterns (aka snippets) in after-dot
208 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000209 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000210 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000211 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
212 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000213}
Sam McCall9aad25f2017-12-05 07:20:26 +0000214
Sam McCallf6ae3232017-12-05 20:11:29 +0000215void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000216 auto Results = completions(
217 R"cpp(
218 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000219
Sam McCall44fdcec22017-12-08 15:00:59 +0000220 int global_var;
221 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000222
Sam McCall44fdcec22017-12-08 15:00:59 +0000223 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000224
Sam McCall44fdcec22017-12-08 15:00:59 +0000225 struct ClassWithMembers {
226 /// Doc for method.
227 int method();
228 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000229
Sam McCall44fdcec22017-12-08 15:00:59 +0000230 int test() {
231 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000232
Sam McCall44fdcec22017-12-08 15:00:59 +0000233 /// Doc for local_var.
234 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000235
Sam McCall44fdcec22017-12-08 15:00:59 +0000236 ^
237 }
238 )cpp",
239 Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000240
241 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000242 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000243 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
244 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000245 EXPECT_IFF(Opts.IncludeGlobals, Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000246 AllOf(Has("global_var"),
247 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
248 Has("GlobalClass")));
249 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000250 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000251 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000252 EXPECT_THAT(Results.items,
253 AllOf(Has("local_var"), Has("LocalClass"),
254 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000255 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000256 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
257 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000258}
259
260TEST(CompletionTest, CompletionOptions) {
261 clangd::CodeCompleteOptions Opts;
Sam McCall9aad25f2017-12-05 07:20:26 +0000262 for (bool IncludeMacros : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000263 Opts.IncludeMacros = IncludeMacros;
Sam McCall9aad25f2017-12-05 07:20:26 +0000264 for (bool IncludeGlobals : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000265 Opts.IncludeGlobals = IncludeGlobals;
Sam McCall9aad25f2017-12-05 07:20:26 +0000266 for (bool IncludeBriefComments : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000267 Opts.IncludeBriefComments = IncludeBriefComments;
Sam McCall9aad25f2017-12-05 07:20:26 +0000268 for (bool EnableSnippets : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000269 Opts.EnableSnippets = EnableSnippets;
Sam McCall9aad25f2017-12-05 07:20:26 +0000270 for (bool IncludeCodePatterns : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000271 Opts.IncludeCodePatterns = IncludeCodePatterns;
Sam McCall9aad25f2017-12-05 07:20:26 +0000272 for (bool IncludeIneligibleResults : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000273 Opts.IncludeIneligibleResults = IncludeIneligibleResults;
274 TestAfterDotCompletion(Opts);
275 TestGlobalScopeCompletion(Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000276 }
277 }
278 }
279 }
280 }
281 }
282}
283
Sam McCallf6ae3232017-12-05 20:11:29 +0000284// Check code completion works when the file contents are overridden.
285TEST(CompletionTest, CheckContentsOverride) {
286 MockFSProvider FS;
287 IgnoreDiagnostics DiagConsumer;
288 MockCompilationDatabase CDB;
289 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000290 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000291 auto File = getVirtualTestFilePath("foo.cpp");
Ilya Biryukov940901e2017-12-13 12:51:22 +0000292 Server.addDocument(Context::empty(), File, "ignored text!");
Sam McCallf6ae3232017-12-05 20:11:29 +0000293
294 auto Example = parseTextMarker("int cbc; int b = ^;");
295 auto Results =
296 Server
Ilya Biryukov940901e2017-12-13 12:51:22 +0000297 .codeComplete(Context::empty(), File, Example.MarkerPos,
298 clangd::CodeCompleteOptions(), StringRef(Example.Text))
Sam McCallf6ae3232017-12-05 20:11:29 +0000299 .get()
Ilya Biryukov940901e2017-12-13 12:51:22 +0000300 .second.Value;
Sam McCallf6ae3232017-12-05 20:11:29 +0000301 EXPECT_THAT(Results.items, Contains(Named("cbc")));
302}
303
Sam McCall44fdcec22017-12-08 15:00:59 +0000304TEST(CompletionTest, Priorities) {
305 auto Internal = completions(R"cpp(
306 class Foo {
307 public: void pub();
308 protected: void prot();
309 private: void priv();
310 };
311 void Foo::pub() { this->^ }
312 )cpp");
313 EXPECT_THAT(Internal.items,
314 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
315
316 auto External = completions(R"cpp(
317 class Foo {
318 public: void pub();
319 protected: void prot();
320 private: void priv();
321 };
322 void test() {
323 Foo F;
324 F.^
325 }
326 )cpp");
327 EXPECT_THAT(External.items,
328 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
329}
330
331TEST(CompletionTest, Qualifiers) {
332 auto Results = completions(R"cpp(
333 class Foo {
334 public: int foo() const;
335 int bar() const;
336 };
337 class Bar : public Foo {
338 int foo() const;
339 };
340 void test() { Bar().^ }
341 )cpp");
342 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
343 Labeled("Foo::foo() const")));
344 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
345}
346
347TEST(CompletionTest, Snippets) {
348 clangd::CodeCompleteOptions Opts;
349 Opts.EnableSnippets = true;
350 auto Results = completions(
351 R"cpp(
352 struct fake {
353 int a;
354 int f(int i, const float f) const;
355 };
356 int main() {
357 fake f;
358 f.^
359 }
360 )cpp",
361 Opts);
362 EXPECT_THAT(Results.items,
363 HasSubsequence(PlainText("a"),
364 Snippet("f(${1:int i}, ${2:const float f})")));
365}
366
367TEST(CompletionTest, Kinds) {
368 auto Results = completions(R"cpp(
369 #define MACRO X
370 int variable;
371 struct Struct {};
372 int function();
373 int X = ^
374 )cpp");
375 EXPECT_THAT(Results.items, Has("function", CompletionItemKind::Function));
376 EXPECT_THAT(Results.items, Has("variable", CompletionItemKind::Variable));
377 EXPECT_THAT(Results.items, Has("int", CompletionItemKind::Keyword));
378 EXPECT_THAT(Results.items, Has("Struct", CompletionItemKind::Class));
379 EXPECT_THAT(Results.items, Has("MACRO", CompletionItemKind::Text));
380
381 clangd::CodeCompleteOptions Opts;
382 Opts.EnableSnippets = true; // Needed for code patterns.
383
384 Results = completions("nam^");
385 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
386}
387
Sam McCall800d4372017-12-19 10:29:27 +0000388SignatureHelp signatures(StringRef Text) {
389 MockFSProvider FS;
390 MockCompilationDatabase CDB;
391 IgnoreDiagnostics DiagConsumer;
392 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
393 /*StorePreamblesInMemory=*/true);
394 auto File = getVirtualTestFilePath("foo.cpp");
395 auto Test = parseTextMarker(Text);
396 Server.addDocument(Context::empty(), File, Test.Text);
397 auto R = Server.signatureHelp(Context::empty(), File, Test.MarkerPos);
398 assert(R);
399 return R.get().Value;
400}
401
402MATCHER_P(ParamsAre, P, "") {
403 if (P.size() != arg.parameters.size())
404 return false;
405 for (unsigned I = 0; I < P.size(); ++I)
406 if (P[I] != arg.parameters[I].label)
407 return false;
408 return true;
409}
410
411Matcher<SignatureInformation> Sig(std::string Label,
412 std::vector<std::string> Params) {
413 return AllOf(Labeled(Label), ParamsAre(Params));
414}
415
416TEST(SignatureHelpTest, Overloads) {
417 auto Results = signatures(R"cpp(
418 void foo(int x, int y);
419 void foo(int x, float y);
420 void foo(float x, int y);
421 void foo(float x, float y);
422 void bar(int x, int y = 0);
423 int main() { foo(^); }
424 )cpp");
425 EXPECT_THAT(Results.signatures,
426 UnorderedElementsAre(
427 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
428 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
429 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
430 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
431 // We always prefer the first signature.
432 EXPECT_EQ(0, Results.activeSignature);
433 EXPECT_EQ(0, Results.activeParameter);
434}
435
436TEST(SignatureHelpTest, DefaultArgs) {
437 auto Results = signatures(R"cpp(
438 void bar(int x, int y = 0);
439 void bar(float x = 0, int y = 42);
440 int main() { bar(^
441 )cpp");
442 EXPECT_THAT(Results.signatures,
443 UnorderedElementsAre(
444 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
445 Sig("bar(float x = 0, int y = 42) -> void",
446 {"float x = 0", "int y = 42"})));
447 EXPECT_EQ(0, Results.activeSignature);
448 EXPECT_EQ(0, Results.activeParameter);
449}
450
451TEST(SignatureHelpTest, ActiveArg) {
452 auto Results = signatures(R"cpp(
453 int baz(int a, int b, int c);
454 int main() { baz(baz(1,2,3), ^); }
455 )cpp");
456 EXPECT_THAT(Results.signatures,
457 ElementsAre(Sig("baz(int a, int b, int c) -> int",
458 {"int a", "int b", "int c"})));
459 EXPECT_EQ(0, Results.activeSignature);
460 EXPECT_EQ(1, Results.activeParameter);
461}
462
Eric Liu6f648df2017-12-19 16:50:37 +0000463std::unique_ptr<SymbolIndex> simpleIndexFromSymbols(
464 std::vector<std::pair<std::string, index::SymbolKind>> Symbols) {
465 auto I = llvm::make_unique<MemIndex>();
466 struct Snapshot {
467 SymbolSlab Slab;
468 std::vector<const Symbol *> Pointers;
469 };
470 auto Snap = std::make_shared<Snapshot>();
471 for (const auto &Pair : Symbols) {
472 Symbol Sym;
473 Sym.ID = SymbolID(Pair.first);
474 llvm::StringRef QName = Pair.first;
475 size_t Pos = QName.rfind("::");
476 if (Pos == llvm::StringRef::npos) {
477 Sym.Name = QName;
478 Sym.Scope = "";
479 } else {
480 Sym.Name = QName.substr(Pos + 2);
481 Sym.Scope = QName.substr(0, Pos);
482 }
483 Sym.SymInfo.Kind = Pair.second;
484 Snap->Slab.insert(std::move(Sym));
485 }
486 for (auto &Iter : Snap->Slab)
487 Snap->Pointers.push_back(&Iter.second);
488 auto S = std::shared_ptr<std::vector<const Symbol *>>(std::move(Snap),
489 &Snap->Pointers);
490 I->build(std::move(S));
Sam McCalle3e15702017-12-19 17:05:00 +0000491 return std::move(I);
Eric Liu6f648df2017-12-19 16:50:37 +0000492}
493
494TEST(CompletionTest, NoIndex) {
495 clangd::CodeCompleteOptions Opts;
496 Opts.Index = nullptr;
497
498 auto Results = completions(R"cpp(
499 namespace ns { class No {}; }
500 void f() { ns::^ }
501 )cpp",
502 Opts);
503 EXPECT_THAT(Results.items, Has("No"));
504}
505
506TEST(CompletionTest, SimpleIndexBased) {
507 clangd::CodeCompleteOptions Opts;
508 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
509 {"nx::XYZ", index::SymbolKind::Class},
510 {"ns::foo", index::SymbolKind::Function}});
511 Opts.Index = I.get();
512
513 auto Results = completions(R"cpp(
514 namespace ns { class No {}; }
515 void f() { ns::^ }
516 )cpp",
517 Opts);
518 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
519 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
520 EXPECT_THAT(Results.items, Not(Has("No")));
521}
522
523TEST(CompletionTest, IndexBasedWithFilter) {
524 clangd::CodeCompleteOptions Opts;
525 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
526 {"ns::foo", index::SymbolKind::Function}});
527 Opts.Index = I.get();
528
529 auto Results = completions(R"cpp(
530 void f() { ns::x^ }
531 )cpp",
532 Opts);
533 EXPECT_THAT(Results.items, Contains(AllOf(Named("XYZ"), Filter("x"))));
534 EXPECT_THAT(Results.items, Not(Has("foo")));
535}
536
537TEST(CompletionTest, GlobalQualified) {
538 clangd::CodeCompleteOptions Opts;
539 auto I = simpleIndexFromSymbols({{"XYZ", index::SymbolKind::Class}});
540 Opts.Index = I.get();
541
542 auto Results = completions(R"cpp(
543 void f() { ::^ }
544 )cpp",
545 Opts);
546 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
547}
548
549TEST(CompletionTest, FullyQualifiedScope) {
550 clangd::CodeCompleteOptions Opts;
551 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
552 Opts.Index = I.get();
553
554 auto Results = completions(R"cpp(
555 void f() { ::ns::^ }
556 )cpp",
557 Opts);
558 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
559}
560
Eric Liubfac8f72017-12-19 18:00:37 +0000561TEST(CompletionTest, ASTIndexMultiFile) {
562 MockFSProvider FS;
563 MockCompilationDatabase CDB;
564 IgnoreDiagnostics DiagConsumer;
565 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
566 /*StorePreamblesInMemory=*/true,
567 /*BuildDynamicSymbolIndex=*/true);
568
569 Server
570 .addDocument(Context::empty(), getVirtualTestFilePath("foo.cpp"), R"cpp(
571 namespace ns { class XYZ {}; void foo() {} }
572 )cpp")
573 .wait();
574
575 auto File = getVirtualTestFilePath("bar.cpp");
576 auto Test = parseTextMarker(R"cpp(
577 namespace ns { class XXX {}; void fooooo() {} }
578 void f() { ns::^ }
579 )cpp");
580 Server.addDocument(Context::empty(), File, Test.Text).wait();
581
582 auto Results = Server.codeComplete(Context::empty(), File, Test.MarkerPos, {})
583 .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));
590 EXPECT_THAT(Results.items, Has("fooooo", CompletionItemKind::Function));
591}
592
Sam McCall9aad25f2017-12-05 07:20:26 +0000593} // namespace
594} // namespace clangd
595} // namespace clang