946 lines · cpp
1//===-- SelectionTests.cpp - ----------------------------------------------===//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#include "Annotations.h"9#include "Selection.h"10#include "SourceCode.h"11#include "TestTU.h"12#include "support/TestTracer.h"13#include "clang/AST/ASTConcept.h"14#include "clang/AST/Decl.h"15#include "llvm/Support/Casting.h"16#include "gmock/gmock.h"17#include "gtest/gtest.h"18 19namespace clang {20namespace clangd {21namespace {22using ::testing::ElementsAreArray;23using ::testing::UnorderedElementsAreArray;24 25// Create a selection tree corresponding to a point or pair of points.26// This uses the precisely-defined createRight semantics. The fuzzier27// createEach is tested separately.28SelectionTree makeSelectionTree(const StringRef MarkedCode, ParsedAST &AST) {29 Annotations Test(MarkedCode);30 switch (Test.points().size()) {31 case 1: { // Point selection.32 unsigned Offset = cantFail(positionToOffset(Test.code(), Test.point()));33 return SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),34 Offset, Offset);35 }36 case 2: // Range selection.37 return SelectionTree::createRight(38 AST.getASTContext(), AST.getTokens(),39 cantFail(positionToOffset(Test.code(), Test.points()[0])),40 cantFail(positionToOffset(Test.code(), Test.points()[1])));41 default:42 ADD_FAILURE() << "Expected 1-2 points for selection.\n" << MarkedCode;43 return SelectionTree::createRight(AST.getASTContext(), AST.getTokens(), 0u,44 0u);45 }46}47 48Range nodeRange(const SelectionTree::Node *N, ParsedAST &AST) {49 if (!N)50 return Range{};51 const SourceManager &SM = AST.getSourceManager();52 const LangOptions &LangOpts = AST.getLangOpts();53 StringRef Buffer = SM.getBufferData(SM.getMainFileID());54 if (llvm::isa_and_nonnull<TranslationUnitDecl>(N->ASTNode.get<Decl>()))55 return Range{Position{}, offsetToPosition(Buffer, Buffer.size())};56 auto FileRange =57 toHalfOpenFileRange(SM, LangOpts, N->ASTNode.getSourceRange());58 assert(FileRange && "We should be able to get the File Range");59 return Range{60 offsetToPosition(Buffer, SM.getFileOffset(FileRange->getBegin())),61 offsetToPosition(Buffer, SM.getFileOffset(FileRange->getEnd()))};62}63 64std::string nodeKind(const SelectionTree::Node *N) {65 return N ? N->kind() : "<null>";66}67 68std::vector<const SelectionTree::Node *> allNodes(const SelectionTree &T) {69 std::vector<const SelectionTree::Node *> Result = {&T.root()};70 for (unsigned I = 0; I < Result.size(); ++I) {71 const SelectionTree::Node *N = Result[I];72 Result.insert(Result.end(), N->Children.begin(), N->Children.end());73 }74 return Result;75}76 77// Returns true if Common is a descendent of Root.78// Verifies nothing is selected above Common.79bool verifyCommonAncestor(const SelectionTree::Node &Root,80 const SelectionTree::Node *Common,81 StringRef MarkedCode) {82 if (&Root == Common)83 return true;84 if (Root.Selected)85 ADD_FAILURE() << "Selected nodes outside common ancestor\n" << MarkedCode;86 bool Seen = false;87 for (const SelectionTree::Node *Child : Root.Children)88 if (verifyCommonAncestor(*Child, Common, MarkedCode)) {89 if (Seen)90 ADD_FAILURE() << "Saw common ancestor twice\n" << MarkedCode;91 Seen = true;92 }93 return Seen;94}95 96TEST(SelectionTest, CommonAncestor) {97 struct Case {98 // Selection is between ^marks^.99 // common ancestor marked with a [[range]].100 const char *Code;101 const char *CommonAncestorKind;102 };103 Case Cases[] = {104 {105 R"cpp(106 template <typename T>107 int x = T::[[^U]]::ccc();108 )cpp",109 "DependentNameTypeLoc",110 },111 {112 R"cpp(113 struct AAA { struct BBB { static int ccc(); };};114 int x = AAA::[[B^B^B]]::ccc();115 )cpp",116 "RecordTypeLoc",117 },118 {119 R"cpp(120 struct AAA { struct BBB { static int ccc(); };};121 int x = AAA::[[B^BB^]]::ccc();122 )cpp",123 "RecordTypeLoc",124 },125 {126 R"cpp(127 struct AAA { struct BBB { static int ccc(); };};128 int x = [[AAA::BBB::c^c^c]]();129 )cpp",130 "DeclRefExpr",131 },132 {133 R"cpp(134 struct AAA { struct BBB { static int ccc(); };};135 int x = [[AAA::BBB::cc^c(^)]];136 )cpp",137 "CallExpr",138 },139 140 {141 R"cpp(142 void foo() { [[if (1^11) { return; } else {^ }]] }143 )cpp",144 "IfStmt",145 },146 {147 R"cpp(148 int x(int);149 #define M(foo) x(foo)150 int a = 42;151 int b = M([[^a]]);152 )cpp",153 "DeclRefExpr",154 },155 {156 R"cpp(157 void foo();158 #define CALL_FUNCTION(X) X()159 void bar() { CALL_FUNCTION([[f^o^o]]); }160 )cpp",161 "DeclRefExpr",162 },163 {164 R"cpp(165 void foo();166 #define CALL_FUNCTION(X) X()167 void bar() { [[CALL_FUNC^TION(fo^o)]]; }168 )cpp",169 "CallExpr",170 },171 {172 R"cpp(173 void foo();174 #define CALL_FUNCTION(X) X()175 void bar() { [[C^ALL_FUNC^TION(foo)]]; }176 )cpp",177 "CallExpr",178 },179 {180 R"cpp(181 void foo();182 #^define CALL_FUNCTION(X) X(^)183 void bar() { CALL_FUNCTION(foo); }184 )cpp",185 nullptr,186 },187 {188 R"cpp(189 void foo();190 #define CALL_FUNCTION(X) X()191 void bar() { CALL_FUNCTION(foo^)^; }192 )cpp",193 nullptr,194 },195 {196 R"cpp(197 namespace ns {198 #if 0199 void fo^o() {}200 #endif201 }202 )cpp",203 nullptr,204 },205 {206 R"cpp(207 #define TARGET void foo()208 [[TAR^GET{ return; }]]209 )cpp",210 "FunctionDecl",211 },212 {213 R"cpp(214 struct S { S(const char*); };215 [[S s ^= "foo"]];216 )cpp",217 // The AST says a CXXConstructExpr covers the = sign in C++14.218 // But we consider CXXConstructExpr to only own brackets.219 // (It's not the interesting constructor anyway, just S(&&)).220 "VarDecl",221 },222 {223 R"cpp(224 struct S { S(const char*); };225 [[S ^s = "foo"]];226 )cpp",227 "VarDecl",228 },229 {230 R"cpp(231 [[^void]] (*S)(int) = nullptr;232 )cpp",233 "BuiltinTypeLoc",234 },235 {236 R"cpp(237 [[void (*S)^(int)]] = nullptr;238 )cpp",239 "FunctionProtoTypeLoc",240 },241 {242 R"cpp(243 [[void (^*S)(int)]] = nullptr;244 )cpp",245 "PointerTypeLoc",246 },247 {248 R"cpp(249 [[void (*^S)(int) = nullptr]];250 )cpp",251 "VarDecl",252 },253 {254 R"cpp(255 [[void ^(*S)(int)]] = nullptr;256 )cpp",257 "ParenTypeLoc",258 },259 {260 R"cpp(261 struct S {262 int foo() const;263 int bar() { return [[f^oo]](); }264 };265 )cpp",266 "MemberExpr", // Not implicit CXXThisExpr, or its implicit cast!267 },268 {269 R"cpp(270 auto lambda = [](const char*){ return 0; };271 int x = lambda([["y^"]]);272 )cpp",273 "StringLiteral", // Not DeclRefExpr to operator()!274 },275 {276 R"cpp(277 struct Foo {};278 struct Bar : [[v^ir^tual private Foo]] {};279 )cpp",280 "CXXBaseSpecifier",281 },282 {283 R"cpp(284 struct Foo {};285 struct Bar : private [[Fo^o]] {};286 )cpp",287 "RecordTypeLoc",288 },289 {290 R"cpp(291 struct Foo {};292 struct Bar : [[Fo^o]] {};293 )cpp",294 "RecordTypeLoc",295 },296 297 // Point selections.298 {"void foo() { [[^foo]](); }", "DeclRefExpr"},299 {"void foo() { [[f^oo]](); }", "DeclRefExpr"},300 {"void foo() { [[fo^o]](); }", "DeclRefExpr"},301 {"void foo() { [[foo^()]]; }", "CallExpr"},302 {"void foo() { [[foo^]] (); }", "DeclRefExpr"},303 {"int bar; void foo() [[{ foo (); }]]^", "CompoundStmt"},304 {"int x = [[42]]^;", "IntegerLiteral"},305 306 // Ignores whitespace, comments, and semicolons in the selection.307 {"void foo() { [[foo^()]]; /*comment*/^}", "CallExpr"},308 309 // Tricky case: FunctionTypeLoc in FunctionDecl has a hole in it.310 {"[[^void]] foo();", "BuiltinTypeLoc"},311 {"[[void foo^()]];", "FunctionProtoTypeLoc"},312 {"[[^void foo^()]];", "FunctionDecl"},313 {"[[void ^foo()]];", "FunctionDecl"},314 // Tricky case: with function attributes, the AttributedTypeLoc's range315 // includes the function name, but we want the name to be associated with316 // the CXXMethodDecl.317 {"struct X { [[const int* ^Get() const <:[clang::lifetimebound]:> "318 "{return nullptr;}]]; };",319 "CXXMethodDecl"},320 // When the cursor is on the attribute itself, we should select the321 // AttributedTypeLoc. Note: Due to a bug or deliberate quirk in the AST322 // modeling of AttributedTypeLoc, its range ends at the attribute name323 // token, not including the closing brackets ":>:>".324 {"struct X { const [[int* Foo() const <:<:clang::life^timebound]]:>:> "325 "{return nullptr;}; };",326 "AttributedTypeLoc"},327 // Tricky case: two VarDecls share a specifier.328 {"[[int ^a]], b;", "VarDecl"},329 {"[[int a, ^b]];", "VarDecl"},330 // Tricky case: CXXConstructExpr wants to claim the whole init range.331 {332 R"cpp(333 struct X { X(int); };334 class Y {335 X x;336 Y() : [[^x(4)]] {}337 };338 )cpp",339 "CXXCtorInitializer", // Not the CXXConstructExpr!340 },341 // Tricky case: anonymous struct is a sibling of the VarDecl.342 {"[[st^ruct {int x;}]] y;", "CXXRecordDecl"},343 {"[[struct {int x;} ^y]];", "VarDecl"},344 {"struct {[[int ^x]];} y;", "FieldDecl"},345 346 // Tricky case: nested ArrayTypeLocs have the same token range.347 {"const int x = 1, y = 2; int array[^[[x]]][10][y];", "DeclRefExpr"},348 {"const int x = 1, y = 2; int array[x][10][^[[y]]];", "DeclRefExpr"},349 {"const int x = 1, y = 2; int array[x][^[[10]]][y];", "IntegerLiteral"},350 {"const int x = 1, y = 2; [[i^nt]] array[x][10][y];", "BuiltinTypeLoc"},351 {"void func(int x) { int v_array[^[[x]]][10]; }", "DeclRefExpr"},352 353 {"int (*getFunc([[do^uble]]))(int);", "BuiltinTypeLoc"},354 355 // Member pointers and pack expansion use declarator syntax, but are356 // restricted so they don't need special casing.357 {"class X{}; [[int X::^*]]y[10];", "MemberPointerTypeLoc"},358 {"template<typename ...T> void foo([[T*^...]]x);",359 "PackExpansionTypeLoc"},360 {"template<typename ...T> void foo([[^T]]*...x);",361 "TemplateTypeParmTypeLoc"},362 363 // FIXME: the AST has no location info for qualifiers.364 {"const [[a^uto]] x = 42;", "AutoTypeLoc"},365 {"co^nst auto x = 42;", nullptr},366 367 {"^", nullptr},368 {"void foo() { [[foo^^]] (); }", "DeclRefExpr"},369 370 // FIXME: Ideally we'd get a declstmt or the VarDecl itself here.371 // This doesn't happen now; the RAV doesn't traverse a node containing ;.372 {"int x = 42;^", nullptr},373 374 // Common ancestor is logically TUDecl, but we never return that.375 {"^int x; int y;^", nullptr},376 377 // Node types that have caused problems in the past.378 {"template <typename T> void foo() { [[^T]] t; }",379 "TemplateTypeParmTypeLoc"},380 381 // No crash382 {383 R"cpp(384 template <class T> struct Foo {};385 template <[[template<class> class /*cursor here*/^U]]>386 struct Foo<U<int>*> {};387 )cpp",388 "TemplateTemplateParmDecl"},389 390 // Foreach has a weird AST, ensure we can select parts of the range init.391 // This used to fail, because the DeclStmt for C claimed the whole range.392 {393 R"cpp(394 struct Str {395 const char *begin();396 const char *end();397 };398 Str makeStr(const char*);399 void loop() {400 for (const char C : [[mak^eStr("foo"^)]])401 ;402 }403 )cpp",404 "CallExpr"},405 406 // User-defined literals are tricky: is 12_i one token or two?407 // For now we treat it as one, and the UserDefinedLiteral as a leaf.408 {409 R"cpp(410 struct Foo{};411 Foo operator""_ud(unsigned long long);412 Foo x = [[^12_ud]];413 )cpp",414 "UserDefinedLiteral"},415 416 {417 R"cpp(418 int a;419 decltype([[^a]] + a) b;420 )cpp",421 "DeclRefExpr"},422 {"[[decltype^(1)]] b;", "DecltypeTypeLoc"}, // Not the VarDecl.423 // decltype(auto) is an AutoTypeLoc!424 {"[[de^cltype(a^uto)]] a = 1;", "AutoTypeLoc"},425 426 // Objective-C nullability attributes.427 {428 R"cpp(429 @interface I{}430 @property(nullable) [[^I]] *x;431 @end432 )cpp",433 "ObjCInterfaceTypeLoc"},434 {435 R"cpp(436 @interface I{}437 - (void)doSomething:(nonnull [[i^d]])argument;438 @end439 )cpp",440 "TypedefTypeLoc"},441 442 // Objective-C OpaqueValueExpr/PseudoObjectExpr has weird ASTs.443 // Need to traverse the contents of the OpaqueValueExpr to the POE,444 // and ensure we traverse only the syntactic form of the PseudoObjectExpr.445 {446 R"cpp(447 @interface I{}448 @property(retain) I*x;449 @property(retain) I*y;450 @end451 void test(I *f) { [[^f]].x.y = 0; }452 )cpp",453 "DeclRefExpr"},454 {455 R"cpp(456 @interface I{}457 @property(retain) I*x;458 @property(retain) I*y;459 @end460 void test(I *f) { [[f.^x]].y = 0; }461 )cpp",462 "ObjCPropertyRefExpr"},463 // Examples with implicit properties.464 {465 R"cpp(466 @interface I{}467 -(int)foo;468 @end469 int test(I *f) { return 42 + [[^f]].foo; }470 )cpp",471 "DeclRefExpr"},472 {473 R"cpp(474 @interface I{}475 -(int)foo;476 @end477 int test(I *f) { return 42 + [[f.^foo]]; }478 )cpp",479 "ObjCPropertyRefExpr"},480 {"struct foo { [[int has^h<:32:>]]; };", "FieldDecl"},481 {"struct foo { [[op^erator int()]]; };", "CXXConversionDecl"},482 {"struct foo { [[^~foo()]]; };", "CXXDestructorDecl"},483 {"struct foo { [[~^foo()]]; };", "CXXDestructorDecl"},484 {"template <class T> struct foo { ~foo<[[^T]]>(){} };",485 "TemplateTypeParmTypeLoc"},486 {"struct foo {}; void bar(foo *f) { [[f->~^foo]](); }", "MemberExpr"},487 {"struct foo { [[fo^o(){}]] };", "CXXConstructorDecl"},488 489 {R"cpp(490 struct S1 { void f(); };491 struct S2 { S1 * operator->(); };492 void test(S2 s2) {493 s2[[-^>]]f();494 }495 )cpp",496 "DeclRefExpr"}, // DeclRefExpr to the "operator->" method.497 498 // Template template argument.499 {R"cpp(500 template <typename> class Vector {};501 template <template <typename> class Container> class A {};502 A<[[V^ector]]> a;503 )cpp",504 "TemplateArgumentLoc"},505 506 // Attributes507 {R"cpp(508 void f(int * __attribute__(([[no^nnull]])) );509 )cpp",510 "NonNullAttr"},511 512 {R"cpp(513 // Digraph syntax for attributes to avoid accidental annotations.514 class <:[gsl::Owner([[in^t]])]:> X{};515 )cpp",516 "BuiltinTypeLoc"},517 518 // This case used to crash - AST has a null Attr519 {R"cpp(520 @interface I521 [[@property(retain, nonnull) <:[My^Object2]:> *x]]; // error-ok522 @end523 )cpp",524 "ObjCPropertyDecl"},525 526 {R"cpp(527 typedef int Foo;528 enum Bar : [[Fo^o]] {};529 )cpp",530 "TypedefTypeLoc"},531 {R"cpp(532 typedef int Foo;533 enum Bar : [[Fo^o]];534 )cpp",535 "TypedefTypeLoc"},536 537 // lambda captured var-decl538 {R"cpp(539 void test(int bar) {540 auto l = [^[[foo = bar]]] { };541 })cpp",542 "VarDecl"},543 {R"cpp(544 /*error-ok*/545 void func() [[{^]])cpp",546 "CompoundStmt"},547 {R"cpp(548 void func() { [[__^func__]]; }549 )cpp",550 "PredefinedExpr"},551 552 // using enum553 {R"cpp(554 namespace ns { enum class A {}; };555 using enum ns::[[^A]];556 )cpp",557 "EnumTypeLoc"},558 {R"cpp(559 namespace ns { enum class A {}; using B = A; };560 using enum ns::[[^B]];561 )cpp",562 "TypedefTypeLoc"},563 {R"cpp(564 namespace ns { enum class A {}; };565 using enum [[^ns::]]A;566 )cpp",567 "NestedNameSpecifierLoc"},568 {R"cpp(569 namespace ns { enum class A {}; };570 [[using ^enum ns::A]];571 )cpp",572 "UsingEnumDecl"},573 {R"cpp(574 namespace ns { enum class A {}; };575 [[^using enum ns::A]];576 )cpp",577 "UsingEnumDecl"},578 579 // concepts580 {R"cpp(581 template <class> concept C = true;582 auto x = [[^C<int>]];583 )cpp",584 "ConceptReference"},585 {R"cpp(586 template <class> concept C = true;587 [[^C]] auto x = 0;588 )cpp",589 "ConceptReference"},590 {R"cpp(591 template <class> concept C = true;592 void foo([[^C]] auto x) {}593 )cpp",594 "ConceptReference"},595 {R"cpp(596 template <class> concept C = true;597 template <[[^C]] x> int i = 0;598 )cpp",599 "ConceptReference"},600 {R"cpp(601 namespace ns { template <class> concept C = true; }602 auto x = [[ns::^C<int>]];603 )cpp",604 "ConceptReference"},605 {R"cpp(606 template <typename T, typename K>607 concept D = true;608 template <typename T> void g(D<[[^T]]> auto abc) {}609 )cpp",610 "TemplateTypeParmTypeLoc"},611 };612 613 for (const Case &C : Cases) {614 trace::TestTracer Tracer;615 Annotations Test(C.Code);616 617 TestTU TU;618 TU.Code = std::string(Test.code());619 620 TU.ExtraArgs.push_back("-xobjective-c++");621 TU.ExtraArgs.push_back("-std=c++20");622 623 auto AST = TU.build();624 auto T = makeSelectionTree(C.Code, AST);625 EXPECT_EQ("TranslationUnitDecl", nodeKind(&T.root())) << C.Code;626 627 if (Test.ranges().empty()) {628 // If no [[range]] is marked in the example, there should be no selection.629 EXPECT_FALSE(T.commonAncestor()) << C.Code << "\n" << T;630 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),631 testing::IsEmpty());632 } else {633 // If there is an expected selection, common ancestor should exist634 // with the appropriate node type.635 EXPECT_EQ(C.CommonAncestorKind, nodeKind(T.commonAncestor()))636 << C.Code << "\n"637 << T;638 // Convert the reported common ancestor to a range and verify it.639 EXPECT_EQ(nodeRange(T.commonAncestor(), AST), Test.range())640 << C.Code << "\n"641 << T;642 643 // Check that common ancestor is reachable on exactly one path from root,644 // and no nodes outside it are selected.645 EXPECT_TRUE(verifyCommonAncestor(T.root(), T.commonAncestor(), C.Code))646 << C.Code;647 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),648 ElementsAreArray({0}));649 }650 }651}652 653// Regression test: this used to match the injected X, not the outer X.654TEST(SelectionTest, InjectedClassName) {655 const char *Code = "struct ^X { int x; };";656 auto AST = TestTU::withCode(Annotations(Code).code()).build();657 auto T = makeSelectionTree(Code, AST);658 ASSERT_EQ("CXXRecordDecl", nodeKind(T.commonAncestor())) << T;659 auto *D = dyn_cast<CXXRecordDecl>(T.commonAncestor()->ASTNode.get<Decl>());660 EXPECT_FALSE(D->isInjectedClassName());661}662 663TEST(SelectionTree, Metrics) {664 const char *Code = R"cpp(665 // error-ok: testing behavior on recovery expression666 int foo();667 int foo(int, int);668 int x = fo^o(42);669 )cpp";670 auto AST = TestTU::withCode(Annotations(Code).code()).build();671 trace::TestTracer Tracer;672 auto T = makeSelectionTree(Code, AST);673 EXPECT_THAT(Tracer.takeMetric("selection_recovery", "C++"),674 ElementsAreArray({1}));675 EXPECT_THAT(Tracer.takeMetric("selection_recovery_type", "C++"),676 ElementsAreArray({1}));677}678 679// FIXME: Doesn't select the binary operator node in680// #define FOO(X) X + 1681// int a, b = [[FOO(a)]];682TEST(SelectionTest, Selected) {683 // Selection with ^marks^.684 // Partially selected nodes marked with a [[range]].685 // Completely selected nodes marked with a $C[[range]].686 const char *Cases[] = {687 R"cpp( int abc, xyz = [[^ab^c]]; )cpp",688 R"cpp( int abc, xyz = [[a^bc^]]; )cpp",689 R"cpp( int abc, xyz = $C[[^abc^]]; )cpp",690 R"cpp(691 void foo() {692 [[if ([[1^11]]) $C[[{693 $C[[return]];694 }]] else [[{^695 }]]]]696 char z;697 }698 )cpp",699 R"cpp(700 template <class T>701 struct unique_ptr {};702 void foo(^$C[[unique_ptr<$C[[unique_ptr<$C[[int]]>]]>]]^ a) {}703 )cpp",704 R"cpp(int a = [[5 >^> 1]];)cpp",705 R"cpp(706 #define ECHO(X) X707 ECHO(EC^HO($C[[int]]) EC^HO(a));708 )cpp",709 R"cpp( $C[[^$C[[int]] a^]]; )cpp",710 R"cpp( $C[[^$C[[int]] a = $C[[5]]^]]; )cpp",711 };712 for (const char *C : Cases) {713 Annotations Test(C);714 auto AST = TestTU::withCode(Test.code()).build();715 auto T = makeSelectionTree(C, AST);716 717 std::vector<Range> Complete, Partial;718 for (const SelectionTree::Node *N : allNodes(T))719 if (N->Selected == SelectionTree::Complete)720 Complete.push_back(nodeRange(N, AST));721 else if (N->Selected == SelectionTree::Partial)722 Partial.push_back(nodeRange(N, AST));723 EXPECT_THAT(Complete, UnorderedElementsAreArray(Test.ranges("C"))) << C;724 EXPECT_THAT(Partial, UnorderedElementsAreArray(Test.ranges())) << C;725 }726}727 728TEST(SelectionTest, PathologicalPreprocessor) {729 const char *Case = R"cpp(730#define MACRO while(1)731 void test() {732#include "Expand.inc"733 br^eak;734 }735 )cpp";736 Annotations Test(Case);737 auto TU = TestTU::withCode(Test.code());738 TU.AdditionalFiles["Expand.inc"] = "MACRO\n";739 auto AST = TU.build();740 EXPECT_THAT(AST.getDiagnostics(), ::testing::IsEmpty());741 auto T = makeSelectionTree(Case, AST);742 743 EXPECT_EQ("BreakStmt", T.commonAncestor()->kind());744 EXPECT_EQ("WhileStmt", T.commonAncestor()->Parent->kind());745}746 747TEST(SelectionTest, IncludedFile) {748 const char *Case = R"cpp(749 void test() {750#include "Exp^and.inc"751 break;752 }753 )cpp";754 Annotations Test(Case);755 auto TU = TestTU::withCode(Test.code());756 TU.AdditionalFiles["Expand.inc"] = "while(1)\n";757 auto AST = TU.build();758 auto T = makeSelectionTree(Case, AST);759 760 EXPECT_EQ(nullptr, T.commonAncestor());761}762 763TEST(SelectionTest, MacroArgExpansion) {764 // If a macro arg is expanded several times, we only consider the first one765 // selected.766 const char *Case = R"cpp(767 int mul(int, int);768 #define SQUARE(X) mul(X, X);769 int nine = SQUARE(^3);770 )cpp";771 Annotations Test(Case);772 auto AST = TestTU::withCode(Test.code()).build();773 auto T = makeSelectionTree(Case, AST);774 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());775 EXPECT_TRUE(T.commonAncestor()->Selected);776 777 // Verify that the common assert() macro doesn't suffer from this.778 // (This is because we don't associate the stringified token with the arg).779 Case = R"cpp(780 void die(const char*);781 #define assert(x) (x ? (void)0 : die(#x))782 void foo() { assert(^42); }783 )cpp";784 Test = Annotations(Case);785 AST = TestTU::withCode(Test.code()).build();786 T = makeSelectionTree(Case, AST);787 EXPECT_EQ("IntegerLiteral", T.commonAncestor()->kind());788 789 // Reduced from private bug involving RETURN_IF_ERROR.790 // Due to >>-splitting and a bug in isBeforeInTranslationUnit, the inner791 // S<int> would claim way too many tokens.792 Case = R"cpp(793 #define ID(x) x794 template <typename T> class S {};795 ID(796 ID(S<S<int>> x);797 int ^y;798 )799 )cpp";800 Test = Annotations(Case);801 AST = TestTU::withCode(Test.code()).build();802 T = makeSelectionTree(Case, AST);803 // not TemplateSpecializationTypeLoc!804 EXPECT_EQ("VarDecl", T.commonAncestor()->kind());805}806 807TEST(SelectionTest, Implicit) {808 const char *Test = R"cpp(809 struct S { S(const char*); };810 int f(S);811 int x = f("^");812 )cpp";813 auto TU = TestTU::withCode(Annotations(Test).code());814 // C++14 AST contains some temporaries that C++17 elides.815 TU.ExtraArgs.push_back("-std=c++17");816 auto AST = TU.build();817 auto T = makeSelectionTree(Test, AST);818 819 const SelectionTree::Node *Str = T.commonAncestor();820 EXPECT_EQ("StringLiteral", nodeKind(Str)) << "Implicit selected?";821 EXPECT_EQ("ImplicitCastExpr", nodeKind(Str->Parent));822 EXPECT_EQ("CXXConstructExpr", nodeKind(Str->Parent->Parent));823 const SelectionTree::Node *ICE = Str->Parent->Parent->Parent;824 EXPECT_EQ("ImplicitCastExpr", nodeKind(ICE));825 EXPECT_EQ("CallExpr", nodeKind(ICE->Parent));826 EXPECT_EQ(Str, &ICE->ignoreImplicit())827 << "Didn't unwrap " << nodeKind(&ICE->ignoreImplicit());828 829 EXPECT_EQ(ICE, &Str->outerImplicit());830}831 832TEST(SelectionTest, CreateAll) {833 llvm::Annotations Test("int$unique^ a=1$ambiguous^+1; $empty^");834 auto AST = TestTU::withCode(Test.code()).build();835 unsigned Seen = 0;836 SelectionTree::createEach(837 AST.getASTContext(), AST.getTokens(), Test.point("ambiguous"),838 Test.point("ambiguous"), [&](SelectionTree T) {839 // Expect to see the right-biased tree first.840 if (Seen == 0) {841 EXPECT_EQ("BinaryOperator", nodeKind(T.commonAncestor()));842 } else if (Seen == 1) {843 EXPECT_EQ("IntegerLiteral", nodeKind(T.commonAncestor()));844 }845 ++Seen;846 return false;847 });848 EXPECT_EQ(2u, Seen);849 850 Seen = 0;851 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),852 Test.point("ambiguous"), Test.point("ambiguous"),853 [&](SelectionTree T) {854 ++Seen;855 return true;856 });857 EXPECT_EQ(1u, Seen) << "Return true --> stop iterating";858 859 Seen = 0;860 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),861 Test.point("unique"), Test.point("unique"),862 [&](SelectionTree T) {863 ++Seen;864 return false;865 });866 EXPECT_EQ(1u, Seen) << "no ambiguity --> only one tree";867 868 Seen = 0;869 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),870 Test.point("empty"), Test.point("empty"),871 [&](SelectionTree T) {872 EXPECT_FALSE(T.commonAncestor());873 ++Seen;874 return false;875 });876 EXPECT_EQ(1u, Seen) << "empty tree still created";877 878 Seen = 0;879 SelectionTree::createEach(AST.getASTContext(), AST.getTokens(),880 Test.point("unique"), Test.point("ambiguous"),881 [&](SelectionTree T) {882 ++Seen;883 return false;884 });885 EXPECT_EQ(1u, Seen) << "one tree for nontrivial selection";886}887 888TEST(SelectionTest, DeclContextIsLexical) {889 llvm::Annotations Test("namespace a { void $1^foo(); } void a::$2^foo();");890 auto AST = TestTU::withCode(Test.code()).build();891 {892 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),893 Test.point("1"), Test.point("1"));894 EXPECT_FALSE(ST.commonAncestor()->getDeclContext().isTranslationUnit());895 }896 {897 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),898 Test.point("2"), Test.point("2"));899 EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isTranslationUnit());900 }901}902 903TEST(SelectionTest, DeclContextLambda) {904 llvm::Annotations Test(R"cpp(905 void foo();906 auto lambda = [] {907 return $1^foo();908 };909 )cpp");910 auto AST = TestTU::withCode(Test.code()).build();911 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),912 Test.point("1"), Test.point("1"));913 EXPECT_TRUE(ST.commonAncestor()->getDeclContext().isFunctionOrMethod());914}915 916TEST(SelectionTest, UsingConcepts) {917 llvm::Annotations Test(R"cpp(918namespace ns {919template <typename T>920concept Foo = true;921}922 923using ns::Foo;924 925template <Fo^o... T, Fo^o auto U>926auto Func(Fo^o auto V) -> Fo^o decltype(auto) {927 Fo^o auto W = V;928 return W;929}930)cpp");931 auto TU = TestTU::withCode(Test.code());932 TU.ExtraArgs.emplace_back("-std=c++2c");933 auto AST = TU.build();934 for (auto Point : Test.points()) {935 auto ST = SelectionTree::createRight(AST.getASTContext(), AST.getTokens(),936 Point, Point);937 auto *C = ST.commonAncestor()->ASTNode.get<ConceptReference>();938 EXPECT_TRUE(C && C->getFoundDecl() &&939 C->getFoundDecl()->getKind() == Decl::UsingShadow);940 }941}942 943} // namespace944} // namespace clangd945} // namespace clang946