4698 lines · cpp
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-exception6//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(named(std::move(Name)));101}102Matcher<const std::vector<CodeCompletion> &> has(std::string Name,103 CompletionItemKind K) {104 return Contains(AllOf(named(std::move(Name)), kind(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(Sym);113 return MemIndex::build(std::move(Slab).build(), RefSlab(), 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(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, Diags);132 if (!CI) {133 ADD_FAILURE() << "Couldn't build CompilerInvocation";134 return {};135 }136 auto Preamble = buildPreamble(testPath(TU.Filename), *CI, Inputs,137 /*InMemory=*/true, /*Callback=*/nullptr);138 return codeComplete(testPath(TU.Filename), Point, Preamble.get(), 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(Test.code());149 // To make sure our tests for completiopns inside templates work on Windows.150 TU.Filename = FilePath.str();151 return completions(TU, Test.point(), std::move(IndexSymbols),152 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(std::move(IndexSymbols));164 Opts.Index = OverrideIndex.get();165 }166 167 MockFS FS;168 Annotations Test(Text);169 ParseInputs ParseInput{tooling::CompileCommand(), &FS, Test.code().str()};170 return codeComplete(FilePath, 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_FOREST180TEST(DecisionForestRankingModel, NameMatchSanityTest) {181 clangd::CodeCompleteOptions Opts;182 Opts.RankingModel = CodeCompleteOptions::DecisionForest;183 auto Results = completions(184 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_FOREST214 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(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(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(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 MotorCar263 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("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 R"cpp(288 int global_var;289 290 int global_func();291 292 // Make sure this is not in preamble.293 #define MACRO X294 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 {cls("IndexClass"), var("index_var"), func("index_func")}, Opts);316 317 EXPECT_TRUE(Results.RanParser);318 // Class members. The only items that must be present in after-dot319 // 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-dot332 // 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 R"cpp(342 int global_var;343 int global_func();344 345 // Make sure this is not in preamble.346 #define MACRO X347 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 {cls("IndexClass"), var("index_var"), func("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(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(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(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(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/1451470TEST(CompletionTest, QualificationWithInlineNamespace) {471 auto Results = completions(R"cpp(472 namespace a { inline namespace b {} }473 using namespace a::b;474 void f() { Foo^ }475 )cpp",476 {cls("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 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());584 585 for (const auto &P : Code.points("canNotBeCall")) {586 auto Results = completions(TU, 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("canBeCall")) {600 auto Results = completions(TU, 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 snippet611 for (const auto &P : Code.points()) {612 auto Results = completions(TU, 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 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("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(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(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 R"cpp(668 int variable;669 struct Struct {};670 int function();671 // make sure MACRO is not included in preamble.672 #define MACRO 10673 int X = ^674 )cpp",675 {func("indexFunction"), var("indexVariable"), cls("indexClass"),676 macro("indexObjMacro"), macro("indexFuncMacro", "(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("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 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 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 R"cpp(734 enum Color {735 Red736 };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 R"cpp(747 class Adapter {748 };749 750 void f() {751 Adapter^752 }753 )cpp",754 {cls("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 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 R"cpp(774 namespace fake { int Babble, Box; };775 int main() { fake::ba^ }776 ")cpp",777 {var("fake::BigBang")});778 EXPECT_THAT(Results.Completions,779 ElementsAre(named("Babble"), named("BigBang")));780}781 782TEST(CompletionTest, ScopedWithFilter) {783 auto Results = completions(784 R"cpp(785 void f() { ns::x^ }786 )cpp",787 {cls("ns::XYZ"), func("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(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 R"cpp(819 void f() { ::^ }820 )cpp",821 {cls("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 R"cpp(830 namespace ns { void bar(); }831 void f() { ::ns::^ }832 )cpp",833 {cls("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 R"cpp(842 namespace ns { int local; void both(); }843 void f() { ::ns::^ }844 )cpp",845 {func("ns::both"), cls("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 R"cpp(860 namespace ns { int local; void both(); }861 void f() { ::ns::^ }862 )cpp",863 {func("ns::both"), cls("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("-I" + testPath("sub"));871 TU.AdditionalFiles["sub/bar.h"] = "";872 auto BarURI = URI::create(testPath("sub/bar.h")).toString();873 874 Symbol Sym = cls("ns::X");875 Sym.CanonicalDeclaration.FileURI = BarURI.c_str();876 Sym.IncludeHeaders.emplace_back(BarURI, 1, 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, Test.point(), {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, Test.point(), {Sym}, 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, Test.point(), {Sym});896 EXPECT_THAT(Results.Completions, ElementsAre(AllOf(named("X"), labeled("X"),897 Not(insertInclude()))));898}899 900TEST(CompletionTest, NoIncludeInsertionWhenDeclFoundInFile) {901 Symbol SymX = cls("ns::X");902 Symbol SymY = cls("ns::Y");903 std::string BarHeader = testPath("bar.h");904 auto BarURI = URI::create(BarHeader).toString();905 SymX.CanonicalDeclaration.FileURI = BarURI.c_str();906 SymY.CanonicalDeclaration.FileURI = BarURI.c_str();907 SymX.IncludeHeaders.emplace_back("<bar>", 1, Symbol::Include);908 SymY.IncludeHeaders.emplace_back("<bar>", 1, Symbol::Include);909 // Shorten include path based on search directory and insert.910 auto Results = completions(R"cpp(911 namespace ns {912 class X;913 class Y {};914 }915 int main() { ns::^ }916 )cpp",917 {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("-I" + testPath("sub"));926 TU.AdditionalFiles["sub/bar.h"] = "";927 auto BarURI = URI::create(testPath("sub/bar.h")).toString();928 929 Symbol Sym = cls("ns::X");930 Sym.CanonicalDeclaration.FileURI = BarURI.c_str();931 Sym.IncludeHeaders.emplace_back(BarURI, 1, Symbol::Include);932 Annotations Test("int main() { ns::^ }");933 TU.Code = Test.code().str();934 auto Results = completions(TU, Test.point(), {Sym});935 // Default for a local path is quoted include936 EXPECT_THAT(Results.Completions,937 ElementsAre(AllOf(named("X"), insertInclude("\"bar.h\""))));938 {939 Config C;940 C.Style.AngledHeaders.push_back(941 [](auto header) { return header.contains("bar.h"); });942 WithContextValue WithCfg(Config::Key, std::move(C));943 Results = completions(TU, Test.point(), {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 [](auto header) { return header.contains("bar.h"); });951 WithContextValue WithCfg(Config::Key, std::move(C));952 Results = completions(TU, Test.point(), {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(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({var("ns::index")});971 Opts.Index = I.get();972 auto WithIndex = completions(TU, Test.point(), {}, Opts);973 EXPECT_THAT(WithIndex.Completions,974 UnorderedElementsAre(named("local"), named("index")));975 auto ClassFromPreamble = completions(TU, Test.point("2"), {}, Opts);976 EXPECT_THAT(ClassFromPreamble.Completions, Contains(named("member")));977 978 Opts.Index = nullptr;979 auto WithoutIndex = completions(TU, Test.point(), {}, 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 and986// try to complete inside it, clang kicks our completion point just outside the987// preamble, resulting in always getting top-level completions.988TEST(CompletionTest, CompletionInPreamble) {989 auto Results = completions(R"cpp(990 #ifnd^ef FOO_H_991 #define BAR_H_992 #include <bar.h>993 int foo() {}994 #endif995 )cpp")996 .Completions;997 EXPECT_THAT(Results, ElementsAre(named("ifndef")));998}999 1000TEST(CompletionTest, CompletionRecoveryASTType) {1001 auto Results = completions(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("foo_header.h")] = R"cpp(1020 #pragma once1021 struct Foo {1022 // Member doc1023 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(testPath("foo_impl.cpp"), FileContent);1033 // Wait for the dynamic index being built.1034 ASSERT_TRUE(Server.blockUntilIdleForTest());1035 1036 auto File = testPath("foo.cpp");1037 Annotations Test("Foo^ foo;");1038 runAddDocument(Server, File, Test.code());1039 auto CompletionList =1040 llvm::cantFail(runCodeComplete(Server, File, Test.point(), {}));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("foo.h")] = R"cpp(1055 namespace ns { class XYZ {}; void foo(int x) {} }1056 )cpp";1057 runAddDocument(Server, testPath("foo.cpp"), R"cpp(1058 #include "foo.h"1059 )cpp");1060 1061 auto File = testPath("bar.cpp");1062 Annotations Test(R"cpp(1063 namespace ns {1064 class XXX {};1065 /// Doooc1066 void fooooo() {}1067 }1068 void f() { ns::^ }1069 )cpp");1070 runAddDocument(Server, File, Test.code());1071 1072 auto Results = cantFail(runCodeComplete(Server, File, Test.point(), {}));1073 // "XYZ" and "foo" are not included in the file being completed but are still1074 // 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 R"cpp(1086 // Non-doxygen comment.1087 __attribute__((annotate("custom_annotation"))) int foo();1088 /// Doxygen comment.1089 /// \param int a1090 int bar(int a);1091 /* Multi-line1092 block comment1093 */1094 int baz();1095 1096 int x = ^1097 )cpp");1098 EXPECT_THAT(1099 Results.Completions,1100 Contains(1101 AllOf(named("foo"),1102 doc("Annotation: custom_annotation\n\nNon-doxygen comment."))));1103 EXPECT_THAT(1104 Results.Completions,1105 Contains(AllOf(named("bar"), doc("Doxygen comment.\n\\param int a"))));1106 EXPECT_THAT(Results.Completions,1107 Contains(AllOf(named("baz"), doc("Multi-line block comment"))));1108}1109 1110TEST(CompletionTest, CommentsFromSystemHeaders) {1111 MockFS FS;1112 MockCompilationDatabase CDB;1113 1114 auto Opts = ClangdServer::optsForTest();1115 Opts.BuildDynamicSymbolIndex = true;1116 1117 ClangdServer Server(CDB, FS, Opts);1118 1119 FS.Files[testPath("foo.h")] = R"cpp(1120 #pragma GCC system_header1121 1122 // This comment should be retained!1123 int foo();1124 )cpp";1125 1126 auto File = testPath("foo.cpp");1127 Annotations Test(R"cpp(1128#include "foo.h"1129int x = foo^1130 )cpp");1131 runAddDocument(Server, File, Test.code());1132 auto CompletionList =1133 llvm::cantFail(runCodeComplete(Server, File, Test.point(), {}));1134 1135 EXPECT_THAT(1136 CompletionList.Completions,1137 Contains(AllOf(named("foo"), doc("This comment should be retained!"))));1138}1139 1140TEST(CompletionTest, CommentsOnMembersFromHeader) {1141 MockFS FS;1142 MockCompilationDatabase CDB;1143 1144 auto Opts = ClangdServer::optsForTest();1145 Opts.BuildDynamicSymbolIndex = true;1146 1147 ClangdServer Server(CDB, FS, Opts);1148 1149 FS.Files[testPath("foo.h")] = R"cpp(1150 struct alpha {1151 /// This is a member field.1152 int gamma;1153 1154 /// This is a member function.1155 int delta();1156 };1157 1158 template <typename T>1159 struct beta {1160 /// This is a member field inside a template.1161 int omega;1162 1163 /// This is a member function inside a template.1164 int epsilon();1165 };1166 )cpp";1167 1168 auto File = testPath("foo.cpp");1169 Annotations Test(R"cpp(1170#include "foo.h"1171alpha a;1172beta<int> b;1173int x = a.$p1^;1174int y = b.$p2^;1175 )cpp");1176 runAddDocument(Server, File, Test.code());1177 auto CompletionList =1178 llvm::cantFail(runCodeComplete(Server, File, Test.point("p1"), {}));1179 1180 EXPECT_THAT(CompletionList.Completions,1181 Contains(AllOf(named("gamma"), doc("This is a member field."))));1182 EXPECT_THAT(1183 CompletionList.Completions,1184 Contains(AllOf(named("delta"), doc("This is a member function."))));1185 1186 CompletionList =1187 llvm::cantFail(runCodeComplete(Server, File, Test.point("p2"), {}));1188 1189 EXPECT_THAT(CompletionList.Completions,1190 Contains(AllOf(named("omega")1191 /* FIXME: Doc retrieval does not work yet*/)));1192 EXPECT_THAT(1193 CompletionList.Completions,1194 Contains(AllOf(named("epsilon"),1195 doc("This is a member function inside a template."))));1196}1197 1198TEST(CompletionTest, CommentsOnMembersFromHeaderOverloadBundling) {1199 using testing::AnyOf;1200 MockFS FS;1201 MockCompilationDatabase CDB;1202 1203 auto Opts = ClangdServer::optsForTest();1204 Opts.BuildDynamicSymbolIndex = true;1205 1206 ClangdServer Server(CDB, FS, Opts);1207 1208 FS.Files[testPath("foo.h")] = R"cpp(1209 struct alpha {1210 /// bool overload.1211 int delta(bool b);1212 1213 /// int overload.1214 int delta(int i);1215 1216 void epsilon(long l);1217 1218 /// This one has a comment.1219 void epsilon(int i);1220 };1221 )cpp";1222 1223 auto File = testPath("foo.cpp");1224 Annotations Test(R"cpp(1225#include "foo.h"1226alpha a;1227int x = a.^1228 )cpp");1229 runAddDocument(Server, File, Test.code());1230 clangd::CodeCompleteOptions CCOpts;1231 CCOpts.BundleOverloads = true;1232 auto CompletionList =1233 llvm::cantFail(runCodeComplete(Server, File, Test.point(), CCOpts));1234 1235 EXPECT_THAT(1236 CompletionList.Completions,1237 Contains(AllOf(named("epsilon"), doc("This one has a comment."))));1238 EXPECT_THAT(CompletionList.Completions,1239 Contains(AllOf(named("delta"), AnyOf(doc("bool overload."),1240 doc("int overload.")))));1241}1242 1243TEST(CompletionTest, GlobalCompletionFiltering) {1244 1245 Symbol Class = cls("XYZ");1246 Class.Flags = static_cast<Symbol::SymbolFlag>(1247 Class.Flags & ~(Symbol::IndexedForCodeCompletion));1248 Symbol Func = func("XYZ::foooo");1249 Func.Flags = static_cast<Symbol::SymbolFlag>(1250 Func.Flags & ~(Symbol::IndexedForCodeCompletion));1251 1252 auto Results = completions(R"(// void f() {1253 XYZ::foooo^1254 })",1255 {Class, Func});1256 EXPECT_THAT(Results.Completions, IsEmpty());1257}1258 1259TEST(CodeCompleteTest, DisableTypoCorrection) {1260 auto Results = completions(R"cpp(1261 namespace clang { int v; }1262 void f() { clangd::^1263 )cpp");1264 EXPECT_TRUE(Results.Completions.empty());1265}1266 1267TEST(CodeCompleteTest, NoColonColonAtTheEnd) {1268 auto Results = completions(R"cpp(1269 namespace clang { }1270 void f() {1271 clan^1272 }1273 )cpp");1274 1275 EXPECT_THAT(Results.Completions, Contains(labeled("clang")));1276 EXPECT_THAT(Results.Completions, Not(Contains(labeled("clang::"))));1277}1278 1279TEST(CompletionTests, EmptySnippetDoesNotCrash) {1280 // See https://github.com/clangd/clangd/issues/12161281 auto Results = completions(R"cpp(1282 int main() {1283 auto w = [&](auto &&f) { return f(f); };1284 auto f = w([&](auto &&f) {1285 return [&](auto &&n) {1286 if (n == 0) {1287 return 1;1288 }1289 return n * ^(f)(n - 1);1290 };1291 })(10);1292 }1293 )cpp");1294}1295 1296TEST(CompletionTest, Issue1427Crash) {1297 // Need to provide main file signals to ensure that the branch in1298 // SymbolRelevanceSignals::computeASTSignals() that tries to1299 // compute a symbol ID is taken.1300 ASTSignals MainFileSignals;1301 CodeCompleteOptions Opts;1302 Opts.MainFileSignals = &MainFileSignals;1303 completions(R"cpp(1304 auto f = []() {1305 1.0_^1306 };1307 )cpp",1308 {}, Opts);1309}1310 1311TEST(CompletionTest, BacktrackCrashes) {1312 // Sema calls code completion callbacks twice in these cases.1313 auto Results = completions(R"cpp(1314 namespace ns {1315 struct FooBarBaz {};1316 } // namespace ns1317 1318 int foo(ns::FooBar^1319 )cpp");1320 1321 EXPECT_THAT(Results.Completions, ElementsAre(labeled("FooBarBaz")));1322 1323 // Check we don't crash in that case too.1324 completions(R"cpp(1325 struct FooBarBaz {};1326 void test() {1327 if (FooBarBaz * x^) {}1328 }1329)cpp");1330}1331 1332TEST(CompletionTest, CompleteInMacroWithStringification) {1333 auto Results = completions(R"cpp(1334void f(const char *, int x);1335#define F(x) f(#x, x)1336 1337namespace ns {1338int X;1339int Y;1340} // namespace ns1341 1342int f(int input_num) {1343 F(ns::^)1344}1345)cpp");1346 1347 EXPECT_THAT(Results.Completions,1348 UnorderedElementsAre(named("X"), named("Y")));1349}1350 1351TEST(CompletionTest, CompleteInMacroAndNamespaceWithStringification) {1352 auto Results = completions(R"cpp(1353void f(const char *, int x);1354#define F(x) f(#x, x)1355 1356namespace ns {1357int X;1358 1359int f(int input_num) {1360 F(^)1361}1362} // namespace ns1363)cpp");1364 1365 EXPECT_THAT(Results.Completions, Contains(named("X")));1366}1367 1368TEST(CompletionTest, IgnoreCompleteInExcludedPPBranchWithRecoveryContext) {1369 auto Results = completions(R"cpp(1370 int bar(int param_in_bar) {1371 }1372 1373 int foo(int param_in_foo) {1374#if 01375 // In recovery mode, "param_in_foo" will also be suggested among many other1376 // unrelated symbols; however, this is really a special case where this works.1377 // If the #if block is outside of the function, "param_in_foo" is still1378 // suggested, but "bar" and "foo" are missing. So the recovery mode doesn't1379 // really provide useful results in excluded branches.1380 par^1381#endif1382 }1383)cpp");1384 1385 EXPECT_TRUE(Results.Completions.empty());1386}1387 1388TEST(CompletionTest, DefaultArgs) {1389 clangd::CodeCompleteOptions Opts;1390 std::string Context = R"cpp(1391 int X(int A = 0);1392 int Y(int A, int B = 0);1393 int Z(int A, int B = 0, int C = 0, int D = 0);1394 )cpp";1395 EXPECT_THAT(completions(Context + "int y = X^", {}, Opts).Completions,1396 UnorderedElementsAre(labeled("X(int A = 0)")));1397 EXPECT_THAT(completions(Context + "int y = Y^", {}, Opts).Completions,1398 UnorderedElementsAre(AllOf(labeled("Y(int A, int B = 0)"),1399 snippetSuffix("(${1:int A})"))));1400 EXPECT_THAT(completions(Context + "int y = Z^", {}, Opts).Completions,1401 UnorderedElementsAre(1402 AllOf(labeled("Z(int A, int B = 0, int C = 0, int D = 0)"),1403 snippetSuffix("(${1:int A})"))));1404}1405 1406TEST(CompletionTest, NoCrashWithTemplateParamsAndPreferredTypes) {1407 auto Completions = completions(R"cpp(1408template <template <class> class TT> int foo() {1409 int a = ^1410}1411)cpp")1412 .Completions;1413 EXPECT_THAT(Completions, Contains(named("TT")));1414}1415 1416TEST(CompletionTest, NestedTemplateHeuristics) {1417 auto Completions = completions(R"cpp(1418struct Plain { int xxx; };1419template <typename T> class Templ { Plain ppp; };1420template <typename T> void foo(Templ<T> &t) {1421 // Formally ppp has DependentTy, because Templ may be specialized.1422 // However we sholud be able to see into it using the primary template.1423 t.ppp.^1424}1425)cpp")1426 .Completions;1427 EXPECT_THAT(Completions, Contains(named("xxx")));1428}1429 1430TEST(CompletionTest, RecordCCResultCallback) {1431 std::vector<CodeCompletion> RecordedCompletions;1432 CodeCompleteOptions Opts;1433 Opts.RecordCCResult = [&RecordedCompletions](const CodeCompletion &CC,1434 const SymbolQualitySignals &,1435 const SymbolRelevanceSignals &,1436 float Score) {1437 RecordedCompletions.push_back(CC);1438 };1439 1440 completions("int xy1, xy2; int a = xy^", /*IndexSymbols=*/{}, Opts);1441 EXPECT_THAT(RecordedCompletions,1442 UnorderedElementsAre(named("xy1"), named("xy2")));1443}1444 1445TEST(CompletionTest, ASTSignals) {1446 struct Completion {1447 std::string Name;1448 unsigned MainFileRefs;1449 unsigned ScopeRefsInFile;1450 };1451 CodeCompleteOptions Opts;1452 std::vector<Completion> RecordedCompletions;1453 Opts.RecordCCResult = [&RecordedCompletions](const CodeCompletion &CC,1454 const SymbolQualitySignals &,1455 const SymbolRelevanceSignals &R,1456 float Score) {1457 RecordedCompletions.push_back({CC.Name, R.MainFileRefs, R.ScopeRefsInFile});1458 };1459 ASTSignals MainFileSignals;1460 MainFileSignals.ReferencedSymbols[var("xy1").ID] = 3;1461 MainFileSignals.ReferencedSymbols[var("xy2").ID] = 1;1462 MainFileSignals.ReferencedSymbols[var("xyindex").ID] = 10;1463 MainFileSignals.RelatedNamespaces["tar::"] = 5;1464 MainFileSignals.RelatedNamespaces["bar::"] = 3;1465 Opts.MainFileSignals = &MainFileSignals;1466 Opts.AllScopes = true;1467 completions(1468 R"cpp(1469 int xy1;1470 int xy2;1471 namespace bar {1472 int xybar = 1;1473 int a = xy^1474 }1475 )cpp",1476 /*IndexSymbols=*/{var("xyindex"), var("tar::xytar"), var("bar::xybar")},1477 Opts);1478 EXPECT_THAT(RecordedCompletions,1479 UnorderedElementsAre(1480 AllOf(named("xy1"), mainFileRefs(3u), scopeRefs(0u)),1481 AllOf(named("xy2"), mainFileRefs(1u), scopeRefs(0u)),1482 AllOf(named("xyindex"), mainFileRefs(10u), scopeRefs(0u)),1483 AllOf(named("xytar"), mainFileRefs(0u), scopeRefs(5u)),1484 AllOf(/*both from sema and index*/ named("xybar"),1485 mainFileRefs(0u), scopeRefs(3u))));1486}1487 1488SignatureHelp1489signatures(llvm::StringRef Text, Position Point,1490 std::vector<Symbol> IndexSymbols = {},1491 MarkupKind DocumentationFormat = MarkupKind::PlainText) {1492 std::unique_ptr<SymbolIndex> Index;1493 if (!IndexSymbols.empty())1494 Index = memIndex(IndexSymbols);1495 1496 auto TU = TestTU::withCode(Text);1497 MockFS FS;1498 auto Inputs = TU.inputs(FS);1499 Inputs.Index = Index.get();1500 IgnoreDiagnostics Diags;1501 auto CI = buildCompilerInvocation(Inputs, Diags);1502 if (!CI) {1503 ADD_FAILURE() << "Couldn't build CompilerInvocation";1504 return {};1505 }1506 auto Preamble = buildPreamble(testPath(TU.Filename), *CI, Inputs,1507 /*InMemory=*/true, /*Callback=*/nullptr);1508 if (!Preamble) {1509 ADD_FAILURE() << "Couldn't build Preamble";1510 return {};1511 }1512 return signatureHelp(testPath(TU.Filename), Point, *Preamble, Inputs,1513 DocumentationFormat);1514}1515 1516SignatureHelp1517signatures(llvm::StringRef Text, std::vector<Symbol> IndexSymbols = {},1518 MarkupKind DocumentationFormat = MarkupKind::PlainText) {1519 Annotations Test(Text);1520 return signatures(Test.code(), Test.point(), std::move(IndexSymbols),1521 DocumentationFormat);1522}1523 1524struct ExpectedParameter {1525 std::string Text;1526 std::pair<unsigned, unsigned> Offsets;1527};1528llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,1529 const ExpectedParameter &P) {1530 return OS << P.Text;1531}1532MATCHER_P(paramsAre, P, "") {1533 if (P.size() != arg.parameters.size())1534 return false;1535 for (unsigned I = 0; I < P.size(); ++I) {1536 if (P[I].Text != arg.parameters[I].labelString ||1537 P[I].Offsets != arg.parameters[I].labelOffsets)1538 return false;1539 }1540 return true;1541}1542MATCHER_P(sigDoc, doc, "") { return arg.documentation.value == doc; }1543 1544/// \p AnnotatedLabel is a signature label with ranges marking parameters, e.g.1545/// foo([[int p1]], [[double p2]]) -> void1546Matcher<SignatureInformation> sig(llvm::StringRef AnnotatedLabel) {1547 llvm::Annotations A(AnnotatedLabel);1548 std::string Label = std::string(A.code());1549 std::vector<ExpectedParameter> Parameters;1550 for (auto Range : A.ranges()) {1551 Parameters.emplace_back();1552 1553 ExpectedParameter &P = Parameters.back();1554 P.Text = Label.substr(Range.Begin, Range.End - Range.Begin);1555 P.Offsets.first = lspLength(llvm::StringRef(Label).substr(0, Range.Begin));1556 P.Offsets.second = lspLength(llvm::StringRef(Label).substr(1, Range.End));1557 }1558 return AllOf(sigHelpLabeled(Label), paramsAre(Parameters));1559}1560 1561TEST(SignatureHelpTest, Overloads) {1562 auto Results = signatures(R"cpp(1563 void foo(int x, int y);1564 void foo(int x, float y);1565 void foo(float x, int y);1566 void foo(float x, float y);1567 void bar(int x, int y = 0);1568 int main() { foo(^); }1569 )cpp");1570 EXPECT_THAT(Results.signatures,1571 UnorderedElementsAre(sig("foo([[float x]], [[float y]]) -> void"),1572 sig("foo([[float x]], [[int y]]) -> void"),1573 sig("foo([[int x]], [[float y]]) -> void"),1574 sig("foo([[int x]], [[int y]]) -> void")));1575 // We always prefer the first signature.1576 EXPECT_EQ(0, Results.activeSignature);1577 EXPECT_EQ(0, Results.activeParameter);1578}1579 1580TEST(SignatureHelpTest, FunctionPointers) {1581 llvm::StringLiteral Tests[] = {1582 // Variable of function pointer type1583 R"cpp(1584 void (*foo)(int x, int y);1585 int main() { foo(^); }1586 )cpp",1587 // Wrapped in an AttributedType1588 R"cpp(1589 void (__stdcall *foo)(int x, int y);1590 int main() { foo(^); }1591 )cpp",1592 // Another syntax for an AttributedType1593 R"cpp(1594 void (__attribute__(stdcall) *foo)(int x, int y);1595 int main() { foo(^); },1596 )cpp",1597 // Wrapped in a typedef1598 R"cpp(1599 typedef void (*fn)(int x, int y);1600 fn foo;1601 int main() { foo(^); }1602 )cpp",1603 // Wrapped in both a typedef and an AttributedTyped1604 R"cpp(1605 typedef void (__stdcall *fn)(int x, int y);1606 fn foo;1607 int main() { foo(^); }1608 )cpp",1609 // Field of function pointer type1610 R"cpp(1611 struct S {1612 void (*foo)(int x, int y);1613 };1614 S s;1615 int main() { s.foo(^); }1616 )cpp",1617 // Field of function pointer typedef type1618 R"cpp(1619 typedef void (*fn)(int x, int y);1620 struct S {1621 fn foo;1622 };1623 S s;1624 int main() { s.foo(^); }1625 )cpp"};1626 for (auto Test : Tests)1627 EXPECT_THAT(signatures(Test).signatures,1628 UnorderedElementsAre(sig("([[int x]], [[int y]]) -> void")));1629}1630 1631TEST(SignatureHelpTest, Constructors) {1632 std::string Top = R"cpp(1633 struct S {1634 S(int);1635 S(const S &) = delete;1636 };1637 )cpp";1638 1639 auto CheckParenInit = [&](std::string Init) {1640 EXPECT_THAT(signatures(Top + Init).signatures,1641 UnorderedElementsAre(sig("S([[int]])")))1642 << Init;1643 };1644 CheckParenInit("S s(^);");1645 CheckParenInit("auto s = S(^);");1646 CheckParenInit("auto s = new S(^);");1647 1648 auto CheckBracedInit = [&](std::string Init) {1649 EXPECT_THAT(signatures(Top + Init).signatures,1650 UnorderedElementsAre(sig("S{[[int]]}")))1651 << Init;1652 };1653 CheckBracedInit("S s{^};");1654 CheckBracedInit("S s = {^};");1655 CheckBracedInit("auto s = S{^};");1656 // FIXME: doesn't work: no ExpectedType set in ParseCXXNewExpression.1657 // CheckBracedInit("auto s = new S{^};");1658 CheckBracedInit("int x(S); int i = x({^});");1659}1660 1661TEST(SignatureHelpTest, Aggregates) {1662 std::string Top = R"cpp(1663 struct S {1664 int a, b, c, d;1665 };1666 )cpp";1667 auto AggregateSig = sig("S{[[int a]], [[int b]], [[int c]], [[int d]]}");1668 EXPECT_THAT(signatures(Top + "S s{^}").signatures,1669 UnorderedElementsAre(AggregateSig, sig("S{}"),1670 sig("S{[[const S &]]}"),1671 sig("S{[[S &&]]}")));1672 EXPECT_THAT(signatures(Top + "S s{1,^}").signatures,1673 ElementsAre(AggregateSig));1674 EXPECT_EQ(signatures(Top + "S s{1,^}").activeParameter, 1);1675 EXPECT_THAT(signatures(Top + "S s{.c=3,^}").signatures,1676 ElementsAre(AggregateSig));1677 EXPECT_EQ(signatures(Top + "S s{.c=3,^}").activeParameter, 3);1678}1679 1680TEST(SignatureHelpTest, OverloadInitListRegression) {1681 auto Results = signatures(R"cpp(1682 struct A {int x;};1683 struct B {B(A);};1684 void f();1685 int main() {1686 B b({1});1687 f(^);1688 }1689 )cpp");1690 EXPECT_THAT(Results.signatures, UnorderedElementsAre(sig("f() -> void")));1691}1692 1693TEST(SignatureHelpTest, DefaultArgs) {1694 auto Results = signatures(R"cpp(1695 void bar(int x, int y = 0);1696 void bar(float x = 0, int y = 42);1697 int main() { bar(^1698 )cpp");1699 EXPECT_THAT(Results.signatures,1700 UnorderedElementsAre(1701 sig("bar([[int x]], [[int y = 0]]) -> void"),1702 sig("bar([[float x = 0]], [[int y = 42]]) -> void")));1703 EXPECT_EQ(0, Results.activeSignature);1704 EXPECT_EQ(0, Results.activeParameter);1705}1706 1707TEST(SignatureHelpTest, ActiveArg) {1708 auto Results = signatures(R"cpp(1709 int baz(int a, int b, int c);1710 int main() { baz(baz(1,2,3), ^); }1711 )cpp");1712 EXPECT_THAT(Results.signatures,1713 ElementsAre(sig("baz([[int a]], [[int b]], [[int c]]) -> int")));1714 EXPECT_EQ(0, Results.activeSignature);1715 EXPECT_EQ(1, Results.activeParameter);1716}1717 1718TEST(SignatureHelpTest, OpeningParen) {1719 llvm::StringLiteral Tests[] = {1720 // Recursive function call.1721 R"cpp(1722 int foo(int a, int b, int c);1723 int main() {1724 foo(foo $p^( foo(10, 10, 10), ^ )));1725 })cpp",1726 // Functional type cast.1727 R"cpp(1728 struct Foo {1729 Foo(int a, int b, int c);1730 };1731 int main() {1732 Foo $p^( 10, ^ );1733 })cpp",1734 // New expression.1735 R"cpp(1736 struct Foo {1737 Foo(int a, int b, int c);1738 };1739 int main() {1740 new Foo $p^( 10, ^ );1741 })cpp",1742 // Macro expansion.1743 R"cpp(1744 int foo(int a, int b, int c);1745 #define FOO foo(1746 1747 int main() {1748 // Macro expansions.1749 $p^FOO 10, ^ );1750 })cpp",1751 // Macro arguments.1752 R"cpp(1753 int foo(int a, int b, int c);1754 int main() {1755 #define ID(X) X1756 // FIXME: figure out why ID(foo (foo(10), )) doesn't work when preserving1757 // the recovery expression.1758 ID(foo $p^( 10, ^ ))1759 })cpp",1760 // Dependent args.1761 R"cpp(1762 int foo(int a, int b);1763 template <typename T> void bar(T t) {1764 foo$p^(t, ^t);1765 })cpp",1766 // Dependent args on templated func.1767 R"cpp(1768 template <typename T>1769 int foo(T, T);1770 template <typename T> void bar(T t) {1771 foo$p^(t, ^t);1772 })cpp",1773 // Dependent args on member.1774 R"cpp(1775 struct Foo { int foo(int, int); };1776 template <typename T> void bar(T t) {1777 Foo f;1778 f.foo$p^(t, ^t);1779 })cpp",1780 // Dependent args on templated member.1781 R"cpp(1782 struct Foo { template <typename T> int foo(T, T); };1783 template <typename T> void bar(T t) {1784 Foo f;1785 f.foo$p^(t, ^t);1786 })cpp",1787 };1788 1789 for (auto Test : Tests) {1790 Annotations Code(Test);1791 EXPECT_EQ(signatures(Code.code(), Code.point()).argListStart,1792 Code.point("p"))1793 << "Test source:" << Test;1794 }1795}1796 1797TEST(SignatureHelpTest, StalePreamble) {1798 TestTU TU;1799 TU.Code = "";1800 IgnoreDiagnostics Diags;1801 MockFS FS;1802 auto Inputs = TU.inputs(FS);1803 auto CI = buildCompilerInvocation(Inputs, Diags);1804 ASSERT_TRUE(CI);1805 auto EmptyPreamble = buildPreamble(testPath(TU.Filename), *CI, Inputs,1806 /*InMemory=*/true, /*Callback=*/nullptr);1807 ASSERT_TRUE(EmptyPreamble);1808 1809 TU.AdditionalFiles["a.h"] = "int foo(int x);";1810 const Annotations Test(R"cpp(1811 #include "a.h"1812 void bar() { foo(^2); })cpp");1813 TU.Code = Test.code().str();1814 auto Results =1815 signatureHelp(testPath(TU.Filename), Test.point(), *EmptyPreamble,1816 TU.inputs(FS), MarkupKind::PlainText);1817 EXPECT_THAT(Results.signatures, ElementsAre(sig("foo([[int x]]) -> int")));1818 EXPECT_EQ(0, Results.activeSignature);1819 EXPECT_EQ(0, Results.activeParameter);1820}1821 1822class IndexRequestCollector : public SymbolIndex {1823public:1824 IndexRequestCollector(std::vector<Symbol> Syms = {}) : Symbols(Syms) {}1825 1826 bool1827 fuzzyFind(const FuzzyFindRequest &Req,1828 llvm::function_ref<void(const Symbol &)> Callback) const override {1829 std::unique_lock<std::mutex> Lock(Mut);1830 Requests.push_back(Req);1831 ReceivedRequestCV.notify_one();1832 for (const auto &Sym : Symbols)1833 Callback(Sym);1834 return true;1835 }1836 1837 void lookup(const LookupRequest &,1838 llvm::function_ref<void(const Symbol &)>) const override {}1839 1840 bool refs(const RefsRequest &,1841 llvm::function_ref<void(const Ref &)>) const override {1842 return false;1843 }1844 1845 bool containedRefs(1846 const ContainedRefsRequest &,1847 llvm::function_ref<void(const ContainedRefsResult &)>) const override {1848 return false;1849 }1850 1851 void relations(const RelationsRequest &,1852 llvm::function_ref<void(const SymbolID &, const Symbol &)>)1853 const override {}1854 1855 void1856 reverseRelations(const RelationsRequest &,1857 llvm::function_ref<void(const SymbolID &, const Symbol &)>)1858 const override {}1859 1860 llvm::unique_function<IndexContents(llvm::StringRef) const>1861 indexedFiles() const override {1862 return [](llvm::StringRef) { return IndexContents::None; };1863 }1864 1865 // This is incorrect, but IndexRequestCollector is not an actual index and it1866 // isn't used in production code.1867 size_t estimateMemoryUsage() const override { return 0; }1868 1869 const std::vector<FuzzyFindRequest> consumeRequests(size_t Num) const {1870 std::unique_lock<std::mutex> Lock(Mut);1871 EXPECT_TRUE(wait(Lock, ReceivedRequestCV, timeoutSeconds(30),1872 [this, Num] { return Requests.size() == Num; }));1873 auto Reqs = std::move(Requests);1874 Requests = {};1875 return Reqs;1876 }1877 1878private:1879 std::vector<Symbol> Symbols;1880 // We need a mutex to handle async fuzzy find requests.1881 mutable std::condition_variable ReceivedRequestCV;1882 mutable std::mutex Mut;1883 mutable std::vector<FuzzyFindRequest> Requests;1884};1885 1886// Clients have to consume exactly Num requests.1887std::vector<FuzzyFindRequest> captureIndexRequests(llvm::StringRef Code,1888 size_t Num = 1) {1889 clangd::CodeCompleteOptions Opts;1890 IndexRequestCollector Requests;1891 Opts.Index = &Requests;1892 completions(Code, {}, Opts);1893 const auto Reqs = Requests.consumeRequests(Num);1894 EXPECT_EQ(Reqs.size(), Num);1895 return Reqs;1896}1897 1898TEST(CompletionTest, UnqualifiedIdQuery) {1899 auto Requests = captureIndexRequests(R"cpp(1900 namespace std {}1901 using namespace std;1902 namespace ns {1903 void f() {1904 vec^1905 }1906 }1907 )cpp");1908 1909 EXPECT_THAT(Requests,1910 ElementsAre(Field(&FuzzyFindRequest::Scopes,1911 UnorderedElementsAre("", "ns::", "std::"))));1912}1913 1914TEST(CompletionTest, EnclosingScopeComesFirst) {1915 auto Requests = captureIndexRequests(R"cpp(1916 namespace std {}1917 using namespace std;1918 namespace nx {1919 namespace ns {1920 namespace {1921 void f() {1922 vec^1923 }1924 }1925 }1926 }1927 )cpp");1928 1929 EXPECT_THAT(Requests,1930 ElementsAre(Field(1931 &FuzzyFindRequest::Scopes,1932 UnorderedElementsAre("", "std::", "nx::ns::", "nx::"))));1933 EXPECT_EQ(Requests[0].Scopes[0], "nx::ns::");1934}1935 1936TEST(CompletionTest, ResolvedQualifiedIdQuery) {1937 auto Requests = captureIndexRequests(R"cpp(1938 namespace ns1 {}1939 namespace ns2 {} // ignore1940 namespace ns3 { namespace nns3 {} }1941 namespace foo {1942 using namespace ns1;1943 using namespace ns3::nns3;1944 }1945 namespace ns {1946 void f() {1947 foo::^1948 }1949 }1950 )cpp");1951 1952 EXPECT_THAT(Requests,1953 ElementsAre(Field(1954 &FuzzyFindRequest::Scopes,1955 UnorderedElementsAre("foo::", "ns1::", "ns3::nns3::"))));1956}1957 1958TEST(CompletionTest, UnresolvedQualifierIdQuery) {1959 auto Requests = captureIndexRequests(R"cpp(1960 namespace a {}1961 using namespace a;1962 namespace ns {1963 void f() {1964 bar::^1965 }1966 } // namespace ns1967 )cpp");1968 1969 EXPECT_THAT(Requests,1970 ElementsAre(Field(1971 &FuzzyFindRequest::Scopes,1972 UnorderedElementsAre("a::bar::", "ns::bar::", "bar::"))));1973}1974 1975TEST(CompletionTest, UnresolvedNestedQualifierIdQuery) {1976 auto Requests = captureIndexRequests(R"cpp(1977 namespace a {}1978 using namespace a;1979 namespace ns {1980 void f() {1981 ::a::bar::^1982 }1983 } // namespace ns1984 )cpp");1985 1986 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,1987 UnorderedElementsAre("a::bar::"))));1988}1989 1990TEST(CompletionTest, EmptyQualifiedQuery) {1991 auto Requests = captureIndexRequests(R"cpp(1992 namespace ns {1993 void f() {1994 ^1995 }1996 } // namespace ns1997 )cpp");1998 1999 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,2000 UnorderedElementsAre("", "ns::"))));2001}2002 2003TEST(CompletionTest, GlobalQualifiedQuery) {2004 auto Requests = captureIndexRequests(R"cpp(2005 namespace ns {2006 void f() {2007 ::^2008 }2009 } // namespace ns2010 )cpp");2011 2012 EXPECT_THAT(Requests, ElementsAre(Field(&FuzzyFindRequest::Scopes,2013 UnorderedElementsAre(""))));2014}2015 2016TEST(CompletionTest, NoDuplicatedQueryScopes) {2017 auto Requests = captureIndexRequests(R"cpp(2018 namespace {}2019 2020 namespace na {2021 namespace {}2022 namespace nb {2023 ^2024 } // namespace nb2025 } // namespace na2026 )cpp");2027 2028 EXPECT_THAT(Requests,2029 ElementsAre(Field(&FuzzyFindRequest::Scopes,2030 UnorderedElementsAre("na::", "na::nb::", ""))));2031}2032 2033TEST(CompletionTest, NoIndexCompletionsInsideClasses) {2034 auto Completions = completions(2035 R"cpp(2036 struct Foo {2037 int SomeNameOfField;2038 typedef int SomeNameOfTypedefField;2039 };2040 2041 Foo::^)cpp",2042 {func("::SomeNameInTheIndex"), func("::Foo::SomeNameInTheIndex")});2043 2044 EXPECT_THAT(Completions.Completions,2045 AllOf(Contains(labeled("SomeNameOfField")),2046 Contains(labeled("SomeNameOfTypedefField")),2047 Not(Contains(labeled("SomeNameInTheIndex")))));2048}2049 2050TEST(CompletionTest, NoIndexCompletionsInsideDependentCode) {2051 {2052 auto Completions = completions(2053 R"cpp(2054 template <class T>2055 void foo() {2056 T::^2057 }2058 )cpp",2059 {func("::SomeNameInTheIndex")});2060 2061 EXPECT_THAT(Completions.Completions,2062 Not(Contains(labeled("SomeNameInTheIndex"))));2063 }2064 2065 {2066 auto Completions = completions(2067 R"cpp(2068 template <class T>2069 void foo() {2070 T::template Y<int>::^2071 }2072 )cpp",2073 {func("::SomeNameInTheIndex")});2074 2075 EXPECT_THAT(Completions.Completions,2076 Not(Contains(labeled("SomeNameInTheIndex"))));2077 }2078 2079 {2080 auto Completions = completions(2081 R"cpp(2082 template <class T>2083 void foo() {2084 T::foo::^2085 }2086 )cpp",2087 {func("::SomeNameInTheIndex")});2088 2089 EXPECT_THAT(Completions.Completions,2090 Not(Contains(labeled("SomeNameInTheIndex"))));2091 }2092}2093 2094TEST(CompletionTest, OverloadBundling) {2095 clangd::CodeCompleteOptions Opts;2096 Opts.BundleOverloads = true;2097 2098 std::string Context = R"cpp(2099 struct X {2100 // Overload with int2101 int a(int) __attribute__((deprecated("", "")));2102 // Overload with bool2103 int a(bool);2104 int b(float);2105 2106 X(int);2107 X(float);2108 };2109 int GFuncC(int);2110 int GFuncD(int);2111 )cpp";2112 2113 // Member completions are bundled.2114 EXPECT_THAT(completions(Context + "int y = X().^", {}, Opts).Completions,2115 UnorderedElementsAre(labeled("a(…)"), labeled("b(float)")));2116 2117 // Constructor completions are bundled.2118 EXPECT_THAT(completions(Context + "X z = X^", {}, Opts).Completions,2119 UnorderedElementsAre(labeled("X"), labeled("X(…)")));2120 2121 // Non-member completions are bundled, including index+sema.2122 Symbol NoArgsGFunc = func("GFuncC");2123 EXPECT_THAT(2124 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,2125 UnorderedElementsAre(labeled("GFuncC(…)"), labeled("GFuncD(int)")));2126 2127 // Differences in header-to-insert suppress bundling.2128 std::string DeclFile = URI::create(testPath("foo")).toString();2129 NoArgsGFunc.CanonicalDeclaration.FileURI = DeclFile.c_str();2130 NoArgsGFunc.IncludeHeaders.emplace_back("<foo>", 1, Symbol::Include);2131 EXPECT_THAT(2132 completions(Context + "int y = GFunc^", {NoArgsGFunc}, Opts).Completions,2133 UnorderedElementsAre(AllOf(named("GFuncC"), insertInclude("<foo>")),2134 labeled("GFuncC(int)"), labeled("GFuncD(int)")));2135 2136 // Examine a bundled completion in detail.2137 auto A =2138 completions(Context + "int y = X().a^", {}, Opts).Completions.front();2139 EXPECT_EQ(A.Name, "a");2140 EXPECT_EQ(A.Signature, "(…)");2141 EXPECT_EQ(A.BundleSize, 2u);2142 EXPECT_EQ(A.Kind, CompletionItemKind::Method);2143 EXPECT_EQ(A.ReturnType, "int"); // All overloads return int.2144 // For now we just return one of the doc strings arbitrarily.2145 ASSERT_TRUE(A.Documentation);2146 ASSERT_FALSE(A.Deprecated); // Not all overloads deprecated.2147 EXPECT_THAT(2148 A.Documentation->asPlainText(),2149 AnyOf(HasSubstr("Overload with int"), HasSubstr("Overload with bool")));2150 EXPECT_EQ(A.SnippetSuffix, "($0)");2151}2152 2153TEST(CompletionTest, OverloadBundlingSameFileDifferentURI) {2154 clangd::CodeCompleteOptions Opts;2155 Opts.BundleOverloads = true;2156 2157 Symbol SymX = sym("ns::X", index::SymbolKind::Function, "@F@\\0#");2158 Symbol SymY = sym("ns::X", index::SymbolKind::Function, "@F@\\0#I#");2159 std::string BarHeader = testPath("bar.h");2160 auto BarURI = URI::create(BarHeader).toString();2161 SymX.CanonicalDeclaration.FileURI = BarURI.c_str();2162 SymY.CanonicalDeclaration.FileURI = BarURI.c_str();2163 // The include header is different, but really it's the same file.2164 SymX.IncludeHeaders.emplace_back("\"bar.h\"", 1, Symbol::Include);2165 SymY.IncludeHeaders.emplace_back(BarURI.c_str(), 1, Symbol::Include);2166 2167 auto Results = completions("void f() { ::ns::^ }", {SymX, SymY}, Opts);2168 // Expect both results are bundled, despite the different-but-same2169 // IncludeHeader.2170 ASSERT_EQ(1u, Results.Completions.size());2171 const auto &R = Results.Completions.front();2172 EXPECT_EQ("X", R.Name);2173 EXPECT_EQ(2u, R.BundleSize);2174}2175 2176TEST(CompletionTest, DocumentationFromChangedFileCrash) {2177 MockFS FS;2178 auto FooH = testPath("foo.h");2179 auto FooCpp = testPath("foo.cpp");2180 FS.Files[FooH] = R"cpp(2181 // this is my documentation comment.2182 int func();2183 )cpp";2184 FS.Files[FooCpp] = "";2185 2186 MockCompilationDatabase CDB;2187 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());2188 2189 Annotations Source(R"cpp(2190 #include "foo.h"2191 int func() {2192 // This makes sure we have func from header in the AST.2193 }2194 int a = fun^2195 )cpp");2196 Server.addDocument(FooCpp, Source.code(), "null", WantDiagnostics::Yes);2197 // We need to wait for preamble to build.2198 ASSERT_TRUE(Server.blockUntilIdleForTest());2199 2200 // Change the header file. Completion will reuse the old preamble!2201 FS.Files[FooH] = R"cpp(2202 int func();2203 )cpp";2204 2205 clangd::CodeCompleteOptions Opts;2206 CodeCompleteResult Completions =2207 cantFail(runCodeComplete(Server, FooCpp, Source.point(), Opts));2208 // We shouldn't crash. Unfortunately, current workaround is to not produce2209 // comments for symbols from headers.2210 EXPECT_THAT(Completions.Completions,2211 Contains(AllOf(Not(isDocumented()), named("func"))));2212}2213 2214TEST(CompletionTest, NonDocComments) {2215 const char *Text = R"cpp(2216 // We ignore namespace comments, for rationale see CodeCompletionStrings.h.2217 namespace comments_ns {2218 }2219 2220 // ------------------2221 int comments_foo();2222 2223 // A comment and a decl are separated by newlines.2224 // Therefore, the comment shouldn't show up as doc comment.2225 2226 int comments_bar();2227 2228 // this comment should be in the results.2229 int comments_baz();2230 2231 2232 template <class T>2233 struct Struct {2234 int comments_qux();2235 int comments_quux();2236 };2237 2238 2239 // This comment should not be there.2240 2241 template <class T>2242 int Struct<T>::comments_qux() {2243 }2244 2245 // This comment **should** be in results.2246 template <class T>2247 int Struct<T>::comments_quux() {2248 int a = comments^;2249 }2250 )cpp";2251 2252 // We should not get any of those comments in completion.2253 EXPECT_THAT(2254 completions(Text).Completions,2255 UnorderedElementsAre(AllOf(Not(isDocumented()), named("comments_foo")),2256 AllOf(isDocumented(), named("comments_baz")),2257 AllOf(isDocumented(), named("comments_quux")),2258 AllOf(Not(isDocumented()), named("comments_ns")),2259 // FIXME(ibiryukov): the following items should have2260 // empty documentation, since they are separated from2261 // a comment with an empty line. Unfortunately, I2262 // couldn't make Sema tests pass if we ignore those.2263 AllOf(isDocumented(), named("comments_bar")),2264 AllOf(isDocumented(), named("comments_qux"))));2265}2266 2267TEST(CompletionTest, CompleteOnInvalidLine) {2268 auto FooCpp = testPath("foo.cpp");2269 2270 MockCompilationDatabase CDB;2271 MockFS FS;2272 FS.Files[FooCpp] = "// empty file";2273 2274 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());2275 // Run completion outside the file range.2276 Position Pos;2277 Pos.line = 100;2278 Pos.character = 0;2279 EXPECT_THAT_EXPECTED(2280 runCodeComplete(Server, FooCpp, Pos, clangd::CodeCompleteOptions()),2281 Failed());2282}2283 2284TEST(CompletionTest, QualifiedNames) {2285 auto Results = completions(2286 R"cpp(2287 namespace ns { int local; void both(); }2288 void f() { ::ns::^ }2289 )cpp",2290 {func("ns::both"), cls("ns::Index")});2291 // We get results from both index and sema, with no duplicates.2292 EXPECT_THAT(2293 Results.Completions,2294 UnorderedElementsAre(scope("ns::"), scope("ns::"), scope("ns::")));2295}2296 2297TEST(CompletionTest, Render) {2298 CodeCompletion C;2299 C.Name = "x";2300 C.FilterText = "x";2301 C.Signature = "(bool) const";2302 C.SnippetSuffix = "(${0:bool})";2303 C.ReturnType = "int";2304 C.RequiredQualifier = "Foo::";2305 C.Scope = "ns::Foo::";2306 C.Documentation.emplace();2307 C.Documentation->addParagraph().appendText("This is ").appendCode("x()");2308 C.Includes.emplace_back();2309 auto &Include = C.Includes.back();2310 Include.Header = "\"foo.h\"";2311 C.Kind = CompletionItemKind::Method;2312 C.Score.Total = 1.0;2313 C.Score.ExcludingName = .5;2314 C.Origin = SymbolOrigin::AST | SymbolOrigin::Static;2315 2316 CodeCompleteOptions Opts;2317 Opts.IncludeIndicator.Insert = "^";2318 Opts.IncludeIndicator.NoInsert = "";2319 Opts.EnableSnippets = false;2320 2321 auto R = C.render(Opts);2322 EXPECT_EQ(R.label, "Foo::x");2323 EXPECT_EQ(R.labelDetails->detail, "(bool) const");2324 EXPECT_EQ(R.insertText, "Foo::x");2325 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);2326 EXPECT_EQ(R.filterText, "x");2327 EXPECT_EQ(R.detail, "int");2328 EXPECT_EQ(R.documentation->value, "From \"foo.h\"\n\nThis is x()");2329 EXPECT_THAT(R.additionalTextEdits, IsEmpty());2330 EXPECT_EQ(R.sortText, sortText(1.0, "x"));2331 EXPECT_FALSE(R.deprecated);2332 EXPECT_EQ(R.score, .5f);2333 2334 C.FilterText = "xtra";2335 R = C.render(Opts);2336 EXPECT_EQ(R.filterText, "xtra");2337 EXPECT_EQ(R.sortText, sortText(1.0, "xtra"));2338 2339 Opts.EnableSnippets = true;2340 R = C.render(Opts);2341 EXPECT_EQ(R.insertText, "Foo::x(${0:bool})");2342 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::Snippet);2343 2344 C.SnippetSuffix = "";2345 R = C.render(Opts);2346 EXPECT_EQ(R.insertText, "Foo::x");2347 EXPECT_EQ(R.insertTextFormat, InsertTextFormat::PlainText);2348 2349 Include.Insertion.emplace();2350 R = C.render(Opts);2351 EXPECT_EQ(R.label, "^Foo::x");2352 EXPECT_EQ(R.labelDetails->detail, "(bool) const");2353 EXPECT_THAT(R.additionalTextEdits, Not(IsEmpty()));2354 2355 Opts.ShowOrigins = true;2356 R = C.render(Opts);2357 EXPECT_EQ(R.label, "^[AS]Foo::x");2358 EXPECT_EQ(R.labelDetails->detail, "(bool) const");2359 2360 C.BundleSize = 2;2361 R = C.render(Opts);2362 EXPECT_EQ(R.detail, "[2 overloads]");2363 EXPECT_EQ(R.documentation->value, "From \"foo.h\"\n\nThis is x()");2364 2365 C.Deprecated = true;2366 R = C.render(Opts);2367 EXPECT_TRUE(R.deprecated);2368 2369 Opts.DocumentationFormat = MarkupKind::Markdown;2370 R = C.render(Opts);2371 EXPECT_EQ(R.documentation->value, "From `\"foo.h\"`\n\nThis is `x()`");2372}2373 2374TEST(CompletionTest, IgnoreRecoveryResults) {2375 auto Results = completions(2376 R"cpp(2377 namespace ns { int NotRecovered() { return 0; } }2378 void f() {2379 // Sema enters recovery mode first and then normal mode.2380 if (auto x = ns::NotRecover^)2381 }2382 )cpp");2383 EXPECT_THAT(Results.Completions, UnorderedElementsAre(named("NotRecovered")));2384}2385 2386TEST(CompletionTest, ScopeOfClassFieldInConstructorInitializer) {2387 auto Results = completions(2388 R"cpp(2389 namespace ns {2390 class X { public: X(); int x_; };2391 X::X() : x_^(0) {}2392 }2393 )cpp");2394 EXPECT_THAT(Results.Completions,2395 UnorderedElementsAre(AllOf(scope("ns::X::"), named("x_"))));2396}2397 2398// Like other class members, constructor init lists have to parse what's below,2399// after the completion point.2400// But recovering from an incomplete constructor init list is particularly2401// tricky because the bulk of the list is not surrounded by brackets.2402TEST(CompletionTest, ConstructorInitListIncomplete) {2403 auto Results = completions(2404 R"cpp(2405 namespace ns {2406 struct X {2407 X() : x^2408 int xyz_;2409 };2410 }2411 )cpp");2412 EXPECT_THAT(Results.Completions, ElementsAre(named("xyz_")));2413 2414 Results = completions(2415 R"cpp(2416 int foo();2417 2418 namespace ns {2419 struct X {2420 X() : xyz_(fo^2421 int xyz_;2422 };2423 }2424 )cpp");2425 EXPECT_THAT(Results.Completions, ElementsAre(named("foo")));2426}2427 2428TEST(CompletionTest, CodeCompletionContext) {2429 auto Results = completions(2430 R"cpp(2431 namespace ns {2432 class X { public: X(); int x_; };2433 void f() {2434 X x;2435 x.^;2436 }2437 }2438 )cpp");2439 2440 EXPECT_THAT(Results.Context, CodeCompletionContext::CCC_DotMemberAccess);2441}2442 2443TEST(CompletionTest, FixItForArrowToDot) {2444 MockFS FS;2445 MockCompilationDatabase CDB;2446 2447 CodeCompleteOptions Opts;2448 Opts.IncludeFixIts = true;2449 const char *Code =2450 R"cpp(2451 class Auxilary {2452 public:2453 void AuxFunction();2454 };2455 class ClassWithPtr {2456 public:2457 void MemberFunction();2458 Auxilary* operator->() const;2459 Auxilary* Aux;2460 };2461 void f() {2462 ClassWithPtr x;2463 x[[->]]^;2464 }2465 )cpp";2466 auto Results = completions(Code, {}, Opts);2467 EXPECT_EQ(Results.Completions.size(), 3u);2468 2469 TextEdit ReplacementEdit;2470 ReplacementEdit.range = Annotations(Code).range();2471 ReplacementEdit.newText = ".";2472 for (const auto &C : Results.Completions) {2473 EXPECT_TRUE(C.FixIts.size() == 1u || C.Name == "AuxFunction");2474 if (!C.FixIts.empty()) {2475 EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit));2476 }2477 }2478}2479 2480TEST(CompletionTest, FixItForDotToArrow) {2481 CodeCompleteOptions Opts;2482 Opts.IncludeFixIts = true;2483 const char *Code =2484 R"cpp(2485 class Auxilary {2486 public:2487 void AuxFunction();2488 };2489 class ClassWithPtr {2490 public:2491 void MemberFunction();2492 Auxilary* operator->() const;2493 Auxilary* Aux;2494 };2495 void f() {2496 ClassWithPtr x;2497 x[[.]]^;2498 }2499 )cpp";2500 auto Results = completions(Code, {}, Opts);2501 EXPECT_EQ(Results.Completions.size(), 3u);2502 2503 TextEdit ReplacementEdit;2504 ReplacementEdit.range = Annotations(Code).range();2505 ReplacementEdit.newText = "->";2506 for (const auto &C : Results.Completions) {2507 EXPECT_TRUE(C.FixIts.empty() || C.Name == "AuxFunction");2508 if (!C.FixIts.empty()) {2509 EXPECT_THAT(C.FixIts, ElementsAre(ReplacementEdit));2510 }2511 }2512}2513 2514TEST(CompletionTest, RenderWithFixItMerged) {2515 TextEdit FixIt;2516 FixIt.range.end.character = 5;2517 FixIt.newText = "->";2518 2519 CodeCompletion C;2520 C.Name = "x";2521 C.RequiredQualifier = "Foo::";2522 C.FixIts = {FixIt};2523 C.CompletionTokenRange.start.character = 5;2524 2525 CodeCompleteOptions Opts;2526 Opts.IncludeFixIts = true;2527 2528 auto R = C.render(Opts);2529 EXPECT_TRUE(R.textEdit);2530 EXPECT_EQ(R.textEdit->newText, "->Foo::x");2531 EXPECT_TRUE(R.additionalTextEdits.empty());2532}2533 2534TEST(CompletionTest, RenderWithFixItNonMerged) {2535 TextEdit FixIt;2536 FixIt.range.end.character = 4;2537 FixIt.newText = "->";2538 2539 CodeCompletion C;2540 C.Name = "x";2541 C.RequiredQualifier = "Foo::";2542 C.FixIts = {FixIt};2543 C.CompletionTokenRange.start.character = 5;2544 2545 CodeCompleteOptions Opts;2546 Opts.IncludeFixIts = true;2547 2548 auto R = C.render(Opts);2549 EXPECT_TRUE(R.textEdit);2550 EXPECT_EQ(R.textEdit->newText, "Foo::x");2551 EXPECT_THAT(R.additionalTextEdits, UnorderedElementsAre(FixIt));2552}2553 2554TEST(CompletionTest, CompletionTokenRange) {2555 MockFS FS;2556 MockCompilationDatabase CDB;2557 TestTU TU;2558 TU.AdditionalFiles["foo/abc/foo.h"] = "";2559 2560 constexpr const char *TestCodes[] = {2561 R"cpp(2562 class Auxilary {2563 public:2564 void AuxFunction();2565 };2566 void f() {2567 Auxilary x;2568 x.[[Aux]]^;2569 }2570 )cpp",2571 R"cpp(2572 class Auxilary {2573 public:2574 void AuxFunction();2575 };2576 void f() {2577 Auxilary x;2578 x.[[]]^;2579 }2580 )cpp",2581 R"cpp(2582 #include "foo/[[a^/]]foo.h"2583 )cpp",2584 R"cpp(2585 #include "foo/abc/[[fo^o.h"]]2586 )cpp",2587 };2588 for (const auto &Text : TestCodes) {2589 Annotations TestCode(Text);2590 TU.Code = TestCode.code().str();2591 auto Results = completions(TU, TestCode.point());2592 if (Results.Completions.size() != 1) {2593 ADD_FAILURE() << "Results.Completions.size() != 1" << Text;2594 continue;2595 }2596 EXPECT_THAT(Results.Completions.front().CompletionTokenRange,2597 TestCode.range());2598 }2599}2600 2601TEST(SignatureHelpTest, OverloadsOrdering) {2602 const auto Results = signatures(R"cpp(2603 void foo(int x);2604 void foo(int x, float y);2605 void foo(float x, int y);2606 void foo(float x, float y);2607 void foo(int x, int y = 0);2608 int main() { foo(^); }2609 )cpp");2610 EXPECT_THAT(Results.signatures,2611 ElementsAre(sig("foo([[int x]]) -> void"),2612 sig("foo([[int x]], [[int y = 0]]) -> void"),2613 sig("foo([[float x]], [[int y]]) -> void"),2614 sig("foo([[int x]], [[float y]]) -> void"),2615 sig("foo([[float x]], [[float y]]) -> void")));2616 // We always prefer the first signature.2617 EXPECT_EQ(0, Results.activeSignature);2618 EXPECT_EQ(0, Results.activeParameter);2619}2620 2621TEST(SignatureHelpTest, InstantiatedSignatures) {2622 StringRef Sig0 = R"cpp(2623 template <class T>2624 void foo(T, T, T);2625 2626 int main() {2627 foo<int>(^);2628 }2629 )cpp";2630 2631 EXPECT_THAT(signatures(Sig0).signatures,2632 ElementsAre(sig("foo([[T]], [[T]], [[T]]) -> void")));2633 2634 StringRef Sig1 = R"cpp(2635 template <class T>2636 void foo(T, T, T);2637 2638 int main() {2639 foo(10, ^);2640 })cpp";2641 2642 EXPECT_THAT(signatures(Sig1).signatures,2643 ElementsAre(sig("foo([[T]], [[T]], [[T]]) -> void")));2644 2645 StringRef Sig2 = R"cpp(2646 template <class ...T>2647 void foo(T...);2648 2649 int main() {2650 foo<int>(^);2651 }2652 )cpp";2653 2654 EXPECT_THAT(signatures(Sig2).signatures,2655 ElementsAre(sig("foo([[T...]]) -> void")));2656 2657 // It is debatable whether we should substitute the outer template parameter2658 // ('T') in that case. Currently we don't substitute it in signature help, but2659 // do substitute in code complete.2660 // FIXME: make code complete and signature help consistent, figure out which2661 // way is better.2662 StringRef Sig3 = R"cpp(2663 template <class T>2664 struct X {2665 template <class U>2666 void foo(T, U);2667 };2668 2669 int main() {2670 X<int>().foo<double>(^)2671 }2672 )cpp";2673 2674 EXPECT_THAT(signatures(Sig3).signatures,2675 ElementsAre(sig("foo([[T]], [[U]]) -> void")));2676}2677 2678TEST(SignatureHelpTest, IndexDocumentation) {2679 Symbol Foo0 = sym("foo", index::SymbolKind::Function, "@F@\\0#");2680 Foo0.Documentation = "doc from the index";2681 Symbol Foo1 = sym("foo", index::SymbolKind::Function, "@F@\\0#I#");2682 Foo1.Documentation = "doc from the index";2683 Symbol Foo2 = sym("foo", index::SymbolKind::Function, "@F@\\0#I#I#");2684 2685 StringRef Sig0 = R"cpp(2686 int foo();2687 int foo(double);2688 2689 void test() {2690 foo(^);2691 }2692 )cpp";2693 2694 EXPECT_THAT(2695 signatures(Sig0, {Foo0}).signatures,2696 ElementsAre(AllOf(sig("foo() -> int"), sigDoc("doc from the index")),2697 AllOf(sig("foo([[double]]) -> int"), sigDoc(""))));2698 2699 StringRef Sig1 = R"cpp(2700 int foo();2701 // Overriden doc from sema2702 int foo(int);2703 // doc from sema2704 int foo(int, int);2705 2706 void test() {2707 foo(^);2708 }2709 )cpp";2710 2711 EXPECT_THAT(2712 signatures(Sig1, {Foo0, Foo1, Foo2}).signatures,2713 ElementsAre(2714 AllOf(sig("foo() -> int"), sigDoc("doc from the index")),2715 AllOf(sig("foo([[int]]) -> int"), sigDoc("Overriden doc from sema")),2716 AllOf(sig("foo([[int]], [[int]]) -> int"), sigDoc("doc from sema"))));2717}2718 2719TEST(SignatureHelpTest, DynamicIndexDocumentation) {2720 MockFS FS;2721 MockCompilationDatabase CDB;2722 ClangdServer::Options Opts = ClangdServer::optsForTest();2723 Opts.BuildDynamicSymbolIndex = true;2724 ClangdServer Server(CDB, FS, Opts);2725 2726 FS.Files[testPath("foo.h")] = R"cpp(2727 struct Foo {2728 // Member doc2729 int foo();2730 };2731 )cpp";2732 Annotations FileContent(R"cpp(2733 #include "foo.h"2734 void test() {2735 Foo f;2736 f.foo(^);2737 }2738 )cpp");2739 auto File = testPath("test.cpp");2740 Server.addDocument(File, FileContent.code());2741 // Wait for the dynamic index being built.2742 ASSERT_TRUE(Server.blockUntilIdleForTest());2743 EXPECT_THAT(llvm::cantFail(runSignatureHelp(Server, File, FileContent.point(),2744 MarkupKind::PlainText))2745 .signatures,2746 ElementsAre(AllOf(sig("foo() -> int"), sigDoc("Member doc"))));2747}2748 2749TEST(CompletionTest, ArgumentListsPolicy) {2750 CodeCompleteOptions Opts;2751 Opts.EnableSnippets = true;2752 Opts.ArgumentLists = Config::ArgumentListsPolicy::Delimiters;2753 2754 {2755 auto Results = completions(2756 R"cpp(2757 void xfoo();2758 void xfoo(int x, int y);2759 void f() { xfo^ })cpp",2760 {}, Opts);2761 EXPECT_THAT(2762 Results.Completions,2763 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix("()")),2764 AllOf(named("xfoo"), snippetSuffix("($0)"))));2765 }2766 {2767 auto Results = completions(2768 R"cpp(2769 void xbar();2770 void f() { xba^ })cpp",2771 {}, Opts);2772 EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf(2773 named("xbar"), snippetSuffix("()"))));2774 }2775 {2776 Opts.BundleOverloads = true;2777 auto Results = completions(2778 R"cpp(2779 void xfoo();2780 void xfoo(int x, int y);2781 void f() { xfo^ })cpp",2782 {}, Opts);2783 EXPECT_THAT(2784 Results.Completions,2785 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix("($0)"))));2786 }2787 {2788 auto Results = completions(2789 R"cpp(2790 template <class T, class U>2791 void xfoo(int a, U b);2792 void f() { xfo^ })cpp",2793 {}, Opts);2794 EXPECT_THAT(2795 Results.Completions,2796 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix("<$1>($0)"))));2797 }2798 {2799 auto Results = completions(2800 R"cpp(2801 template <class T>2802 class foo_class{};2803 template <class T>2804 using foo_alias = T**;2805 template <class T>2806 T foo_var = T{};2807 void f() { foo_^ })cpp",2808 {}, Opts);2809 EXPECT_THAT(2810 Results.Completions,2811 UnorderedElementsAre(AllOf(named("foo_class"), snippetSuffix("<$0>")),2812 AllOf(named("foo_alias"), snippetSuffix("<$0>")),2813 AllOf(named("foo_var"), snippetSuffix("<$0>"))));2814 }2815 {2816 auto Results = completions(2817 R"cpp(2818 #define FOO(x, y) x##f2819 FO^ )cpp",2820 {}, Opts);2821 EXPECT_THAT(Results.Completions, UnorderedElementsAre(AllOf(2822 named("FOO"), snippetSuffix("($0)"))));2823 }2824 {2825 Opts.ArgumentLists = Config::ArgumentListsPolicy::None;2826 auto Results = completions(2827 R"cpp(2828 void xfoo(int x, int y);2829 void f() { xfo^ })cpp",2830 {}, Opts);2831 EXPECT_THAT(Results.Completions,2832 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix(""))));2833 }2834 {2835 Opts.ArgumentLists = Config::ArgumentListsPolicy::OpenDelimiter;2836 auto Results = completions(2837 R"cpp(2838 void xfoo(int x, int y);2839 void f() { xfo^ })cpp",2840 {}, Opts);2841 EXPECT_THAT(Results.Completions,2842 UnorderedElementsAre(AllOf(named("xfoo"), snippetSuffix("("))));2843 }2844}2845 2846TEST(CompletionTest, SuggestOverrides) {2847 constexpr const char *const Text(R"cpp(2848 class A {2849 public:2850 virtual void vfunc(bool param);2851 virtual void vfunc(bool param, int p);2852 void func(bool param);2853 };2854 class B : public A {2855 virtual void ttt(bool param) const;2856 void vfunc(bool param, int p) override;2857 };2858 class C : public B {2859 public:2860 void vfunc(bool param) override;2861 ^2862 };2863 )cpp");2864 const auto Results = completions(Text);2865 EXPECT_THAT(2866 Results.Completions,2867 AllOf(Contains(AllOf(labeled("void vfunc(bool param, int p) override"),2868 nameStartsWith("vfunc"))),2869 Contains(AllOf(labeled("void ttt(bool param) const override"),2870 nameStartsWith("ttt"))),2871 Not(Contains(labeled("void vfunc(bool param) override")))));2872}2873 2874TEST(CompletionTest, OverridesNonIdentName) {2875 // Check the completions call does not crash.2876 completions(R"cpp(2877 struct Base {2878 virtual ~Base() = 0;2879 virtual operator int() = 0;2880 virtual Base& operator+(Base&) = 0;2881 };2882 2883 struct Derived : Base {2884 ^2885 };2886 )cpp");2887}2888 2889TEST(CompletionTest, NoCrashOnMissingNewLineAtEOF) {2890 auto FooCpp = testPath("foo.cpp");2891 2892 MockCompilationDatabase CDB;2893 MockFS FS;2894 Annotations F("#pragma ^ // no new line");2895 FS.Files[FooCpp] = F.code().str();2896 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());2897 runAddDocument(Server, FooCpp, F.code());2898 // Run completion outside the file range.2899 EXPECT_THAT(cantFail(runCodeComplete(Server, FooCpp, F.point(),2900 clangd::CodeCompleteOptions()))2901 .Completions,2902 IsEmpty());2903 EXPECT_THAT(cantFail(runSignatureHelp(Server, FooCpp, F.point(),2904 MarkupKind::PlainText))2905 .signatures,2906 IsEmpty());2907}2908 2909TEST(GuessCompletionPrefix, Filters) {2910 for (llvm::StringRef Case : {2911 "[[scope::]][[ident]]^",2912 "[[]][[]]^",2913 "\n[[]][[]]^",2914 "[[]][[ab]]^",2915 "x.[[]][[ab]]^",2916 "x.[[]][[]]^",2917 "[[x::]][[ab]]^",2918 "[[x::]][[]]^",2919 "[[::x::]][[ab]]^",2920 "some text [[scope::more::]][[identif]]^ier",2921 "some text [[scope::]][[mor]]^e::identifier",2922 "weird case foo::[[::bar::]][[baz]]^",2923 "/* [[]][[]]^ */",2924 }) {2925 Annotations F(Case);2926 auto Offset = cantFail(positionToOffset(F.code(), F.point()));2927 auto ToStringRef = [&](Range R) {2928 return F.code().slice(cantFail(positionToOffset(F.code(), R.start)),2929 cantFail(positionToOffset(F.code(), R.end)));2930 };2931 auto WantQualifier = ToStringRef(F.ranges()[0]),2932 WantName = ToStringRef(F.ranges()[1]);2933 2934 auto Prefix = guessCompletionPrefix(F.code(), Offset);2935 // Even when components are empty, check their offsets are correct.2936 EXPECT_EQ(WantQualifier, Prefix.Qualifier) << Case;2937 EXPECT_EQ(WantQualifier.begin(), Prefix.Qualifier.begin()) << Case;2938 EXPECT_EQ(WantName, Prefix.Name) << Case;2939 EXPECT_EQ(WantName.begin(), Prefix.Name.begin()) << Case;2940 }2941}2942 2943TEST(CompletionTest, EnableSpeculativeIndexRequest) {2944 MockFS FS;2945 MockCompilationDatabase CDB;2946 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());2947 2948 auto File = testPath("foo.cpp");2949 Annotations Test(R"cpp(2950 namespace ns1 { int abc; }2951 namespace ns2 { int abc; }2952 void f() { ns1::ab$1^; ns1::ab$2^; }2953 void f2() { ns2::ab$3^; }2954 )cpp");2955 runAddDocument(Server, File, Test.code());2956 clangd::CodeCompleteOptions Opts = {};2957 2958 IndexRequestCollector Requests;2959 Opts.Index = &Requests;2960 2961 auto CompleteAtPoint = [&](StringRef P) {2962 auto CCR = cantFail(runCodeComplete(Server, File, Test.point(P), Opts));2963 EXPECT_TRUE(CCR.HasMore);2964 };2965 2966 CompleteAtPoint("1");2967 auto Reqs1 = Requests.consumeRequests(1);2968 ASSERT_EQ(Reqs1.size(), 1u);2969 EXPECT_THAT(Reqs1[0].Scopes, UnorderedElementsAre("ns1::"));2970 2971 CompleteAtPoint("2");2972 auto Reqs2 = Requests.consumeRequests(1);2973 // Speculation succeeded. Used speculative index result.2974 ASSERT_EQ(Reqs2.size(), 1u);2975 EXPECT_EQ(Reqs2[0], Reqs1[0]);2976 2977 CompleteAtPoint("3");2978 // Speculation failed. Sent speculative index request and the new index2979 // request after sema.2980 auto Reqs3 = Requests.consumeRequests(2);2981 ASSERT_EQ(Reqs3.size(), 2u);2982}2983 2984TEST(CompletionTest, InsertTheMostPopularHeader) {2985 std::string DeclFile = URI::create(testPath("foo")).toString();2986 Symbol Sym = func("Func");2987 Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();2988 Sym.IncludeHeaders.emplace_back("\"foo.h\"", 2, Symbol::Include);2989 Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000, Symbol::Include);2990 2991 auto Results = completions("Fun^", {Sym}).Completions;2992 assert(!Results.empty());2993 EXPECT_THAT(Results[0], AllOf(named("Func"), insertInclude("\"bar.h\"")));2994 EXPECT_EQ(Results[0].Includes.size(), 2u);2995}2996 2997TEST(CompletionTest, InsertIncludeOrImport) {2998 std::string DeclFile = URI::create(testPath("foo")).toString();2999 Symbol Sym = func("Func");3000 Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();3001 Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000,3002 Symbol::Include | Symbol::Import);3003 CodeCompleteOptions Opts;3004 // Should only take effect in import contexts.3005 Opts.ImportInsertions = true;3006 auto Results = completions("Fun^", {Sym}, Opts).Completions;3007 assert(!Results.empty());3008 EXPECT_THAT(Results[0],3009 AllOf(named("Func"), insertIncludeText("#include \"bar.h\"\n")));3010 3011 ASTSignals Signals;3012 Signals.InsertionDirective = Symbol::IncludeDirective::Import;3013 Opts.MainFileSignals = &Signals;3014 Results = completions("Fun^", {Sym}, Opts, "Foo.m").Completions;3015 assert(!Results.empty());3016 EXPECT_THAT(Results[0],3017 AllOf(named("Func"), insertIncludeText("#import \"bar.h\"\n")));3018 3019 Sym.IncludeHeaders[0].SupportedDirectives = Symbol::Import;3020 Results = completions("Fun^", {Sym}).Completions;3021 assert(!Results.empty());3022 EXPECT_THAT(Results[0], AllOf(named("Func"), Not(insertInclude())));3023}3024 3025TEST(CompletionTest, NoInsertIncludeIfOnePresent) {3026 Annotations Test(R"cpp(3027 #include "foo.h"3028 Fun^3029 )cpp");3030 auto TU = TestTU::withCode(Test.code());3031 TU.AdditionalFiles["foo.h"] = "";3032 3033 std::string DeclFile = URI::create(testPath("foo")).toString();3034 Symbol Sym = func("Func");3035 Sym.CanonicalDeclaration.FileURI = DeclFile.c_str();3036 Sym.IncludeHeaders.emplace_back("\"foo.h\"", 2, Symbol::Include);3037 Sym.IncludeHeaders.emplace_back("\"bar.h\"", 1000, Symbol::Include);3038 3039 EXPECT_THAT(completions(TU, Test.point(), {Sym}).Completions,3040 UnorderedElementsAre(AllOf(named("Func"), hasInclude("\"foo.h\""),3041 Not(insertInclude()))));3042}3043 3044TEST(CompletionTest, MergeMacrosFromIndexAndSema) {3045 Symbol Sym;3046 Sym.Name = "Clangd_Macro_Test";3047 Sym.ID = SymbolID("c:foo.cpp@8@macro@Clangd_Macro_Test");3048 Sym.SymInfo.Kind = index::SymbolKind::Macro;3049 Sym.Flags |= Symbol::IndexedForCodeCompletion;3050 EXPECT_THAT(completions("#define Clangd_Macro_Test\nClangd_Macro_T^", {Sym})3051 .Completions,3052 UnorderedElementsAre(named("Clangd_Macro_Test")));3053}3054 3055TEST(CompletionTest, MacroFromPreamble) {3056 Annotations Test(R"cpp(#define CLANGD_PREAMBLE_MAIN x3057 3058 int x = 0;3059 #define CLANGD_MAIN x3060 void f() { CLANGD_^ }3061 )cpp");3062 auto TU = TestTU::withCode(Test.code());3063 TU.HeaderCode = "#define CLANGD_PREAMBLE_HEADER x";3064 auto Results = completions(TU, Test.point(), {func("CLANGD_INDEX")});3065 // We should get results from the main file, including the preamble section.3066 // However no results from included files (the index should cover them).3067 EXPECT_THAT(Results.Completions,3068 UnorderedElementsAre(named("CLANGD_PREAMBLE_MAIN"),3069 named("CLANGD_MAIN"),3070 named("CLANGD_INDEX")));3071}3072 3073TEST(CompletionTest, DeprecatedResults) {3074 std::string Body = R"cpp(3075 void TestClangd();3076 void TestClangc() __attribute__((deprecated("", "")));3077 )cpp";3078 3079 EXPECT_THAT(3080 completions(Body + "int main() { TestClang^ }").Completions,3081 UnorderedElementsAre(AllOf(named("TestClangd"), Not(deprecated())),3082 AllOf(named("TestClangc"), deprecated())));3083}3084 3085TEST(SignatureHelpTest, PartialSpec) {3086 const auto Results = signatures(R"cpp(3087 template <typename T> struct Foo {};3088 template <typename T> struct Foo<T*> { Foo(T); };3089 Foo<int*> F(^);)cpp");3090 EXPECT_THAT(Results.signatures, Contains(sig("Foo([[T]])")));3091 EXPECT_EQ(0, Results.activeParameter);3092}3093 3094TEST(SignatureHelpTest, InsideArgument) {3095 {3096 const auto Results = signatures(R"cpp(3097 void foo(int x);3098 void foo(int x, int y);3099 int main() { foo(1+^); }3100 )cpp");3101 EXPECT_THAT(Results.signatures,3102 ElementsAre(sig("foo([[int x]]) -> void"),3103 sig("foo([[int x]], [[int y]]) -> void")));3104 EXPECT_EQ(0, Results.activeParameter);3105 }3106 {3107 const auto Results = signatures(R"cpp(3108 void foo(int x);3109 void foo(int x, int y);3110 int main() { foo(1^); }3111 )cpp");3112 EXPECT_THAT(Results.signatures,3113 ElementsAre(sig("foo([[int x]]) -> void"),3114 sig("foo([[int x]], [[int y]]) -> void")));3115 EXPECT_EQ(0, Results.activeParameter);3116 }3117 {3118 const auto Results = signatures(R"cpp(3119 void foo(int x);3120 void foo(int x, int y);3121 int main() { foo(1^0); }3122 )cpp");3123 EXPECT_THAT(Results.signatures,3124 ElementsAre(sig("foo([[int x]]) -> void"),3125 sig("foo([[int x]], [[int y]]) -> void")));3126 EXPECT_EQ(0, Results.activeParameter);3127 }3128 {3129 const auto Results = signatures(R"cpp(3130 void foo(int x);3131 void foo(int x, int y);3132 int bar(int x, int y);3133 int main() { bar(foo(2, 3^)); }3134 )cpp");3135 EXPECT_THAT(Results.signatures,3136 ElementsAre(sig("foo([[int x]], [[int y]]) -> void")));3137 EXPECT_EQ(1, Results.activeParameter);3138 }3139}3140 3141TEST(SignatureHelpTest, ConstructorInitializeFields) {3142 {3143 const auto Results = signatures(R"cpp(3144 struct A { A(int); };3145 struct B {3146 B() : a_elem(^) {}3147 A a_elem;3148 };3149 )cpp");3150 EXPECT_THAT(Results.signatures,3151 UnorderedElementsAre(sig("A([[int]])"), sig("A([[A &&]])"),3152 sig("A([[const A &]])")));3153 }3154 {3155 const auto Results = signatures(R"cpp(3156 struct A { A(int); };3157 struct B {3158 B() : a_elem(^3159 A a_elem;3160 };3161 )cpp");3162 // FIXME: currently the parser skips over the decl of a_elem as part of the3163 // (broken) init list, so we don't get signatures for the first member.3164 EXPECT_THAT(Results.signatures, IsEmpty());3165 }3166 {3167 const auto Results = signatures(R"cpp(3168 struct A { A(int); };3169 struct B {3170 B() : a_elem(^3171 int dummy_elem;3172 A a_elem;3173 };3174 )cpp");3175 EXPECT_THAT(Results.signatures,3176 UnorderedElementsAre(sig("A([[int]])"), sig("A([[A &&]])"),3177 sig("A([[const A &]])")));3178 }3179 {3180 const auto Results = signatures(R"cpp(3181 struct A {3182 A(int);3183 };3184 struct C {3185 C(int);3186 C(A);3187 };3188 struct B {3189 B() : c_elem(A(1^)) {}3190 C c_elem;3191 };3192 )cpp");3193 EXPECT_THAT(Results.signatures,3194 UnorderedElementsAre(sig("A([[int]])"), sig("A([[A &&]])"),3195 sig("A([[const A &]])")));3196 }3197}3198 3199TEST(SignatureHelpTest, Variadic) {3200 const std::string Header = R"cpp(3201 void fun(int x, ...) {}3202 void test() {)cpp";3203 const std::string ExpectedSig = "fun([[int x]], [[...]]) -> void";3204 3205 {3206 const auto Result = signatures(Header + "fun(^);}");3207 EXPECT_EQ(0, Result.activeParameter);3208 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3209 }3210 {3211 const auto Result = signatures(Header + "fun(1, ^);}");3212 EXPECT_EQ(1, Result.activeParameter);3213 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3214 }3215 {3216 const auto Result = signatures(Header + "fun(1, 2, ^);}");3217 EXPECT_EQ(1, Result.activeParameter);3218 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3219 }3220}3221 3222TEST(SignatureHelpTest, VariadicTemplate) {3223 const std::string Header = R"cpp(3224 template<typename T, typename ...Args>3225 void fun(T t, Args ...args) {}3226 void test() {)cpp";3227 const std::string ExpectedSig = "fun([[T t]], [[Args args...]]) -> void";3228 3229 {3230 const auto Result = signatures(Header + "fun(^);}");3231 EXPECT_EQ(0, Result.activeParameter);3232 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3233 }3234 {3235 const auto Result = signatures(Header + "fun(1, ^);}");3236 EXPECT_EQ(1, Result.activeParameter);3237 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3238 }3239 {3240 const auto Result = signatures(Header + "fun(1, 2, ^);}");3241 EXPECT_EQ(1, Result.activeParameter);3242 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3243 }3244}3245 3246TEST(SignatureHelpTest, VariadicMethod) {3247 const std::string Header = R"cpp(3248 class C {3249 template<typename T, typename ...Args>3250 void fun(T t, Args ...args) {}3251 };3252 void test() {C c; )cpp";3253 const std::string ExpectedSig = "fun([[T t]], [[Args args...]]) -> void";3254 3255 {3256 const auto Result = signatures(Header + "c.fun(^);}");3257 EXPECT_EQ(0, Result.activeParameter);3258 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3259 }3260 {3261 const auto Result = signatures(Header + "c.fun(1, ^);}");3262 EXPECT_EQ(1, Result.activeParameter);3263 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3264 }3265 {3266 const auto Result = signatures(Header + "c.fun(1, 2, ^);}");3267 EXPECT_EQ(1, Result.activeParameter);3268 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3269 }3270}3271 3272TEST(SignatureHelpTest, VariadicType) {3273 const std::string Header = R"cpp(3274 void fun(int x, ...) {}3275 auto get_fun() { return fun; }3276 void test() {3277 )cpp";3278 const std::string ExpectedSig = "([[int]], [[...]]) -> void";3279 3280 {3281 const auto Result = signatures(Header + "get_fun()(^);}");3282 EXPECT_EQ(0, Result.activeParameter);3283 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3284 }3285 {3286 const auto Result = signatures(Header + "get_fun()(1, ^);}");3287 EXPECT_EQ(1, Result.activeParameter);3288 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3289 }3290 {3291 const auto Result = signatures(Header + "get_fun()(1, 2, ^);}");3292 EXPECT_EQ(1, Result.activeParameter);3293 EXPECT_THAT(Result.signatures, UnorderedElementsAre(sig(ExpectedSig)));3294 }3295}3296 3297TEST(SignatureHelpTest, SkipExplicitObjectParameter) {3298 Annotations Code(R"cpp(3299 struct A {3300 void foo(this auto&& self, int arg); 3301 void bar(this A self, int arg);3302 };3303 int main() {3304 A a {};3305 a.foo($c1^);3306 (&A::bar)($c2^);3307 (&A::foo)($c3^);3308 }3309 )cpp");3310 3311 auto TU = TestTU::withCode(Code.code());3312 TU.ExtraArgs = {"-std=c++23"};3313 3314 MockFS FS;3315 auto Inputs = TU.inputs(FS);3316 3317 auto Preamble = TU.preamble();3318 ASSERT_TRUE(Preamble);3319 3320 {3321 const auto Result = signatureHelp(testPath(TU.Filename), Code.point("c1"),3322 *Preamble, Inputs, MarkupKind::PlainText);3323 3324 EXPECT_EQ(1U, Result.signatures.size());3325 3326 EXPECT_THAT(Result.signatures[0], AllOf(sig("foo([[int arg]]) -> void")));3327 }3328 {3329 const auto Result = signatureHelp(testPath(TU.Filename), Code.point("c2"),3330 *Preamble, Inputs, MarkupKind::PlainText);3331 3332 EXPECT_EQ(1U, Result.signatures.size());3333 3334 EXPECT_THAT(Result.signatures[0], AllOf(sig("([[A]], [[int]]) -> void")));3335 }3336 {3337 // TODO: llvm/llvm-project/1466493338 const auto Result = signatureHelp(testPath(TU.Filename), Code.point("c3"),3339 *Preamble, Inputs, MarkupKind::PlainText);3340 // TODO: We expect 1 signature here, with this signature3341 EXPECT_EQ(0U, Result.signatures.size());3342 // EXPECT_THAT(Result.signatures[0], AllOf(sig("([[auto&&]], [[int]]) ->3343 // void")));3344 }3345}3346 3347TEST(CompletionTest, IncludedCompletionKinds) {3348 Annotations Test(R"cpp(#include "^)cpp");3349 auto TU = TestTU::withCode(Test.code());3350 TU.AdditionalFiles["sub/bar.h"] = "";3351 TU.ExtraArgs.push_back("-I" + testPath("sub"));3352 3353 auto Results = completions(TU, Test.point());3354 EXPECT_THAT(Results.Completions,3355 AllOf(has("sub/", CompletionItemKind::Folder),3356 has("bar.h\"", CompletionItemKind::File)));3357}3358 3359TEST(CompletionTest, NoCrashAtNonAlphaIncludeHeader) {3360 completions(3361 R"cpp(3362 #include "./^"3363 )cpp");3364}3365 3366TEST(CompletionTest, NoAllScopesCompletionWhenQualified) {3367 clangd::CodeCompleteOptions Opts = {};3368 Opts.AllScopes = true;3369 3370 auto Results = completions(3371 R"cpp(3372 void f() { na::Clangd^ }3373 )cpp",3374 {cls("na::ClangdA"), cls("nx::ClangdX"), cls("Clangd3")}, Opts);3375 EXPECT_THAT(Results.Completions,3376 UnorderedElementsAre(3377 AllOf(qualifier(""), scope("na::"), named("ClangdA"))));3378}3379 3380TEST(CompletionTest, AllScopesCompletion) {3381 clangd::CodeCompleteOptions Opts = {};3382 Opts.AllScopes = true;3383 3384 auto Results = completions(3385 R"cpp(3386 namespace na {3387 void f() { Clangd^ }3388 }3389 )cpp",3390 {cls("nx::Clangd1"), cls("ny::Clangd2"), cls("Clangd3"),3391 cls("na::nb::Clangd4"), enmConstant("na::C::Clangd5")},3392 Opts);3393 EXPECT_THAT(3394 Results.Completions,3395 UnorderedElementsAre(AllOf(qualifier("nx::"), named("Clangd1"),3396 kind(CompletionItemKind::Class)),3397 AllOf(qualifier("ny::"), named("Clangd2"),3398 kind(CompletionItemKind::Class)),3399 AllOf(qualifier(""), scope(""), named("Clangd3"),3400 kind(CompletionItemKind::Class)),3401 AllOf(qualifier("nb::"), named("Clangd4"),3402 kind(CompletionItemKind::Class)),3403 AllOf(qualifier("C::"), named("Clangd5"),3404 kind(CompletionItemKind::EnumMember))));3405}3406 3407TEST(CompletionTest, NoCodePatternsIfDisabled) {3408 clangd::CodeCompleteOptions Opts = {};3409 Opts.EnableSnippets = true;3410 Opts.CodePatterns = Config::CodePatternsPolicy::None;3411 3412 auto Results = completions(R"cpp(3413 void function() {3414 /// Trying to trigger "for (init-statement; condition; inc-expression)3415 /// {statements}~" code pattern3416 for^3417 }3418 )cpp",3419 {}, Opts);3420 3421 EXPECT_THAT(Results.Completions,3422 Not(Contains(kind(CompletionItemKind::Snippet))));3423}3424 3425TEST(CompletionTest, CompleteIncludeIfCodePatternsNone) {3426 clangd::CodeCompleteOptions Opts = {};3427 Opts.EnableSnippets = true;3428 Opts.CodePatterns = Config::CodePatternsPolicy::None;3429 3430 Annotations Test(R"cpp(#include "^)cpp");3431 auto TU = TestTU::withCode(Test.code());3432 TU.AdditionalFiles["foo/bar.h"] = "";3433 TU.ExtraArgs.push_back("-I" + testPath("foo"));3434 3435 auto Results = completions(TU, Test.point(), {}, Opts);3436 EXPECT_THAT(Results.Completions,3437 AllOf(has("foo/", CompletionItemKind::Folder),3438 has("bar.h\"", CompletionItemKind::File)));3439}3440 3441TEST(CompletionTest, NoQualifierIfShadowed) {3442 clangd::CodeCompleteOptions Opts = {};3443 Opts.AllScopes = true;3444 3445 auto Results = completions(R"cpp(3446 namespace nx { class Clangd1 {}; }3447 using nx::Clangd1;3448 void f() { Clangd^ }3449 )cpp",3450 {cls("nx::Clangd1"), cls("nx::Clangd2")}, Opts);3451 // Although Clangd1 is from another namespace, Sema tells us it's in-scope and3452 // needs no qualifier.3453 EXPECT_THAT(Results.Completions,3454 UnorderedElementsAre(AllOf(qualifier(""), named("Clangd1")),3455 AllOf(qualifier("nx::"), named("Clangd2"))));3456}3457 3458TEST(CompletionTest, NoCompletionsForNewNames) {3459 clangd::CodeCompleteOptions Opts;3460 Opts.AllScopes = true;3461 auto Results = completions(R"cpp(3462 void f() { int n^ }3463 )cpp",3464 {cls("naber"), cls("nx::naber")}, Opts);3465 EXPECT_THAT(Results.Completions, UnorderedElementsAre());3466}3467 3468TEST(CompletionTest, Lambda) {3469 clangd::CodeCompleteOptions Opts = {};3470 3471 auto Results = completions(R"cpp(3472 void function() {3473 auto Lambda = [](int a, const double &b) {return 1.f;};3474 Lam^3475 }3476 )cpp",3477 {}, Opts);3478 3479 ASSERT_EQ(Results.Completions.size(), 1u);3480 const auto &A = Results.Completions.front();3481 EXPECT_EQ(A.Name, "Lambda");3482 EXPECT_EQ(A.Signature, "(int a, const double &b) const");3483 EXPECT_EQ(A.Kind, CompletionItemKind::Variable);3484 EXPECT_EQ(A.ReturnType, "float");3485 EXPECT_EQ(A.SnippetSuffix, "(${1:int a}, ${2:const double &b})");3486}3487 3488TEST(CompletionTest, StructuredBinding) {3489 clangd::CodeCompleteOptions Opts = {};3490 3491 auto Results = completions(R"cpp(3492 struct S {3493 using Float = float;3494 int x;3495 Float y;3496 };3497 void function() {3498 const auto &[xxx, yyy] = S{};3499 yyy^3500 }3501 )cpp",3502 {}, Opts);3503 3504 ASSERT_EQ(Results.Completions.size(), 1u);3505 const auto &A = Results.Completions.front();3506 EXPECT_EQ(A.Name, "yyy");3507 EXPECT_EQ(A.Kind, CompletionItemKind::Variable);3508 EXPECT_EQ(A.ReturnType, "const Float");3509}3510 3511TEST(CompletionTest, ObjectiveCMethodNoArguments) {3512 auto Results = completions(R"objc(3513 @interface Foo3514 @property(nonatomic, setter=setXToIgnoreComplete:) int value;3515 @end3516 Foo *foo = [Foo new]; int y = [foo v^]3517 )objc",3518 /*IndexSymbols=*/{},3519 /*Opts=*/{}, "Foo.m");3520 3521 auto C = Results.Completions;3522 EXPECT_THAT(C, ElementsAre(named("value")));3523 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3524 EXPECT_THAT(C, ElementsAre(returnType("int")));3525 EXPECT_THAT(C, ElementsAre(signature("")));3526 EXPECT_THAT(C, ElementsAre(snippetSuffix("")));3527}3528 3529TEST(CompletionTest, ObjectiveCMethodOneArgument) {3530 auto Results = completions(R"objc(3531 @interface Foo3532 - (int)valueForCharacter:(char)c;3533 @end3534 Foo *foo = [Foo new]; int y = [foo v^]3535 )objc",3536 /*IndexSymbols=*/{},3537 /*Opts=*/{}, "Foo.m");3538 3539 auto C = Results.Completions;3540 EXPECT_THAT(C, ElementsAre(named("valueForCharacter:")));3541 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3542 EXPECT_THAT(C, ElementsAre(returnType("int")));3543 EXPECT_THAT(C, ElementsAre(signature("(char)")));3544 EXPECT_THAT(C, ElementsAre(snippetSuffix("${1:(char)}")));3545}3546 3547TEST(CompletionTest, ObjectiveCMethodTwoArgumentsFromBeginning) {3548 auto Results = completions(R"objc(3549 @interface Foo3550 + (id)fooWithValue:(int)value fooey:(unsigned int)fooey;3551 @end3552 id val = [Foo foo^]3553 )objc",3554 /*IndexSymbols=*/{},3555 /*Opts=*/{}, "Foo.m");3556 3557 auto C = Results.Completions;3558 EXPECT_THAT(C, ElementsAre(named("fooWithValue:")));3559 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3560 EXPECT_THAT(C, ElementsAre(returnType("id")));3561 EXPECT_THAT(C, ElementsAre(signature("(int) fooey:(unsigned int)")));3562 EXPECT_THAT(3563 C, ElementsAre(snippetSuffix("${1:(int)} fooey:${2:(unsigned int)}")));3564}3565 3566TEST(CompletionTest, ObjectiveCMethodTwoArgumentsFromMiddle) {3567 auto Results = completions(R"objc(3568 @interface Foo3569 + (id)fooWithValue:(int)value fooey:(unsigned int)fooey;3570 @end3571 id val = [Foo fooWithValue:10 f^]3572 )objc",3573 /*IndexSymbols=*/{},3574 /*Opts=*/{}, "Foo.m");3575 3576 auto C = Results.Completions;3577 EXPECT_THAT(C, ElementsAre(named("fooey:")));3578 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3579 EXPECT_THAT(C, ElementsAre(returnType("id")));3580 EXPECT_THAT(C, ElementsAre(signature("(unsigned int)")));3581 EXPECT_THAT(C, ElementsAre(snippetSuffix("${1:(unsigned int)}")));3582}3583 3584TEST(CompletionTest, ObjectiveCMethodFilterOnEntireSelector) {3585 auto Results = completions(R"objc(3586 @interface Foo3587 + (id)player:(id)player willRun:(id)run;3588 @end3589 id val = [Foo wi^]3590 )objc",3591 /*IndexSymbols=*/{},3592 /*Opts=*/{}, "Foo.m");3593 3594 auto C = Results.Completions;3595 EXPECT_THAT(C, ElementsAre(named("player:")));3596 EXPECT_THAT(C, ElementsAre(filterText("player:willRun:")));3597 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3598 EXPECT_THAT(C, ElementsAre(returnType("id")));3599 EXPECT_THAT(C, ElementsAre(signature("(id) willRun:(id)")));3600 EXPECT_THAT(C, ElementsAre(snippetSuffix("${1:(id)} willRun:${2:(id)}")));3601}3602 3603TEST(CompletionTest, ObjectiveCSimpleMethodDeclaration) {3604 auto Results = completions(R"objc(3605 @interface Foo3606 - (void)foo;3607 @end3608 @implementation Foo3609 fo^3610 @end3611 )objc",3612 /*IndexSymbols=*/{},3613 /*Opts=*/{}, "Foo.m");3614 3615 auto C = Results.Completions;3616 EXPECT_THAT(C, ElementsAre(named("foo")));3617 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3618 EXPECT_THAT(C, ElementsAre(qualifier("- (void)")));3619}3620 3621TEST(CompletionTest, ObjectiveCMethodDeclaration) {3622 auto Results = completions(R"objc(3623 @interface Foo3624 - (int)valueForCharacter:(char)c secondArgument:(id)object;3625 @end3626 @implementation Foo3627 valueFor^3628 @end3629 )objc",3630 /*IndexSymbols=*/{},3631 /*Opts=*/{}, "Foo.m");3632 3633 auto C = Results.Completions;3634 EXPECT_THAT(C, ElementsAre(named("valueForCharacter:")));3635 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3636 EXPECT_THAT(C, ElementsAre(qualifier("- (int)")));3637 EXPECT_THAT(C, ElementsAre(signature("(char)c secondArgument:(id)object")));3638}3639 3640TEST(CompletionTest, ObjectiveCMethodDeclarationFilterOnEntireSelector) {3641 auto Results = completions(R"objc(3642 @interface Foo3643 - (int)valueForCharacter:(char)c secondArgument:(id)object;3644 @end3645 @implementation Foo3646 secondArg^3647 @end3648 )objc",3649 /*IndexSymbols=*/{},3650 /*Opts=*/{}, "Foo.m");3651 3652 auto C = Results.Completions;3653 EXPECT_THAT(C, ElementsAre(named("valueForCharacter:")));3654 EXPECT_THAT(C, ElementsAre(filterText("valueForCharacter:secondArgument:")));3655 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3656 EXPECT_THAT(C, ElementsAre(qualifier("- (int)")));3657 EXPECT_THAT(C, ElementsAre(signature("(char)c secondArgument:(id)object")));3658}3659 3660TEST(CompletionTest, ObjectiveCMethodDeclarationPrefixTyped) {3661 auto Results = completions(R"objc(3662 @interface Foo3663 - (int)valueForCharacter:(char)c;3664 @end3665 @implementation Foo3666 - (int)valueFor^3667 @end3668 )objc",3669 /*IndexSymbols=*/{},3670 /*Opts=*/{}, "Foo.m");3671 3672 auto C = Results.Completions;3673 EXPECT_THAT(C, ElementsAre(named("valueForCharacter:")));3674 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3675 EXPECT_THAT(C, ElementsAre(signature("(char)c")));3676}3677 3678TEST(CompletionTest, ObjectiveCMethodDeclarationFromMiddle) {3679 auto Results = completions(R"objc(3680 @interface Foo3681 - (int)valueForCharacter:(char)c secondArgument:(id)object;3682 @end3683 @implementation Foo3684 - (int)valueForCharacter:(char)c second^3685 @end3686 )objc",3687 /*IndexSymbols=*/{},3688 /*Opts=*/{}, "Foo.m");3689 3690 auto C = Results.Completions;3691 EXPECT_THAT(C, ElementsAre(named("secondArgument:")));3692 EXPECT_THAT(C, ElementsAre(kind(CompletionItemKind::Method)));3693 EXPECT_THAT(C, ElementsAre(signature("(id)object")));3694}3695 3696TEST(CompletionTest, ObjectiveCProtocolFromIndex) {3697 Symbol FoodClass = objcClass("FoodClass");3698 Symbol SymFood = objcProtocol("Food");3699 Symbol SymFooey = objcProtocol("Fooey");3700 auto Results = completions("id<Foo^>", {SymFood, FoodClass, SymFooey},3701 /*Opts=*/{}, "Foo.m");3702 3703 // Should only give protocols for ObjC protocol completions.3704 EXPECT_THAT(Results.Completions,3705 UnorderedElementsAre(3706 AllOf(named("Food"), kind(CompletionItemKind::Interface)),3707 AllOf(named("Fooey"), kind(CompletionItemKind::Interface))));3708 3709 Results = completions("Fo^", {SymFood, FoodClass, SymFooey},3710 /*Opts=*/{}, "Foo.m");3711 // Shouldn't give protocols for non protocol completions.3712 EXPECT_THAT(3713 Results.Completions,3714 ElementsAre(AllOf(named("FoodClass"), kind(CompletionItemKind::Class))));3715}3716 3717TEST(CompletionTest, ObjectiveCProtocolFromIndexSpeculation) {3718 MockFS FS;3719 MockCompilationDatabase CDB;3720 ClangdServer Server(CDB, FS, ClangdServer::optsForTest());3721 3722 auto File = testPath("Foo.m");3723 Annotations Test(R"cpp(3724 @protocol Food3725 @end3726 id<Foo$1^> foo;3727 Foo$2^ bar;3728 )cpp");3729 runAddDocument(Server, File, Test.code());3730 clangd::CodeCompleteOptions Opts = {};3731 3732 Symbol FoodClass = objcClass("FoodClass");3733 IndexRequestCollector Requests({FoodClass});3734 Opts.Index = &Requests;3735 3736 auto CompleteAtPoint = [&](StringRef P) {3737 return cantFail(runCodeComplete(Server, File, Test.point(P), Opts))3738 .Completions;3739 };3740 3741 auto C = CompleteAtPoint("1");3742 auto Reqs1 = Requests.consumeRequests(1);3743 ASSERT_EQ(Reqs1.size(), 1u);3744 EXPECT_THAT(C, ElementsAre(AllOf(named("Food"),3745 kind(CompletionItemKind::Interface))));3746 3747 C = CompleteAtPoint("2");3748 auto Reqs2 = Requests.consumeRequests(1);3749 // Speculation succeeded. Used speculative index result, but filtering now to3750 // now include FoodClass.3751 ASSERT_EQ(Reqs2.size(), 1u);3752 EXPECT_EQ(Reqs2[0], Reqs1[0]);3753 EXPECT_THAT(C, ElementsAre(AllOf(named("FoodClass"),3754 kind(CompletionItemKind::Class))));3755}3756 3757TEST(CompletionTest, ObjectiveCCategoryFromIndexIgnored) {3758 Symbol FoodCategory = objcCategory("FoodClass", "Extension");3759 auto Results = completions(R"objc(3760 @interface Foo3761 @end3762 @interface Foo (^)3763 @end3764 )objc",3765 {FoodCategory},3766 /*Opts=*/{}, "Foo.m");3767 EXPECT_THAT(Results.Completions, IsEmpty());3768}3769 3770TEST(CompletionTest, ObjectiveCForwardDeclFromIndex) {3771 Symbol FoodClass = objcClass("FoodClass");3772 FoodClass.IncludeHeaders.emplace_back("\"Foo.h\"", 2, Symbol::Import);3773 Symbol SymFood = objcProtocol("Food");3774 auto Results = completions("@class Foo^", {SymFood, FoodClass},3775 /*Opts=*/{}, "Foo.m");3776 3777 // Should only give class names without any include insertion.3778 EXPECT_THAT(Results.Completions,3779 UnorderedElementsAre(AllOf(named("FoodClass"),3780 kind(CompletionItemKind::Class),3781 Not(insertInclude()))));3782}3783 3784TEST(CompletionTest, CursorInSnippets) {3785 clangd::CodeCompleteOptions Options;3786 Options.EnableSnippets = true;3787 auto Results = completions(3788 R"cpp(3789 void while_foo(int a, int b);3790 void test() {3791 whil^3792 })cpp",3793 /*IndexSymbols=*/{}, Options);3794 3795 // Last placeholder in code patterns should be $0 to put the cursor there.3796 EXPECT_THAT(Results.Completions,3797 Contains(AllOf(named("while"),3798 snippetSuffix(" (${1:condition}) {\n$0\n}"))));3799 // However, snippets for functions must *not* end with $0.3800 EXPECT_THAT(Results.Completions,3801 Contains(AllOf(named("while_foo"),3802 snippetSuffix("(${1:int a}, ${2:int b})"))));3803 3804 Results = completions(R"cpp(3805 struct Base {3806 Base(int a, int b) {}3807 };3808 3809 struct Derived : Base {3810 Derived() : Base^3811 };3812 )cpp",3813 /*IndexSymbols=*/{}, Options);3814 // Constructors from base classes are a kind of pattern that shouldn't end3815 // with $0.3816 EXPECT_THAT(Results.Completions,3817 Contains(AllOf(named("Base"),3818 snippetSuffix("(${1:int a}, ${2:int b})"))));3819}3820 3821TEST(CompletionTest, WorksWithNullType) {3822 auto R = completions(R"cpp(3823 int main() {3824 for (auto [loopVar] : y ) { // y has to be unresolved.3825 int z = loopV^;3826 }3827 }3828 )cpp");3829 EXPECT_THAT(R.Completions, ElementsAre(named("loopVar")));3830}3831 3832TEST(CompletionTest, UsingDecl) {3833 const char *Header(R"cpp(3834 void foo(int);3835 namespace std {3836 using ::foo;3837 })cpp");3838 const char *Source(R"cpp(3839 void bar() {3840 std::^;3841 })cpp");3842 auto Index = TestTU::withHeaderCode(Header).index();3843 clangd::CodeCompleteOptions Opts;3844 Opts.Index = Index.get();3845 Opts.AllScopes = true;3846 auto R = completions(Source, {}, Opts);3847 EXPECT_THAT(R.Completions,3848 ElementsAre(AllOf(scope("std::"), named("foo"),3849 kind(CompletionItemKind::Reference))));3850}3851 3852TEST(CompletionTest, Enums) {3853 const char *Header(R"cpp(3854 namespace ns {3855 enum Unscoped { Clangd1 };3856 class C {3857 enum Unscoped { Clangd2 };3858 };3859 enum class Scoped { Clangd3 };3860 })cpp");3861 const char *Source(R"cpp(3862 void bar() {3863 Clangd^3864 })cpp");3865 auto Index = TestTU::withHeaderCode(Header).index();3866 clangd::CodeCompleteOptions Opts;3867 Opts.Index = Index.get();3868 Opts.AllScopes = true;3869 auto R = completions(Source, {}, Opts);3870 EXPECT_THAT(R.Completions, UnorderedElementsAre(3871 AllOf(scope("ns::"), named("Clangd1"),3872 kind(CompletionItemKind::EnumMember)),3873 AllOf(scope("ns::C::"), named("Clangd2"),3874 kind(CompletionItemKind::EnumMember)),3875 AllOf(scope("ns::Scoped::"), named("Clangd3"),3876 kind(CompletionItemKind::EnumMember))));3877}3878 3879TEST(CompletionTest, ScopeIsUnresolved) {3880 clangd::CodeCompleteOptions Opts = {};3881 Opts.AllScopes = true;3882 3883 auto Results = completions(R"cpp(3884 namespace a {3885 void f() { b::X^ }3886 }3887 )cpp",3888 {cls("a::b::XYZ")}, Opts);3889 EXPECT_THAT(Results.Completions,3890 UnorderedElementsAre(AllOf(qualifier(""), named("XYZ"))));3891}3892 3893TEST(CompletionTest, NestedScopeIsUnresolved) {3894 clangd::CodeCompleteOptions Opts = {};3895 Opts.AllScopes = true;3896 3897 auto Results = completions(R"cpp(3898 namespace a {3899 namespace b {}3900 void f() { b::c::X^ }3901 }3902 )cpp",3903 {cls("a::b::c::XYZ")}, Opts);3904 EXPECT_THAT(Results.Completions,3905 UnorderedElementsAre(AllOf(qualifier(""), named("XYZ"))));3906}3907 3908// Clang parser gets confused here and doesn't report the ns:: prefix.3909// Naive behavior is to insert it again. We examine the source and recover.3910TEST(CompletionTest, NamespaceDoubleInsertion) {3911 clangd::CodeCompleteOptions Opts = {};3912 3913 auto Results = completions(R"cpp(3914 namespace foo {3915 namespace ns {}3916 #define M(X) < X3917 M(ns::ABC^3918 }3919 )cpp",3920 {cls("foo::ns::ABCDE")}, Opts);3921 EXPECT_THAT(Results.Completions,3922 UnorderedElementsAre(AllOf(qualifier(""), named("ABCDE"))));3923}3924 3925TEST(CompletionTest, DerivedMethodsAreAlwaysVisible) {3926 // Despite the fact that base method matches the ref-qualifier better,3927 // completion results should only include the derived method.3928 auto Completions = completions(R"cpp(3929 struct deque_base {3930 float size();3931 double size() const;3932 };3933 struct deque : deque_base {3934 int size() const;3935 };3936 3937 auto x = deque().^3938 )cpp")3939 .Completions;3940 EXPECT_THAT(Completions,3941 ElementsAre(AllOf(returnType("int"), named("size"))));3942}3943 3944TEST(CompletionTest, NoCrashWithIncompleteLambda) {3945 auto Completions = completions("auto&& x = []{^").Completions;3946 // The completion of x itself can cause a problem: in the code completion3947 // callback, its type is not known, which affects the linkage calculation.3948 // A bad linkage value gets cached, and subsequently updated.3949 EXPECT_THAT(Completions, Contains(named("x")));3950 3951 auto Signatures = signatures("auto x() { x(^").signatures;3952 EXPECT_THAT(Signatures, Contains(sig("x() -> auto")));3953}3954 3955TEST(CompletionTest, DelayedTemplateParsing) {3956 Annotations Test(R"cpp(3957 int xxx;3958 template <typename T> int foo() { return xx^; }3959 )cpp");3960 auto TU = TestTU::withCode(Test.code());3961 // Even though delayed-template-parsing is on, we will disable it to provide3962 // completion in templates.3963 TU.ExtraArgs.push_back("-fdelayed-template-parsing");3964 3965 EXPECT_THAT(completions(TU, Test.point()).Completions,3966 Contains(named("xxx")));3967}3968 3969TEST(CompletionTest, CompletionRange) {3970 const char *WithRange = "auto x = [[abc]]^";3971 auto Completions = completions(WithRange);3972 EXPECT_EQ(Completions.CompletionRange, Annotations(WithRange).range());3973 Completions = completionsNoCompile(WithRange);3974 EXPECT_EQ(Completions.CompletionRange, Annotations(WithRange).range());3975 3976 const char *EmptyRange = "auto x = [[]]^";3977 Completions = completions(EmptyRange);3978 EXPECT_EQ(Completions.CompletionRange, Annotations(EmptyRange).range());3979 Completions = completionsNoCompile(EmptyRange);3980 EXPECT_EQ(Completions.CompletionRange, Annotations(EmptyRange).range());3981 3982 // Sema doesn't trigger at all here, while the no-sema completion runs3983 // heuristics as normal and reports a range. It'd be nice to be consistent.3984 const char *NoCompletion = "/* foo [[]]^ */";3985 Completions = completions(NoCompletion);3986 EXPECT_EQ(Completions.CompletionRange, std::nullopt);3987 Completions = completionsNoCompile(NoCompletion);3988 EXPECT_EQ(Completions.CompletionRange, Annotations(NoCompletion).range());3989}3990 3991TEST(NoCompileCompletionTest, Basic) {3992 auto Results = completionsNoCompile(R"cpp(3993 void func() {3994 int xyz;3995 int abc;3996 ^3997 }3998 )cpp");3999 EXPECT_FALSE(Results.RanParser);4000 EXPECT_THAT(Results.Completions,4001 UnorderedElementsAre(named("void"), named("func"), named("int"),4002 named("xyz"), named("abc")));4003}4004 4005TEST(NoCompileCompletionTest, WithFilter) {4006 auto Results = completionsNoCompile(R"cpp(4007 void func() {4008 int sym1;4009 int sym2;4010 int xyz1;4011 int xyz2;4012 sy^4013 }4014 )cpp");4015 EXPECT_THAT(Results.Completions,4016 UnorderedElementsAre(named("sym1"), named("sym2")));4017}4018 4019TEST(NoCompileCompletionTest, WithIndex) {4020 std::vector<Symbol> Syms = {func("xxx"), func("a::xxx"), func("ns::b::xxx"),4021 func("c::xxx"), func("ns::d::xxx")};4022 auto Results = completionsNoCompile(4023 R"cpp(4024 // Current-scopes, unqualified completion.4025 using namespace a;4026 namespace ns {4027 using namespace b;4028 void foo() {4029 xx^4030 }4031 }4032 )cpp",4033 Syms);4034 EXPECT_THAT(Results.Completions,4035 UnorderedElementsAre(AllOf(qualifier(""), scope("")),4036 AllOf(qualifier(""), scope("a::")),4037 AllOf(qualifier(""), scope("ns::b::"))));4038 CodeCompleteOptions Opts;4039 Opts.AllScopes = true;4040 Results = completionsNoCompile(4041 R"cpp(4042 // All-scopes unqualified completion.4043 using namespace a;4044 namespace ns {4045 using namespace b;4046 void foo() {4047 xx^4048 }4049 }4050 )cpp",4051 Syms, Opts);4052 EXPECT_THAT(Results.Completions,4053 UnorderedElementsAre(AllOf(qualifier(""), scope("")),4054 AllOf(qualifier(""), scope("a::")),4055 AllOf(qualifier(""), scope("ns::b::")),4056 AllOf(qualifier("c::"), scope("c::")),4057 AllOf(qualifier("d::"), scope("ns::d::"))));4058 Results = completionsNoCompile(4059 R"cpp(4060 // Qualified completion.4061 using namespace a;4062 namespace ns {4063 using namespace b;4064 void foo() {4065 b::xx^4066 }4067 }4068 )cpp",4069 Syms, Opts);4070 EXPECT_THAT(Results.Completions,4071 ElementsAre(AllOf(qualifier(""), scope("ns::b::"))));4072 Results = completionsNoCompile(4073 R"cpp(4074 // Absolutely qualified completion.4075 using namespace a;4076 namespace ns {4077 using namespace b;4078 void foo() {4079 ::a::xx^4080 }4081 }4082 )cpp",4083 Syms, Opts);4084 EXPECT_THAT(Results.Completions,4085 ElementsAre(AllOf(qualifier(""), scope("a::"))));4086}4087 4088TEST(AllowImplicitCompletion, All) {4089 const char *Yes[] = {4090 "foo.^bar",4091 "foo->^bar",4092 "foo::^bar",4093 " # include <^foo.h>",4094 "#import <foo/^bar.h>",4095 "#include_next \"^",4096 };4097 const char *No[] = {4098 "foo>^bar",4099 "foo:^bar",4100 "foo\n^bar",4101 "#include <foo.h> //^",4102 "#include \"foo.h\"^",4103 "#error <^",4104 "#<^",4105 };4106 for (const char *Test : Yes) {4107 llvm::Annotations A(Test);4108 EXPECT_TRUE(allowImplicitCompletion(A.code(), A.point())) << Test;4109 }4110 for (const char *Test : No) {4111 llvm::Annotations A(Test);4112 EXPECT_FALSE(allowImplicitCompletion(A.code(), A.point())) << Test;4113 }4114}4115 4116TEST(CompletionTest, FunctionArgsExist) {4117 clangd::CodeCompleteOptions Opts;4118 Opts.EnableSnippets = true;4119 std::string Context = R"cpp(4120 #define MACRO(x)4121 int foo(int A);4122 int bar();4123 struct Object {4124 Object(int B) {}4125 };4126 template <typename T>4127 struct Container {4128 Container(int Size) {}4129 };4130 )cpp";4131 EXPECT_THAT(completions(Context + "int y = fo^", {}, Opts).Completions,4132 UnorderedElementsAre(4133 AllOf(labeled("foo(int A)"), snippetSuffix("(${1:int A})"))));4134 EXPECT_THAT(4135 completions(Context + "int y = fo^(42)", {}, Opts).Completions,4136 UnorderedElementsAre(AllOf(labeled("foo(int A)"), snippetSuffix(""))));4137 // FIXME(kirillbobyrev): No snippet should be produced here.4138 EXPECT_THAT(completions(Context + "int y = fo^o(42)", {}, Opts).Completions,4139 UnorderedElementsAre(4140 AllOf(labeled("foo(int A)"), snippetSuffix("(${1:int A})"))));4141 EXPECT_THAT(4142 completions(Context + "int y = ba^", {}, Opts).Completions,4143 UnorderedElementsAre(AllOf(labeled("bar()"), snippetSuffix("()"))));4144 EXPECT_THAT(completions(Context + "int y = ba^()", {}, Opts).Completions,4145 UnorderedElementsAre(AllOf(labeled("bar()"), snippetSuffix(""))));4146 EXPECT_THAT(4147 completions(Context + "Object o = Obj^", {}, Opts).Completions,4148 Contains(AllOf(labeled("Object(int B)"), snippetSuffix("(${1:int B})"),4149 kind(CompletionItemKind::Constructor))));4150 EXPECT_THAT(completions(Context + "Object o = Obj^()", {}, Opts).Completions,4151 Contains(AllOf(labeled("Object(int B)"), snippetSuffix(""),4152 kind(CompletionItemKind::Constructor))));4153 EXPECT_THAT(4154 completions(Context + "Container c = Cont^", {}, Opts).Completions,4155 Contains(AllOf(labeled("Container<typename T>(int Size)"),4156 snippetSuffix("<${1:typename T}>(${2:int Size})"),4157 kind(CompletionItemKind::Constructor))));4158 EXPECT_THAT(4159 completions(Context + "Container c = Cont^()", {}, Opts).Completions,4160 Contains(AllOf(labeled("Container<typename T>(int Size)"),4161 snippetSuffix("<${1:typename T}>"),4162 kind(CompletionItemKind::Constructor))));4163 EXPECT_THAT(4164 completions(Context + "Container c = Cont^<int>()", {}, Opts).Completions,4165 Contains(AllOf(labeled("Container<typename T>(int Size)"),4166 snippetSuffix(""),4167 kind(CompletionItemKind::Constructor))));4168 EXPECT_THAT(completions(Context + "MAC^(2)", {}, Opts).Completions,4169 Contains(AllOf(labeled("MACRO(x)"), snippetSuffix(""),4170 kind(CompletionItemKind::Function))));4171}4172 4173TEST(CompletionTest, FunctionArgsExist_Issue1785) {4174 // This is a scenario where the implementation of our check for4175 // "is there a function argument list right after the cursor"4176 // gave a bogus result.4177 clangd::CodeCompleteOptions Opts;4178 Opts.EnableSnippets = true;4179 // The whitespace in this testcase is important!4180 std::string Code = R"cpp(4181void waldo(int);4182 4183int main()4184{4185 wal^4186 4187 4188 // ( )4189}4190 )cpp";4191 EXPECT_THAT(4192 completions(Code, {}, Opts).Completions,4193 Contains(AllOf(labeled("waldo(int)"), snippetSuffix("(${1:int})"))));4194}4195 4196TEST(CompletionTest, NoCrashDueToMacroOrdering) {4197 EXPECT_THAT(completions(R"cpp(4198 #define ECHO(X) X4199 #define ECHO2(X) ECHO(X)4200 int finish_preamble = EC^HO(2);)cpp")4201 .Completions,4202 UnorderedElementsAre(labeled("ECHO(X)"), labeled("ECHO2(X)")));4203}4204 4205TEST(CompletionTest, ObjCCategoryDecls) {4206 TestTU TU;4207 TU.ExtraArgs.push_back("-xobjective-c");4208 TU.HeaderCode = R"objc(4209 @interface Foo4210 @end4211 4212 @interface Foo (FooExt1)4213 @end4214 4215 @interface Foo (FooExt2)4216 @end4217 4218 @interface Bar4219 @end4220 4221 @interface Bar (BarExt)4222 @end)objc";4223 4224 {4225 Annotations Test(R"objc(4226 @implementation Foo (^)4227 @end4228 )objc");4229 TU.Code = Test.code().str();4230 auto Results = completions(TU, Test.point());4231 EXPECT_THAT(Results.Completions,4232 UnorderedElementsAre(labeled("FooExt1"), labeled("FooExt2")));4233 }4234 {4235 Annotations Test(R"objc(4236 @interface Foo (^)4237 @end4238 )objc");4239 TU.Code = Test.code().str();4240 auto Results = completions(TU, Test.point());4241 EXPECT_THAT(Results.Completions, UnorderedElementsAre(labeled("BarExt")));4242 }4243}4244 4245TEST(CompletionTest, PreambleCodeComplete) {4246 llvm::StringLiteral Baseline = "\n#define MACRO 12\nint num = MACRO;";4247 llvm::StringLiteral ModifiedCC =4248 "#include \"header.h\"\n#define MACRO 12\nint num = MACRO; int num2 = M^";4249 4250 Annotations Test(ModifiedCC);4251 auto BaselineTU = TestTU::withCode(Baseline);4252 auto ModifiedTU = TestTU::withCode(Test.code());4253 4254 MockFS FS;4255 auto Inputs = ModifiedTU.inputs(FS);4256 auto Result = codeComplete(testPath(ModifiedTU.Filename), Test.point(),4257 BaselineTU.preamble().get(), Inputs, {});4258 EXPECT_THAT(Result.Completions, Not(testing::IsEmpty()));4259}4260 4261TEST(CompletionTest, CommentParamName) {4262 const std::string Code = R"cpp(4263 void fun(int foo, int bar);4264 void overloaded(int param_int);4265 void overloaded(int param_int, int param_other);4266 void overloaded(char param_char);4267 int main() {4268 )cpp";4269 4270 EXPECT_THAT(completions(Code + "fun(/*^").Completions,4271 UnorderedElementsAre(labeled("foo=*/")));4272 EXPECT_THAT(completions(Code + "fun(1, /*^").Completions,4273 UnorderedElementsAre(labeled("bar=*/")));4274 EXPECT_THAT(completions(Code + "/*^").Completions, IsEmpty());4275 // Test de-duplication.4276 EXPECT_THAT(4277 completions(Code + "overloaded(/*^").Completions,4278 UnorderedElementsAre(labeled("param_int=*/"), labeled("param_char=*/")));4279 // Comment already has some text in it.4280 EXPECT_THAT(completions(Code + "fun(/* ^").Completions,4281 UnorderedElementsAre(labeled("foo=*/")));4282 EXPECT_THAT(completions(Code + "fun(/* f^").Completions,4283 UnorderedElementsAre(labeled("foo=*/")));4284 EXPECT_THAT(completions(Code + "fun(/* x^").Completions, IsEmpty());4285 EXPECT_THAT(completions(Code + "fun(/* f ^").Completions, IsEmpty());4286 4287 // Test ranges4288 {4289 std::string CompletionRangeTest(Code + "fun(/*[[^]]");4290 auto Results = completions(CompletionRangeTest);4291 EXPECT_THAT(Results.CompletionRange,4292 llvm::ValueIs(Annotations(CompletionRangeTest).range()));4293 EXPECT_THAT(4294 Results.Completions,4295 testing::Each(4296 AllOf(replacesRange(Annotations(CompletionRangeTest).range()),4297 origin(SymbolOrigin::AST), kind(CompletionItemKind::Text))));4298 }4299 {4300 std::string CompletionRangeTest(Code + "fun(/*[[fo^]]");4301 auto Results = completions(CompletionRangeTest);4302 EXPECT_THAT(Results.CompletionRange,4303 llvm::ValueIs(Annotations(CompletionRangeTest).range()));4304 EXPECT_THAT(4305 Results.Completions,4306 testing::Each(4307 AllOf(replacesRange(Annotations(CompletionRangeTest).range()),4308 origin(SymbolOrigin::AST), kind(CompletionItemKind::Text))));4309 }4310}4311 4312TEST(CompletionTest, Concepts) {4313 Annotations Code(R"cpp(4314 template<class T>4315 concept A = sizeof(T) <= 8;4316 4317 template<$tparam^A U>4318 int foo();4319 4320 template<typename T>4321 int bar(T t) requires $expr^A<int>;4322 4323 template<class T>4324 concept b = $expr^A && $expr^sizeof(T) % 2 == 0 || $expr^A && sizeof(T) == 1;4325 4326 $toplevel^A auto i = 19;4327 4328 template<$toplevel^A auto i> void constrainedNTTP();4329 4330 // FIXME: The first parameter should be dropped in this case.4331 void abbreviated($expr^A auto x) {}4332 )cpp");4333 TestTU TU;4334 TU.Code = Code.code().str();4335 TU.ExtraArgs = {"-std=c++20"};4336 4337 auto Sym = conceptSym("same_as");4338 Sym.Signature = "<typename Tp, typename Up>";4339 Sym.CompletionSnippetSuffix = "<${1:typename Tp}, ${2:typename Up}>";4340 std::vector<Symbol> Syms = {Sym};4341 for (auto P : Code.points("tparam")) {4342 ASSERT_THAT(4343 completions(TU, P, Syms).Completions,4344 AllOf(Contains(AllOf(named("A"), signature(""), snippetSuffix(""))),4345 Contains(AllOf(named("same_as"), signature("<typename Up>"),4346 snippetSuffix("<${2:typename Up}>"))),4347 Contains(named("class")), Contains(named("typename"))))4348 << "Completing template parameter at position " << P;4349 }4350 4351 for (auto P : Code.points("toplevel")) {4352 EXPECT_THAT(4353 completions(TU, P, Syms).Completions,4354 AllOf(Contains(AllOf(named("A"), signature(""), snippetSuffix(""))),4355 Contains(AllOf(named("same_as"), signature("<typename Up>"),4356 snippetSuffix("<${2:typename Up}>")))))4357 << "Completing 'requires' expression at position " << P;4358 }4359 4360 for (auto P : Code.points("expr")) {4361 EXPECT_THAT(4362 completions(TU, P, Syms).Completions,4363 AllOf(Contains(AllOf(named("A"), signature("<class T>"),4364 snippetSuffix("<${1:class T}>"))),4365 Contains(AllOf(4366 named("same_as"), signature("<typename Tp, typename Up>"),4367 snippetSuffix("<${1:typename Tp}, ${2:typename Up}>")))))4368 << "Completing 'requires' expression at position " << P;4369 }4370}4371 4372TEST(SignatureHelp, DocFormat) {4373 Annotations Code(R"cpp(4374 // Comment `with` markup.4375 void foo(int);4376 void bar() { foo(^); }4377 )cpp");4378 for (auto DocumentationFormat :4379 {MarkupKind::PlainText, MarkupKind::Markdown}) {4380 auto Sigs = signatures(Code.code(), Code.point(), /*IndexSymbols=*/{},4381 DocumentationFormat);4382 ASSERT_EQ(Sigs.signatures.size(), 1U);4383 EXPECT_EQ(Sigs.signatures[0].documentation.kind, DocumentationFormat);4384 }4385}4386 4387TEST(SignatureHelp, TemplateArguments) {4388 std::string Top = R"cpp(4389 template <typename T, int> bool foo(char);4390 template <int I, int> bool foo(float);4391 )cpp";4392 4393 auto First = signatures(Top + "bool x = foo<^");4394 EXPECT_THAT(4395 First.signatures,4396 UnorderedElementsAre(sig("foo<[[typename T]], [[int]]>() -> bool"),4397 sig("foo<[[int I]], [[int]]>() -> bool")));4398 EXPECT_EQ(First.activeParameter, 0);4399 4400 auto Second = signatures(Top + "bool x = foo<1, ^");4401 EXPECT_THAT(Second.signatures,4402 ElementsAre(sig("foo<[[int I]], [[int]]>() -> bool")));4403 EXPECT_EQ(Second.activeParameter, 1);4404}4405 4406TEST(CompletionTest, DoNotCrash) {4407 llvm::StringLiteral Cases[] = {4408 R"cpp(4409 template <typename = int> struct Foo {};4410 auto a = [x(3)](Foo<^>){};4411 )cpp",4412 };4413 for (auto Case : Cases) {4414 SCOPED_TRACE(Case);4415 auto Completions = completions(Case);4416 }4417}4418TEST(CompletionTest, PreambleFromDifferentTarget) {4419 constexpr std::string_view PreambleTarget = "x86_64";4420 constexpr std::string_view Contents =4421 "int foo(int); int num; int num2 = foo(n^";4422 4423 Annotations Test(Contents);4424 auto TU = TestTU::withCode(Test.code());4425 TU.ExtraArgs.emplace_back("-target");4426 TU.ExtraArgs.emplace_back(PreambleTarget);4427 auto Preamble = TU.preamble();4428 ASSERT_TRUE(Preamble);4429 // Switch target to wasm.4430 TU.ExtraArgs.pop_back();4431 TU.ExtraArgs.emplace_back("wasm32");4432 4433 MockFS FS;4434 auto Inputs = TU.inputs(FS);4435 auto Result = codeComplete(testPath(TU.Filename), Test.point(),4436 Preamble.get(), Inputs, {});4437 auto Signatures =4438 signatureHelp(testPath(TU.Filename), Test.point(), *Preamble, Inputs, {});4439 4440 // Make sure we don't crash.4441 EXPECT_THAT(Result.Completions, Not(testing::IsEmpty()));4442 EXPECT_THAT(Signatures.signatures, Not(testing::IsEmpty()));4443}4444 4445TEST(CompletionTest, SkipExplicitObjectParameter) {4446 Annotations Code(R"cpp(4447 struct A {4448 void foo(this auto&& self, int arg); 4449 void bar(this A self, int arg);4450 };4451 4452 int main() {4453 A a {};4454 a.$c1^;4455 (&A::fo$c2^;4456 (&A::ba$c3^;4457 }4458 )cpp");4459 4460 // TODO: llvm/llvm-project/1466494461 // This is incorrect behavior. Correct Result should be a variant of,4462 // c2: signature = (auto&& self, int arg)4463 // snippet = (${1: auto&& self}, ${2: int arg})4464 // c3: signature = (A self, int arg)4465 // snippet = (${1: A self}, ${2: int arg})4466 4467 auto TU = TestTU::withCode(Code.code());4468 TU.ExtraArgs = {"-std=c++23"};4469 4470 auto Preamble = TU.preamble();4471 ASSERT_TRUE(Preamble);4472 4473 CodeCompleteOptions Opts{};4474 4475 MockFS FS;4476 auto Inputs = TU.inputs(FS);4477 {4478 auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"),4479 Preamble.get(), Inputs, Opts);4480 4481 EXPECT_THAT(Result.Completions,4482 UnorderedElementsAre(AllOf(named("foo"), signature("(int arg)"),4483 snippetSuffix("(${1:int arg})")),4484 AllOf(named("bar"), signature("(int arg)"),4485 snippetSuffix("(${1:int arg})"))));4486 }4487 {4488 auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),4489 Preamble.get(), Inputs, Opts);4490 EXPECT_THAT(4491 Result.Completions,4492 ElementsAre(AllOf(named("foo"), signature("<class self:auto>(int arg)"),4493 snippetSuffix("<${1:class self:auto}>"))));4494 }4495 {4496 auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"),4497 Preamble.get(), Inputs, Opts);4498 EXPECT_THAT(Result.Completions,4499 ElementsAre(AllOf(named("bar"), signature("(int arg)"),4500 snippetSuffix(""))));4501 }4502}4503 4504TEST(CompletionTest, MemberAccessInExplicitObjMemfn) {4505 Annotations Code(R"cpp(4506 struct A {4507 int member {};4508 int memberFnA(int a);4509 int memberFnA(this A&, float a);4510 4511 void foo(this A& self) {4512 // Should not offer any members here, since 4513 // it needs to be referenced through `self`.4514 mem$c1^;4515 // should offer all results4516 self.mem$c2^;4517 4518 [&]() {4519 // should not offer any results4520 mem$c3^;4521 }();4522 }4523 };4524 )cpp");4525 4526 auto TU = TestTU::withCode(Code.code());4527 TU.ExtraArgs = {"-std=c++23"};4528 4529 auto Preamble = TU.preamble();4530 ASSERT_TRUE(Preamble);4531 4532 CodeCompleteOptions Opts{};4533 4534 MockFS FS;4535 auto Inputs = TU.inputs(FS);4536 4537 {4538 auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"),4539 Preamble.get(), Inputs, Opts);4540 4541 EXPECT_THAT(Result.Completions, ElementsAre());4542 }4543 {4544 auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),4545 Preamble.get(), Inputs, Opts);4546 4547 EXPECT_THAT(4548 Result.Completions,4549 UnorderedElementsAre(named("member"),4550 AllOf(named("memberFnA"), signature("(int a)"),4551 snippetSuffix("(${1:int a})")),4552 AllOf(named("memberFnA"), signature("(float a)"),4553 snippetSuffix("(${1:float a})"))));4554 }4555 {4556 auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"),4557 Preamble.get(), Inputs, Opts);4558 4559 EXPECT_THAT(Result.Completions, ElementsAre());4560 }4561}4562 4563TEST(CompletionTest, ListExplicitObjectOverloads) {4564 Annotations Code(R"cpp(4565 struct S {4566 void foo1(int a);4567 void foo2(int a) const;4568 void foo2(this const S& self, float a);4569 void foo3(this const S& self, int a);4570 void foo4(this S& self, int a);4571 };4572 4573 void S::foo1(int a) {4574 this->$c1^;4575 }4576 4577 void S::foo2(int a) const {4578 this->$c2^;4579 }4580 4581 void S::foo3(this const S& self, int a) {4582 self.$c3^;4583 }4584 4585 void S::foo4(this S& self, int a) {4586 self.$c4^;4587 }4588 4589 void test1(S s) {4590 s.$c5^;4591 }4592 4593 void test2(const S s) {4594 s.$c6^;4595 }4596 )cpp");4597 4598 auto TU = TestTU::withCode(Code.code());4599 TU.ExtraArgs = {"-std=c++23"};4600 4601 auto Preamble = TU.preamble();4602 ASSERT_TRUE(Preamble);4603 4604 CodeCompleteOptions Opts{};4605 4606 MockFS FS;4607 auto Inputs = TU.inputs(FS);4608 4609 {4610 auto Result = codeComplete(testPath(TU.Filename), Code.point("c1"),4611 Preamble.get(), Inputs, Opts);4612 EXPECT_THAT(4613 Result.Completions,4614 UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),4615 snippetSuffix("(${1:int a})")),4616 AllOf(named("foo2"), signature("(int a) const"),4617 snippetSuffix("(${1:int a})")),4618 AllOf(named("foo2"), signature("(float a) const"),4619 snippetSuffix("(${1:float a})")),4620 AllOf(named("foo3"), signature("(int a) const"),4621 snippetSuffix("(${1:int a})")),4622 AllOf(named("foo4"), signature("(int a)"),4623 snippetSuffix("(${1:int a})"))));4624 }4625 {4626 auto Result = codeComplete(testPath(TU.Filename), Code.point("c2"),4627 Preamble.get(), Inputs, Opts);4628 EXPECT_THAT(4629 Result.Completions,4630 UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),4631 snippetSuffix("(${1:int a})")),4632 AllOf(named("foo2"), signature("(float a) const"),4633 snippetSuffix("(${1:float a})")),4634 AllOf(named("foo3"), signature("(int a) const"),4635 snippetSuffix("(${1:int a})"))));4636 }4637 {4638 auto Result = codeComplete(testPath(TU.Filename), Code.point("c3"),4639 Preamble.get(), Inputs, Opts);4640 EXPECT_THAT(4641 Result.Completions,4642 UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),4643 snippetSuffix("(${1:int a})")),4644 AllOf(named("foo2"), signature("(float a) const"),4645 snippetSuffix("(${1:float a})")),4646 AllOf(named("foo3"), signature("(int a) const"),4647 snippetSuffix("(${1:int a})"))));4648 }4649 {4650 auto Result = codeComplete(testPath(TU.Filename), Code.point("c4"),4651 Preamble.get(), Inputs, Opts);4652 EXPECT_THAT(4653 Result.Completions,4654 UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),4655 snippetSuffix("(${1:int a})")),4656 AllOf(named("foo2"), signature("(int a) const"),4657 snippetSuffix("(${1:int a})")),4658 AllOf(named("foo2"), signature("(float a) const"),4659 snippetSuffix("(${1:float a})")),4660 AllOf(named("foo3"), signature("(int a) const"),4661 snippetSuffix("(${1:int a})")),4662 AllOf(named("foo4"), signature("(int a)"),4663 snippetSuffix("(${1:int a})"))));4664 }4665 {4666 auto Result = codeComplete(testPath(TU.Filename), Code.point("c5"),4667 Preamble.get(), Inputs, Opts);4668 EXPECT_THAT(4669 Result.Completions,4670 UnorderedElementsAre(AllOf(named("foo1"), signature("(int a)"),4671 snippetSuffix("(${1:int a})")),4672 AllOf(named("foo2"), signature("(int a) const"),4673 snippetSuffix("(${1:int a})")),4674 AllOf(named("foo2"), signature("(float a) const"),4675 snippetSuffix("(${1:float a})")),4676 AllOf(named("foo3"), signature("(int a) const"),4677 snippetSuffix("(${1:int a})")),4678 AllOf(named("foo4"), signature("(int a)"),4679 snippetSuffix("(${1:int a})"))));4680 }4681 {4682 auto Result = codeComplete(testPath(TU.Filename), Code.point("c6"),4683 Preamble.get(), Inputs, Opts);4684 EXPECT_THAT(4685 Result.Completions,4686 UnorderedElementsAre(AllOf(named("foo2"), signature("(int a) const"),4687 snippetSuffix("(${1:int a})")),4688 AllOf(named("foo2"), signature("(float a) const"),4689 snippetSuffix("(${1:float a})")),4690 AllOf(named("foo3"), signature("(int a) const"),4691 snippetSuffix("(${1:int a})"))));4692 }4693}4694 4695} // namespace4696} // namespace clangd4697} // namespace clang4698