1//===-- CodeCompleteTests.cpp -----------------------------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "ASTSignals.h"
10#include "Annotations.h"
11#include "ClangdServer.h"
12#include "CodeComplete.h"
13#include "Compiler.h"
14#include "Config.h"
15#include "Feature.h"
16#include "Matchers.h"
17#include "Protocol.h"
18#include "Quality.h"
19#include "SourceCode.h"
20#include "SyncAPI.h"
21#include "TestFS.h"
22#include "TestIndex.h"
23#include "TestTU.h"
24#include "index/Index.h"
25#include "index/MemIndex.h"
26#include "index/SymbolOrigin.h"
27#include "support/Threading.h"
28#include "clang/Sema/CodeCompleteConsumer.h"
29#include "clang/Tooling/CompilationDatabase.h"
30#include "llvm/ADT/StringRef.h"
31#include "llvm/Support/Error.h"
32#include "llvm/Support/Path.h"
33#include "llvm/Testing/Annotations/Annotations.h"
34#include "llvm/Testing/Support/Error.h"
35#include "llvm/Testing/Support/SupportHelpers.h"
36#include "gmock/gmock.h"
37#include "gtest/gtest.h"
38#include <condition_variable>
39#include <functional>
40#include <mutex>
41#include <vector>
42
43namespace clang {
44namespace clangd {
45
46namespace {
47using ::llvm::Failed;
48using ::testing::AllOf;
49using ::testing::Contains;
50using ::testing::ElementsAre;
51using ::testing::Field;
52using ::testing::HasSubstr;
53using ::testing::IsEmpty;
54using ::testing::Not;
55using ::testing::UnorderedElementsAre;
56using ContextKind = CodeCompletionContext::Kind;
57
58// GMock helpers for matching completion items.
59MATCHER_P(named, Name, "") { return arg.Name == Name; }
60MATCHER_P(mainFileRefs, Refs, "") { return arg.MainFileRefs == Refs; }
61MATCHER_P(scopeRefs, Refs, "") { return arg.ScopeRefsInFile == Refs; }
62MATCHER_P(nameStartsWith, Prefix, "") {
63 return llvm::StringRef(arg.Name).starts_with(Prefix);
64}
65MATCHER_P(filterText, F, "") { return arg.FilterText == F; }
66MATCHER_P(scope, S, "") { return arg.Scope == S; }
67MATCHER_P(qualifier, Q, "") { return arg.RequiredQualifier == Q; }
68MATCHER_P(labeled, Label, "") {
69 return arg.RequiredQualifier + arg.Name + arg.Signature == Label;
70}
71MATCHER_P(sigHelpLabeled, Label, "") { return arg.label == Label; }
72MATCHER_P(kind, K, "") { return arg.Kind == K; }
73MATCHER_P(doc, D, "") {
74 return arg.Documentation && arg.Documentation->asPlainText() == D;
75}
76MATCHER_P(returnType, D, "") { return arg.ReturnType == D; }
77MATCHER_P(hasInclude, IncludeHeader, "") {
78 return !arg.Includes.empty() && arg.Includes[0].Header == IncludeHeader;
79}
80MATCHER_P(insertInclude, IncludeHeader, "") {
81 return !arg.Includes.empty() && arg.Includes[0].Header == IncludeHeader &&
82 bool(arg.Includes[0].Insertion);
83}
84MATCHER_P(insertIncludeText, InsertedText, "") {
85 return !arg.Includes.empty() && arg.Includes[0].Insertion &&
86 arg.Includes[0].Insertion->newText == InsertedText;
87}
88MATCHER(insertInclude, "") {
89 return !arg.Includes.empty() && bool(arg.Includes[0].Insertion);
90}
91MATCHER_P(snippetSuffix, Text, "") { return arg.SnippetSuffix == Text; }
92MATCHER_P(origin, OriginSet, "") { return arg.Origin == OriginSet; }
93MATCHER_P(signature, S, "") { return arg.Signature == S; }
94MATCHER_P(replacesRange, Range, "") {
95 return arg.CompletionTokenRange == Range;
96}
97
98// Shorthand for Contains(named(Name)).
99Matcher<const std::vector<CodeCompletion> &> has(std::string Name) {
100 return Contains(matcher: named(gmock_p0: std::move(Name)));
101}
102Matcher<const std::vector<CodeCompletion> &> has(std::string Name,
103 CompletionItemKind K) {
104 return Contains(matcher: AllOf(matchers: named(gmock_p0: std::move(Name)), matchers: kind(gmock_p0: K)));
105}
106MATCHER(isDocumented, "") { return arg.Documentation.has_value(); }
107MATCHER(deprecated, "") { return arg.Deprecated; }
108
109std::unique_ptr<SymbolIndex> memIndex(std::vector<Symbol> Symbols) {
110 SymbolSlab::Builder Slab;
111 for (const auto &Sym : Symbols)
112 Slab.insert(S: Sym);
113 return MemIndex::build(Symbols: std::move(Slab).build(), Refs: RefSlab(), Relations: RelationSlab());
114}
115
116// Runs code completion.
117// If IndexSymbols is non-empty, an index will be built and passed to opts.
118CodeCompleteResult completions(const TestTU &TU, Position Point,
119 std::vector<Symbol> IndexSymbols = {},
120 clangd::CodeCompleteOptions Opts = {}) {
121 std::unique_ptr<SymbolIndex> OverrideIndex;
122 if (!IndexSymbols.empty()) {
123 assert(!Opts.Index && "both Index and IndexSymbols given!");
124 OverrideIndex = memIndex(Symbols: std::move(IndexSymbols));
125 Opts.Index = OverrideIndex.get();
126 }
127
128 MockFS FS;
129 auto Inputs = TU.inputs(FS);
130 IgnoreDiagnostics Diags;
131 auto CI = buildCompilerInvocation(Inputs, D&: Diags);
132 if (!CI) {
133 ADD_FAILURE() << "Couldn't build CompilerInvocation";
134 return {};
135 }
136 auto Preamble = buildPreamble(FileName: testPath(File: TU.Filename), CI: *CI, Inputs,
137 /*InMemory=*/StoreInMemory: true, /*Callback=*/PreambleCallback: nullptr);
138 return codeComplete(FileName: testPath(File: TU.Filename), Pos: Point, Preamble: Preamble.get(), ParseInput: Inputs,
139 Opts);
140}
141
142// Runs code completion.
143CodeCompleteResult completions(llvm::StringRef Text,
144 std::vector<Symbol> IndexSymbols = {},
145 clangd::CodeCompleteOptions Opts = {},
146 PathRef FilePath = "foo.cpp") {
147 Annotations Test(Text);
148 auto TU = TestTU::withCode(Code: Test.code());
149 // To make sure our tests for completiopns inside templates work on Windows.
150 TU.Filename = FilePath.str();
151 return completions(TU, Point: Test.point(), IndexSymbols: std::move(IndexSymbols),
152 Opts: std::move(Opts));
153}
154
155// Runs code completion without the clang parser.
156CodeCompleteResult completionsNoCompile(llvm::StringRef Text,
157 std::vector<Symbol> IndexSymbols = {},
158 clangd::CodeCompleteOptions Opts = {},
159 PathRef FilePath = "foo.cpp") {
160 std::unique_ptr<SymbolIndex> OverrideIndex;
161 if (!IndexSymbols.empty()) {
162 assert(!Opts.Index && "both Index and IndexSymbols given!");
163 OverrideIndex = memIndex(Symbols: std::move(IndexSymbols));
164 Opts.Index = OverrideIndex.get();
165 }
166
167 MockFS FS;
168 Annotations Test(Text);
169 ParseInputs ParseInput{.CompileCommand: tooling::CompileCommand(), .TFS: &FS, .Contents: Test.code().str()};
170 return codeComplete(FileName: FilePath, Pos: Test.point(), /*Preamble=*/nullptr, ParseInput,
171 Opts);
172}
173
174Symbol withReferences(int N, Symbol S) {
175 S.References = N;
176 return S;
177}
178
179#if CLANGD_DECISION_FOREST
180TEST(DecisionForestRankingModel, NameMatchSanityTest) {
181 clangd::CodeCompleteOptions Opts;
182 Opts.RankingModel = CodeCompleteOptions::DecisionForest;
183 auto Results = completions(
184 Text: R"cpp(
185struct MemberAccess {
186 int ABG();
187 int AlphaBetaGamma();
188};
189int func() { MemberAccess().ABG^ }
190)cpp",
191 /*IndexSymbols=*/{}, Opts);
192 EXPECT_THAT(Results.Completions,
193 ElementsAre(named("ABG"), named("AlphaBetaGamma")));
194}
195
196TEST(DecisionForestRankingModel, ReferencesAffectRanking) {
197 clangd::CodeCompleteOptions Opts;
198 Opts.RankingModel = CodeCompleteOptions::DecisionForest;
199 constexpr int NumReferences = 100000;
200 EXPECT_THAT(
201 completions("int main() { clang^ }",
202 {ns("clangA"), withReferences(NumReferences, func("clangD"))},
203 Opts)
204 .Completions,
205 ElementsAre(named("clangD"), named("clangA")));
206 EXPECT_THAT(
207 completions("int main() { clang^ }",
208 {withReferences(NumReferences, ns("clangA")), func("clangD")},
209 Opts)
210 .Completions,
211 ElementsAre(named("clangA"), named("clangD")));
212}
213#endif // CLANGD_DECISION_FOREST
214
215TEST(DecisionForestRankingModel, DecisionForestScorerCallbackTest) {
216 clangd::CodeCompleteOptions Opts;
217 constexpr float MagicNumber = 1234.5678f;
218 Opts.RankingModel = CodeCompleteOptions::DecisionForest;
219 Opts.DecisionForestScorer = [&](const SymbolQualitySignals &,
220 const SymbolRelevanceSignals &, float Base) {
221 DecisionForestScores Scores;
222 Scores.Total = MagicNumber;
223 Scores.ExcludingName = MagicNumber;
224 return Scores;
225 };
226 llvm::StringRef Code = "int func() { int xyz; xy^ }";
227 auto Results = completions(Text: Code,
228 /*IndexSymbols=*/{}, Opts);
229 ASSERT_EQ(Results.Completions.size(), 1u);
230 EXPECT_EQ(Results.Completions[0].Score.Total, MagicNumber);
231 EXPECT_EQ(Results.Completions[0].Score.ExcludingName, MagicNumber);
232
233 // Do not use DecisionForestScorer for heuristics model.
234 Opts.RankingModel = CodeCompleteOptions::Heuristics;
235 Results = completions(Text: Code,
236 /*IndexSymbols=*/{}, Opts);
237 ASSERT_EQ(Results.Completions.size(), 1u);
238 EXPECT_NE(Results.Completions[0].Score.Total, MagicNumber);
239 EXPECT_NE(Results.Completions[0].Score.ExcludingName, MagicNumber);
240}
241
242TEST(CompletionTest, Limit) {
243 clangd::CodeCompleteOptions Opts;
244 Opts.Limit = 2;
245 auto Results = completions(Text: R"cpp(
246struct ClassWithMembers {
247 int AAA();
248 int BBB();
249 int CCC();
250};
251
252int main() { ClassWithMembers().^ }
253 )cpp",
254 /*IndexSymbols=*/{}, Opts);
255
256 EXPECT_TRUE(Results.HasMore);
257 EXPECT_THAT(Results.Completions, ElementsAre(named("AAA"), named("BBB")));
258}
259
260TEST(CompletionTest, Filter) {
261 std::string Body = R"cpp(
262 #define MotorCar
263 int Car;
264 struct S {
265 int FooBar;
266 int FooBaz;
267 int Qux;
268 };
269 )cpp";
270
271 // Only items matching the fuzzy query are returned.
272 EXPECT_THAT(completions(Body + "int main() { S().Foba^ }").Completions,
273 AllOf(has("FooBar"), has("FooBaz"), Not(has("Qux"))));
274
275 // Macros require prefix match, either from index or AST.
276 Symbol Sym = var(Name: "MotorCarIndex");
277 Sym.SymInfo.Kind = index::SymbolKind::Macro;
278 EXPECT_THAT(
279 completions(Body + "int main() { C^ }", {Sym}).Completions,
280 AllOf(has("Car"), Not(has("MotorCar")), Not(has("MotorCarIndex"))));
281 EXPECT_THAT(completions(Body + "int main() { M^ }", {Sym}).Completions,
282 AllOf(has("MotorCar"), has("MotorCarIndex")));
283}
284
285void testAfterDotCompletion(clangd::CodeCompleteOptions Opts) {
286 auto Results = completions(
287 Text: R"cpp(
288 int global_var;
289
290 int global_func();
291
292 // Make sure this is not in preamble.
293 #define MACRO X
294
295 struct GlobalClass {};
296
297 struct ClassWithMembers {
298 /// doc for method.
299 int method();
300
301 int field;
302 private:
303 int private_field;
304 };
305
306 int test() {
307 struct LocalClass {};
308
309 /// doc for local_var.
310 int local_var;
311
312 ClassWithMembers().^
313 }
314 )cpp",
315 IndexSymbols: {cls(Name: "IndexClass"), var(Name: "index_var"), func(Name: "index_func")}, Opts);
316
317 EXPECT_TRUE(Results.RanParser);
318 // Class members. The only items that must be present in after-dot
319 // completion.
320 EXPECT_THAT(Results.Completions,
321 AllOf(has("method"), has("field"), Not(has("ClassWithMembers")),
322 Not(has("operator=")), Not(has("~ClassWithMembers"))));
323 EXPECT_IFF(Opts.IncludeIneligibleResults, Results.Completions,
324 has("private_field"));
325 // Global items.
326 EXPECT_THAT(
327 Results.Completions,
328 Not(AnyOf(has("global_var"), has("index_var"), has("global_func"),
329 has("global_func()"), has("index_func"), has("GlobalClass"),
330 has("IndexClass"), has("MACRO"), has("LocalClass"))));
331 // There should be no code patterns (aka snippets) in after-dot
332 // completion. At least there aren't any we're aware of.
333 EXPECT_THAT(Results.Completions,
334 Not(Contains(kind(CompletionItemKind::Snippet))));
335 // Check documentation.
336 EXPECT_THAT(Results.Completions, Contains(isDocumented()));
337}
338
339void testGlobalScopeCompletion(clangd::CodeCompleteOptions Opts) {
340 auto Results = completions(
341 Text: R"cpp(
342 int global_var;
343 int global_func();
344
345 // Make sure this is not in preamble.
346 #define MACRO X
347
348 struct GlobalClass {};
349
350 struct ClassWithMembers {
351 /// doc for method.
352 int method();
353 };
354
355 int test() {
356 struct LocalClass {};
357
358 /// doc for local_var.
359 int local_var;
360
361 ^
362 }
363 )cpp",
364 IndexSymbols: {cls(Name: "IndexClass"), var(Name: "index_var"), func(Name: "index_func")}, Opts);
365
366 EXPECT_TRUE(Results.RanParser);
367 // Class members. Should never be present in global completions.
368 EXPECT_THAT(Results.Completions,
369 Not(AnyOf(has("method"), has("method()"), has("field"))));
370 // Global items.
371 EXPECT_THAT(Results.Completions,
372 AllOf(has("global_var"), has("index_var"), has("global_func"),
373 has("index_func" /* our fake symbol doesn't include () */),
374 has("GlobalClass"), has("IndexClass")));
375 // A macro.
376 EXPECT_THAT(Results.Completions, has("MACRO"));
377 // Local items. Must be present always.
378 EXPECT_THAT(Results.Completions,
379 AllOf(has("local_var"), has("LocalClass"),
380 Contains(kind(CompletionItemKind::Snippet))));
381 // Check documentation.
382 EXPECT_THAT(Results.Completions, Contains(isDocumented()));
383}
384
385TEST(CompletionTest, CompletionOptions) {
386 auto Test = [&](const clangd::CodeCompleteOptions &Opts) {
387 testAfterDotCompletion(Opts);
388 testGlobalScopeCompletion(Opts);
389 };
390 // We used to test every combination of options, but that got too slow (2^N).
391 auto Flags = {
392 &clangd::CodeCompleteOptions::IncludeIneligibleResults,
393 };
394 // Test default options.
395 Test({});
396 // Test with one flag flipped.
397 for (auto &F : Flags) {
398 clangd::CodeCompleteOptions O;
399 O.*F ^= true;
400 Test(O);
401 }
402}
403
404TEST(CompletionTest, Accessible) {
405 auto Internal = completions(Text: R"cpp(
406 class Foo {
407 public: void pub();
408 protected: void prot();
409 private: void priv();
410 };
411 void Foo::pub() { this->^ }
412 )cpp");
413 EXPECT_THAT(Internal.Completions,
414 AllOf(has("priv"), has("prot"), has("pub")));
415
416 auto External = completions(Text: R"cpp(
417 class Foo {
418 public: void pub();
419 protected: void prot();
420 private: void priv();
421 };
422 void test() {
423 Foo F;
424 F.^
425 }
426 )cpp");
427 EXPECT_THAT(External.Completions,
428 AllOf(has("pub"), Not(has("prot")), Not(has("priv"))));
429
430 auto Results = completions(Text: R"cpp(
431 struct Foo {
432 public: void pub();
433 protected: void prot();
434 private: void priv();
435 };
436 struct Bar : public Foo {
437 private: using Foo::pub;
438 };
439 void test() {
440 Bar B;
441 B.^
442 }
443 )cpp");
444 EXPECT_THAT(Results.Completions,
445 AllOf(Not(has("priv")), Not(has("prot")), Not(has("pub"))));
446}
447
448TEST(CompletionTest, Qualifiers) {
449 auto Results = completions(Text: R"cpp(
450 class Foo {
451 public: int foo() const;
452 int bar() const;
453 };
454 class Bar : public Foo {
455 int foo() const;
456 };
457 void test() { Bar().^ }
458 )cpp");
459 EXPECT_THAT(Results.Completions,
460 Contains(AllOf(qualifier(""), named("bar"))));
461 // Hidden members are not shown.
462 EXPECT_THAT(Results.Completions,
463 Not(Contains(AllOf(qualifier("Foo::"), named("foo")))));
464 // Private members are not shown.
465 EXPECT_THAT(Results.Completions,
466 Not(Contains(AllOf(qualifier(""), named("foo")))));
467}
468
469// https://github.com/clangd/clangd/issues/1451
470TEST(CompletionTest, QualificationWithInlineNamespace) {
471 auto Results = completions(Text: R"cpp(
472 namespace a { inline namespace b {} }
473 using namespace a::b;
474 void f() { Foo^ }
475 )cpp",
476 IndexSymbols: {cls(Name: "a::Foo")});
477 EXPECT_THAT(Results.Completions,
478 UnorderedElementsAre(AllOf(qualifier("a::"), named("Foo"))));
479}
480
481TEST(CompletionTest, InjectedTypename) {
482 // These are suppressed when accessed as a member...
483 EXPECT_THAT(completions("struct X{}; void foo(){ X().^ }").Completions,
484 Not(has("X")));
485 EXPECT_THAT(completions("struct X{ void foo(){ this->^ } };").Completions,
486 Not(has("X")));
487 // ...but accessible in other, more useful cases.
488 EXPECT_THAT(completions("struct X{ void foo(){ ^ } };").Completions,
489 has("X"));
490 EXPECT_THAT(
491 completions("struct Y{}; struct X:Y{ void foo(){ ^ } };").Completions,
492 has("Y"));
493 EXPECT_THAT(
494 completions(
495 "template<class> struct Y{}; struct X:Y<int>{ void foo(){ ^ } };")
496 .Completions,
497 has("Y"));
498 // This case is marginal (`using X::X` is useful), we allow it for now.
499 EXPECT_THAT(completions("struct X{}; void foo(){ X::^ }").Completions,
500 has("X"));
501}
502
503TEST(CompletionTest, SkipInjectedWhenUnqualified) {
504 EXPECT_THAT(completions("struct X { void f() { X^ }};").Completions,
505 ElementsAre(named("X"), named("~X")));
506}
507
508TEST(CompletionTest, Snippets) {
509 clangd::CodeCompleteOptions Opts;
510 auto Results = completions(
511 Text: R"cpp(
512 struct fake {
513 int a;
514 int f(int i, const float f) const;
515 };
516 int main() {
517 fake f;
518 f.^
519 }
520 )cpp",
521 /*IndexSymbols=*/{}, Opts);
522 EXPECT_THAT(
523 Results.Completions,
524 HasSubsequence(named("a"),
525 snippetSuffix("(${1:int i}, ${2:const float f})")));
526}
527
528TEST(CompletionTest, HeuristicsForMemberFunctionCompletion) {
529 clangd::CodeCompleteOptions Opts;
530 Opts.EnableSnippets = true;
531
532 Annotations Code(R"cpp(
533 struct Foo {
534 static int staticMethod(int);
535 int method(int) const;
536 template <typename T, typename U, typename V = int>
537 T generic(U, V);
538 template <typename T, int U>
539 static T staticGeneric();
540 Foo() {
541 this->$canBeCall^
542 $canBeCall^
543 Foo::$canBeCall^
544 }
545 };
546
547 struct Derived : Foo {
548 using Foo::method;
549 using Foo::generic;
550 Derived() {
551 Foo::$canBeCall^
552 }
553 };
554
555 struct OtherClass {
556 OtherClass() {
557 Foo f;
558 Derived d;
559 f.$canBeCall^
560 ; // Prevent parsing as 'f.f'
561 f.Foo::$canBeCall^
562 &Foo::$canNotBeCall^
563 ;
564 d.Foo::$canBeCall^
565 ;
566 d.Derived::$canBeCall^
567 }
568 };
569
570 int main() {
571 Foo f;
572 Derived d;
573 f.$canBeCall^
574 ; // Prevent parsing as 'f.f'
575 f.Foo::$canBeCall^
576 &Foo::$canNotBeCall^
577 ;
578 d.Foo::$canBeCall^
579 ;
580 d.Derived::$canBeCall^
581 }
582 )cpp");
583 auto TU = TestTU::withCode(Code: Code.code());
584
585 for (const auto &P : Code.points(Name: "canNotBeCall")) {
586 auto Results = completions(TU, Point: P, /*IndexSymbols*/ {}, Opts);
587 EXPECT_THAT(Results.Completions,
588 Contains(AllOf(named("method"), signature("(int) const"),
589 snippetSuffix(""))));
590 // We don't have any arguments to deduce against if this isn't a call.
591 // Thus, we should emit these deducible template arguments explicitly.
592 EXPECT_THAT(
593 Results.Completions,
594 Contains(AllOf(named("generic"),
595 signature("<typename T, typename U>(U, V)"),
596 snippetSuffix("<${1:typename T}, ${2:typename U}>"))));
597 }
598
599 for (const auto &P : Code.points(Name: "canBeCall")) {
600 auto Results = completions(TU, Point: P, /*IndexSymbols*/ {}, Opts);
601 EXPECT_THAT(Results.Completions,
602 Contains(AllOf(named("method"), signature("(int) const"),
603 snippetSuffix("(${1:int})"))));
604 EXPECT_THAT(
605 Results.Completions,
606 Contains(AllOf(named("generic"), signature("<typename T>(U, V)"),
607 snippetSuffix("<${1:typename T}>(${2:U}, ${3:V})"))));
608 }
609
610 // static method will always keep the snippet
611 for (const auto &P : Code.points()) {
612 auto Results = completions(TU, Point: P, /*IndexSymbols*/ {}, Opts);
613 EXPECT_THAT(Results.Completions,
614 Contains(AllOf(named("staticMethod"), signature("(int)"),
615 snippetSuffix("(${1:int})"))));
616 EXPECT_THAT(Results.Completions,
617 Contains(AllOf(
618 named("staticGeneric"), signature("<typename T, int U>()"),
619 snippetSuffix("<${1:typename T}, ${2:int U}>()"))));
620 }
621}
622
623TEST(CompletionTest, NoSnippetsInUsings) {
624 clangd::CodeCompleteOptions Opts;
625 Opts.EnableSnippets = true;
626 auto Results = completions(
627 Text: R"cpp(
628 namespace ns {
629 int func(int a, int b);
630 }
631
632 using ns::^;
633 )cpp",
634 /*IndexSymbols=*/{}, Opts);
635 EXPECT_THAT(Results.Completions,
636 ElementsAre(AllOf(named("func"), labeled("func(int a, int b)"),
637 snippetSuffix(""))));
638
639 // Check index completions too.
640 auto Func = func(Name: "ns::func");
641 Func.CompletionSnippetSuffix = "(${1:int a}, ${2: int b})";
642 Func.Signature = "(int a, int b)";
643 Func.ReturnType = "void";
644
645 Results = completions(Text: R"cpp(
646 namespace ns {}
647 using ns::^;
648 )cpp",
649 /*IndexSymbols=*/{Func}, Opts);
650 EXPECT_THAT(Results.Completions,
651 ElementsAre(AllOf(named("func"), labeled("func(int a, int b)"),
652 snippetSuffix(""))));
653
654 // Check all-scopes completions too.
655 Opts.AllScopes = true;
656 Results = completions(Text: R"cpp(
657 using ^;
658 )cpp",
659 /*IndexSymbols=*/{Func}, Opts);
660 EXPECT_THAT(Results.Completions,
661 Contains(AllOf(named("func"), labeled("ns::func(int a, int b)"),
662 snippetSuffix(""))));
663}
664
665TEST(CompletionTest, Kinds) {
666 auto Results = completions(
667 Text: R"cpp(
668 int variable;
669 struct Struct {};
670 int function();
671 // make sure MACRO is not included in preamble.
672 #define MACRO 10
673 int X = ^
674 )cpp",
675 IndexSymbols: {func(Name: "indexFunction"), var(Name: "indexVariable"), cls(Name: "indexClass"),
676 macro(Name: "indexObjMacro"), macro(Name: "indexFuncMacro", ArgList: "(x, y)")});
677 EXPECT_THAT(Results.Completions,
678 AllOf(has("function", CompletionItemKind::Function),
679 has("variable", CompletionItemKind::Variable),
680 has("int", CompletionItemKind::Keyword),
681 has("Struct", CompletionItemKind::Struct),
682 has("MACRO", CompletionItemKind::Constant),
683 has("indexFunction", CompletionItemKind::Function),
684 has("indexVariable", CompletionItemKind::Variable),
685 has("indexClass", CompletionItemKind::Class),
686 has("indexObjMacro", CompletionItemKind::Constant),
687 has("indexFuncMacro", CompletionItemKind::Function)));
688
689 Results = completions(Text: "nam^");
690 EXPECT_THAT(Results.Completions,
691 has("namespace", CompletionItemKind::Snippet));
692
693 // Members of anonymous unions are of kind 'field'.
694 Results = completions(
695 Text: R"cpp(
696 struct X{
697 union {
698 void *a;
699 };
700 };
701 auto u = X().^
702 )cpp");
703 EXPECT_THAT(
704 Results.Completions,
705 UnorderedElementsAre(AllOf(named("a"), kind(CompletionItemKind::Field))));
706
707 // Completion kinds for templates should not be unknown.
708 Results = completions(
709 Text: R"cpp(
710 template <class T> struct complete_class {};
711 template <class T> void complete_function();
712 template <class T> using complete_type_alias = int;
713 template <class T> int complete_variable = 10;
714
715 struct X {
716 template <class T> static int complete_static_member = 10;
717
718 static auto x = complete_^
719 }
720 )cpp");
721 EXPECT_THAT(
722 Results.Completions,
723 UnorderedElementsAre(
724 AllOf(named("complete_class"), kind(CompletionItemKind::Class)),
725 AllOf(named("complete_function"), kind(CompletionItemKind::Function)),
726 AllOf(named("complete_type_alias"),
727 kind(CompletionItemKind::Interface)),
728 AllOf(named("complete_variable"), kind(CompletionItemKind::Variable)),
729 AllOf(named("complete_static_member"),
730 kind(CompletionItemKind::Property))));
731
732 Results = completions(
733 Text: R"cpp(
734 enum Color {
735 Red
736 };
737 Color u = ^
738 )cpp");
739 EXPECT_THAT(
740 Results.Completions,
741 Contains(AllOf(named("Red"), kind(CompletionItemKind::EnumMember))));
742}
743
744TEST(CompletionTest, NoDuplicates) {
745 auto Results = completions(
746 Text: R"cpp(
747 class Adapter {
748 };
749
750 void f() {
751 Adapter^
752 }
753 )cpp",
754 IndexSymbols: {cls(Name: "Adapter")});
755
756 // Make sure there are no duplicate entries of 'Adapter'.
757 EXPECT_THAT(Results.Completions, ElementsAre(named("Adapter")));
758}
759
760TEST(CompletionTest, ScopedNoIndex) {
761 auto Results = completions(
762 Text: R"cpp(
763 namespace fake { int BigBang, Babble, Box; };
764 int main() { fake::ba^ }
765 ")cpp");
766 // Babble is a better match than BigBang. Box doesn't match at all.
767 EXPECT_THAT(Results.Completions,
768 ElementsAre(named("Babble"), named("BigBang")));
769}
770
771TEST(CompletionTest, Scoped) {
772 auto Results = completions(
773 Text: R"cpp(
774 namespace fake { int Babble, Box; };
775 int main() { fake::ba^ }
776 ")cpp",
777 IndexSymbols: {var(Name: "fake::BigBang")});
778 EXPECT_THAT(Results.Completions,
779 ElementsAre(named("Babble"), named("BigBang")));
780}
781
782TEST(CompletionTest, ScopedWithFilter) {
783 auto Results = completions(
784 Text: R"cpp(
785 void f() { ns::x^ }
786 )cpp",
787 IndexSymbols: {cls(Name: "ns::XYZ"), func(Name: "ns::foo")});
788 EXPECT_THAT(Results.Completions, UnorderedElementsAre(named("XYZ")));
789}
790
791TEST(CompletionTest, ReferencesAffectRanking) {
792 EXPECT_THAT(completions("int main() { abs^ }", {func("absA"), func("absB")})
793 .Completions,
794 HasSubsequence(named("absA"), named("absB")));
795 EXPECT_THAT(completions("int main() { abs^ }",
796 {func("absA"), withReferences(1000, func("absB"))})
797 .Completions,
798 HasSubsequence(named("absB"), named("absA")));
799}
800
801TEST(CompletionTest, ContextWords) {
802 auto Results = completions(Text: R"cpp(
803 enum class Color { RED, YELLOW, BLUE };
804
805 // (blank lines so the definition above isn't "context")
806
807 // "It was a yellow car," he said. "Big yellow car, new."
808 auto Finish = Color::^
809 )cpp");
810 // Yellow would normally sort last (alphabetic).
811 // But the recent mention should bump it up.
812 ASSERT_THAT(Results.Completions,
813 HasSubsequence(named("YELLOW"), named("BLUE")));
814}
815
816TEST(CompletionTest, GlobalQualified) {
817 auto Results = completions(
818 Text: R"cpp(
819 void f() { ::^ }
820 )cpp",
821 IndexSymbols: {cls(Name: "XYZ")});
822 EXPECT_THAT(Results.Completions,
823 AllOf(has("XYZ", CompletionItemKind::Class),
824 has("f", CompletionItemKind::Function)));
825}
826
827TEST(CompletionTest, FullyQualified) {
828 auto Results = completions(
829 Text: R"cpp(
830 namespace ns { void bar(); }
831 void f() { ::ns::^ }
832 )cpp",
833 IndexSymbols: {cls(Name: "ns::XYZ")});
834 EXPECT_THAT(Results.Completions,
835 AllOf(has("XYZ", CompletionItemKind::Class),
836 has("bar", CompletionItemKind::Function)));
837}
838
839TEST(CompletionTest, SemaIndexMerge) {
840 auto Results = completions(
841 Text: R"cpp(
842 namespace ns { int local; void both(); }
843 void f() { ::ns::^ }
844 )cpp",
845 IndexSymbols: {func(Name: "ns::both"), cls(Name: "ns::Index")});
846 // We get results from both index and sema, with no duplicates.
847 EXPECT_THAT(Results.Completions,
848 UnorderedElementsAre(
849 AllOf(named("local"), origin(SymbolOrigin::AST)),
850 AllOf(named("Index"), origin(SymbolOrigin::Static)),
851 AllOf(named("both"),
852 origin(SymbolOrigin::AST | SymbolOrigin::Static))));
853}
854
855TEST(CompletionTest, SemaIndexMergeWithLimit) {
856 clangd::CodeCompleteOptions Opts;
857 Opts.Limit = 1;
858 auto Results = completions(
859 Text: R"cpp(
860 namespace ns { int local; void both(); }
861 void f() { ::ns::^ }
862 )cpp",
863 IndexSymbols: {func(Name: "ns::both"), cls(Name: "ns::Index")}, Opts);
864 EXPECT_EQ(Results.Completions.size(), Opts.Limit);
865 EXPECT_TRUE(Results.HasMore);
866}
867
868TEST(CompletionTest, IncludeInsertionPreprocessorIntegrationTests) {
869 TestTU TU;
870 TU.ExtraArgs.push_back(x: "-I" + testPath(File: "sub"));
871 TU.AdditionalFiles["sub/bar.h"] = "";
872 auto BarURI = URI::create(AbsolutePath: testPath(File: "sub/bar.h")).toString();
873
874 Symbol Sym = cls(Name: "ns::X");
875 Sym.CanonicalDeclaration.FileURI = BarURI.c_str();
876 Sym.IncludeHeaders.emplace_back(Args&: BarURI, Args: 1, Args: Symbol::Include);
877 // Shorten include path based on search directory and insert.
878 Annotations Test("int main() { ns::^ }");
879 TU.Code = Test.code().str();
880 auto Results = completions(TU, Point: Test.point(), IndexSymbols: {Sym});
881 EXPECT_THAT(Results.Completions,
882 ElementsAre(AllOf(named("X"), insertInclude("\"bar.h\""))));
883 // Can be disabled via option.
884 CodeCompleteOptions NoInsertion;
885 NoInsertion.InsertIncludes = Config::HeaderInsertionPolicy::NeverInsert;
886 Results = completions(TU, Point: Test.point(), IndexSymbols: {Sym}, Opts: NoInsertion);
887 EXPECT_THAT(Results.Completions,
888 ElementsAre(AllOf(named("X"), Not(insertInclude()))));
889 // Duplicate based on inclusions in preamble.
890 Test = Annotations(R"cpp(
891 #include "sub/bar.h" // not shortest, so should only match resolved.
892 int main() { ns::^ }
893 )cpp");
894 TU.Code = Test.code().str();
895 Results = completions(TU, Point: Test.point(), IndexSymbols: {Sym});
896 EXPECT_THAT(Results.Completions, ElementsAre(AllOf(named("X"), labeled("X"),
897 Not(insertInclude()))));
898}
899
900TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {
901 Symbol SymX = cls(Name: "ns::X");
902 Symbol SymY = cls(Name: "ns::Y");
903 std::string BarHeader = testPath(File: "bar.h");
904 auto BarURI = URI::create(AbsolutePath: BarHeader).toString();
905 SymX.CanonicalDeclaration.FileURI = BarURI.c_str();
906 SymY.CanonicalDeclaration.FileURI = BarURI.c_str();
907 SymX.IncludeHeaders.emplace_back(Args: "<bar>", Args: 1, Args: Symbol::Include);
908 SymY.IncludeHeaders.emplace_back(Args: "<bar>", Args: 1, Args: Symbol::Include);
909 // Shorten include path based on search directory and insert.
910 auto Results = completions(Text: R"cpp(
911 namespace ns {
912 class X;
913 class Y {};
914 }
915 int main() { ns::^ }
916 )cpp",
917 IndexSymbols: {SymX, SymY});
918 EXPECT_THAT(Results.Completions,
919 ElementsAre(AllOf(named("X"), Not(insertInclude())),
920 AllOf(named("Y"), Not(insertInclude()))));
921}
922
923TEST(CompletionTest, IncludeInsertionRespectsQuotedAngledConfig) {
924 TestTU TU;
925 TU.ExtraArgs.push_back(x: "-I" + testPath(File: "sub"));
926 TU.AdditionalFiles["sub/bar.h"] = "";
927 auto BarURI = URI::create(AbsolutePath: testPath(File: "sub/bar.h")).toString();
928
929 Symbol Sym = cls(Name: "ns::X");
930 Sym.CanonicalDeclaration.FileURI = BarURI.c_str();
931 Sym.IncludeHeaders.emplace_back(Args&: BarURI, Args: 1, Args: Symbol::Include);
932 Annotations Test("int main() { ns::^ }");
933 TU.Code = Test.code().str();
934 auto Results = completions(TU, Point: Test.point(), IndexSymbols: {Sym});
935 // Default for a local path is quoted include
936 EXPECT_THAT(Results.Completions,
937 ElementsAre(AllOf(named("X"), insertInclude("\"bar.h\""))));
938 {
939 Config C;
940 C.Style.AngledHeaders.push_back(
941 x: [](auto header) { return header == "bar.h"; });
942 WithContextValue WithCfg(Config::Key, std::move(C));
943 Results = completions(TU, Point: Test.point(), IndexSymbols: {Sym});
944 EXPECT_THAT(Results.Completions,
945 ElementsAre(AllOf(named("X"), insertInclude("<bar.h>"))));
946 }
947 {
948 Config C;
949 C.Style.QuotedHeaders.push_back(
950 x: [](auto header) { return header == "bar.h"; });
951 WithContextValue WithCfg(Config::Key, std::move(C));
952 Results = completions(TU, Point: Test.point(), IndexSymbols: {Sym});
953 EXPECT_THAT(Results.Completions,
954 ElementsAre(AllOf(named("X"), insertInclude("\"bar.h\""))));
955 }
956}
957
958TEST(CompletionTest, IndexSuppressesPreambleCompletions) {
959 Annotations Test(R"cpp(
960 #include "bar.h"
961 namespace ns { int local; }
962 void f() { ns::^; }
963 void f2() { ns::preamble().$2^; }
964 )cpp");
965 auto TU = TestTU::withCode(Code: Test.code());
966 TU.AdditionalFiles["bar.h"] =
967 R"cpp(namespace ns { struct preamble { int member; }; })cpp";
968
969 clangd::CodeCompleteOptions Opts = {};
970 auto I = memIndex(Symbols: {var(Name: "ns::index")});
971 Opts.Index = I.get();
972 auto WithIndex = completions(TU, Point: Test.point(), IndexSymbols: {}, Opts);
973 EXPECT_THAT(WithIndex.Completions,
974 UnorderedElementsAre(named("local"), named("index")));
975 auto ClassFromPreamble = completions(TU, Point: Test.point(Name: "2"), IndexSymbols: {}, Opts);
976 EXPECT_THAT(ClassFromPreamble.Completions, Contains(named("member")));
977
978 Opts.Index = nullptr;
979 auto WithoutIndex = completions(TU, Point: Test.point(), IndexSymbols: {}, Opts);
980 EXPECT_THAT(WithoutIndex.Completions,
981 UnorderedElementsAre(named("local"), named("preamble")));
982}
983
984// This verifies that we get normal preprocessor completions in the preamble.
985// This is a regression test for an old bug: if we override the preamble and
986// try to complete inside it, clang kicks our completion point just outside the
987// preamble, resulting in always getting top-level completions.
988TEST(CompletionTest, CompletionInPreamble) {
989 auto Results = completions(Text: R"cpp(
990 #ifnd^ef FOO_H_
991 #define BAR_H_
992 #include <bar.h>
993 int foo() {}
994 #endif
995 )cpp")
996 .Completions;
997 EXPECT_THAT(Results, ElementsAre(named("ifndef")));
998}
999
1000TEST(CompletionTest, CompletionRecoveryASTType) {
1001 auto Results = completions(Text: R"cpp(
1002 struct S { int member; };
1003 S overloaded(int);
1004 void foo() {
1005 // No overload matches, but we have recovery-expr with the correct type.
1006 overloaded().^
1007 })cpp")
1008 .Completions;
1009 EXPECT_THAT(Results, ElementsAre(named("member")));
1010}
1011
1012TEST(CompletionTest, DynamicIndexIncludeInsertion) {
1013 MockFS FS;
1014 MockCompilationDatabase CDB;
1015 ClangdServer::Options Opts = ClangdServer::optsForTest();
1016 Opts.BuildDynamicSymbolIndex = true;
1017 ClangdServer Server(CDB, FS, Opts);
1018
1019 FS.Files[testPath(File: "foo_header.h")] = R"cpp(
1020 #pragma once
1021 struct Foo {
1022 // Member doc
1023 int foo();
1024 };
1025 )cpp";
1026 const std::string FileContent(R"cpp(
1027 #include "foo_header.h"
1028 int Foo::foo() {
1029 return 42;
1030 }
1031 )cpp");
1032 Server.addDocument(File: testPath(File: "foo_impl.cpp"), Contents: FileContent);
1033 // Wait for the dynamic index being built.
1034 ASSERT_TRUE(Server.blockUntilIdleForTest());
1035
1036 auto File = testPath(File: "foo.cpp");
1037 Annotations Test("Foo^ foo;");
1038 runAddDocument(Server, File, Contents: Test.code());
1039 auto CompletionList =
1040 llvm::cantFail(ValOrErr: runCodeComplete(Server, File, Pos: Test.point(), Opts: {}));
1041
1042 EXPECT_THAT(CompletionList.Completions,
1043 ElementsAre(AllOf(named("Foo"), hasInclude("\"foo_header.h\""),
1044 insertInclude())));
1045}
1046
1047TEST(CompletionTest, DynamicIndexMultiFile) {
1048 MockFS FS;
1049 MockCompilationDatabase CDB;
1050 auto Opts = ClangdServer::optsForTest();
1051 Opts.BuildDynamicSymbolIndex = true;
1052 ClangdServer Server(CDB, FS, Opts);
1053
1054 FS.Files[testPath(File: "foo.h")] = R"cpp(
1055 namespace ns { class XYZ {}; void foo(int x) {} }
1056 )cpp";
1057 runAddDocument(Server, File: testPath(File: "foo.cpp"), Contents: R"cpp(
1058 #include "foo.h"
1059 )cpp");
1060
1061 auto File = testPath(File: "bar.cpp");
1062 Annotations Test(R"cpp(
1063 namespace ns {
1064 class XXX {};
1065 /// Doooc
1066 void fooooo() {}
1067 }
1068 void f() { ns::^ }
1069 )cpp");
1070 runAddDocument(Server, File, Contents: Test.code());
1071
1072 auto Results = cantFail(ValOrErr: runCodeComplete(Server, File, Pos: Test.point(), Opts: {}));
1073 // "XYZ" and "foo" are not included in the file being completed but are still
1074 // visible through the index.
1075 EXPECT_THAT(Results.Completions, has("XYZ", CompletionItemKind::Class));
1076 EXPECT_THAT(Results.Completions, has("foo", CompletionItemKind::Function));
1077 EXPECT_THAT(Results.Completions, has("XXX", CompletionItemKind::Class));
1078 EXPECT_THAT(Results.Completions,
1079 Contains((named("fooooo"), kind(CompletionItemKind::Function),
1080 doc("Doooc"), returnType("void"))));
1081}
1082
1083TEST(CompletionTest, Documentation) {
1084 auto Results = completions(
1085 Text: R"cpp(
1086 // Non-doxygen comment.
1087 __attribute__((annotate("custom_annotation"))) int foo();
1088 /// Doxygen comment.
1089 /// \param int a
1090 int bar(int a);
1091 /* Multi-line
1092 block comment
1093 */
1094 int baz();
1095
1096 int x = ^
1097 )cpp");
1098 EXPECT_THAT(Results.Completions,
1099 Contains(AllOf(
1100 named("foo"),
1101 doc("Annotation: custom_annotation\nNon-doxygen comment."))));
1102 EXPECT_THAT(
1103 Results.Completions,
1104 Contains(AllOf(named("bar"), doc("Doxygen comment.\n\\param int a"))));
1105 EXPECT_THAT(Results.Completions,
1106 Contains(AllOf(named("baz"), doc("Multi-line block comment"))));
1107}
1108
1109TEST(CompletionTest, CommentsFromSystemHeaders) {
1110 MockFS FS;
1111 MockCompilationDatabase CDB;
1112
1113 auto Opts = ClangdServer::optsForTest();
1114 Opts.BuildDynamicSymbolIndex = true;
1115
1116 ClangdServer Server(CDB, FS, Opts);
1117
1118 FS.Files[testPath(File: "foo.h")] = R"cpp(
1119 #pragma GCC system_header
1120
1121 // This comment should be retained!
1122 int foo();
1123 )cpp";
1124
1125 auto File = testPath(File: "foo.cpp");
1126 Annotations Test(R"cpp(
1127#include "foo.h"
1128int x = foo^
1129 )cpp");
1130 runAddDocument(Server, File, Contents: Test.code());
1131 auto CompletionList =
1132 llvm::cantFail(ValOrErr: runCodeComplete(Server, File, Pos: Test.point(), Opts: {}));
1133
1134 EXPECT_THAT(
1135 CompletionList.Completions,
1136 Contains(AllOf(named("foo"), doc("This comment should be retained!"))));
1137}
1138
1139TEST(CompletionTest, CommentsOnMembersFromHeader) {
1140 MockFS FS;
1141 MockCompilationDatabase CDB;
1142
1143 auto Opts = ClangdServer::optsForTest();
1144 Opts.BuildDynamicSymbolIndex = true;
1145
1146 ClangdServer Server(CDB, FS, Opts);
1147
1148 FS.Files[testPath(File: "foo.h")] = R"cpp(
1149 struct alpha {
1150 /// This is a member field.
1151 int gamma;
1152
1153 /// This is a member function.
1154 int delta();
1155 };
1156 )cpp";
1157
1158 auto File = testPath(File: "foo.cpp");
1159 Annotations Test(R"cpp(
1160#include "foo.h"
1161alpha a;
1162int x = a.^
1163 )cpp");
1164 runAddDocument(Server, File, Contents: Test.code());
1165 auto CompletionList =
1166 llvm::cantFail(ValOrErr: runCodeComplete(Server, File, Pos: Test.point(), Opts: {}));
1167
1168 EXPECT_THAT(CompletionList.Completions,
1169 Contains(AllOf(named("gamma"), doc("This is a member field."))));
1170 EXPECT_THAT(
1171 CompletionList.Completions,
1172 Contains(AllOf(named("delta"), doc("This is a member function."))));
1173}
1174
1175TEST(CompletionTest, CommentsOnMembersFromHeaderOverloadBundling) {
1176 using testing::AnyOf;
1177 MockFS FS;
1178 MockCompilationDatabase CDB;
1179
1180 auto Opts = ClangdServer::optsForTest();
1181 Opts.BuildDynamicSymbolIndex = true;
1182
1183 ClangdServer Server(CDB, FS, Opts);
1184
1185 FS.Files[testPath(File: "foo.h")] = R"cpp(
1186 struct alpha {
1187 /// bool overload.
1188 int delta(bool b);
1189
1190 /// int overload.
1191 int delta(int i);
1192
1193 void epsilon(long l);
1194
1195 /// This one has a comment.
1196 void epsilon(int i);
1197 };
1198 )cpp";
1199
1200 auto File = testPath(File: "foo.cpp");
1201 Annotations Test(R"cpp(
1202#include "foo.h"
1203alpha a;
1204int x = a.^
1205 )cpp");
1206 runAddDocument(Server, File, Contents: Test.code());
1207 clangd::CodeCompleteOptions CCOpts;
1208 CCOpts.BundleOverloads = true;
1209 auto CompletionList =
1210 llvm::cantFail(ValOrErr: runCodeComplete(Server, File, Pos: Test.point(), Opts: CCOpts));
1211
1212 EXPECT_THAT(
1213 CompletionList.Completions,
1214 Contains(AllOf(named("epsilon"), doc("This one has a comment."))));
1215 EXPECT_THAT(CompletionList.Completions,
1216 Contains(AllOf(named("delta"), AnyOf(doc("bool overload."),
1217 doc("int overload.")))));
1218}
1219
1220TEST(CompletionTest, GlobalCompletionFiltering) {
1221
1222 Symbol Class = cls(Name: "XYZ");
1223 Class.Flags = static_cast<Symbol::SymbolFlag>(
1224 Class.Flags & ~(Symbol::IndexedForCodeCompletion));
1225 Symbol Func = func(Name: "XYZ::foooo");
1226 Func.Flags = static_cast<Symbol::SymbolFlag>(
1227 Func.Flags & ~(Symbol::IndexedForCodeCompletion));
1228
1229 auto Results = completions(Text: R"(// void f() {
1230 XYZ::foooo^
1231 })",
1232 IndexSymbols: {Class, Func});
1233 EXPECT_THAT(Results.Completions, IsEmpty());
1234}
1235
1236TEST(CodeCompleteTest, DisableTypoCorrection) {
1237 auto Results = completions(Text: R"cpp(
1238 namespace clang { int v; }
1239 void f() { clangd::^
1240 )cpp");
1241 EXPECT_TRUE(Results.Completions.empty());
1242}
1243
1244TEST(CodeCompleteTest, NoColonColonAtTheEnd) {
1245 auto Results = completions(Text: R"cpp(
1246 namespace clang { }
1247 void f() {
1248 clan^
1249 }
1250 )cpp");
1251
1252 EXPECT_THAT(Results.Completions, Contains(labeled("clang")));
1253 EXPECT_THAT(Results.Completions, Not(Contains(labeled("clang::"))));
1254}
1255
1256TEST(CompletionTests, EmptySnippetDoesNotCrash) {
1257 // See https://github.com/clangd/clangd/issues/1216
1258 auto Results = completions(Text: R"cpp(
1259 int main() {
1260 auto w = [&](auto &&f) { return f(f); };
1261 auto f = w([&](auto &&f) {
1262 return [&](auto &&n) {
1263 if (n == 0) {
1264 return 1;
1265 }
1266 return n * ^(f)(n - 1);
1267 };
1268 })(10);
1269 }
1270 )cpp");
1271}
1272
1273TEST(CompletionTest, Issue1427Crash) {
1274 // Need to provide main file signals to ensure that the branch in
1275 // SymbolRelevanceSignals::computeASTSignals() that tries to
1276 // compute a symbol ID is taken.
1277 ASTSignals MainFileSignals;
1278 CodeCompleteOptions Opts;
1279 Opts.MainFileSignals = &MainFileSignals;
1280 completions(Text: R"cpp(
1281 auto f = []() {
1282 1.0_^
1283 };
1284 )cpp",
1285 IndexSymbols: {}, Opts);
1286}
1287
1288TEST(CompletionTest, BacktrackCrashes) {
1289 // Sema calls code completion callbacks twice in these cases.
1290 auto Results = completions(Text: R"cpp(
1291 namespace ns {
1292 struct FooBarBaz {};
1293 } // namespace ns
1294
1295 int foo(ns::FooBar^
1296 )cpp");
1297
1298 EXPECT_THAT(Results.Completions, ElementsAre(labeled("FooBarBaz")));
1299
1300 // Check we don't crash in that case too.
1301 completions(Text: R"cpp(
1302 struct FooBarBaz {};
1303 void test() {
1304 if (FooBarBaz * x^) {}
1305 }
1306)cpp");
1307}
1308
1309TEST(CompletionTest, CompleteInMacroWithStringification) {
1310 auto Results = completions(Text: R"cpp(
1311void f(const char *, int x);
1312#define F(x) f(#x, x)
1313
1314namespace ns {
1315int X;
1316int Y;
1317} // namespace ns
1318
1319int f(int input_num) {
1320 F(ns::^)
1321}
1322)cpp");
1323
1324 EXPECT_THAT(Results.Completions,
1325 UnorderedElementsAre(named("X"), named("Y")));
1326}
1327
1328TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {
1329 auto Results = completions(Text: R"cpp(
1330void f(const char *, int x);
1331#define F(x) f(#x, x)
1332
1333namespace ns {
1334int X;
1335
1336int f(int input_num) {
1337 F(^)
1338}
1339} // namespace ns
1340)cpp");
1341
1342 EXPECT_THAT(Results.Completions, Contains(named("X")));
1343}
1344
1345TEST(CompletionTest, IgnoreCompleteInExcludedPPBranchWithRecoveryContext) {
1346 auto Results = completions(Text: R"cpp(
1347 int bar(int param_in_bar) {
1348 }
1349
1350 int foo(int param_in_foo) {
1351#if 0
1352 // In recovery mode, "param_in_foo" will also be suggested among many other
1353 // unrelated symbols; however, this is really a special case where this works.
1354 // If the #if block is outside of the function, "param_in_foo" is still
1355 // suggested, but "bar" and "foo" are missing. So the recovery mode doesn't
1356 // really provide useful results in excluded branches.
1357 par^
1358#endif
1359 }
1360)cpp");
1361
1362 EXPECT_TRUE(Results.Completions.empty());
1363}
1364
1365TEST(CompletionTest, DefaultArgs) {
1366 clangd::CodeCompleteOptions Opts;
1367 std::string Context = R"cpp(
1368 int X(int A = 0);
1369 int Y(int A, int B = 0);
1370 int Z(int A, int B = 0, int C = 0, int D = 0);
1371 )cpp";
1372 EXPECT_THAT(completions(Context + "int y = X^", {}, Opts).Completions,
1373 UnorderedElementsAre(labeled("X(int A = 0)")));
1374 EXPECT_THAT(completions(Context + "int y = Y^", {}, Opts).Completions,
1375 UnorderedElementsAre(AllOf(labeled("Y(int A, int B = 0)"),
1376 snippetSuffix("(${1:int A})"))));
1377 EXPECT_THAT(completions(Context + "int y = Z^", {}, Opts).Completions,
1378 UnorderedElementsAre(
1379 AllOf(labeled("Z(int A, int B = 0, int C = 0, int D = 0)"),
1380 snippetSuffix("(${1:int A})"))));
1381}
1382
1383TEST(CompletionTest, NoCrashWithTemplateParamsAndPreferredTypes) {
1384 auto Completions = completions(Text: R"cpp(
1385template <template <class> class TT> int foo() {
1386 int a = ^
1387}
1388)cpp")
1389 .Completions;
1390 EXPECT_THAT(Completions, Contains(named("TT")));
1391}
1392
1393TEST(CompletionTest, NestedTemplateHeuristics) {
1394 auto Completions = completions(Text: R"cpp(
1395struct Plain { int xxx; };
1396template <typename T> class Templ { Plain ppp; };
1397template <typename T> void foo(Templ<T> &t) {
1398 // Formally ppp has DependentTy, because Templ may be specialized.
1399 // However we sholud be able to see into it using the primary template.
1400 t.ppp.^
1401}
1402)cpp")
1403 .Completions;
1404 EXPECT_THAT(Completions, Contains(named("xxx")));
1405}
1406
1407TEST(CompletionTest, RecordCCResultCallback) {
1408 std::vector<CodeCompletion> RecordedCompletions;
1409 CodeCompleteOptions Opts;
1410 Opts.RecordCCResult = [&RecordedCompletions](const CodeCompletion &CC,
1411 const SymbolQualitySignals &,
1412 const SymbolRelevanceSignals &,
1413 float Score) {
1414 RecordedCompletions.push_back(x: CC);
1415 };
1416
1417 completions(Text: "int xy1, xy2; int a = xy^", /*IndexSymbols=*/{}, Opts);
1418 EXPECT_THAT(RecordedCompletions,
1419 UnorderedElementsAre(named("xy1"), named("xy2")));
1420}
1421
1422TEST(CompletionTest, ASTSignals) {
1423 struct Completion {
1424 std::string Name;
1425 unsigned MainFileRefs;
1426 unsigned ScopeRefsInFile;
1427 };
1428 CodeCompleteOptions Opts;
1429 std::vector<Completion> RecordedCompletions;
1430 Opts.RecordCCResult = [&RecordedCompletions](const CodeCompletion &CC,
1431 const SymbolQualitySignals &,
1432 const SymbolRelevanceSignals &R,
1433 float Score) {
1434 RecordedCompletions.push_back(x: {.Name: CC.Name, .MainFileRefs: R.MainFileRefs, .ScopeRefsInFile: R.ScopeRefsInFile});
1435 };
1436 ASTSignals MainFileSignals;
1437 MainFileSignals.ReferencedSymbols[var(Name: "xy1").ID] = 3;
1438 MainFileSignals.ReferencedSymbols[var(Name: "xy2").ID] = 1;
1439 MainFileSignals.ReferencedSymbols[var(Name: "xyindex").ID] = 10;
1440 MainFileSignals.RelatedNamespaces["tar::"] = 5;
1441 MainFileSignals.RelatedNamespaces["bar::"] = 3;
1442 Opts.MainFileSignals = &MainFileSignals;
1443 Opts.AllScopes = true;
1444 completions(
1445 Text: R"cpp(
1446 int xy1;
1447 int xy2;
1448 namespace bar {
1449 int xybar = 1;
1450 int a = xy^
1451 }
1452 )cpp",
1453 /*IndexSymbols=*/{var(Name: "xyindex"), var(Name: "tar::xytar"), var(Name: "bar::xybar")},
1454 Opts);
1455 EXPECT_THAT(RecordedCompletions,
1456 UnorderedElementsAre(
1457 AllOf(named("xy1"), mainFileRefs(3u), scopeRefs(0u)),
1458 AllOf(named("xy2"), mainFileRefs(1u), scopeRefs(0u)),
1459 AllOf(named("xyindex"), mainFileRefs(10u), scopeRefs(0u)),
1460 AllOf(named("xytar"), mainFileRefs(0u), scopeRefs(5u)),
1461 AllOf(/*both from sema and index*/ named("xybar"),
1462 mainFileRefs(0u), scopeRefs(3u))));
1463}
1464
1465SignatureHelp
1466signatures(llvm::StringRef Text, Position Point,
1467 std::vector<Symbol> IndexSymbols = {},
1468 MarkupKind DocumentationFormat = MarkupKind::PlainText) {
1469 std::unique_ptr<SymbolIndex> Index;
1470 if (!IndexSymbols.empty())
1471 Index = memIndex(Symbols: IndexSymbols);
1472
1473 auto TU = TestTU::withCode(Code: Text);
1474 MockFS FS;
1475 auto Inputs = TU.inputs(FS);
1476 Inputs.Index = Index.get();
1477 IgnoreDiagnostics Diags;
1478 auto CI = buildCompilerInvocation(Inputs, D&: Diags);
1479 if (!CI) {
1480 ADD_FAILURE() << "Couldn't build CompilerInvocation";
1481 return {};
1482 }
1483 auto Preamble = buildPreamble(FileName: testPath(File: TU.Filename), CI: *CI, Inputs,
1484 /*InMemory=*/StoreInMemory: true, /*Callback=*/PreambleCallback: nullptr);
1485 if (!Preamble) {
1486 ADD_FAILURE() << "Couldn't build Preamble";
1487 return {};
1488 }
1489 return signatureHelp(FileName: testPath(File: TU.Filename), Pos: Point, Preamble: *Preamble, ParseInput: Inputs,
1490 DocumentationFormat);
1491}
1492
1493SignatureHelp
1494signatures(llvm::StringRef Text, std::vector<Symbol> IndexSymbols = {},
1495 MarkupKind DocumentationFormat = MarkupKind::PlainText) {
1496 Annotations Test(Text);
1497 return signatures(Text: Test.code(), Point: Test.point(), IndexSymbols: std::move(IndexSymbols),
1498 DocumentationFormat);
1499}
1500
1501struct ExpectedParameter {
1502 std::string Text;
1503 std::pair<unsigned, unsigned> Offsets;
1504};
1505llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
1506 const ExpectedParameter &P) {
1507 return OS << P.Text;
1508}
1509MATCHER_P(paramsAre, P, "") {
1510 if (P.size() != arg.parameters.size())
1511 return false;
1512 for (unsigned I = 0; I < P.size(); ++I) {
1513 if (P[I].Text != arg.parameters[I].labelString ||
1514 P[I].Offsets != arg.parameters[I].labelOffsets)
1515 return false;
1516 }
1517 return true;
1518}
1519MATCHER_P(sigDoc, doc, "") { return arg.documentation.value == doc; }
1520
1521/// \p AnnotatedLabel is a signature label with ranges marking parameters, e.g.
1522/// foo([[int p1]], [[double p2]]) -> void
1523Matcher<SignatureInformation> sig(llvm::StringRef AnnotatedLabel) {
1524 llvm::Annotations A(AnnotatedLabel);
1525 std::string Label = std::string(A.code());
1526 std::vector<ExpectedParameter> Parameters;
1527 for (auto Range : A.ranges()) {
1528 Parameters.emplace_back();
1529
1530 ExpectedParameter &P = Parameters.back();
1531 P.Text = Label.substr(pos: Range.Begin, n: Range.End - Range.Begin);
1532 P.Offsets.first = lspLength(Code: llvm::StringRef(Label).substr(Start: 0, N: Range.Begin));
1533 P.Offsets.second = lspLength(Code: llvm::StringRef(Label).substr(Start: 1, N: Range.End));
1534 }
1535 return AllOf(matchers: sigHelpLabeled(gmock_p0: Label), matchers: paramsAre(gmock_p0: Parameters));
1536}
1537
1538TEST(SignatureHelpTest, Overloads) {
1539 auto Results = signatures(Text: R"cpp(
1540 void foo(int x, int y);
1541 void foo(int x, float y);
1542 void foo(float x, int y);
1543 void foo(float x, float y);
1544 void bar(int x, int y = 0);
1545 int main() { foo(^); }
1546 )cpp");
1547 EXPECT_THAT(Results.signatures,
1548 UnorderedElementsAre(sig("foo([[float x]], [[float y]]) -> void"),
1549 sig("foo([[float x]], [[int y]]) -> void"),
1550 sig("foo([[int x]], [[float y]]) -> void"),
1551 sig("foo([[int x]], [[int y]]) -> void")));
1552 // We always prefer the first signature.
1553 EXPECT_EQ(0, Results.activeSignature);
1554 EXPECT_EQ(0, Results.activeParameter);
1555}
1556
1557TEST(SignatureHelpTest, FunctionPointers) {
1558 llvm::StringLiteral Tests[] = {
1559 // Variable of function pointer type
1560 R"cpp(
1561 void (*foo)(int x, int y);
1562 int main() { foo(^); }
1563 )cpp",
1564 // Wrapped in an AttributedType
1565 R"cpp(
1566 void (__stdcall *foo)(int x, int y);
1567 int main() { foo(^); }
1568 )cpp",
1569 // Another syntax for an AttributedType
1570 R"cpp(
1571 void (__attribute__(stdcall) *foo)(int x, int y);
1572 int main() { foo(^); },
1573 )cpp",
1574 // Wrapped in a typedef
1575 R"cpp(
1576 typedef void (*fn)(int x, int y);
1577 fn foo;
1578 int main() { foo(^); }
1579 )cpp",
1580 // Wrapped in both a typedef and an AttributedTyped
1581 R"cpp(
1582 typedef void (__stdcall *fn)(int x, int y);
1583 fn foo;
1584 int main() { foo(^); }
1585 )cpp",
1586 // Field of function pointer type
1587 R"cpp(
1588 struct S {
1589 void (*foo)(int x, int y);
1590 };
1591 S s;
1592 int main() { s.foo(^); }
1593 )cpp",
1594 // Field of function pointer typedef type
1595 R"cpp(
1596 typedef void (*fn)(int x, int y);
1597 struct S {
1598 fn foo;
1599 };
1600 S s;
1601 int main() { s.foo(^); }
1602 )cpp"};
1603 for (auto Test : Tests)
1604 EXPECT_THAT(signatures(Test).signatures,
1605 UnorderedElementsAre(sig("([[int x]], [[int y]]) -> void")));
1606}
1607
1608TEST(SignatureHelpTest, Constructors) {
1609 std::string Top = R"cpp(
1610 struct S {
1611 S(int);
1612 S(const S &) = delete;
1613 };
1614 )cpp";
1615
1616 auto CheckParenInit = [&](std::string Init) {
1617 EXPECT_THAT(signatures(Top + Init).signatures,
1618 UnorderedElementsAre(sig("S([[int]])")))
1619 << Init;
1620 };
1621 CheckParenInit("S s(^);");
1622 CheckParenInit("auto s = S(^);");
1623 CheckParenInit("auto s = new S(^);");
1624
1625 auto CheckBracedInit = [&](std::string Init) {
1626 EXPECT_THAT(signatures(Top + Init).signatures,
1627 UnorderedElementsAre(sig("S{[[int]]}")))
1628 << Init;
1629 };
1630 CheckBracedInit("S s{^};");
1631 CheckBracedInit("S s = {^};");
1632 CheckBracedInit("auto s = S{^};");
1633 // FIXME: doesn't work: no ExpectedType set in ParseCXXNewExpression.
1634 // CheckBracedInit("auto s = new S{^};");
1635 CheckBracedInit("int x(S); int i = x({^});");
1636}
1637
1638TEST(SignatureHelpTest, Aggregates) {
1639 std::string Top = R"cpp(
1640 struct S {
1641 int a, b, c, d;
1642 };
1643 )cpp";
1644 auto AggregateSig = sig(AnnotatedLabel: "S{[[int a]], [[int b]], [[int c]], [[int d]]}");
1645 EXPECT_THAT(signatures(Top + "S s{^}").signatures,
1646 UnorderedElementsAre(AggregateSig, sig("S{}"),
1647 sig("S{[[const S &]]}"),
1648 sig("S{[[S &&]]}")));
1649 EXPECT_THAT(signatures(Top + "S s{1,^}").signatures,
1650 ElementsAre(AggregateSig));
1651 EXPECT_EQ(signatures(Top + "S s{1,^}").activeParameter, 1);
1652 EXPECT_THAT(signatures(Top + "S s{.c=3,^}").signatures,
1653 ElementsAre(AggregateSig));
1654 EXPECT_EQ(signatures(Top + "S s{.c=3,^}").activeParameter, 3);
1655}
1656
1657TEST(SignatureHelpTest, OverloadInitListRegression) {
1658 auto Results = signatures(Text: R"cpp(
1659 struct A {int x;};
1660 struct B {B(A);};
1661 void f();
1662 int main() {
1663 B b({1});
1664 f(^);
1665 }
1666 )cpp");
1667 EXPECT_THAT(Results.signatures, UnorderedElementsAre(sig("f() -> void")));
1668}
1669
1670TEST(SignatureHelpTest, DefaultArgs) {
1671 auto Results = signatures(Text: R"cpp(
1672 void bar(int x, int y = 0);
1673 void bar(float x = 0, int y = 42);
1674 int main() { bar(^
1675 )cpp");
1676 EXPECT_THAT(Results.signatures,
1677 UnorderedElementsAre(
1678 sig("bar([[int x]], [[int y = 0]]) -> void"),
1679 sig("bar([[float x = 0]], [[int y = 42]]) -> void")));
1680 EXPECT_EQ(0, Results.activeSignature);
1681 EXPECT_EQ(0, Results.activeParameter);
1682}
1683
1684TEST(SignatureHelpTest, ActiveArg) {
1685 auto Results = signatures(Text: R"cpp(
1686 int baz(int a, int b, int c);
1687 int main() { baz(baz(1,2,3), ^); }
1688 )cpp");
1689 EXPECT_THAT(Results.signatures,
1690 ElementsAre(sig("baz([[int a]], [[int b]], [[int c]]) -> int")));
1691 EXPECT_EQ(0, Results.activeSignature);
1692 EXPECT_EQ(1, Results.activeParameter);
1693}
1694
1695TEST(SignatureHelpTest, OpeningParen) {
1696 llvm::StringLiteral Tests[] = {
1697 // Recursive function call.
1698 R"cpp(
1699 int foo(int a, int b, int c);
1700 int main() {
1701 foo(foo $p^( foo(10, 10, 10), ^ )));
1702 })cpp",
1703 // Functional type cast.
1704 R"cpp(
1705 struct Foo {
1706 Foo(int a, int b, int c);
1707 };
1708 int main() {
1709 Foo $p^( 10, ^ );
1710 })cpp",
1711 // New expression.
1712 R"cpp(
1713 struct Foo {
1714 Foo(int a, int b, int c);
1715 };
1716 int main() {
1717 new Foo $p^( 10, ^ );
1718 })cpp",
1719 // Macro expansion.
1720 R"cpp(
1721 int foo(int a, int b, int c);
1722 #define FOO foo(
1723
1724 int main() {
1725 // Macro expansions.
1726 $p^FOO 10, ^ );
1727 })cpp",
1728 // Macro arguments.
1729 R"cpp(
1730 int foo(int a, int b, int c);
1731 int main() {
1732 #define ID(X) X
1733 // FIXME: figure out why ID(foo (foo(10), )) doesn't work when preserving
1734 // the recovery expression.
1735 ID(foo $p^( 10, ^ ))
1736 })cpp",
1737 // Dependent args.
1738 R"cpp(
1739 int foo(int a, int b);
1740 template <typename T> void bar(T t) {
1741 foo$p^(t, ^t);
1742 })cpp",
1743 // Dependent args on templated func.
1744 R"cpp(
1745 template <typename T>
1746 int foo(T, T);
1747 template <typename T> void bar(T t) {
1748 foo$p^(t, ^t);
1749 })cpp",
1750 // Dependent args on member.
1751 R"cpp(
1752 struct Foo { int foo(int, int); };
1753 template <typename T> void bar(T t) {
1754 Foo f;
1755 f.foo$p^(t, ^t);
1756 })cpp",
1757 // Dependent args on templated member.
1758 R"cpp(
1759 struct Foo { template <typename T> int foo(T, T); };
1760 template <typename T> void bar(T t) {
1761 Foo f;
1762 f.foo$p^(t, ^t);
1763 })cpp",
1764 };
1765
1766 for (auto Test : Tests) {
1767 Annotations Code(Test);
1768 EXPECT_EQ(signatures(Code.code(), Code.point()).argListStart,
1769 Code.point("p"))
1770 << "Test source:" << Test;
1771 }
1772}
1773
1774TEST(SignatureHelpTest, StalePreamble) {
1775 TestTU TU;
1776 TU.Code = "";
1777 IgnoreDiagnostics Diags;
1778 MockFS FS;
1779 auto Inputs = TU.inputs(FS);
1780 auto CI = buildCompilerInvocation(Inputs, D&: Diags);
1781 ASSERT_TRUE(CI);
1782 auto EmptyPreamble = buildPreamble(FileName: testPath(File: TU.Filename), CI: *CI, Inputs,
1783 /*InMemory=*/StoreInMemory: true, /*Callback=*/PreambleCallback: nullptr);
1784 ASSERT_TRUE(EmptyPreamble);
1785
1786 TU.AdditionalFiles["a.h"] = "int foo(int x);";
1787 const Annotations Test(R"cpp(
1788 #include "a.h"
1789 void bar() { foo(^2); })cpp");
1790 TU.Code = Test.code().str();
1791 auto Results =
1792 signatureHelp(FileName: testPath(File: TU.Filename), Pos: Test.point(), Preamble: *EmptyPreamble,
1793 ParseInput: TU.inputs(FS), DocumentationFormat: MarkupKind::PlainText);
1794 EXPECT_THAT(Results.signatures, ElementsAre(sig("foo([[int x]]) -> int")));
1795 EXPECT_EQ(0, Results.activeSignature);
1796 EXPECT_EQ(0, Results.activeParameter);
1797}
1798
1799class IndexRequestCollector : public SymbolIndex {
1800public:
1801 IndexRequestCollector(std::vector<Symbol> Syms = {}) : Symbols(Syms) {}
1802
1803 bool
1804 fuzzyFind(const FuzzyFindRequest &Req,
1805 llvm::function_ref<void(const Symbol &)> Callback) const override {
1806 std::unique_lock<std::mutex> Lock(Mut);
1807 Requests.push_back(x: Req);
1808 ReceivedRequestCV.notify_one();
1809 for (const auto &Sym : Symbols)
1810 Callback(Sym);
1811 return true;
1812 }
1813
1814 void lookup(const LookupRequest &,
1815 llvm::function_ref<void(const Symbol &)>) const override {}
1816
1817 bool refs(const RefsRequest &,
1818 llvm::function_ref<void(const Ref &)>) const override {
1819 return false;
1820 }
1821
1822 bool containedRefs(
1823 const ContainedRefsRequest &,
1824 llvm::function_ref<void(const ContainedRefsResult &)>) const override {
1825 return false;
1826 }
1827
1828 void relations(const RelationsRequest &,
1829 llvm::function_ref<void(const SymbolID &, const Symbol &)>)
1830 const override {}
1831
1832 llvm::unique_function<IndexContents(llvm::StringRef) const>
1833 indexedFiles() const override {
1834 return [](llvm::StringRef) { return IndexContents::None; };
1835 }
1836
1837 // This is incorrect, but IndexRequestCollector is not an actual index and it
1838 // isn't used in production code.
1839 size_t estimateMemoryUsage() const override { return 0; }
1840
1841 const std::vector<FuzzyFindRequest> consumeRequests(size_t Num) const {
1842 std::unique_lock<std::mutex> Lock(Mut);
1843 EXPECT_TRUE(wait(Lock, ReceivedRequestCV, timeoutSeconds(30),
1844 [this, Num] { return Requests.size() == Num; }));
1845 auto Reqs = std::move(Requests);
1846 Requests = {};
1847 return Reqs;
1848 }
1849
1850private:
1851 std::vector<Symbol> Symbols;
1852 // We need a mutex to handle async fuzzy find requests.
1853 mutable std::condition_variable ReceivedRequestCV;
1854 mutable std::mutex Mut;
1855 mutable std::vector<FuzzyFindRequest> Requests;
1856};
1857
1858// Clients have to consume exactly Num requests.
1859std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code,
1860 size_t Num = 1) {
1861 clangd::CodeCompleteOptions Opts;
1862 IndexRequestCollector Requests;
1863 Opts.Index = &Requests;
1864 completions(Text: Code, IndexSymbols: {}, Opts);
1865 const auto Reqs = Requests.consumeRequests(Num);
1866 EXPECT_EQ(Reqs.size(), Num);
1867 return Reqs;
1868}
1869
1870TEST(CompletionTest, UnqualifiedIdQuery) {
1871 auto Requests = captureIndexRequests(Code: R"cpp(
1872 namespace std {}
1873 using namespace std;
1874 namespace ns {
1875 void f() {
1876 vec^
1877 }
1878 }
1879 )cpp");
1880
1881 EXPECT_THAT(Requests,
1882 ElementsAre(Field(&FuzzyFindRequest::Scopes,
1883 UnorderedElementsAre("", "ns::", "std::"))));
1884}
1885
1886TEST(CompletionTest, EnclosingScopeComesFirst) {
1887 auto Requests = captureIndexRequests(Code: R"cpp(
1888 namespace std {}
1889 using namespace std;
1890 namespace nx {
1891 namespace ns {
1892 namespace {
1893 void f() {
1894 vec^
1895 }
1896 }
1897 }
1898 }
1899 )cpp");
1900
1901 EXPECT_THAT(Requests,
1902 ElementsAre(Field(
1903 &FuzzyFindRequest::Scopes,
1904 UnorderedElementsAre("", "std::", "nx::ns::", "nx::"))));
1905 EXPECT_EQ(Requests[0].Scopes[0], "nx::ns::");
1906}
1907
1908TEST(CompletionTest, ResolvedQualifiedIdQuery) {
1909 auto Requests = captureIndexRequests(Code: R"cpp(
1910 namespace ns1 {}
1911 namespace ns2 {} // ignore
1912 namespace ns3 { namespace nns3 {} }
1913 namespace foo {
1914 using namespace ns1;
1915 using namespace ns3::nns3;
1916 }
1917 namespace ns {
1918 void f() {
1919 foo::^
1920 }
1921 }
1922 )cpp");
1923
1924 EXPECT_THAT(Requests,
1925 ElementsAre(Field(
1926 &FuzzyFindRequest::Scopes,
1927 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));
1928}
1929
1930TEST(CompletionTest, UnresolvedQualifierIdQuery) {
1931 auto Requests = captureIndexRequests(Code: R"cpp(
1932 namespace a {}
1933 using namespace a;
1934 namespace ns {
1935 void f() {
1936 bar::^
1937 }
1938 } // namespace ns
1939 )cpp");
1940
1941 EXPECT_THAT(Requests,
1942 ElementsAre(Field(
1943 &FuzzyFindRequest::Scopes,
1944 UnorderedElementsAre("a::bar::", "ns::bar::", "bar::"))));
1945}
1946
1947TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {
1948 auto Requests = captureIndexRequests(Code: R"cpp(
1949 namespace a {}
1950 using namespace a;
1951 namespace ns {
1952 void f() {
1953 ::a::bar::^
1954 }
1955 } // namespace ns
1956 )cpp");
1957
1958 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1959 UnorderedElementsAre("a::bar::"))));
1960}
1961
1962TEST(CompletionTest, EmptyQualifiedQuery) {
1963 auto Requests = captureIndexRequests(Code: R"cpp(
1964 namespace ns {
1965 void f() {
1966 ^
1967 }
1968 } // namespace ns
1969 )cpp");
1970
1971 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1972 UnorderedElementsAre("", "ns::"))));
1973}
1974
1975TEST(CompletionTest, GlobalQualifiedQuery) {
1976 auto Requests = captureIndexRequests(Code: R"cpp(
1977 namespace ns {
1978 void f() {
1979 ::^
1980 }
1981 } // namespace ns
1982 )cpp");
1983
1984 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,
1985 UnorderedElementsAre(""))));
1986}
1987
1988TEST(CompletionTest, NoDuplicatedQueryScopes) {
1989 auto Requests = captureIndexRequests(Code: R"cpp(
1990 namespace {}
1991
1992 namespace na {
1993 namespace {}
1994 namespace nb {
1995 ^
1996 } // namespace nb
1997 } // namespace na
1998 )cpp");
1999
2000 EXPECT_THAT(Requests,
2001 ElementsAre(Field(&FuzzyFindRequest::Scopes,
2002 UnorderedElementsAre("na::", "na::nb::", ""))));
2003}
2004
2005TEST(CompletionTest, NoIndexCompletionsInsideClasses) {
2006 auto Completions = completions(
2007 Text: R"cpp(
2008 struct Foo {
2009 int SomeNameOfField;
2010 typedef int SomeNameOfTypedefField;
2011 };
2012
2013 Foo::^)cpp",
2014 IndexSymbols: {func(Name: "::SomeNameInTheIndex"), func(Name: "::Foo::SomeNameInTheIndex")});
2015
2016 EXPECT_THAT(Completions.Completions,
2017 AllOf(Contains(labeled("SomeNameOfField")),
2018 Contains(labeled("SomeNameOfTypedefField")),
2019 Not(Contains(labeled("SomeNameInTheIndex")))));
2020}
2021
2022TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {
2023 {
2024 auto Completions = completions(
2025 Text: R"cpp(
2026 template <class T>
2027 void foo() {
2028 T::^
2029 }
2030 )cpp",
2031 IndexSymbols: {func(Name: "::SomeNameInTheIndex")});
2032
2033 EXPECT_THAT(Completions.Completions,
2034 Not(Contains(labeled("SomeNameInTheIndex"))));
2035 }
2036
2037 {
2038 auto Completions = completions(
2039 Text: R"cpp(
2040 template <class T>
2041 void foo() {
2042 T::template Y<int>::^
2043 }
2044 )cpp",
2045 IndexSymbols: {func(Name: "::SomeNameInTheIndex")});
2046
2047 EXPECT_THAT(Completions.Completions,
2048 Not(Contains(labeled("SomeNameInTheIndex"))));
2049 }
2050
2051 {
2052 auto Completions = completions(
2053 Text: R"cpp(
2054 template <class T>
2055 void foo() {
2056 T::foo::^
2057 }
2058 )cpp",
2059 IndexSymbols: {func(Name: "::SomeNameInTheIndex")});
2060
2061 EXPECT_THAT(Completions.Completions,
2062 Not(Contains(labeled("SomeNameInTheIndex"))));
2063 }
2064}
2065
2066TEST(CompletionTest, OverloadBundling) {
2067 clangd::CodeCompleteOptions Opts;
2068 Opts.BundleOverloads = true;
2069
2070 std::string Context = R"cpp(
2071 struct X {
2072 // Overload with int
2073 int a(int) __attribute__((deprecated("", "")));
2074 // Overload with bool
2075 int a(bool);
2076 int b(float);
2077
2078 X(int);
2079 X(float);
2080 };
2081 int GFuncC(int);
2082 int GFuncD(int);
2083 )cpp";
2084
2085 // Member completions are bundled.
2086 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).Completions,
2087 UnorderedElementsAre(labeled("a(…)"), labeled("b(float)")));
2088
2089 // Constructor completions are bundled.
2090 EXPECT_THAT(completions(Context + "X z = X^", {}, Opts).Completions,
2091 UnorderedElementsAre(labeled("X"), labeled("X(…)")));
2092
2093 // Non-member completions are bundled, including index+sema.
2094 Symbol NoArgsGFunc = func(Name: "GFuncC");
2095 EXPECT_THAT(
2096 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
2097 UnorderedElementsAre(labeled("GFuncC(…)"), labeled("GFuncD(int)")));
2098
2099 // Differences in header-to-insert suppress bundling.
2100 std::string DeclFile = URI::create(AbsolutePath: testPath(File: "foo")).toString();
2101 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile.c_str();
2102 NoArgsGFunc.IncludeHeaders.emplace_back(Args: "<foo>", Args: 1, Args: Symbol::Include);
2103 EXPECT_THAT(
2104 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,
2105 UnorderedElementsAre(AllOf(named("GFuncC"), insertInclude("<foo>")),
2106 labeled("GFuncC(int)"), labeled("GFuncD(int)")));
2107
2108 // Examine a bundled completion in detail.
2109 auto A =
2110 completions(Text: Context + "int y = X().a^", IndexSymbols: {}, Opts).Completions.front();
2111 EXPECT_EQ(A.Name, "a");
2112 EXPECT_EQ(A.Signature, "(…)");
2113 EXPECT_EQ(A.BundleSize, 2u);
2114 EXPECT_EQ(A.Kind, CompletionItemKind::Method);
2115 EXPECT_EQ(A.ReturnType, "int"); // All overloads return int.
2116 // For now we just return one of the doc strings arbitrarily.
2117 ASSERT_TRUE(A.Documentation);
2118 ASSERT_FALSE(A.Deprecated); // Not all overloads deprecated.
2119 EXPECT_THAT(
2120 A.Documentation->asPlainText(),
2121 AnyOf(HasSubstr("Overload with int"), HasSubstr("Overload with bool")));
2122 EXPECT_EQ(A.SnippetSuffix, "($0)");
2123}
2124
2125TEST(CompletionTest, OverloadBundlingSameFileDifferentURI) {
2126 clangd::CodeCompleteOptions Opts;
2127 Opts.BundleOverloads = true;
2128
2129 Symbol SymX = sym(QName: "ns::X", Kind: index::SymbolKind::Function, USRFormat: "@F@\\0#");
2130 Symbol SymY = sym(QName: "ns::X", Kind: index::SymbolKind::Function, USRFormat: "@F@\\0#I#");
2131 std::string BarHeader = testPath(File: "bar.h");
2132 auto BarURI = URI::create(AbsolutePath: BarHeader).toString();
2133 SymX.CanonicalDeclaration.FileURI = BarURI.c_str();
2134 SymY.CanonicalDeclaration.FileURI = BarURI.c_str();
2135 // The include header is different, but really it's the same file.
2136 SymX.IncludeHeaders.emplace_back(Args: "\"bar.h\"", Args: 1, Args: Symbol::Include);
2137 SymY.IncludeHeaders.emplace_back(Args: BarURI.c_str(), Args: 1, Args: Symbol::Include);
2138
2139 auto Results = completions(Text: "void f() { ::ns::^ }", IndexSymbols: {SymX, SymY}, Opts);
2140 // Expect both results are bundled, despite the different-but-same
2141 // IncludeHeader.
2142 ASSERT_EQ(1u, Results.Completions.size());
2143 const auto &R = Results.Completions.front();
2144 EXPECT_EQ("X", R.Name);
2145 EXPECT_EQ(2u, R.BundleSize);
2146}
2147
2148TEST(CompletionTest, DocumentationFromChangedFileCrash) {
2149 MockFS FS;
2150 auto FooH = testPath(File: "foo.h");
2151 auto FooCpp = testPath(File: "foo.cpp");
2152 FS.Files[FooH] = R"cpp(
2153 // this is my documentation comment.
2154 int func();
2155 )cpp";
2156 FS.Files[FooCpp] = "";
2157
2158 MockCompilationDatabase CDB;
2159 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
2160
2161 Annotations Source(R"cpp(
2162 #include "foo.h"
2163 int func() {
2164 // This makes sure we have func from header in the AST.
2165 }
2166 int a = fun^
2167 )cpp");
2168 Server.addDocument(File: FooCpp, Contents: Source.code(), Version: "null", WD: WantDiagnostics::Yes);
2169 // We need to wait for preamble to build.
2170 ASSERT_TRUE(Server.blockUntilIdleForTest());
2171
2172 // Change the header file. Completion will reuse the old preamble!
2173 FS.Files[FooH] = R"cpp(
2174 int func();
2175 )cpp";
2176
2177 clangd::CodeCompleteOptions Opts;
2178 CodeCompleteResult Completions =
2179 cantFail(ValOrErr: runCodeComplete(Server, File: FooCpp, Pos: Source.point(), Opts));
2180 // We shouldn't crash. Unfortunately, current workaround is to not produce
2181 // comments for symbols from headers.
2182 EXPECT_THAT(Completions.Completions,
2183 Contains(AllOf(Not(isDocumented()), named("func"))));
2184}
2185
2186TEST(CompletionTest, NonDocComments) {
2187 const char *Text = R"cpp(
2188 // We ignore namespace comments, for rationale see CodeCompletionStrings.h.
2189 namespace comments_ns {
2190 }
2191
2192 // ------------------
2193 int comments_foo();
2194
2195 // A comment and a decl are separated by newlines.
2196 // Therefore, the comment shouldn't show up as doc comment.
2197
2198 int comments_bar();
2199
2200 // this comment should be in the results.
2201 int comments_baz();
2202
2203
2204 template <class T>
2205 struct Struct {
2206 int comments_qux();
2207 int comments_quux();
2208 };
2209
2210
2211 // This comment should not be there.
2212
2213 template <class T>
2214 int Struct<T>::comments_qux() {
2215 }
2216
2217 // This comment **should** be in results.
2218 template <class T>
2219 int Struct<T>::comments_quux() {
2220 int a = comments^;
2221 }
2222 )cpp";
2223
2224 // We should not get any of those comments in completion.
2225 EXPECT_THAT(
2226 completions(Text).Completions,
2227 UnorderedElementsAre(AllOf(Not(isDocumented()), named("comments_foo")),
2228 AllOf(isDocumented(), named("comments_baz")),
2229 AllOf(isDocumented(), named("comments_quux")),
2230 AllOf(Not(isDocumented()), named("comments_ns")),
2231 // FIXME(ibiryukov): the following items should have
2232 // empty documentation, since they are separated from
2233 // a comment with an empty line. Unfortunately, I
2234 // couldn't make Sema tests pass if we ignore those.
2235 AllOf(isDocumented(), named("comments_bar")),
2236 AllOf(isDocumented(), named("comments_qux"))));
2237}
2238
2239TEST(CompletionTest, CompleteOnInvalidLine) {
2240 auto FooCpp = testPath(File: "foo.cpp");
2241
2242 MockCompilationDatabase CDB;
2243 MockFS FS;
2244 FS.Files[FooCpp] = "// empty file";
2245
2246 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
2247 // Run completion outside the file range.
2248 Position Pos;
2249 Pos.line = 100;
2250 Pos.character = 0;
2251 EXPECT_THAT_EXPECTED(
2252 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),
2253 Failed());
2254}
2255
2256TEST(CompletionTest, QualifiedNames) {
2257 auto Results = completions(
2258 Text: R"cpp(
2259 namespace ns { int local; void both(); }
2260 void f() { ::ns::^ }
2261 )cpp",
2262 IndexSymbols: {func(Name: "ns::both"), cls(Name: "ns::Index")});
2263 // We get results from both index and sema, with no duplicates.
2264 EXPECT_THAT(
2265 Results.Completions,
2266 UnorderedElementsAre(scope("ns::"), scope("ns::"), scope("ns::")));
2267}
2268
2269TEST(CompletionTest, Render) {
2270 CodeCompletion C;
2271 C.Name = "x";
2272 C.FilterText = "x";
2273 C.Signature = "(bool) const";
2274 C.SnippetSuffix = "(${0:bool})";
2275 C.ReturnType = "int";
2276 C.RequiredQualifier = "Foo::";
2277 C.Scope = "ns::Foo::";
2278 C.Documentation.emplace();
2279 C.Documentation->addParagraph().appendText(Text: "This is ").appendCode(Code: "x()");
2280 C.Includes.emplace_back();
2281 auto &Include = C.Includes.back();
2282 Include.Header = "\"foo.h\"";
2283 C.Kind = CompletionItemKind::Method;
2284 C.Score.Total = 1.0;
2285 C.Score.ExcludingName = .5;
2286 C.Origin = SymbolOrigin::AST | SymbolOrigin::Static;
2287
2288 CodeCompleteOptions Opts;
2289 Opts.IncludeIndicator.Insert = "^";
2290 Opts.IncludeIndicator.NoInsert = "";
2291 Opts.EnableSnippets = false;
2292
2293 auto R = C.render(Opts);
2294 EXPECT_EQ(R.label, "Foo::x");
2295 EXPECT_EQ(R.labelDetails->detail, "(bool) const");
2296 EXPECT_EQ(R.insertText, "Foo::x");
2297 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
2298 EXPECT_EQ(R.filterText, "x");
2299 EXPECT_EQ(R.detail, "int");
2300 EXPECT_EQ(R.documentation->value, "From \"foo.h\"\nThis is x()");
2301 EXPECT_THAT(R.additionalTextEdits, IsEmpty());
2302 EXPECT_EQ(R.sortText, sortText(1.0, "x"));
2303 EXPECT_FALSE(R.deprecated);
2304 EXPECT_EQ(R.score, .5f);
2305
2306 C.FilterText = "xtra";
2307 R = C.render(Opts);
2308 EXPECT_EQ(R.filterText, "xtra");
2309 EXPECT_EQ(R.sortText, sortText(1.0, "xtra"));
2310
2311 Opts.EnableSnippets = true;
2312 R = C.render(Opts);
2313 EXPECT_EQ(R.insertText, "Foo::x(${0:bool})");
2314 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);
2315
2316 C.SnippetSuffix = "";
2317 R = C.render(Opts);
2318 EXPECT_EQ(R.insertText, "Foo::x");
2319 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);
2320
2321 Include.Insertion.emplace();
2322 R = C.render(Opts);
2323 EXPECT_EQ(R.label, "^Foo::x");
2324 EXPECT_EQ(R.labelDetails->detail, "(bool) const");
2325 EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));
2326
2327 Opts.ShowOrigins = true;
2328 R = C.render(Opts);
2329 EXPECT_EQ(R.label, "^[AS]Foo::x");
2330 EXPECT_EQ(R.labelDetails->detail, "(bool) const");
2331
2332 C.BundleSize = 2;
2333 R = C.render(Opts);
2334 EXPECT_EQ(R.detail, "[2 overloads]");
2335 EXPECT_EQ(R.documentation->value, "From \"foo.h\"\nThis is x()");
2336
2337 C.Deprecated = true;
2338 R = C.render(Opts);
2339 EXPECT_TRUE(R.deprecated);
2340
2341 Opts.DocumentationFormat = MarkupKind::Markdown;
2342 R = C.render(Opts);
2343 EXPECT_EQ(R.documentation->value, "From `\"foo.h\"` \nThis is `x()`");
2344}
2345
2346TEST(CompletionTest, IgnoreRecoveryResults) {
2347 auto Results = completions(
2348 Text: R"cpp(
2349 namespace ns { int NotRecovered() { return 0; } }
2350 void f() {
2351 // Sema enters recovery mode first and then normal mode.
2352 if (auto x = ns::NotRecover^)
2353 }
2354 )cpp");
2355 EXPECT_THAT(Results.Completions, UnorderedElementsAre(named("NotRecovered")));
2356}
2357
2358TEST(CompletionTest, ScopeOfClassFieldInConstructorInitializer) {
2359 auto Results = completions(
2360 Text: R"cpp(
2361 namespace ns {
2362 class X { public: X(); int x_; };
2363 X::X() : x_^(0) {}
2364 }
2365 )cpp");
2366 EXPECT_THAT(Results.Completions,
2367 UnorderedElementsAre(AllOf(scope("ns::X::"), named("x_"))));
2368}
2369
2370// Like other class members, constructor init lists have to parse what's below,
2371// after the completion point.
2372// But recovering from an incomplete constructor init list is particularly
2373// tricky because the bulk of the list is not surrounded by brackets.
2374TEST(CompletionTest, ConstructorInitListIncomplete) {
2375 auto Results = completions(
2376 Text: R"cpp(
2377 namespace ns {
2378 struct X {
2379 X() : x^
2380 int xyz_;
2381 };
2382 }
2383 )cpp");
2384 EXPECT_THAT(Results.Completions, ElementsAre(named("xyz_")));
2385
2386 Results = completions(
2387 Text: R"cpp(
2388 int foo();
2389
2390 namespace ns {
2391 struct X {
2392 X() : xyz_(fo^
2393 int xyz_;
2394 };
2395 }
2396 )cpp");
2397 EXPECT_THAT(Results.Completions, ElementsAre(named("foo")));
2398}
2399
2400TEST(CompletionTest, CodeCompletionContext) {
2401 auto Results = completions(
2402 Text: R"cpp(
2403 namespace ns {
2404 class X { public: X(); int x_; };
2405 void f() {
2406 X x;
2407 x.^;
2408 }
2409 }
2410 )cpp");
2411
2412 EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);
2413}
2414
2415TEST(CompletionTest, FixItForArrowToDot) {
2416 MockFS FS;
2417 MockCompilationDatabase CDB;
2418
2419 CodeCompleteOptions Opts;
2420 Opts.IncludeFixIts = true;
2421 const char *Code =
2422 R"cpp(
2423 class Auxilary {
2424 public:
2425 void AuxFunction();
2426 };
2427 class ClassWithPtr {
2428 public:
2429 void MemberFunction();
2430 Auxilary* operator->() const;
2431 Auxilary* Aux;
2432 };
2433 void f() {
2434 ClassWithPtr x;
2435 x[[->]]^;
2436 }
2437 )cpp";
2438 auto Results = completions(Text: Code, IndexSymbols: {}, Opts);
2439 EXPECT_EQ(Results.Completions.size(), 3u);
2440
2441 TextEdit ReplacementEdit;
2442 ReplacementEdit.range = Annotations(Code).range();
2443 ReplacementEdit.newText = ".";
2444 for (const auto &C : Results.Completions) {
2445 EXPECT_TRUE(C.FixIts.size() == 1u || C.Name == "AuxFunction");
2446 if (!C.FixIts.empty()) {
2447 EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit));
2448 }
2449 }
2450}
2451
2452TEST(CompletionTest, FixItForDotToArrow) {
2453 CodeCompleteOptions Opts;
2454 Opts.IncludeFixIts = true;
2455 const char *Code =
2456 R"cpp(
2457 class Auxilary {
2458 public:
2459 void AuxFunction();
2460 };
2461 class ClassWithPtr {
2462 public:
2463 void MemberFunction();
2464 Auxilary* operator->() const;
2465 Auxilary* Aux;
2466 };
2467 void f() {
2468 ClassWithPtr x;
2469 x[[.]]^;
2470 }
2471 )cpp";
2472 auto Results = completions(Text: Code, IndexSymbols: {}, Opts);
2473 EXPECT_EQ(Results.Completions.size(), 3u);
2474
2475 TextEdit ReplacementEdit;
2476 ReplacementEdit.range = Annotations(Code).range();
2477 ReplacementEdit.newText = "->";
2478 for (const auto &C : Results.Completions) {
2479 EXPECT_TRUE(C.FixIts.empty() || C.Name == "AuxFunction");
2480 if (!C.FixIts.empty()) {
2481 EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit));
2482 }
2483 }
2484}
2485
2486TEST(CompletionTest, RenderWithFixItMerged) {
2487 TextEdit FixIt;
2488 FixIt.range.end.character = 5;
2489 FixIt.newText = "->";
2490
2491 CodeCompletion C;
2492 C.Name = "x";
2493 C.RequiredQualifier = "Foo::";
2494 C.FixIts = {FixIt};
2495 C.CompletionTokenRange.start.character = 5;
2496
2497 CodeCompleteOptions Opts;
2498 Opts.IncludeFixIts = true;
2499
2500 auto R = C.render(Opts);
2501 EXPECT_TRUE(R.textEdit);
2502 EXPECT_EQ(R.textEdit->newText, "->Foo::x");
2503 EXPECT_TRUE(R.additionalTextEdits.empty());
2504}
2505
2506TEST(CompletionTest, RenderWithFixItNonMerged) {
2507 TextEdit FixIt;
2508 FixIt.range.end.character = 4;
2509 FixIt.newText = "->";
2510
2511 CodeCompletion C;
2512 C.Name = "x";
2513 C.RequiredQualifier = "Foo::";
2514 C.FixIts = {FixIt};
2515 C.CompletionTokenRange.start.character = 5;
2516
2517 CodeCompleteOptions Opts;
2518 Opts.IncludeFixIts = true;
2519
2520 auto R = C.render(Opts);
2521 EXPECT_TRUE(R.textEdit);
2522 EXPECT_EQ(R.textEdit->newText, "Foo::x");
2523 EXPECT_THAT(R.additionalTextEdits, UnorderedElementsAre(FixIt));
2524}
2525
2526TEST(CompletionTest, CompletionTokenRange) {
2527 MockFS FS;
2528 MockCompilationDatabase CDB;
2529 TestTU TU;
2530 TU.AdditionalFiles["foo/abc/foo.h"] = "";
2531
2532 constexpr const char *TestCodes[] = {
2533 R"cpp(
2534 class Auxilary {
2535 public:
2536 void AuxFunction();
2537 };
2538 void f() {
2539 Auxilary x;
2540 x.[[Aux]]^;
2541 }
2542 )cpp",
2543 R"cpp(
2544 class Auxilary {
2545 public:
2546 void AuxFunction();
2547 };
2548 void f() {
2549 Auxilary x;
2550 x.[[]]^;
2551 }
2552 )cpp",
2553 R"cpp(
2554 #include "foo/[[a^/]]foo.h"
2555 )cpp",
2556 R"cpp(
2557 #include "foo/abc/[[fo^o.h"]]
2558 )cpp",
2559 };
2560 for (const auto &Text : TestCodes) {
2561 Annotations TestCode(Text);
2562 TU.Code = TestCode.code().str();
2563 auto Results = completions(TU, Point: TestCode.point());
2564 if (Results.Completions.size() != 1) {
2565 ADD_FAILURE() << "Results.Completions.size() != 1" << Text;
2566 continue;
2567 }
2568 EXPECT_THAT(Results.Completions.front().CompletionTokenRange,
2569 TestCode.range());
2570 }
2571}
2572
2573TEST(SignatureHelpTest, OverloadsOrdering) {
2574 const auto Results = signatures(Text: R"cpp(
2575 void foo(int x);
2576 void foo(int x, float y);
2577 void foo(float x, int y);
2578 void foo(float x, float y);
2579 void foo(int x, int y = 0);
2580 int main() { foo(^); }
2581 )cpp");
2582 EXPECT_THAT(Results.signatures,
2583 ElementsAre(sig("foo([[int x]]) -> void"),
2584 sig("foo([[int x]], [[int y = 0]]) -> void"),
2585 sig("foo([[float x]], [[int y]]) -> void"),
2586 sig("foo([[int x]], [[float y]]) -> void"),
2587 sig("foo([[float x]], [[float y]]) -> void")));
2588 // We always prefer the first signature.
2589 EXPECT_EQ(0, Results.activeSignature);
2590 EXPECT_EQ(0, Results.activeParameter);
2591}
2592
2593TEST(SignatureHelpTest, InstantiatedSignatures) {
2594 StringRef Sig0 = R"cpp(
2595 template <class T>
2596 void foo(T, T, T);
2597
2598 int main() {
2599 foo<int>(^);
2600 }
2601 )cpp";
2602
2603 EXPECT_THAT(signatures(Sig0).signatures,
2604 ElementsAre(sig("foo([[T]], [[T]], [[T]]) -> void")));
2605
2606 StringRef Sig1 = R"cpp(
2607 template <class T>
2608 void foo(T, T, T);
2609
2610 int main() {
2611 foo(10, ^);
2612 })cpp";
2613
2614 EXPECT_THAT(signatures(Sig1).signatures,
2615 ElementsAre(sig("foo([[T]], [[T]], [[T]]) -> void")));
2616
2617 StringRef Sig2 = R"cpp(
2618 template <class ...T>
2619 void foo(T...);
2620
2621 int main() {
2622 foo<int>(^);
2623 }
2624 )cpp";
2625
2626 EXPECT_THAT(signatures(Sig2).signatures,
2627 ElementsAre(sig("foo([[T...]]) -> void")));
2628
2629 // It is debatable whether we should substitute the outer template parameter
2630 // ('T') in that case. Currently we don't substitute it in signature help, but
2631 // do substitute in code complete.
2632 // FIXME: make code complete and signature help consistent, figure out which
2633 // way is better.
2634 StringRef Sig3 = R"cpp(
2635 template <class T>
2636 struct X {
2637 template <class U>
2638 void foo(T, U);
2639 };
2640
2641 int main() {
2642 X<int>().foo<double>(^)
2643 }
2644 )cpp";
2645
2646 EXPECT_THAT(signatures(Sig3).signatures,
2647 ElementsAre(sig("foo([[T]], [[U]]) -> void")));
2648}
2649
2650TEST(SignatureHelpTest, IndexDocumentation) {
2651 Symbol Foo0 = sym(QName: "foo", Kind: index::SymbolKind::Function, USRFormat: "@F@\\0#");
2652 Foo0.Documentation = "doc from the index";
2653 Symbol Foo1 = sym(QName: "foo", Kind: index::SymbolKind::Function, USRFormat: "@F@\\0#I#");
2654 Foo1.Documentation = "doc from the index";
2655 Symbol Foo2 = sym(QName: "foo", Kind: index::SymbolKind::Function, USRFormat: "@F@\\0#I#I#");
2656
2657 StringRef Sig0 = R"cpp(
2658 int foo();
2659 int foo(double);
2660
2661 void test() {
2662 foo(^);
2663 }
2664 )cpp";
2665
2666 EXPECT_THAT(
2667 signatures(Sig0, {Foo0}).signatures,
2668 ElementsAre(AllOf(sig("foo() -> int"), sigDoc("doc from the index")),
2669 AllOf(sig("foo([[double]]) -> int"), sigDoc(""))));
2670
2671 StringRef Sig1 = R"cpp(
2672 int foo();
2673 // Overriden doc from sema
2674 int foo(int);
2675 // doc from sema
2676 int foo(int, int);
2677
2678 void test() {
2679 foo(^);
2680 }
2681 )cpp";
2682
2683 EXPECT_THAT(
2684 signatures(Sig1, {Foo0, Foo1, Foo2}).signatures,
2685 ElementsAre(
2686 AllOf(sig("foo() -> int"), sigDoc("doc from the index")),
2687 AllOf(sig("foo([[int]]) -> int"), sigDoc("Overriden doc from sema")),
2688 AllOf(sig("foo([[int]], [[int]]) -> int"), sigDoc("doc from sema"))));
2689}
2690
2691TEST(SignatureHelpTest, DynamicIndexDocumentation) {
2692 MockFS FS;
2693 MockCompilationDatabase CDB;
2694 ClangdServer::Options Opts = ClangdServer::optsForTest();
2695 Opts.BuildDynamicSymbolIndex = true;
2696 ClangdServer Server(CDB, FS, Opts);
2697
2698 FS.Files[testPath(File: "foo.h")] = R"cpp(
2699 struct Foo {
2700 // Member doc
2701 int foo();
2702 };
2703 )cpp";
2704 Annotations FileContent(R"cpp(
2705 #include "foo.h"
2706 void test() {
2707 Foo f;
2708 f.foo(^);
2709 }
2710 )cpp");
2711 auto File = testPath(File: "test.cpp");
2712 Server.addDocument(File, Contents: FileContent.code());
2713 // Wait for the dynamic index being built.
2714 ASSERT_TRUE(Server.blockUntilIdleForTest());
2715 EXPECT_THAT(llvm::cantFail(runSignatureHelp(Server, File, FileContent.point(),
2716 MarkupKind::PlainText))
2717 .signatures,
2718 ElementsAre(AllOf(sig("foo() -> int"), sigDoc("Member doc"))));
2719}
2720
2721TEST(CompletionTest, ArgumentListsPolicy) {
2722 CodeCompleteOptions Opts;
2723 Opts.EnableSnippets = true;
2724 Opts.ArgumentLists = Config::ArgumentListsPolicy::Delimiters;
2725
2726 {
2727 auto Results = completions(
2728 Text: R"cpp(
2729 void xfoo();
2730 void xfoo(int x, int y);
2731 void f() { xfo^ })cpp",
2732 IndexSymbols: {}, Opts);
2733 EXPECT_THAT(
2734 Results.Completions,
2735 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix("()")),
2736 AllOf(named("xfoo"), snippetSuffix("($0)"))));
2737 }
2738 {
2739 auto Results = completions(
2740 Text: R"cpp(
2741 void xbar();
2742 void f() { xba^ })cpp",
2743 IndexSymbols: {}, Opts);
2744 EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf(
2745 named("xbar"), snippetSuffix("()"))));
2746 }
2747 {
2748 Opts.BundleOverloads = true;
2749 auto Results = completions(
2750 Text: R"cpp(
2751 void xfoo();
2752 void xfoo(int x, int y);
2753 void f() { xfo^ })cpp",
2754 IndexSymbols: {}, Opts);
2755 EXPECT_THAT(
2756 Results.Completions,
2757 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix("($0)"))));
2758 }
2759 {
2760 auto Results = completions(
2761 Text: R"cpp(
2762 template <class T, class U>
2763 void xfoo(int a, U b);
2764 void f() { xfo^ })cpp",
2765 IndexSymbols: {}, Opts);
2766 EXPECT_THAT(
2767 Results.Completions,
2768 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix("<$1>($0)"))));
2769 }
2770 {
2771 auto Results = completions(
2772 Text: R"cpp(
2773 template <class T>
2774 class foo_class{};
2775 template <class T>
2776 using foo_alias = T**;
2777 template <class T>
2778 T foo_var = T{};
2779 void f() { foo_^ })cpp",
2780 IndexSymbols: {}, Opts);
2781 EXPECT_THAT(
2782 Results.Completions,
2783 UnorderedElementsAre(AllOf(named("foo_class"), snippetSuffix("<$0>")),
2784 AllOf(named("foo_alias"), snippetSuffix("<$0>")),
2785 AllOf(named("foo_var"), snippetSuffix("<$0>"))));
2786 }
2787 {
2788 auto Results = completions(
2789 Text: R"cpp(
2790 #define FOO(x, y) x##f
2791 FO^ )cpp",
2792 IndexSymbols: {}, Opts);
2793 EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf(
2794 named("FOO"), snippetSuffix("($0)"))));
2795 }
2796 {
2797 Opts.ArgumentLists = Config::ArgumentListsPolicy::None;
2798 auto Results = completions(
2799 Text: R"cpp(
2800 void xfoo(int x, int y);
2801 void f() { xfo^ })cpp",
2802 IndexSymbols: {}, Opts);
2803 EXPECT_THAT(Results.Completions,
2804 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix(""))));
2805 }
2806 {
2807 Opts.ArgumentLists = Config::ArgumentListsPolicy::OpenDelimiter;
2808 auto Results = completions(
2809 Text: R"cpp(
2810 void xfoo(int x, int y);
2811 void f() { xfo^ })cpp",
2812 IndexSymbols: {}, Opts);
2813 EXPECT_THAT(Results.Completions,
2814 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix("("))));
2815 }
2816}
2817
2818TEST(CompletionTest, SuggestOverrides) {
2819 constexpr const char *const Text(R"cpp(
2820 class A {
2821 public:
2822 virtual void vfunc(bool param);
2823 virtual void vfunc(bool param, int p);
2824 void func(bool param);
2825 };
2826 class B : public A {
2827 virtual void ttt(bool param) const;
2828 void vfunc(bool param, int p) override;
2829 };
2830 class C : public B {
2831 public:
2832 void vfunc(bool param) override;
2833 ^
2834 };
2835 )cpp");
2836 const auto Results = completions(Text);
2837 EXPECT_THAT(
2838 Results.Completions,
2839 AllOf(Contains(AllOf(labeled("void vfunc(bool param, int p) override"),
2840 nameStartsWith("vfunc"))),
2841 Contains(AllOf(labeled("void ttt(bool param) const override"),
2842 nameStartsWith("ttt"))),
2843 Not(Contains(labeled("void vfunc(bool param) override")))));
2844}
2845
2846TEST(CompletionTest, OverridesNonIdentName) {
2847 // Check the completions call does not crash.
2848 completions(Text: R"cpp(
2849 struct Base {
2850 virtual ~Base() = 0;
2851 virtual operator int() = 0;
2852 virtual Base& operator+(Base&) = 0;
2853 };
2854
2855 struct Derived : Base {
2856 ^
2857 };
2858 )cpp");
2859}
2860
2861TEST(CompletionTest, NoCrashOnMissingNewLineAtEOF) {
2862 auto FooCpp = testPath(File: "foo.cpp");
2863
2864 MockCompilationDatabase CDB;
2865 MockFS FS;
2866 Annotations F("#pragma ^ // no new line");
2867 FS.Files[FooCpp] = F.code().str();
2868 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
2869 runAddDocument(Server, File: FooCpp, Contents: F.code());
2870 // Run completion outside the file range.
2871 EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, F.point(),
2872 clangd::CodeCompleteOptions()))
2873 .Completions,
2874 IsEmpty());
2875 EXPECT_THAT(cantFail(runSignatureHelp(Server, FooCpp, F.point(),
2876 MarkupKind::PlainText))
2877 .signatures,
2878 IsEmpty());
2879}
2880
2881TEST(GuessCompletionPrefix, Filters) {
2882 for (llvm::StringRef Case : {
2883 "[[scope::]][[ident]]^",
2884 "[[]][[]]^",
2885 "\n[[]][[]]^",
2886 "[[]][[ab]]^",
2887 "x.[[]][[ab]]^",
2888 "x.[[]][[]]^",
2889 "[[x::]][[ab]]^",
2890 "[[x::]][[]]^",
2891 "[[::x::]][[ab]]^",
2892 "some text [[scope::more::]][[identif]]^ier",
2893 "some text [[scope::]][[mor]]^e::identifier",
2894 "weird case foo::[[::bar::]][[baz]]^",
2895 "/* [[]][[]]^ */",
2896 }) {
2897 Annotations F(Case);
2898 auto Offset = cantFail(ValOrErr: positionToOffset(Code: F.code(), P: F.point()));
2899 auto ToStringRef = [&](Range R) {
2900 return F.code().slice(Start: cantFail(ValOrErr: positionToOffset(Code: F.code(), P: R.start)),
2901 End: cantFail(ValOrErr: positionToOffset(Code: F.code(), P: R.end)));
2902 };
2903 auto WantQualifier = ToStringRef(F.ranges()[0]),
2904 WantName = ToStringRef(F.ranges()[1]);
2905
2906 auto Prefix = guessCompletionPrefix(Content: F.code(), Offset);
2907 // Even when components are empty, check their offsets are correct.
2908 EXPECT_EQ(WantQualifier, Prefix.Qualifier) << Case;
2909 EXPECT_EQ(WantQualifier.begin(), Prefix.Qualifier.begin()) << Case;
2910 EXPECT_EQ(WantName, Prefix.Name) << Case;
2911 EXPECT_EQ(WantName.begin(), Prefix.Name.begin()) << Case;
2912 }
2913}
2914
2915TEST(CompletionTest, EnableSpeculativeIndexRequest) {
2916 MockFS FS;
2917 MockCompilationDatabase CDB;
2918 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
2919
2920 auto File = testPath(File: "foo.cpp");
2921 Annotations Test(R"cpp(
2922 namespace ns1 { int abc; }
2923 namespace ns2 { int abc; }
2924 void f() { ns1::ab$1^; ns1::ab$2^; }
2925 void f2() { ns2::ab$3^; }
2926 )cpp");
2927 runAddDocument(Server, File, Contents: Test.code());
2928 clangd::CodeCompleteOptions Opts = {};
2929
2930 IndexRequestCollector Requests;
2931 Opts.Index = &Requests;
2932
2933 auto CompleteAtPoint = [&](StringRef P) {
2934 auto CCR = cantFail(ValOrErr: runCodeComplete(Server, File, Pos: Test.point(Name: P), Opts));
2935 EXPECT_TRUE(CCR.HasMore);
2936 };
2937
2938 CompleteAtPoint("1");
2939 auto Reqs1 = Requests.consumeRequests(Num: 1);
2940 ASSERT_EQ(Reqs1.size(), 1u);
2941 EXPECT_THAT(Reqs1[0].Scopes, UnorderedElementsAre("ns1::"));
2942
2943 CompleteAtPoint("2");
2944 auto Reqs2 = Requests.consumeRequests(Num: 1);
2945 // Speculation succeeded. Used speculative index result.
2946 ASSERT_EQ(Reqs2.size(), 1u);
2947 EXPECT_EQ(Reqs2[0], Reqs1[0]);
2948
2949 CompleteAtPoint("3");
2950 // Speculation failed. Sent speculative index request and the new index
2951 // request after sema.
2952 auto Reqs3 = Requests.consumeRequests(Num: 2);
2953 ASSERT_EQ(Reqs3.size(), 2u);
2954}
2955
2956TEST(CompletionTest, InsertTheMostPopularHeader) {
2957 std::string DeclFile = URI::create(AbsolutePath: testPath(File: "foo")).toString();
2958 Symbol Sym = func(Name: "Func");
2959 Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();
2960 Sym.IncludeHeaders.emplace_back(Args: "\"foo.h\"", Args: 2, Args: Symbol::Include);
2961 Sym.IncludeHeaders.emplace_back(Args: "\"bar.h\"", Args: 1000, Args: Symbol::Include);
2962
2963 auto Results = completions(Text: "Fun^", IndexSymbols: {Sym}).Completions;
2964 assert(!Results.empty());
2965 EXPECT_THAT(Results[0], AllOf(named("Func"), insertInclude("\"bar.h\"")));
2966 EXPECT_EQ(Results[0].Includes.size(), 2u);
2967}
2968
2969TEST(CompletionTest, InsertIncludeOrImport) {
2970 std::string DeclFile = URI::create(AbsolutePath: testPath(File: "foo")).toString();
2971 Symbol Sym = func(Name: "Func");
2972 Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();
2973 Sym.IncludeHeaders.emplace_back(Args: "\"bar.h\"", Args: 1000,
2974 Args: Symbol::Include | Symbol::Import);
2975 CodeCompleteOptions Opts;
2976 // Should only take effect in import contexts.
2977 Opts.ImportInsertions = true;
2978 auto Results = completions(Text: "Fun^", IndexSymbols: {Sym}, Opts).Completions;
2979 assert(!Results.empty());
2980 EXPECT_THAT(Results[0],
2981 AllOf(named("Func"), insertIncludeText("#include \"bar.h\"\n")));
2982
2983 ASTSignals Signals;
2984 Signals.InsertionDirective = Symbol::IncludeDirective::Import;
2985 Opts.MainFileSignals = &Signals;
2986 Results = completions(Text: "Fun^", IndexSymbols: {Sym}, Opts, FilePath: "Foo.m").Completions;
2987 assert(!Results.empty());
2988 EXPECT_THAT(Results[0],
2989 AllOf(named("Func"), insertIncludeText("#import \"bar.h\"\n")));
2990
2991 Sym.IncludeHeaders[0].SupportedDirectives = Symbol::Import;
2992 Results = completions(Text: "Fun^", IndexSymbols: {Sym}).Completions;
2993 assert(!Results.empty());
2994 EXPECT_THAT(Results[0], AllOf(named("Func"), Not(insertInclude())));
2995}
2996
2997TEST(CompletionTest, NoInsertIncludeIfOnePresent) {
2998 Annotations Test(R"cpp(
2999 #include "foo.h"
3000 Fun^
3001 )cpp");
3002 auto TU = TestTU::withCode(Code: Test.code());
3003 TU.AdditionalFiles["foo.h"] = "";
3004
3005 std::string DeclFile = URI::create(AbsolutePath: testPath(File: "foo")).toString();
3006 Symbol Sym = func(Name: "Func");
3007 Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();
3008 Sym.IncludeHeaders.emplace_back(Args: "\"foo.h\"", Args: 2, Args: Symbol::Include);
3009 Sym.IncludeHeaders.emplace_back(Args: "\"bar.h\"", Args: 1000, Args: Symbol::Include);
3010
3011 EXPECT_THAT(completions(TU, Test.point(), {Sym}).Completions,
3012 UnorderedElementsAre(AllOf(named("Func"), hasInclude("\"foo.h\""),
3013 Not(insertInclude()))));
3014}
3015
3016TEST(CompletionTest, MergeMacrosFromIndexAndSema) {
3017 Symbol Sym;
3018 Sym.Name = "Clangd_Macro_Test";
3019 Sym.ID = SymbolID("c:foo.cpp@8@macro@Clangd_Macro_Test");
3020 Sym.SymInfo.Kind = index::SymbolKind::Macro;
3021 Sym.Flags |= Symbol::IndexedForCodeCompletion;
3022 EXPECT_THAT(completions("#define Clangd_Macro_Test\nClangd_Macro_T^", {Sym})
3023 .Completions,
3024 UnorderedElementsAre(named("Clangd_Macro_Test")));
3025}
3026
3027TEST(CompletionTest, MacroFromPreamble) {
3028 Annotations Test(R"cpp(#define CLANGD_PREAMBLE_MAIN x
3029
3030 int x = 0;
3031 #define CLANGD_MAIN x
3032 void f() { CLANGD_^ }
3033 )cpp");
3034 auto TU = TestTU::withCode(Code: Test.code());
3035 TU.HeaderCode = "#define CLANGD_PREAMBLE_HEADER x";
3036 auto Results = completions(TU, Point: Test.point(), IndexSymbols: {func(Name: "CLANGD_INDEX")});
3037 // We should get results from the main file, including the preamble section.
3038 // However no results from included files (the index should cover them).
3039 EXPECT_THAT(Results.Completions,
3040 UnorderedElementsAre(named("CLANGD_PREAMBLE_MAIN"),
3041 named("CLANGD_MAIN"),
3042 named("CLANGD_INDEX")));
3043}
3044
3045TEST(CompletionTest, DeprecatedResults) {
3046 std::string Body = R"cpp(
3047 void TestClangd();
3048 void TestClangc() __attribute__((deprecated("", "")));
3049 )cpp";
3050
3051 EXPECT_THAT(
3052 completions(Body + "int main() { TestClang^ }").Completions,
3053 UnorderedElementsAre(AllOf(named("TestClangd"), Not(deprecated())),
3054 AllOf(named("TestClangc"), deprecated())));
3055}
3056
3057TEST(SignatureHelpTest, PartialSpec) {
3058 const auto Results = signatures(Text: R"cpp(
3059 template <typename T> struct Foo {};
3060 template <typename T> struct Foo<T*> { Foo(T); };
3061 Foo<int*> F(^);)cpp");
3062 EXPECT_THAT(Results.signatures, Contains(sig("Foo([[T]])")));
3063 EXPECT_EQ(0, Results.activeParameter);
3064}
3065
3066TEST(SignatureHelpTest, InsideArgument) {
3067 {
3068 const auto Results = signatures(Text: R"cpp(
3069 void foo(int x);
3070 void foo(int x, int y);
3071 int main() { foo(1+^); }
3072 )cpp");
3073 EXPECT_THAT(Results.signatures,
3074 ElementsAre(sig("foo([[int x]]) -> void"),
3075 sig("foo([[int x]], [[int y]]) -> void")));
3076 EXPECT_EQ(0, Results.activeParameter);
3077 }
3078 {
3079 const auto Results = signatures(Text: R"cpp(
3080 void foo(int x);
3081 void foo(int x, int y);
3082 int main() { foo(1^); }
3083 )cpp");
3084 EXPECT_THAT(Results.signatures,
3085 ElementsAre(sig("foo([[int x]]) -> void"),
3086 sig("foo([[int x]], [[int y]]) -> void")));
3087 EXPECT_EQ(0, Results.activeParameter);
3088 }
3089 {
3090 const auto Results = signatures(Text: R"cpp(
3091 void foo(int x);
3092 void foo(int x, int y);
3093 int main() { foo(1^0); }
3094 )cpp");
3095 EXPECT_THAT(Results.signatures,
3096 ElementsAre(sig("foo([[int x]]) -> void"),
3097 sig("foo([[int x]], [[int y]]) -> void")));
3098 EXPECT_EQ(0, Results.activeParameter);
3099 }
3100 {
3101 const auto Results = signatures(Text: R"cpp(
3102 void foo(int x);
3103 void foo(int x, int y);
3104 int bar(int x, int y);
3105 int main() { bar(foo(2, 3^)); }
3106 )cpp");
3107 EXPECT_THAT(Results.signatures,
3108 ElementsAre(sig("foo([[int x]], [[int y]]) -> void")));
3109 EXPECT_EQ(1, Results.activeParameter);
3110 }
3111}
3112
3113TEST(SignatureHelpTest, ConstructorInitializeFields) {
3114 {
3115 const auto Results = signatures(Text: R"cpp(
3116 struct A { A(int); };
3117 struct B {
3118 B() : a_elem(^) {}
3119 A a_elem;
3120 };
3121 )cpp");
3122 EXPECT_THAT(Results.signatures,
3123 UnorderedElementsAre(sig("A([[int]])"), sig("A([[A &&]])"),
3124 sig("A([[const A &]])")));
3125 }
3126 {
3127 const auto Results = signatures(Text: R"cpp(
3128 struct A { A(int); };
3129 struct B {
3130 B() : a_elem(^
3131 A a_elem;
3132 };
3133 )cpp");
3134 // FIXME: currently the parser skips over the decl of a_elem as part of the
3135 // (broken) init list, so we don't get signatures for the first member.
3136 EXPECT_THAT(Results.signatures, IsEmpty());
3137 }
3138 {
3139 const auto Results = signatures(Text: R"cpp(
3140 struct A { A(int); };
3141 struct B {
3142 B() : a_elem(^
3143 int dummy_elem;
3144 A a_elem;
3145 };
3146 )cpp");
3147 EXPECT_THAT(Results.signatures,
3148 UnorderedElementsAre(sig("A([[int]])"), sig("A([[A &&]])"),
3149 sig("A([[const A &]])")));
3150 }
3151 {
3152 const auto Results = signatures(Text: R"cpp(
3153 struct A {
3154 A(int);
3155 };
3156 struct C {
3157 C(int);
3158 C(A);
3159 };
3160 struct B {
3161 B() : c_elem(A(1^)) {}
3162 C c_elem;
3163 };
3164 )cpp");
3165 EXPECT_THAT(Results.signatures,
3166 UnorderedElementsAre(sig("A([[int]])"), sig("A([[A &&]])"),
3167 sig("A([[const A &]])")));
3168 }
3169}
3170
3171TEST(SignatureHelpTest, Variadic) {
3172 const std::string Header = R"cpp(
3173 void fun(int x, ...) {}
3174 void test() {)cpp";
3175 const std::string ExpectedSig = "fun([[int x]], [[...]]) -> void";
3176
3177 {
3178 const auto Result = signatures(Text: Header + "fun(^);}");
3179 EXPECT_EQ(0, Result.activeParameter);
3180 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3181 }
3182 {
3183 const auto Result = signatures(Text: Header + "fun(1, ^);}");
3184 EXPECT_EQ(1, Result.activeParameter);
3185 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3186 }
3187 {
3188 const auto Result = signatures(Text: Header + "fun(1, 2, ^);}");
3189 EXPECT_EQ(1, Result.activeParameter);
3190 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3191 }
3192}
3193
3194TEST(SignatureHelpTest, VariadicTemplate) {
3195 const std::string Header = R"cpp(
3196 template<typename T, typename ...Args>
3197 void fun(T t, Args ...args) {}
3198 void test() {)cpp";
3199 const std::string ExpectedSig = "fun([[T t]], [[Args args...]]) -> void";
3200
3201 {
3202 const auto Result = signatures(Text: Header + "fun(^);}");
3203 EXPECT_EQ(0, Result.activeParameter);
3204 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3205 }
3206 {
3207 const auto Result = signatures(Text: Header + "fun(1, ^);}");
3208 EXPECT_EQ(1, Result.activeParameter);
3209 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3210 }
3211 {
3212 const auto Result = signatures(Text: Header + "fun(1, 2, ^);}");
3213 EXPECT_EQ(1, Result.activeParameter);
3214 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3215 }
3216}
3217
3218TEST(SignatureHelpTest, VariadicMethod) {
3219 const std::string Header = R"cpp(
3220 class C {
3221 template<typename T, typename ...Args>
3222 void fun(T t, Args ...args) {}
3223 };
3224 void test() {C c; )cpp";
3225 const std::string ExpectedSig = "fun([[T t]], [[Args args...]]) -> void";
3226
3227 {
3228 const auto Result = signatures(Text: Header + "c.fun(^);}");
3229 EXPECT_EQ(0, Result.activeParameter);
3230 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3231 }
3232 {
3233 const auto Result = signatures(Text: Header + "c.fun(1, ^);}");
3234 EXPECT_EQ(1, Result.activeParameter);
3235 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3236 }
3237 {
3238 const auto Result = signatures(Text: Header + "c.fun(1, 2, ^);}");
3239 EXPECT_EQ(1, Result.activeParameter);
3240 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3241 }
3242}
3243
3244TEST(SignatureHelpTest, VariadicType) {
3245 const std::string Header = R"cpp(
3246 void fun(int x, ...) {}
3247 auto get_fun() { return fun; }
3248 void test() {
3249 )cpp";
3250 const std::string ExpectedSig = "([[int]], [[...]]) -> void";
3251
3252 {
3253 const auto Result = signatures(Text: Header + "get_fun()(^);}");
3254 EXPECT_EQ(0, Result.activeParameter);
3255 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3256 }
3257 {
3258 const auto Result = signatures(Text: Header + "get_fun()(1, ^);}");
3259 EXPECT_EQ(1, Result.activeParameter);
3260 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3261 }
3262 {
3263 const auto Result = signatures(Text: Header + "get_fun()(1, 2, ^);}");
3264 EXPECT_EQ(1, Result.activeParameter);
3265 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));
3266 }
3267}
3268
3269TEST(CompletionTest, IncludedCompletionKinds) {
3270 Annotations Test(R"cpp(#include "^)cpp");
3271 auto TU = TestTU::withCode(Code: Test.code());
3272 TU.AdditionalFiles["sub/bar.h"] = "";
3273 TU.ExtraArgs.push_back(x: "-I" + testPath(File: "sub"));
3274
3275 auto Results = completions(TU, Point: Test.point());
3276 EXPECT_THAT(Results.Completions,
3277 AllOf(has("sub/", CompletionItemKind::Folder),
3278 has("bar.h\"", CompletionItemKind::File)));
3279}
3280
3281TEST(CompletionTest, NoCrashAtNonAlphaIncludeHeader) {
3282 completions(
3283 Text: R"cpp(
3284 #include "./^"
3285 )cpp");
3286}
3287
3288TEST(CompletionTest, NoAllScopesCompletionWhenQualified) {
3289 clangd::CodeCompleteOptions Opts = {};
3290 Opts.AllScopes = true;
3291
3292 auto Results = completions(
3293 Text: R"cpp(
3294 void f() { na::Clangd^ }
3295 )cpp",
3296 IndexSymbols: {cls(Name: "na::ClangdA"), cls(Name: "nx::ClangdX"), cls(Name: "Clangd3")}, Opts);
3297 EXPECT_THAT(Results.Completions,
3298 UnorderedElementsAre(
3299 AllOf(qualifier(""), scope("na::"), named("ClangdA"))));
3300}
3301
3302TEST(CompletionTest, AllScopesCompletion) {
3303 clangd::CodeCompleteOptions Opts = {};
3304 Opts.AllScopes = true;
3305
3306 auto Results = completions(
3307 Text: R"cpp(
3308 namespace na {
3309 void f() { Clangd^ }
3310 }
3311 )cpp",
3312 IndexSymbols: {cls(Name: "nx::Clangd1"), cls(Name: "ny::Clangd2"), cls(Name: "Clangd3"),
3313 cls(Name: "na::nb::Clangd4"), enmConstant(Name: "na::C::Clangd5")},
3314 Opts);
3315 EXPECT_THAT(
3316 Results.Completions,
3317 UnorderedElementsAre(AllOf(qualifier("nx::"), named("Clangd1"),
3318 kind(CompletionItemKind::Class)),
3319 AllOf(qualifier("ny::"), named("Clangd2"),
3320 kind(CompletionItemKind::Class)),
3321 AllOf(qualifier(""), scope(""), named("Clangd3"),
3322 kind(CompletionItemKind::Class)),
3323 AllOf(qualifier("nb::"), named("Clangd4"),
3324 kind(CompletionItemKind::Class)),
3325 AllOf(qualifier("C::"), named("Clangd5"),
3326 kind(CompletionItemKind::EnumMember))));
3327}
3328
3329TEST(CompletionTest, NoCodePatternsIfDisabled) {
3330 clangd::CodeCompleteOptions Opts = {};
3331 Opts.EnableSnippets = true;
3332 Opts.CodePatterns = Config::CodePatternsPolicy::None;
3333
3334 auto Results = completions(Text: R"cpp(
3335 void function() {
3336 /// Trying to trigger "for (init-statement; condition; inc-expression)
3337 /// {statements}~" code pattern
3338 for^
3339 }
3340 )cpp",
3341 IndexSymbols: {}, Opts);
3342
3343 EXPECT_THAT(Results.Completions,
3344 Not(Contains(kind(CompletionItemKind::Snippet))));
3345}
3346
3347TEST(CompletionTest, CompleteIncludeIfCodePatternsNone) {
3348 clangd::CodeCompleteOptions Opts = {};
3349 Opts.EnableSnippets = true;
3350 Opts.CodePatterns = Config::CodePatternsPolicy::None;
3351
3352 Annotations Test(R"cpp(#include "^)cpp");
3353 auto TU = TestTU::withCode(Code: Test.code());
3354 TU.AdditionalFiles["foo/bar.h"] = "";
3355 TU.ExtraArgs.push_back(x: "-I" + testPath(File: "foo"));
3356
3357 auto Results = completions(TU, Point: Test.point(), IndexSymbols: {}, Opts);
3358 EXPECT_THAT(Results.Completions,
3359 AllOf(has("foo/", CompletionItemKind::Folder),
3360 has("bar.h\"", CompletionItemKind::File)));
3361}
3362
3363TEST(CompletionTest, NoQualifierIfShadowed) {
3364 clangd::CodeCompleteOptions Opts = {};
3365 Opts.AllScopes = true;
3366
3367 auto Results = completions(Text: R"cpp(
3368 namespace nx { class Clangd1 {}; }
3369 using nx::Clangd1;
3370 void f() { Clangd^ }
3371 )cpp",
3372 IndexSymbols: {cls(Name: "nx::Clangd1"), cls(Name: "nx::Clangd2")}, Opts);
3373 // Although Clangd1 is from another namespace, Sema tells us it's in-scope and
3374 // needs no qualifier.
3375 EXPECT_THAT(Results.Completions,
3376 UnorderedElementsAre(AllOf(qualifier(""), named("Clangd1")),
3377 AllOf(qualifier("nx::"), named("Clangd2"))));
3378}
3379
3380TEST(CompletionTest, NoCompletionsForNewNames) {
3381 clangd::CodeCompleteOptions Opts;
3382 Opts.AllScopes = true;
3383 auto Results = completions(Text: R"cpp(
3384 void f() { int n^ }
3385 )cpp",
3386 IndexSymbols: {cls(Name: "naber"), cls(Name: "nx::naber")}, Opts);
3387 EXPECT_THAT(Results.Completions, UnorderedElementsAre());
3388}
3389
3390TEST(CompletionTest, Lambda) {
3391 clangd::CodeCompleteOptions Opts = {};
3392
3393 auto Results = completions(Text: R"cpp(
3394 void function() {
3395 auto Lambda = [](int a, const double &b) {return 1.f;};
3396 Lam^
3397 }
3398 )cpp",
3399 IndexSymbols: {}, Opts);
3400
3401 ASSERT_EQ(Results.Completions.size(), 1u);
3402 const auto &A = Results.Completions.front();
3403 EXPECT_EQ(A.Name, "Lambda");
3404 EXPECT_EQ(A.Signature, "(int a, const double &b) const");
3405 EXPECT_EQ(A.Kind, CompletionItemKind::Variable);
3406 EXPECT_EQ(A.ReturnType, "float");
3407 EXPECT_EQ(A.SnippetSuffix, "(${1:int a}, ${2:const double &b})");
3408}
3409
3410TEST(CompletionTest, StructuredBinding) {
3411 clangd::CodeCompleteOptions Opts = {};
3412
3413 auto Results = completions(Text: R"cpp(
3414 struct S {
3415 using Float = float;
3416 int x;
3417 Float y;
3418 };
3419 void function() {
3420 const auto &[xxx, yyy] = S{};
3421 yyy^
3422 }
3423 )cpp",
3424 IndexSymbols: {}, Opts);
3425
3426 ASSERT_EQ(Results.Completions.size(), 1u);
3427 const auto &A = Results.Completions.front();
3428 EXPECT_EQ(A.Name, "yyy");
3429 EXPECT_EQ(A.Kind, CompletionItemKind::Variable);
3430 EXPECT_EQ(A.ReturnType, "const Float");
3431}
3432
3433TEST(CompletionTest, ObjectiveCMethodNoArguments) {
3434 auto Results = completions(Text: R"objc(
3435 @interface Foo
3436 @property(nonatomic, setter=setXToIgnoreComplete:) int value;
3437 @end
3438 Foo *foo = [Foo new]; int y = [foo v^]
3439 )objc",
3440 /*IndexSymbols=*/{},
3441 /*Opts=*/{}, FilePath: "Foo.m");
3442
3443 auto C = Results.Completions;
3444 EXPECT_THAT(C, ElementsAre(named("value")));
3445 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3446 EXPECT_THAT(C, ElementsAre(returnType("int")));
3447 EXPECT_THAT(C, ElementsAre(signature("")));
3448 EXPECT_THAT(C, ElementsAre(snippetSuffix("")));
3449}
3450
3451TEST(CompletionTest, ObjectiveCMethodOneArgument) {
3452 auto Results = completions(Text: R"objc(
3453 @interface Foo
3454 - (int)valueForCharacter:(char)c;
3455 @end
3456 Foo *foo = [Foo new]; int y = [foo v^]
3457 )objc",
3458 /*IndexSymbols=*/{},
3459 /*Opts=*/{}, FilePath: "Foo.m");
3460
3461 auto C = Results.Completions;
3462 EXPECT_THAT(C, ElementsAre(named("valueForCharacter:")));
3463 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3464 EXPECT_THAT(C, ElementsAre(returnType("int")));
3465 EXPECT_THAT(C, ElementsAre(signature("(char)")));
3466 EXPECT_THAT(C, ElementsAre(snippetSuffix("${1:(char)}")));
3467}
3468
3469TEST(CompletionTest, ObjectiveCMethodTwoArgumentsFromBeginning) {
3470 auto Results = completions(Text: R"objc(
3471 @interface Foo
3472 + (id)fooWithValue:(int)value fooey:(unsigned int)fooey;
3473 @end
3474 id val = [Foo foo^]
3475 )objc",
3476 /*IndexSymbols=*/{},
3477 /*Opts=*/{}, FilePath: "Foo.m");
3478
3479 auto C = Results.Completions;
3480 EXPECT_THAT(C, ElementsAre(named("fooWithValue:")));
3481 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3482 EXPECT_THAT(C, ElementsAre(returnType("id")));
3483 EXPECT_THAT(C, ElementsAre(signature("(int) fooey:(unsigned int)")));
3484 EXPECT_THAT(
3485 C, ElementsAre(snippetSuffix("${1:(int)} fooey:${2:(unsigned int)}")));
3486}
3487
3488TEST(CompletionTest, ObjectiveCMethodTwoArgumentsFromMiddle) {
3489 auto Results = completions(Text: R"objc(
3490 @interface Foo
3491 + (id)fooWithValue:(int)value fooey:(unsigned int)fooey;
3492 @end
3493 id val = [Foo fooWithValue:10 f^]
3494 )objc",
3495 /*IndexSymbols=*/{},
3496 /*Opts=*/{}, FilePath: "Foo.m");
3497
3498 auto C = Results.Completions;
3499 EXPECT_THAT(C, ElementsAre(named("fooey:")));
3500 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3501 EXPECT_THAT(C, ElementsAre(returnType("id")));
3502 EXPECT_THAT(C, ElementsAre(signature("(unsigned int)")));
3503 EXPECT_THAT(C, ElementsAre(snippetSuffix("${1:(unsigned int)}")));
3504}
3505
3506TEST(CompletionTest, ObjectiveCMethodFilterOnEntireSelector) {
3507 auto Results = completions(Text: R"objc(
3508 @interface Foo
3509 + (id)player:(id)player willRun:(id)run;
3510 @end
3511 id val = [Foo wi^]
3512 )objc",
3513 /*IndexSymbols=*/{},
3514 /*Opts=*/{}, FilePath: "Foo.m");
3515
3516 auto C = Results.Completions;
3517 EXPECT_THAT(C, ElementsAre(named("player:")));
3518 EXPECT_THAT(C, ElementsAre(filterText("player:willRun:")));
3519 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3520 EXPECT_THAT(C, ElementsAre(returnType("id")));
3521 EXPECT_THAT(C, ElementsAre(signature("(id) willRun:(id)")));
3522 EXPECT_THAT(C, ElementsAre(snippetSuffix("${1:(id)} willRun:${2:(id)}")));
3523}
3524
3525TEST(CompletionTest, ObjectiveCSimpleMethodDeclaration) {
3526 auto Results = completions(Text: R"objc(
3527 @interface Foo
3528 - (void)foo;
3529 @end
3530 @implementation Foo
3531 fo^
3532 @end
3533 )objc",
3534 /*IndexSymbols=*/{},
3535 /*Opts=*/{}, FilePath: "Foo.m");
3536
3537 auto C = Results.Completions;
3538 EXPECT_THAT(C, ElementsAre(named("foo")));
3539 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3540 EXPECT_THAT(C, ElementsAre(qualifier("- (void)")));
3541}
3542
3543TEST(CompletionTest, ObjectiveCMethodDeclaration) {
3544 auto Results = completions(Text: R"objc(
3545 @interface Foo
3546 - (int)valueForCharacter:(char)c secondArgument:(id)object;
3547 @end
3548 @implementation Foo
3549 valueFor^
3550 @end
3551 )objc",
3552 /*IndexSymbols=*/{},
3553 /*Opts=*/{}, FilePath: "Foo.m");
3554
3555 auto C = Results.Completions;
3556 EXPECT_THAT(C, ElementsAre(named("valueForCharacter:")));
3557 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3558 EXPECT_THAT(C, ElementsAre(qualifier("- (int)")));
3559 EXPECT_THAT(C, ElementsAre(signature("(char)c secondArgument:(id)object")));
3560}
3561
3562TEST(CompletionTest, ObjectiveCMethodDeclarationFilterOnEntireSelector) {
3563 auto Results = completions(Text: R"objc(
3564 @interface Foo
3565 - (int)valueForCharacter:(char)c secondArgument:(id)object;
3566 @end
3567 @implementation Foo
3568 secondArg^
3569 @end
3570 )objc",
3571 /*IndexSymbols=*/{},
3572 /*Opts=*/{}, FilePath: "Foo.m");
3573
3574 auto C = Results.Completions;
3575 EXPECT_THAT(C, ElementsAre(named("valueForCharacter:")));
3576 EXPECT_THAT(C, ElementsAre(filterText("valueForCharacter:secondArgument:")));
3577 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3578 EXPECT_THAT(C, ElementsAre(qualifier("- (int)")));
3579 EXPECT_THAT(C, ElementsAre(signature("(char)c secondArgument:(id)object")));
3580}
3581
3582TEST(CompletionTest, ObjectiveCMethodDeclarationPrefixTyped) {
3583 auto Results = completions(Text: R"objc(
3584 @interface Foo
3585 - (int)valueForCharacter:(char)c;
3586 @end
3587 @implementation Foo
3588 - (int)valueFor^
3589 @end
3590 )objc",
3591 /*IndexSymbols=*/{},
3592 /*Opts=*/{}, FilePath: "Foo.m");
3593
3594 auto C = Results.Completions;
3595 EXPECT_THAT(C, ElementsAre(named("valueForCharacter:")));
3596 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3597 EXPECT_THAT(C, ElementsAre(signature("(char)c")));
3598}
3599
3600TEST(CompletionTest, ObjectiveCMethodDeclarationFromMiddle) {
3601 auto Results = completions(Text: R"objc(
3602 @interface Foo
3603 - (int)valueForCharacter:(char)c secondArgument:(id)object;
3604 @end
3605 @implementation Foo
3606 - (int)valueForCharacter:(char)c second^
3607 @end
3608 )objc",
3609 /*IndexSymbols=*/{},
3610 /*Opts=*/{}, FilePath: "Foo.m");
3611
3612 auto C = Results.Completions;
3613 EXPECT_THAT(C, ElementsAre(named("secondArgument:")));
3614 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));
3615 EXPECT_THAT(C, ElementsAre(signature("(id)object")));
3616}
3617
3618TEST(CompletionTest, ObjectiveCProtocolFromIndex) {
3619 Symbol FoodClass = objcClass(Name: "FoodClass");
3620 Symbol SymFood = objcProtocol(Name: "Food");
3621 Symbol SymFooey = objcProtocol(Name: "Fooey");
3622 auto Results = completions(Text: "id<Foo^>", IndexSymbols: {SymFood, FoodClass, SymFooey},
3623 /*Opts=*/{}, FilePath: "Foo.m");
3624
3625 // Should only give protocols for ObjC protocol completions.
3626 EXPECT_THAT(Results.Completions,
3627 UnorderedElementsAre(
3628 AllOf(named("Food"), kind(CompletionItemKind::Interface)),
3629 AllOf(named("Fooey"), kind(CompletionItemKind::Interface))));
3630
3631 Results = completions(Text: "Fo^", IndexSymbols: {SymFood, FoodClass, SymFooey},
3632 /*Opts=*/{}, FilePath: "Foo.m");
3633 // Shouldn't give protocols for non protocol completions.
3634 EXPECT_THAT(
3635 Results.Completions,
3636 ElementsAre(AllOf(named("FoodClass"), kind(CompletionItemKind::Class))));
3637}
3638
3639TEST(CompletionTest, ObjectiveCProtocolFromIndexSpeculation) {
3640 MockFS FS;
3641 MockCompilationDatabase CDB;
3642 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());
3643
3644 auto File = testPath(File: "Foo.m");
3645 Annotations Test(R"cpp(
3646 @protocol Food
3647 @end
3648 id<Foo$1^> foo;
3649 Foo$2^ bar;
3650 )cpp");
3651 runAddDocument(Server, File, Contents: Test.code());
3652 clangd::CodeCompleteOptions Opts = {};
3653
3654 Symbol FoodClass = objcClass(Name: "FoodClass");
3655 IndexRequestCollector Requests({FoodClass});
3656 Opts.Index = &Requests;
3657
3658 auto CompleteAtPoint = [&](StringRef P) {
3659 return cantFail(ValOrErr: runCodeComplete(Server, File, Pos: Test.point(Name: P), Opts))
3660 .Completions;
3661 };
3662
3663 auto C = CompleteAtPoint("1");
3664 auto Reqs1 = Requests.consumeRequests(Num: 1);
3665 ASSERT_EQ(Reqs1.size(), 1u);
3666 EXPECT_THAT(C, ElementsAre(AllOf(named("Food"),
3667 kind(CompletionItemKind::Interface))));
3668
3669 C = CompleteAtPoint("2");
3670 auto Reqs2 = Requests.consumeRequests(Num: 1);
3671 // Speculation succeeded. Used speculative index result, but filtering now to
3672 // now include FoodClass.
3673 ASSERT_EQ(Reqs2.size(), 1u);
3674 EXPECT_EQ(Reqs2[0], Reqs1[0]);
3675 EXPECT_THAT(C, ElementsAre(AllOf(named("FoodClass"),
3676 kind(CompletionItemKind::Class))));
3677}
3678
3679TEST(CompletionTest, ObjectiveCCategoryFromIndexIgnored) {
3680 Symbol FoodCategory = objcCategory(Name: "FoodClass", CategoryName: "Extension");
3681 auto Results = completions(Text: R"objc(
3682 @interface Foo
3683 @end
3684 @interface Foo (^)
3685 @end
3686 )objc",
3687 IndexSymbols: {FoodCategory},
3688 /*Opts=*/{}, FilePath: "Foo.m");
3689 EXPECT_THAT(Results.Completions, IsEmpty());
3690}
3691
3692TEST(CompletionTest, ObjectiveCForwardDeclFromIndex) {
3693 Symbol FoodClass = objcClass(Name: "FoodClass");
3694 FoodClass.IncludeHeaders.emplace_back(Args: "\"Foo.h\"", Args: 2, Args: Symbol::Import);
3695 Symbol SymFood = objcProtocol(Name: "Food");
3696 auto Results = completions(Text: "@class Foo^", IndexSymbols: {SymFood, FoodClass},
3697 /*Opts=*/{}, FilePath: "Foo.m");
3698
3699 // Should only give class names without any include insertion.
3700 EXPECT_THAT(Results.Completions,
3701 UnorderedElementsAre(AllOf(named("FoodClass"),
3702 kind(CompletionItemKind::Class),
3703 Not(insertInclude()))));
3704}
3705
3706TEST(CompletionTest, CursorInSnippets) {
3707 clangd::CodeCompleteOptions Options;
3708 Options.EnableSnippets = true;
3709 auto Results = completions(
3710 Text: R"cpp(
3711 void while_foo(int a, int b);
3712 void test() {
3713 whil^
3714 })cpp",
3715 /*IndexSymbols=*/{}, Opts: Options);
3716
3717 // Last placeholder in code patterns should be $0 to put the cursor there.
3718 EXPECT_THAT(Results.Completions,
3719 Contains(AllOf(named("while"),
3720 snippetSuffix(" (${1:condition}) {\n$0\n}"))));
3721 // However, snippets for functions must *not* end with $0.
3722 EXPECT_THAT(Results.Completions,
3723 Contains(AllOf(named("while_foo"),
3724 snippetSuffix("(${1:int a}, ${2:int b})"))));
3725
3726 Results = completions(Text: R"cpp(
3727 struct Base {
3728 Base(int a, int b) {}
3729 };
3730
3731 struct Derived : Base {
3732 Derived() : Base^
3733 };
3734 )cpp",
3735 /*IndexSymbols=*/{}, Opts: Options);
3736 // Constructors from base classes are a kind of pattern that shouldn't end
3737 // with $0.
3738 EXPECT_THAT(Results.Completions,
3739 Contains(AllOf(named("Base"),
3740 snippetSuffix("(${1:int a}, ${2:int b})"))));
3741}
3742
3743TEST(CompletionTest, WorksWithNullType) {
3744 auto R = completions(Text: R"cpp(
3745 int main() {
3746 for (auto [loopVar] : y ) { // y has to be unresolved.
3747 int z = loopV^;
3748 }
3749 }
3750 )cpp");
3751 EXPECT_THAT(R.Completions, ElementsAre(named("loopVar")));
3752}
3753
3754TEST(CompletionTest, UsingDecl) {
3755 const char *Header(R"cpp(
3756 void foo(int);
3757 namespace std {
3758 using ::foo;
3759 })cpp");
3760 const char *Source(R"cpp(
3761 void bar() {
3762 std::^;
3763 })cpp");
3764 auto Index = TestTU::withHeaderCode(HeaderCode: Header).index();
3765 clangd::CodeCompleteOptions Opts;
3766 Opts.Index = Index.get();
3767 Opts.AllScopes = true;
3768 auto R = completions(Text: Source, IndexSymbols: {}, Opts);
3769 EXPECT_THAT(R.Completions,
3770 ElementsAre(AllOf(scope("std::"), named("foo"),
3771 kind(CompletionItemKind::Reference))));
3772}
3773
3774TEST(CompletionTest, Enums) {
3775 const char *Header(R"cpp(
3776 namespace ns {
3777 enum Unscoped { Clangd1 };
3778 class C {
3779 enum Unscoped { Clangd2 };
3780 };
3781 enum class Scoped { Clangd3 };
3782 })cpp");
3783 const char *Source(R"cpp(
3784 void bar() {
3785 Clangd^
3786 })cpp");
3787 auto Index = TestTU::withHeaderCode(HeaderCode: Header).index();
3788 clangd::CodeCompleteOptions Opts;
3789 Opts.Index = Index.get();
3790 Opts.AllScopes = true;
3791 auto R = completions(Text: Source, IndexSymbols: {}, Opts);
3792 EXPECT_THAT(R.Completions, UnorderedElementsAre(
3793 AllOf(scope("ns::"), named("Clangd1"),
3794 kind(CompletionItemKind::EnumMember)),
3795 AllOf(scope("ns::C::"), named("Clangd2"),
3796 kind(CompletionItemKind::EnumMember)),
3797 AllOf(scope("ns::Scoped::"), named("Clangd3"),
3798 kind(CompletionItemKind::EnumMember))));
3799}
3800
3801TEST(CompletionTest, ScopeIsUnresolved) {
3802 clangd::CodeCompleteOptions Opts = {};
3803 Opts.AllScopes = true;
3804
3805 auto Results = completions(Text: R"cpp(
3806 namespace a {
3807 void f() { b::X^ }
3808 }
3809 )cpp",
3810 IndexSymbols: {cls(Name: "a::b::XYZ")}, Opts);
3811 EXPECT_THAT(Results.Completions,
3812 UnorderedElementsAre(AllOf(qualifier(""), named("XYZ"))));
3813}
3814
3815TEST(CompletionTest, NestedScopeIsUnresolved) {
3816 clangd::CodeCompleteOptions Opts = {};
3817 Opts.AllScopes = true;
3818
3819 auto Results = completions(Text: R"cpp(
3820 namespace a {
3821 namespace b {}
3822 void f() { b::c::X^ }
3823 }
3824 )cpp",
3825 IndexSymbols: {cls(Name: "a::b::c::XYZ")}, Opts);
3826 EXPECT_THAT(Results.Completions,
3827 UnorderedElementsAre(AllOf(qualifier(""), named("XYZ"))));
3828}
3829
3830// Clang parser gets confused here and doesn't report the ns:: prefix.
3831// Naive behavior is to insert it again. We examine the source and recover.
3832TEST(CompletionTest, NamespaceDoubleInsertion) {
3833 clangd::CodeCompleteOptions Opts = {};
3834
3835 auto Results = completions(Text: R"cpp(
3836 namespace foo {
3837 namespace ns {}
3838 #define M(X) < X
3839 M(ns::ABC^
3840 }
3841 )cpp",
3842 IndexSymbols: {cls(Name: "foo::ns::ABCDE")}, Opts);
3843 EXPECT_THAT(Results.Completions,
3844 UnorderedElementsAre(AllOf(qualifier(""), named("ABCDE"))));
3845}
3846
3847TEST(CompletionTest, DerivedMethodsAreAlwaysVisible) {
3848 // Despite the fact that base method matches the ref-qualifier better,
3849 // completion results should only include the derived method.
3850 auto Completions = completions(Text: R"cpp(
3851 struct deque_base {
3852 float size();
3853 double size() const;
3854 };
3855 struct deque : deque_base {
3856 int size() const;
3857 };
3858
3859 auto x = deque().^
3860 )cpp")
3861 .Completions;
3862 EXPECT_THAT(Completions,
3863 ElementsAre(AllOf(returnType("int"), named("size"))));
3864}
3865
3866TEST(CompletionTest, NoCrashWithIncompleteLambda) {
3867 auto Completions = completions(Text: "auto&& x = []{^").Completions;
3868 // The completion of x itself can cause a problem: in the code completion
3869 // callback, its type is not known, which affects the linkage calculation.
3870 // A bad linkage value gets cached, and subsequently updated.
3871 EXPECT_THAT(Completions, Contains(named("x")));
3872
3873 auto Signatures = signatures(Text: "auto x() { x(^").signatures;
3874 EXPECT_THAT(Signatures, Contains(sig("x() -> auto")));
3875}
3876
3877TEST(CompletionTest, DelayedTemplateParsing) {
3878 Annotations Test(R"cpp(
3879 int xxx;
3880 template <typename T> int foo() { return xx^; }
3881 )cpp");
3882 auto TU = TestTU::withCode(Code: Test.code());
3883 // Even though delayed-template-parsing is on, we will disable it to provide
3884 // completion in templates.
3885 TU.ExtraArgs.push_back(x: "-fdelayed-template-parsing");
3886
3887 EXPECT_THAT(completions(TU, Test.point()).Completions,
3888 Contains(named("xxx")));
3889}
3890
3891TEST(CompletionTest, CompletionRange) {
3892 const char *WithRange = "auto x = [[abc]]^";
3893 auto Completions = completions(Text: WithRange);
3894 EXPECT_EQ(Completions.CompletionRange, Annotations(WithRange).range());
3895 Completions = completionsNoCompile(Text: WithRange);
3896 EXPECT_EQ(Completions.CompletionRange, Annotations(WithRange).range());
3897
3898 const char *EmptyRange = "auto x = [[]]^";
3899 Completions = completions(Text: EmptyRange);
3900 EXPECT_EQ(Completions.CompletionRange, Annotations(EmptyRange).range());
3901 Completions = completionsNoCompile(Text: EmptyRange);
3902 EXPECT_EQ(Completions.CompletionRange, Annotations(EmptyRange).range());
3903
3904 // Sema doesn't trigger at all here, while the no-sema completion runs
3905 // heuristics as normal and reports a range. It'd be nice to be consistent.
3906 const char *NoCompletion = "/* foo [[]]^ */";
3907 Completions = completions(Text: NoCompletion);
3908 EXPECT_EQ(Completions.CompletionRange, std::nullopt);
3909 Completions = completionsNoCompile(Text: NoCompletion);
3910 EXPECT_EQ(Completions.CompletionRange, Annotations(NoCompletion).range());
3911}
3912
3913TEST(NoCompileCompletionTest, Basic) {
3914 auto Results = completionsNoCompile(Text: R"cpp(
3915 void func() {
3916 int xyz;
3917 int abc;
3918 ^
3919 }
3920 )cpp");
3921 EXPECT_FALSE(Results.RanParser);
3922 EXPECT_THAT(Results.Completions,
3923 UnorderedElementsAre(named("void"), named("func"), named("int"),
3924 named("xyz"), named("abc")));
3925}
3926
3927TEST(NoCompileCompletionTest, WithFilter) {
3928 auto Results = completionsNoCompile(Text: R"cpp(
3929 void func() {
3930 int sym1;
3931 int sym2;
3932 int xyz1;
3933 int xyz2;
3934 sy^
3935 }
3936 )cpp");
3937 EXPECT_THAT(Results.Completions,
3938 UnorderedElementsAre(named("sym1"), named("sym2")));
3939}
3940
3941TEST(NoCompileCompletionTest, WithIndex) {
3942 std::vector<Symbol> Syms = {func(Name: "xxx"), func(Name: "a::xxx"), func(Name: "ns::b::xxx"),
3943 func(Name: "c::xxx"), func(Name: "ns::d::xxx")};
3944 auto Results = completionsNoCompile(
3945 Text: R"cpp(
3946 // Current-scopes, unqualified completion.
3947 using namespace a;
3948 namespace ns {
3949 using namespace b;
3950 void foo() {
3951 xx^
3952 }
3953 }
3954 )cpp",
3955 IndexSymbols: Syms);
3956 EXPECT_THAT(Results.Completions,
3957 UnorderedElementsAre(AllOf(qualifier(""), scope("")),
3958 AllOf(qualifier(""), scope("a::")),
3959 AllOf(qualifier(""), scope("ns::b::"))));
3960 CodeCompleteOptions Opts;
3961 Opts.AllScopes = true;
3962 Results = completionsNoCompile(
3963 Text: R"cpp(
3964 // All-scopes unqualified completion.
3965 using namespace a;
3966 namespace ns {
3967 using namespace b;
3968 void foo() {
3969 xx^
3970 }
3971 }
3972 )cpp",
3973 IndexSymbols: Syms, Opts);
3974 EXPECT_THAT(Results.Completions,
3975 UnorderedElementsAre(AllOf(qualifier(""), scope("")),
3976 AllOf(qualifier(""), scope("a::")),
3977 AllOf(qualifier(""), scope("ns::b::")),
3978 AllOf(qualifier("c::"), scope("c::")),
3979 AllOf(qualifier("d::"), scope("ns::d::"))));
3980 Results = completionsNoCompile(
3981 Text: R"cpp(
3982 // Qualified completion.
3983 using namespace a;
3984 namespace ns {
3985 using namespace b;
3986 void foo() {
3987 b::xx^
3988 }
3989 }
3990 )cpp",
3991 IndexSymbols: Syms, Opts);
3992 EXPECT_THAT(Results.Completions,
3993 ElementsAre(AllOf(qualifier(""), scope("ns::b::"))));
3994 Results = completionsNoCompile(
3995 Text: R"cpp(
3996 // Absolutely qualified completion.
3997 using namespace a;
3998 namespace ns {
3999 using namespace b;
4000 void foo() {
4001 ::a::xx^
4002 }
4003 }
4004 )cpp",
4005 IndexSymbols: Syms, Opts);
4006 EXPECT_THAT(Results.Completions,
4007 ElementsAre(AllOf(qualifier(""), scope("a::"))));
4008}
4009
4010TEST(AllowImplicitCompletion, All) {
4011 const char *Yes[] = {
4012 "foo.^bar",
4013 "foo->^bar",
4014 "foo::^bar",
4015 " # include <^foo.h>",
4016 "#import <foo/^bar.h>",
4017 "#include_next \"^",
4018 };
4019 const char *No[] = {
4020 "foo>^bar",
4021 "foo:^bar",
4022 "foo\n^bar",
4023 "#include <foo.h> //^",
4024 "#include \"foo.h\"^",
4025 "#error <^",
4026 "#<^",
4027 };
4028 for (const char *Test : Yes) {
4029 llvm::Annotations A(Test);
4030 EXPECT_TRUE(allowImplicitCompletion(A.code(), A.point())) << Test;
4031 }
4032 for (const char *Test : No) {
4033 llvm::Annotations A(Test);
4034 EXPECT_FALSE(allowImplicitCompletion(A.code(), A.point())) << Test;
4035 }
4036}
4037
4038TEST(CompletionTest, FunctionArgsExist) {
4039 clangd::CodeCompleteOptions Opts;
4040 Opts.EnableSnippets = true;
4041 std::string Context = R"cpp(
4042 #define MACRO(x)
4043 int foo(int A);
4044 int bar();
4045 struct Object {
4046 Object(int B) {}
4047 };
4048 template <typename T>
4049 struct Container {
4050 Container(int Size) {}
4051 };
4052 )cpp";
4053 EXPECT_THAT(completions(Context + "int y = fo^", {}, Opts).Completions,
4054 UnorderedElementsAre(
4055 AllOf(labeled("foo(int A)"), snippetSuffix("(${1:int A})"))));
4056 EXPECT_THAT(
4057 completions(Context + "int y = fo^(42)", {}, Opts).Completions,
4058 UnorderedElementsAre(AllOf(labeled("foo(int A)"), snippetSuffix(""))));
4059 // FIXME(kirillbobyrev): No snippet should be produced here.
4060 EXPECT_THAT(completions(Context + "int y = fo^o(42)", {}, Opts).Completions,
4061 UnorderedElementsAre(
4062 AllOf(labeled("foo(int A)"), snippetSuffix("(${1:int A})"))));
4063 EXPECT_THAT(
4064 completions(Context + "int y = ba^", {}, Opts).Completions,
4065 UnorderedElementsAre(AllOf(labeled("bar()"), snippetSuffix("()"))));
4066 EXPECT_THAT(completions(Context + "int y = ba^()", {}, Opts).Completions,
4067 UnorderedElementsAre(AllOf(labeled("bar()"), snippetSuffix(""))));
4068 EXPECT_THAT(
4069 completions(Context + "Object o = Obj^", {}, Opts).Completions,
4070 Contains(AllOf(labeled("Object(int B)"), snippetSuffix("(${1:int B})"),
4071 kind(CompletionItemKind::Constructor))));
4072 EXPECT_THAT(completions(Context + "Object o = Obj^()", {}, Opts).Completions,
4073 Contains(AllOf(labeled("Object(int B)"), snippetSuffix(""),
4074 kind(CompletionItemKind::Constructor))));
4075 EXPECT_THAT(
4076 completions(Context + "Container c = Cont^", {}, Opts).Completions,
4077 Contains(AllOf(labeled("Container<typename T>(int Size)"),
4078 snippetSuffix("<${1:typename T}>(${2:int Size})"),
4079 kind(CompletionItemKind::Constructor))));
4080 EXPECT_THAT(
4081 completions(Context + "Container c = Cont^()", {}, Opts).Completions,
4082 Contains(AllOf(labeled("Container<typename T>(int Size)"),
4083 snippetSuffix("<${1:typename T}>"),
4084 kind(CompletionItemKind::Constructor))));
4085 EXPECT_THAT(
4086 completions(Context + "Container c = Cont^<int>()", {}, Opts).Completions,
4087 Contains(AllOf(labeled("Container<typename T>(int Size)"),
4088 snippetSuffix(""),
4089 kind(CompletionItemKind::Constructor))));
4090 EXPECT_THAT(completions(Context + "MAC^(2)", {}, Opts).Completions,
4091 Contains(AllOf(labeled("MACRO(x)"), snippetSuffix(""),
4092 kind(CompletionItemKind::Function))));
4093}
4094
4095TEST(CompletionTest, FunctionArgsExist_Issue1785) {
4096 // This is a scenario where the implementation of our check for
4097 // "is there a function argument list right after the cursor"
4098 // gave a bogus result.
4099 clangd::CodeCompleteOptions Opts;
4100 Opts.EnableSnippets = true;
4101 // The whitespace in this testcase is important!
4102 std::string Code = R"cpp(
4103void waldo(int);
4104
4105int main()
4106{
4107 wal^
4108
4109
4110 // ( )
4111}
4112 )cpp";
4113 EXPECT_THAT(
4114 completions(Code, {}, Opts).Completions,
4115 Contains(AllOf(labeled("waldo(int)"), snippetSuffix("(${1:int})"))));
4116}
4117
4118TEST(CompletionTest, NoCrashDueToMacroOrdering) {
4119 EXPECT_THAT(completions(R"cpp(
4120 #define ECHO(X) X
4121 #define ECHO2(X) ECHO(X)
4122 int finish_preamble = EC^HO(2);)cpp")
4123 .Completions,
4124 UnorderedElementsAre(labeled("ECHO(X)"), labeled("ECHO2(X)")));
4125}
4126
4127TEST(CompletionTest, ObjCCategoryDecls) {
4128 TestTU TU;
4129 TU.ExtraArgs.push_back(x: "-xobjective-c");
4130 TU.HeaderCode = R"objc(
4131 @interface Foo
4132 @end
4133
4134 @interface Foo (FooExt1)
4135 @end
4136
4137 @interface Foo (FooExt2)
4138 @end
4139
4140 @interface Bar
4141 @end
4142
4143 @interface Bar (BarExt)
4144 @end)objc";
4145
4146 {
4147 Annotations Test(R"objc(
4148 @implementation Foo (^)
4149 @end
4150 )objc");
4151 TU.Code = Test.code().str();
4152 auto Results = completions(TU, Point: Test.point());
4153 EXPECT_THAT(Results.Completions,
4154 UnorderedElementsAre(labeled("FooExt1"), labeled("FooExt2")));
4155 }
4156 {
4157 Annotations Test(R"objc(
4158 @interface Foo (^)
4159 @end
4160 )objc");
4161 TU.Code = Test.code().str();
4162 auto Results = completions(TU, Point: Test.point());
4163 EXPECT_THAT(Results.Completions, UnorderedElementsAre(labeled("BarExt")));
4164 }
4165}
4166
4167TEST(CompletionTest, PreambleCodeComplete) {
4168 llvm::StringLiteral Baseline = "\n#define MACRO 12\nint num = MACRO;";
4169 llvm::StringLiteral ModifiedCC =
4170 "#include \"header.h\"\n#define MACRO 12\nint num = MACRO; int num2 = M^";
4171
4172 Annotations Test(ModifiedCC);
4173 auto BaselineTU = TestTU::withCode(Code: Baseline);
4174 auto ModifiedTU = TestTU::withCode(Code: Test.code());
4175
4176 MockFS FS;
4177 auto Inputs = ModifiedTU.inputs(FS);
4178 auto Result = codeComplete(FileName: testPath(File: ModifiedTU.Filename), Pos: Test.point(),
4179 Preamble: BaselineTU.preamble().get(), ParseInput: Inputs, Opts: {});
4180 EXPECT_THAT(Result.Completions, Not(testing::IsEmpty()));
4181}
4182
4183TEST(CompletionTest, CommentParamName) {
4184 const std::string Code = R"cpp(
4185 void fun(int foo, int bar);
4186 void overloaded(int param_int);
4187 void overloaded(int param_int, int param_other);
4188 void overloaded(char param_char);
4189 int main() {
4190 )cpp";
4191
4192 EXPECT_THAT(completions(Code + "fun(/*^").Completions,
4193 UnorderedElementsAre(labeled("foo=*/")));
4194 EXPECT_THAT(completions(Code + "fun(1, /*^").Completions,
4195 UnorderedElementsAre(labeled("bar=*/")));
4196 EXPECT_THAT(completions(Code + "/*^").Completions, IsEmpty());
4197 // Test de-duplication.
4198 EXPECT_THAT(
4199 completions(Code + "overloaded(/*^").Completions,
4200 UnorderedElementsAre(labeled("param_int=*/"), labeled("param_char=*/")));
4201 // Comment already has some text in it.
4202 EXPECT_THAT(completions(Code + "fun(/* ^").Completions,
4203 UnorderedElementsAre(labeled("foo=*/")));
4204 EXPECT_THAT(completions(Code + "fun(/* f^").Completions,
4205 UnorderedElementsAre(labeled("foo=*/")));
4206 EXPECT_THAT(completions(Code + "fun(/* x^").Completions, IsEmpty());
4207 EXPECT_THAT(completions(Code + "fun(/* f ^").Completions, IsEmpty());
4208
4209 // Test ranges
4210 {
4211 std::string CompletionRangeTest(Code + "fun(/*[[^]]");
4212 auto Results = completions(Text: CompletionRangeTest);
4213 EXPECT_THAT(Results.CompletionRange,
4214 llvm::ValueIs(Annotations(CompletionRangeTest).range()));
4215 EXPECT_THAT(
4216 Results.Completions,
4217 testing::Each(
4218 AllOf(replacesRange(Annotations(CompletionRangeTest).range()),
4219 origin(SymbolOrigin::AST), kind(CompletionItemKind::Text))));
4220 }
4221 {
4222 std::string CompletionRangeTest(Code + "fun(/*[[fo^]]");
4223 auto Results = completions(Text: CompletionRangeTest);
4224 EXPECT_THAT(Results.CompletionRange,
4225 llvm::ValueIs(Annotations(CompletionRangeTest).range()));
4226 EXPECT_THAT(
4227 Results.Completions,
4228 testing::Each(
4229 AllOf(replacesRange(Annotations(CompletionRangeTest).range()),
4230 origin(SymbolOrigin::AST), kind(CompletionItemKind::Text))));
4231 }
4232}
4233
4234TEST(CompletionTest, Concepts) {
4235 Annotations Code(R"cpp(
4236 template<class T>
4237 concept A = sizeof(T) <= 8;
4238
4239 template<$tparam^A U>
4240 int foo();
4241
4242 template<typename T>
4243 int bar(T t) requires $expr^A<int>;
4244
4245 template<class T>
4246 concept b = $expr^A && $expr^sizeof(T) % 2 == 0 || $expr^A && sizeof(T) == 1;
4247
4248 $toplevel^A auto i = 19;
4249
4250 template<$toplevel^A auto i> void constrainedNTTP();
4251
4252 // FIXME: The first parameter should be dropped in this case.
4253 void abbreviated($expr^A auto x) {}
4254 )cpp");
4255 TestTU TU;
4256 TU.Code = Code.code().str();
4257 TU.ExtraArgs = {"-std=c++20"};
4258
4259 auto Sym = conceptSym(Name: "same_as");
4260 Sym.Signature = "<typename Tp, typename Up>";
4261 Sym.CompletionSnippetSuffix = "<${1:typename Tp}, ${2:typename Up}>";
4262 std::vector<Symbol> Syms = {Sym};
4263 for (auto P : Code.points(Name: "tparam")) {
4264 ASSERT_THAT(
4265 completions(TU, P, Syms).Completions,
4266 AllOf(Contains(AllOf(named("A"), signature(""), snippetSuffix(""))),
4267 Contains(AllOf(named("same_as"), signature("<typename Up>"),
4268 snippetSuffix("<${2:typename Up}>"))),
4269 Contains(named("class")), Contains(named("typename"))))
4270 << "Completing template parameter at position " << P;
4271 }
4272
4273 for (auto P : Code.points(Name: "toplevel")) {
4274 EXPECT_THAT(
4275 completions(TU, P, Syms).Completions,
4276 AllOf(Contains(AllOf(named("A"), signature(""), snippetSuffix(""))),
4277 Contains(AllOf(named("same_as"), signature("<typename Up>"),
4278 snippetSuffix("<${2:typename Up}>")))))
4279 << "Completing 'requires' expression at position " << P;
4280 }
4281
4282 for (auto P : Code.points(Name: "expr")) {
4283 EXPECT_THAT(
4284 completions(TU, P, Syms).Completions,
4285 AllOf(Contains(AllOf(named("A"), signature("<class T>"),
4286 snippetSuffix("<${1:class T}>"))),
4287 Contains(AllOf(
4288 named("same_as"), signature("<typename Tp, typename Up>"),
4289 snippetSuffix("<${1:typename Tp}, ${2:typename Up}>")))))
4290 << "Completing 'requires' expression at position " << P;
4291 }
4292}
4293
4294TEST(SignatureHelp, DocFormat) {
4295 Annotations Code(R"cpp(
4296 // Comment `with` markup.
4297 void foo(int);
4298 void bar() { foo(^); }
4299 )cpp");
4300 for (auto DocumentationFormat :
4301 {MarkupKind::PlainText, MarkupKind::Markdown}) {
4302 auto Sigs = signatures(Text: Code.code(), Point: Code.point(), /*IndexSymbols=*/{},
4303 DocumentationFormat);
4304 ASSERT_EQ(Sigs.signatures.size(), 1U);
4305 EXPECT_EQ(Sigs.signatures[0].documentation.kind, DocumentationFormat);
4306 }
4307}
4308
4309TEST(SignatureHelp, TemplateArguments) {
4310 std::string Top = R"cpp(
4311 template <typename T, int> bool foo(char);
4312 template <int I, int> bool foo(float);
4313 )cpp";
4314
4315 auto First = signatures(Text: Top + "bool x = foo<^");
4316 EXPECT_THAT(
4317 First.signatures,
4318 UnorderedElementsAre(sig("foo<[[typename T]], [[int]]>() -> bool"),
4319 sig("foo<[[int I]], [[int]]>() -> bool")));
4320 EXPECT_EQ(First.activeParameter, 0);
4321
4322 auto Second = signatures(Text: Top + "bool x = foo<1, ^");
4323 EXPECT_THAT(Second.signatures,
4324 ElementsAre(sig("foo<[[int I]], [[int]]>() -> bool")));
4325 EXPECT_EQ(Second.activeParameter, 1);
4326}
4327
4328TEST(CompletionTest, DoNotCrash) {
4329 llvm::StringLiteral Cases[] = {
4330 R"cpp(
4331 template <typename = int> struct Foo {};
4332 auto a = [x(3)](Foo<^>){};
4333 )cpp",
4334 };
4335 for (auto Case : Cases) {
4336 SCOPED_TRACE(Case);
4337 auto Completions = completions(Text: Case);
4338 }
4339}
4340TEST(CompletionTest, PreambleFromDifferentTarget) {
4341 constexpr std::string_view PreambleTarget = "x86_64";
4342 constexpr std::string_view Contents =
4343 "int foo(int); int num; int num2 = foo(n^";
4344
4345 Annotations Test(Contents);
4346 auto TU = TestTU::withCode(Code: Test.code());
4347 TU.ExtraArgs.emplace_back(args: "-target");
4348 TU.ExtraArgs.emplace_back(args: PreambleTarget);
4349 auto Preamble = TU.preamble();
4350 ASSERT_TRUE(Preamble);
4351 // Switch target to wasm.
4352 TU.ExtraArgs.pop_back();
4353 TU.ExtraArgs.emplace_back(args: "wasm32");
4354
4355 MockFS FS;
4356 auto Inputs = TU.inputs(FS);
4357 auto Result = codeComplete(FileName: testPath(File: TU.Filename), Pos: Test.point(),
4358 Preamble: Preamble.get(), ParseInput: Inputs, Opts: {});
4359 auto Signatures =
4360 signatureHelp(FileName: testPath(File: TU.Filename), Pos: Test.point(), Preamble: *Preamble, ParseInput: Inputs, DocumentationFormat: {});
4361
4362 // Make sure we don't crash.
4363 EXPECT_THAT(Result.Completions, Not(testing::IsEmpty()));
4364 EXPECT_THAT(Signatures.signatures, Not(testing::IsEmpty()));
4365}
4366} // namespace
4367} // namespace clangd
4368} // namespace clang
4369

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of clang-tools-extra/clangd/unittests/CodeCompleteTests.cpp