blob: 3329794b985993316286720c1efe7def66378a2a [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 McCall3d139c52018-01-12 18:30:08 +000060using ::testing::UnorderedElementsAre;
Sam McCall9aad25f2017-12-05 07:20:26 +000061
62class IgnoreDiagnostics : public DiagnosticsConsumer {
Ilya Biryukov95558392018-01-10 17:59:27 +000063 void
64 onDiagnosticsReady(const Context &Ctx, PathRef File,
65 Tagged<std::vector<DiagWithFixIts>> Diagnostics) override {
66 }
Sam McCall9aad25f2017-12-05 07:20:26 +000067};
68
Sam McCallf6ae3232017-12-05 20:11:29 +000069// GMock helpers for matching completion items.
70MATCHER_P(Named, Name, "") { return arg.insertText == Name; }
Sam McCall44fdcec22017-12-08 15:00:59 +000071MATCHER_P(Labeled, Label, "") { return arg.label == Label; }
72MATCHER_P(Kind, K, "") { return arg.kind == K; }
Eric Liu6f648df2017-12-19 16:50:37 +000073MATCHER_P(Filter, F, "") { return arg.filterText == F; }
Eric Liu76f6b442018-01-09 17:32:00 +000074MATCHER_P(Doc, D, "") { return arg.documentation == D; }
75MATCHER_P(Detail, D, "") { return arg.detail == D; }
Sam McCall44fdcec22017-12-08 15:00:59 +000076MATCHER_P(PlainText, Text, "") {
77 return arg.insertTextFormat == clangd::InsertTextFormat::PlainText &&
78 arg.insertText == Text;
79}
80MATCHER_P(Snippet, Text, "") {
81 return arg.insertTextFormat == clangd::InsertTextFormat::Snippet &&
82 arg.insertText == Text;
83}
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +000084MATCHER(FilterContainsName, "") {
85 if (arg.filterText.empty())
86 return true;
87 return llvm::StringRef(arg.insertText).contains(arg.filterText);
88}
Sam McCallf6ae3232017-12-05 20:11:29 +000089// Shorthand for Contains(Named(Name)).
90Matcher<const std::vector<CompletionItem> &> Has(std::string Name) {
91 return Contains(Named(std::move(Name)));
92}
Sam McCall44fdcec22017-12-08 15:00:59 +000093Matcher<const std::vector<CompletionItem> &> Has(std::string Name,
94 CompletionItemKind K) {
95 return Contains(AllOf(Named(std::move(Name)), Kind(K)));
Sam McCallf6ae3232017-12-05 20:11:29 +000096}
Sam McCall44fdcec22017-12-08 15:00:59 +000097MATCHER(IsDocumented, "") { return !arg.documentation.empty(); }
Sam McCall9aad25f2017-12-05 07:20:26 +000098
Sam McCallf6ae3232017-12-05 20:11:29 +000099CompletionList completions(StringRef Text,
100 clangd::CodeCompleteOptions Opts = {}) {
Sam McCall9aad25f2017-12-05 07:20:26 +0000101 MockFSProvider FS;
Sam McCall93cd9912017-12-05 07:34:35 +0000102 MockCompilationDatabase CDB;
Sam McCallf6ae3232017-12-05 20:11:29 +0000103 IgnoreDiagnostics DiagConsumer;
Sam McCall9aad25f2017-12-05 07:20:26 +0000104 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000105 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000106 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000107 Annotations Test(Text);
Sam McCall3d139c52018-01-12 18:30:08 +0000108 Server.addDocument(Context::empty(), File, Test.code()).wait();
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000109 auto CompletionList =
110 Server.codeComplete(Context::empty(), File, Test.point(), Opts)
111 .get()
112 .second.Value;
113 // Sanity-check that filterText is valid.
114 EXPECT_THAT(CompletionList.items, Each(FilterContainsName()));
115 return CompletionList;
Sam McCall9aad25f2017-12-05 07:20:26 +0000116}
117
Sam McCallf6ae3232017-12-05 20:11:29 +0000118TEST(CompletionTest, Limit) {
119 clangd::CodeCompleteOptions Opts;
120 Opts.Limit = 2;
121 auto Results = completions(R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000122struct ClassWithMembers {
123 int AAA();
124 int BBB();
125 int CCC();
126}
Sam McCallf6ae3232017-12-05 20:11:29 +0000127int main() { ClassWithMembers().^ }
Sam McCall9aad25f2017-12-05 07:20:26 +0000128 )cpp",
Sam McCallf6ae3232017-12-05 20:11:29 +0000129 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000130
131 EXPECT_TRUE(Results.isIncomplete);
Sam McCallf6ae3232017-12-05 20:11:29 +0000132 EXPECT_THAT(Results.items, ElementsAre(Named("AAA"), Named("BBB")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000133}
134
Sam McCallf6ae3232017-12-05 20:11:29 +0000135TEST(CompletionTest, Filter) {
136 std::string Body = R"cpp(
Sam McCall9aad25f2017-12-05 07:20:26 +0000137 int Abracadabra;
138 int Alakazam;
139 struct S {
140 int FooBar;
141 int FooBaz;
142 int Qux;
143 };
144 )cpp";
Sam McCallf6ae3232017-12-05 20:11:29 +0000145 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").items,
146 AllOf(Has("FooBar"), 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().FR^ }").items,
149 AllOf(Has("FooBar"), Not(Has("FooBaz")), Not(Has("Qux"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000150
Sam McCallf6ae3232017-12-05 20:11:29 +0000151 EXPECT_THAT(completions(Body + "int main() { S().opr^ }").items,
152 Has("operator="));
Sam McCall9aad25f2017-12-05 07:20:26 +0000153
Sam McCallf6ae3232017-12-05 20:11:29 +0000154 EXPECT_THAT(completions(Body + "int main() { aaa^ }").items,
155 AllOf(Has("Abracadabra"), Has("Alakazam")));
Sam McCall9aad25f2017-12-05 07:20:26 +0000156
Sam McCallf6ae3232017-12-05 20:11:29 +0000157 EXPECT_THAT(completions(Body + "int main() { _a^ }").items,
158 AllOf(Has("static_cast"), Not(Has("Abracadabra"))));
Sam McCall9aad25f2017-12-05 07:20:26 +0000159}
160
Sam McCallf6ae3232017-12-05 20:11:29 +0000161void TestAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000162 auto Results = completions(
163 R"cpp(
164 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000165
Sam McCall44fdcec22017-12-08 15:00:59 +0000166 int global_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000167
Sam McCall44fdcec22017-12-08 15:00:59 +0000168 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000169
Sam McCall44fdcec22017-12-08 15:00:59 +0000170 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000171
Sam McCall44fdcec22017-12-08 15:00:59 +0000172 struct ClassWithMembers {
173 /// Doc for method.
174 int method();
Sam McCall9aad25f2017-12-05 07:20:26 +0000175
Sam McCall44fdcec22017-12-08 15:00:59 +0000176 int field;
177 private:
178 int private_field;
179 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000180
Sam McCall44fdcec22017-12-08 15:00:59 +0000181 int test() {
182 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000183
Sam McCall44fdcec22017-12-08 15:00:59 +0000184 /// Doc for local_var.
185 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000186
Sam McCall44fdcec22017-12-08 15:00:59 +0000187 ClassWithMembers().^
188 }
189 )cpp",
190 Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000191
Sam McCallf6ae3232017-12-05 20:11:29 +0000192 // Class members. The only items that must be present in after-dot
193 // completion.
Sam McCall44fdcec22017-12-08 15:00:59 +0000194 EXPECT_THAT(
195 Results.items,
196 AllOf(Has(Opts.EnableSnippets ? "method()" : "method"), Has("field")));
197 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.items,
198 Has("private_field"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000199 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000200 EXPECT_THAT(Results.items, Not(AnyOf(Has("global_var"), Has("global_func"),
201 Has("global_func()"), Has("GlobalClass"),
202 Has("MACRO"), Has("LocalClass"))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000203 // There should be no code patterns (aka snippets) in after-dot
204 // completion. At least there aren't any we're aware of.
Sam McCall44fdcec22017-12-08 15:00:59 +0000205 EXPECT_THAT(Results.items, Not(Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000206 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000207 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
208 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000209}
Sam McCall9aad25f2017-12-05 07:20:26 +0000210
Sam McCallf6ae3232017-12-05 20:11:29 +0000211void TestGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
Sam McCall44fdcec22017-12-08 15:00:59 +0000212 auto Results = completions(
213 R"cpp(
214 #define MACRO X
Sam McCall9aad25f2017-12-05 07:20:26 +0000215
Sam McCall44fdcec22017-12-08 15:00:59 +0000216 int global_var;
217 int global_func();
Sam McCall9aad25f2017-12-05 07:20:26 +0000218
Sam McCall44fdcec22017-12-08 15:00:59 +0000219 struct GlobalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000220
Sam McCall44fdcec22017-12-08 15:00:59 +0000221 struct ClassWithMembers {
222 /// Doc for method.
223 int method();
224 };
Sam McCall9aad25f2017-12-05 07:20:26 +0000225
Sam McCall44fdcec22017-12-08 15:00:59 +0000226 int test() {
227 struct LocalClass {};
Sam McCall9aad25f2017-12-05 07:20:26 +0000228
Sam McCall44fdcec22017-12-08 15:00:59 +0000229 /// Doc for local_var.
230 int local_var;
Sam McCall9aad25f2017-12-05 07:20:26 +0000231
Sam McCall44fdcec22017-12-08 15:00:59 +0000232 ^
233 }
234 )cpp",
235 Opts);
Sam McCallf6ae3232017-12-05 20:11:29 +0000236
237 // Class members. Should never be present in global completions.
Sam McCall44fdcec22017-12-08 15:00:59 +0000238 EXPECT_THAT(Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000239 Not(AnyOf(Has("method"), Has("method()"), Has("field"))));
240 // Global items.
Sam McCall44fdcec22017-12-08 15:00:59 +0000241 EXPECT_IFF(Opts.IncludeGlobals, Results.items,
Sam McCallf6ae3232017-12-05 20:11:29 +0000242 AllOf(Has("global_var"),
243 Has(Opts.EnableSnippets ? "global_func()" : "global_func"),
244 Has("GlobalClass")));
245 // A macro.
Sam McCall44fdcec22017-12-08 15:00:59 +0000246 EXPECT_IFF(Opts.IncludeMacros, Results.items, Has("MACRO"));
Sam McCallf6ae3232017-12-05 20:11:29 +0000247 // Local items. Must be present always.
Ilya Biryukov9b5ffc22017-12-12 12:56:46 +0000248 EXPECT_THAT(Results.items,
249 AllOf(Has("local_var"), Has("LocalClass"),
250 Contains(Kind(CompletionItemKind::Snippet))));
Sam McCallf6ae3232017-12-05 20:11:29 +0000251 // Check documentation.
Sam McCall44fdcec22017-12-08 15:00:59 +0000252 EXPECT_IFF(Opts.IncludeBriefComments, Results.items,
253 Contains(IsDocumented()));
Sam McCallf6ae3232017-12-05 20:11:29 +0000254}
255
256TEST(CompletionTest, CompletionOptions) {
257 clangd::CodeCompleteOptions Opts;
Sam McCall9aad25f2017-12-05 07:20:26 +0000258 for (bool IncludeMacros : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000259 Opts.IncludeMacros = IncludeMacros;
Sam McCall9aad25f2017-12-05 07:20:26 +0000260 for (bool IncludeGlobals : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000261 Opts.IncludeGlobals = IncludeGlobals;
Sam McCall9aad25f2017-12-05 07:20:26 +0000262 for (bool IncludeBriefComments : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000263 Opts.IncludeBriefComments = IncludeBriefComments;
Sam McCall9aad25f2017-12-05 07:20:26 +0000264 for (bool EnableSnippets : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000265 Opts.EnableSnippets = EnableSnippets;
Sam McCall9aad25f2017-12-05 07:20:26 +0000266 for (bool IncludeCodePatterns : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000267 Opts.IncludeCodePatterns = IncludeCodePatterns;
Sam McCall9aad25f2017-12-05 07:20:26 +0000268 for (bool IncludeIneligibleResults : {true, false}) {
Sam McCallf6ae3232017-12-05 20:11:29 +0000269 Opts.IncludeIneligibleResults = IncludeIneligibleResults;
270 TestAfterDotCompletion(Opts);
271 TestGlobalScopeCompletion(Opts);
Sam McCall9aad25f2017-12-05 07:20:26 +0000272 }
273 }
274 }
275 }
276 }
277 }
278}
279
Sam McCallf6ae3232017-12-05 20:11:29 +0000280// Check code completion works when the file contents are overridden.
281TEST(CompletionTest, CheckContentsOverride) {
282 MockFSProvider FS;
283 IgnoreDiagnostics DiagConsumer;
284 MockCompilationDatabase CDB;
285 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
Ilya Biryukov940901e2017-12-13 12:51:22 +0000286 /*StorePreamblesInMemory=*/true);
Sam McCallf6ae3232017-12-05 20:11:29 +0000287 auto File = getVirtualTestFilePath("foo.cpp");
Ilya Biryukov940901e2017-12-13 12:51:22 +0000288 Server.addDocument(Context::empty(), File, "ignored text!");
Sam McCallf6ae3232017-12-05 20:11:29 +0000289
Sam McCall328cbdb2017-12-20 16:06:05 +0000290 Annotations Example("int cbc; int b = ^;");
291 auto Results = Server
292 .codeComplete(Context::empty(), File, Example.point(),
293 clangd::CodeCompleteOptions(),
294 StringRef(Example.code()))
295 .get()
296 .second.Value;
Sam McCallf6ae3232017-12-05 20:11:29 +0000297 EXPECT_THAT(Results.items, Contains(Named("cbc")));
298}
299
Sam McCall44fdcec22017-12-08 15:00:59 +0000300TEST(CompletionTest, Priorities) {
301 auto Internal = completions(R"cpp(
302 class Foo {
303 public: void pub();
304 protected: void prot();
305 private: void priv();
306 };
307 void Foo::pub() { this->^ }
308 )cpp");
309 EXPECT_THAT(Internal.items,
310 HasSubsequence(Named("priv"), Named("prot"), Named("pub")));
311
312 auto External = completions(R"cpp(
313 class Foo {
314 public: void pub();
315 protected: void prot();
316 private: void priv();
317 };
318 void test() {
319 Foo F;
320 F.^
321 }
322 )cpp");
323 EXPECT_THAT(External.items,
324 AllOf(Has("pub"), Not(Has("prot")), Not(Has("priv"))));
325}
326
327TEST(CompletionTest, Qualifiers) {
328 auto Results = completions(R"cpp(
329 class Foo {
330 public: int foo() const;
331 int bar() const;
332 };
333 class Bar : public Foo {
334 int foo() const;
335 };
336 void test() { Bar().^ }
337 )cpp");
338 EXPECT_THAT(Results.items, HasSubsequence(Labeled("bar() const"),
339 Labeled("Foo::foo() const")));
340 EXPECT_THAT(Results.items, Not(Contains(Labeled("foo() const")))); // private
341}
342
343TEST(CompletionTest, Snippets) {
344 clangd::CodeCompleteOptions Opts;
345 Opts.EnableSnippets = true;
346 auto Results = completions(
347 R"cpp(
348 struct fake {
349 int a;
350 int f(int i, const float f) const;
351 };
352 int main() {
353 fake f;
354 f.^
355 }
356 )cpp",
357 Opts);
358 EXPECT_THAT(Results.items,
Eric Liu63696e12017-12-20 17:24:31 +0000359 HasSubsequence(Snippet("a"),
Sam McCall44fdcec22017-12-08 15:00:59 +0000360 Snippet("f(${1:int i}, ${2:const float f})")));
361}
362
363TEST(CompletionTest, Kinds) {
364 auto Results = completions(R"cpp(
365 #define MACRO X
366 int variable;
367 struct Struct {};
368 int function();
369 int X = ^
370 )cpp");
371 EXPECT_THAT(Results.items, Has("function", CompletionItemKind::Function));
372 EXPECT_THAT(Results.items, Has("variable", CompletionItemKind::Variable));
373 EXPECT_THAT(Results.items, Has("int", CompletionItemKind::Keyword));
374 EXPECT_THAT(Results.items, Has("Struct", CompletionItemKind::Class));
375 EXPECT_THAT(Results.items, Has("MACRO", CompletionItemKind::Text));
376
377 clangd::CodeCompleteOptions Opts;
378 Opts.EnableSnippets = true; // Needed for code patterns.
379
380 Results = completions("nam^");
381 EXPECT_THAT(Results.items, Has("namespace", CompletionItemKind::Snippet));
382}
383
Sam McCall84652cc2018-01-12 16:16:09 +0000384TEST(CompletionTest, NoDuplicates) {
385 auto Items = completions(R"cpp(
386struct Adapter {
387 void method();
388};
389
390void Adapter::method() {
391 Adapter^
392}
393 )cpp")
394 .items;
395
396 // Make sure there are no duplicate entries of 'Adapter'.
397 EXPECT_THAT(Items, ElementsAre(Named("Adapter"), Named("~Adapter")));
398}
399
400TEST(CompletionTest, FuzzyRanking) {
401 auto Items = completions(R"cpp(
402 struct fake { int BigBang, Babble, Ball; };
403 int main() { fake().bb^ }")cpp").items;
404 // BigBang is a better match than Babble. Ball doesn't match at all.
405 EXPECT_THAT(Items, ElementsAre(Named("BigBang"), Named("Babble")));
406}
407
Sam McCall800d4372017-12-19 10:29:27 +0000408SignatureHelp signatures(StringRef Text) {
409 MockFSProvider FS;
410 MockCompilationDatabase CDB;
411 IgnoreDiagnostics DiagConsumer;
412 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
413 /*StorePreamblesInMemory=*/true);
414 auto File = getVirtualTestFilePath("foo.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000415 Annotations Test(Text);
416 Server.addDocument(Context::empty(), File, Test.code());
417 auto R = Server.signatureHelp(Context::empty(), File, Test.point());
Sam McCall800d4372017-12-19 10:29:27 +0000418 assert(R);
419 return R.get().Value;
420}
421
422MATCHER_P(ParamsAre, P, "") {
423 if (P.size() != arg.parameters.size())
424 return false;
425 for (unsigned I = 0; I < P.size(); ++I)
426 if (P[I] != arg.parameters[I].label)
427 return false;
428 return true;
429}
430
431Matcher<SignatureInformation> Sig(std::string Label,
432 std::vector<std::string> Params) {
433 return AllOf(Labeled(Label), ParamsAre(Params));
434}
435
436TEST(SignatureHelpTest, Overloads) {
437 auto Results = signatures(R"cpp(
438 void foo(int x, int y);
439 void foo(int x, float y);
440 void foo(float x, int y);
441 void foo(float x, float y);
442 void bar(int x, int y = 0);
443 int main() { foo(^); }
444 )cpp");
445 EXPECT_THAT(Results.signatures,
446 UnorderedElementsAre(
447 Sig("foo(float x, float y) -> void", {"float x", "float y"}),
448 Sig("foo(float x, int y) -> void", {"float x", "int y"}),
449 Sig("foo(int x, float y) -> void", {"int x", "float y"}),
450 Sig("foo(int x, int y) -> void", {"int x", "int y"})));
451 // We always prefer the first signature.
452 EXPECT_EQ(0, Results.activeSignature);
453 EXPECT_EQ(0, Results.activeParameter);
454}
455
456TEST(SignatureHelpTest, DefaultArgs) {
457 auto Results = signatures(R"cpp(
458 void bar(int x, int y = 0);
459 void bar(float x = 0, int y = 42);
460 int main() { bar(^
461 )cpp");
462 EXPECT_THAT(Results.signatures,
463 UnorderedElementsAre(
464 Sig("bar(int x, int y = 0) -> void", {"int x", "int y = 0"}),
465 Sig("bar(float x = 0, int y = 42) -> void",
466 {"float x = 0", "int y = 42"})));
467 EXPECT_EQ(0, Results.activeSignature);
468 EXPECT_EQ(0, Results.activeParameter);
469}
470
471TEST(SignatureHelpTest, ActiveArg) {
472 auto Results = signatures(R"cpp(
473 int baz(int a, int b, int c);
474 int main() { baz(baz(1,2,3), ^); }
475 )cpp");
476 EXPECT_THAT(Results.signatures,
477 ElementsAre(Sig("baz(int a, int b, int c) -> int",
478 {"int a", "int b", "int c"})));
479 EXPECT_EQ(0, Results.activeSignature);
480 EXPECT_EQ(1, Results.activeParameter);
481}
482
Eric Liu6f648df2017-12-19 16:50:37 +0000483std::unique_ptr<SymbolIndex> simpleIndexFromSymbols(
484 std::vector<std::pair<std::string, index::SymbolKind>> Symbols) {
Sam McCall4b9bbb32017-12-23 19:38:03 +0000485 SymbolSlab::Builder Slab;
Eric Liu6f648df2017-12-19 16:50:37 +0000486 for (const auto &Pair : Symbols) {
487 Symbol Sym;
488 Sym.ID = SymbolID(Pair.first);
489 llvm::StringRef QName = Pair.first;
490 size_t Pos = QName.rfind("::");
491 if (Pos == llvm::StringRef::npos) {
492 Sym.Name = QName;
493 Sym.Scope = "";
494 } else {
495 Sym.Name = QName.substr(Pos + 2);
496 Sym.Scope = QName.substr(0, Pos);
497 }
Eric Liu76f6b442018-01-09 17:32:00 +0000498 Sym.CompletionPlainInsertText = Sym.Name;
Eric Liu6f648df2017-12-19 16:50:37 +0000499 Sym.SymInfo.Kind = Pair.second;
Sam McCall4b9bbb32017-12-23 19:38:03 +0000500 Slab.insert(Sym);
Eric Liu6f648df2017-12-19 16:50:37 +0000501 }
Haojian Wuba28e9a2018-01-10 14:44:34 +0000502 return MemIndex::build(std::move(Slab).build());
Eric Liu6f648df2017-12-19 16:50:37 +0000503}
504
505TEST(CompletionTest, NoIndex) {
506 clangd::CodeCompleteOptions Opts;
507 Opts.Index = nullptr;
508
509 auto Results = completions(R"cpp(
Sam McCall3d139c52018-01-12 18:30:08 +0000510 namespace ns { class Local {}; }
Eric Liu6f648df2017-12-19 16:50:37 +0000511 void f() { ns::^ }
512 )cpp",
513 Opts);
Sam McCall3d139c52018-01-12 18:30:08 +0000514 EXPECT_THAT(Results.items, Has("Local"));
Eric Liu6f648df2017-12-19 16:50:37 +0000515}
516
Haojian Wuba28e9a2018-01-10 14:44:34 +0000517TEST(CompletionTest, StaticAndDynamicIndex) {
518 clangd::CodeCompleteOptions Opts;
519 auto StaticIdx =
520 simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
521 Opts.StaticIndex = StaticIdx.get();
522 auto DynamicIdx =
523 simpleIndexFromSymbols({{"ns::foo", index::SymbolKind::Function}});
524 Opts.Index = DynamicIdx.get();
525
526 auto Results = completions(R"cpp(
527 void f() { ::ns::^ }
528 )cpp",
529 Opts);
Sam McCall93483e72018-01-12 17:09:49 +0000530 EXPECT_THAT(Results.items, Contains(Labeled("[S]XYZ")));
531 EXPECT_THAT(Results.items, Contains(Labeled("[D]foo")));
Haojian Wuba28e9a2018-01-10 14:44:34 +0000532}
533
Eric Liu6f648df2017-12-19 16:50:37 +0000534TEST(CompletionTest, SimpleIndexBased) {
535 clangd::CodeCompleteOptions Opts;
536 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
537 {"nx::XYZ", index::SymbolKind::Class},
538 {"ns::foo", index::SymbolKind::Function}});
539 Opts.Index = I.get();
540
541 auto Results = completions(R"cpp(
Sam McCall3d139c52018-01-12 18:30:08 +0000542 namespace ns { int local; }
Eric Liu6f648df2017-12-19 16:50:37 +0000543 void f() { ns::^ }
544 )cpp",
545 Opts);
546 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
547 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
Sam McCall3d139c52018-01-12 18:30:08 +0000548 EXPECT_THAT(Results.items, Has("local"));
Eric Liu6f648df2017-12-19 16:50:37 +0000549}
550
551TEST(CompletionTest, IndexBasedWithFilter) {
552 clangd::CodeCompleteOptions Opts;
553 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class},
554 {"ns::foo", index::SymbolKind::Function}});
555 Opts.Index = I.get();
556
557 auto Results = completions(R"cpp(
558 void f() { ns::x^ }
559 )cpp",
560 Opts);
Ilya Biryukov5a5e1ca2017-12-29 14:59:22 +0000561 EXPECT_THAT(Results.items, Contains(AllOf(Named("XYZ"), Filter("XYZ"))));
Eric Liu6f648df2017-12-19 16:50:37 +0000562 EXPECT_THAT(Results.items, Not(Has("foo")));
563}
564
565TEST(CompletionTest, GlobalQualified) {
566 clangd::CodeCompleteOptions Opts;
567 auto I = simpleIndexFromSymbols({{"XYZ", index::SymbolKind::Class}});
568 Opts.Index = I.get();
569
570 auto Results = completions(R"cpp(
571 void f() { ::^ }
572 )cpp",
573 Opts);
574 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
575}
576
577TEST(CompletionTest, FullyQualifiedScope) {
578 clangd::CodeCompleteOptions Opts;
579 auto I = simpleIndexFromSymbols({{"ns::XYZ", index::SymbolKind::Class}});
580 Opts.Index = I.get();
581
582 auto Results = completions(R"cpp(
583 void f() { ::ns::^ }
584 )cpp",
585 Opts);
586 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
587}
588
Sam McCall3d139c52018-01-12 18:30:08 +0000589TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
590 MockFSProvider FS;
591 MockCompilationDatabase CDB;
592 IgnoreDiagnostics DiagConsumer;
593 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
594 /*StorePreamblesInMemory=*/true);
595
596 FS.Files[getVirtualTestFilePath("bar.h")] =
597 R"cpp(namespace ns { int preamble; })cpp";
598 auto File = getVirtualTestFilePath("foo.cpp");
599 Annotations Test(R"cpp(
600 #include "bar.h"
601 namespace ns { int local; }
602 void f() { ns::^ }
603 )cpp");
604 Server.addDocument(Context::empty(), File, Test.code()).wait();
605 clangd::CodeCompleteOptions Opts = {};
606
607 auto WithoutIndex =
608 Server.codeComplete(Context::empty(), File, Test.point(), Opts)
609 .get()
610 .second.Value;
611 EXPECT_THAT(WithoutIndex.items,
612 UnorderedElementsAre(Named("local"), Named("preamble")));
613
614 auto I = simpleIndexFromSymbols({{"ns::index", index::SymbolKind::Variable}});
615 Opts.Index = I.get();
616 auto WithIndex =
617 Server.codeComplete(Context::empty(), File, Test.point(), Opts)
618 .get()
619 .second.Value;
620 EXPECT_THAT(WithIndex.items,
621 UnorderedElementsAre(Named("local"), Named("index")));
622}
623
Eric Liubfac8f72017-12-19 18:00:37 +0000624TEST(CompletionTest, ASTIndexMultiFile) {
625 MockFSProvider FS;
626 MockCompilationDatabase CDB;
627 IgnoreDiagnostics DiagConsumer;
628 ClangdServer Server(CDB, DiagConsumer, FS, getDefaultAsyncThreadsCount(),
629 /*StorePreamblesInMemory=*/true,
630 /*BuildDynamicSymbolIndex=*/true);
631
632 Server
633 .addDocument(Context::empty(), getVirtualTestFilePath("foo.cpp"), R"cpp(
Eric Liu76f6b442018-01-09 17:32:00 +0000634 namespace ns { class XYZ {}; void foo(int x) {} }
Eric Liubfac8f72017-12-19 18:00:37 +0000635 )cpp")
636 .wait();
637
638 auto File = getVirtualTestFilePath("bar.cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000639 Annotations Test(R"cpp(
Eric Liu76f6b442018-01-09 17:32:00 +0000640 namespace ns {
641 class XXX {};
642 /// Doooc
643 void fooooo() {}
644 }
Eric Liubfac8f72017-12-19 18:00:37 +0000645 void f() { ns::^ }
646 )cpp");
Sam McCall328cbdb2017-12-20 16:06:05 +0000647 Server.addDocument(Context::empty(), File, Test.code()).wait();
Eric Liubfac8f72017-12-19 18:00:37 +0000648
Sam McCall328cbdb2017-12-20 16:06:05 +0000649 auto Results = Server.codeComplete(Context::empty(), File, Test.point(), {})
Eric Liubfac8f72017-12-19 18:00:37 +0000650 .get()
651 .second.Value;
652 // "XYZ" and "foo" are not included in the file being completed but are still
653 // visible through the index.
654 EXPECT_THAT(Results.items, Has("XYZ", CompletionItemKind::Class));
655 EXPECT_THAT(Results.items, Has("foo", CompletionItemKind::Function));
656 EXPECT_THAT(Results.items, Has("XXX", CompletionItemKind::Class));
Eric Liu76f6b442018-01-09 17:32:00 +0000657 EXPECT_THAT(Results.items, Contains(AllOf(Named("fooooo"), Filter("fooooo"),
658 Kind(CompletionItemKind::Function),
659 Doc("Doooc"), Detail("void"))));
Eric Liubfac8f72017-12-19 18:00:37 +0000660}
661
Sam McCall9aad25f2017-12-05 07:20:26 +0000662} // namespace
663} // namespace clangd
664} // namespace clang