2084 lines · cpp
1//===- unittests/AST/ASTTraverserTest.h------------------------------------===//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 "clang/AST/ASTContext.h"10#include "clang/AST/ASTNodeTraverser.h"11#include "clang/AST/TextNodeDumper.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13#include "clang/ASTMatchers/ASTMatchers.h"14#include "clang/Tooling/Tooling.h"15#include "gmock/gmock.h"16#include "gtest/gtest.h"17 18using namespace clang::tooling;19using namespace clang::ast_matchers;20 21namespace clang {22 23class NodeTreePrinter : public TextTreeStructure {24 llvm::raw_ostream &OS;25 26public:27 NodeTreePrinter(llvm::raw_ostream &OS)28 : TextTreeStructure(OS, /* showColors */ false), OS(OS) {}29 30 void Visit(const Decl *D) {31 if (!D) {32 OS << "<<<NULL>>>";33 return;34 }35 OS << D->getDeclKindName() << "Decl";36 if (auto *ND = dyn_cast<NamedDecl>(D)) {37 OS << " '" << ND->getDeclName() << "'";38 }39 }40 41 void Visit(const Stmt *S) {42 if (!S) {43 OS << "<<<NULL>>>";44 return;45 }46 OS << S->getStmtClassName();47 if (auto *E = dyn_cast<DeclRefExpr>(S)) {48 OS << " '" << E->getDecl()->getDeclName() << "'";49 }50 }51 52 void Visit(QualType QT) {53 OS << "QualType " << QT.split().Quals.getAsString();54 }55 56 void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; }57 58 void Visit(const comments::Comment *C, const comments::FullComment *FC) {59 OS << C->getCommentKindName();60 }61 62 void Visit(const CXXCtorInitializer *Init) {63 OS << "CXXCtorInitializer";64 if (const auto *F = Init->getAnyMember()) {65 OS << " '" << F->getNameAsString() << "'";66 } else if (auto const *TSI = Init->getTypeSourceInfo()) {67 OS << " '" << TSI->getType() << "'";68 }69 }70 71 void Visit(const Attr *A) {72 switch (A->getKind()) {73#define ATTR(X) \74 case attr::X: \75 OS << #X; \76 break;77#include "clang/Basic/AttrList.inc"78 }79 OS << "Attr";80 }81 82 void Visit(const OMPClause *C) { OS << "OMPClause"; }83 void Visit(const TemplateArgument &A, SourceRange R = {},84 const Decl *From = nullptr, const char *Label = nullptr) {85 OS << "TemplateArgument";86 switch (A.getKind()) {87 case TemplateArgument::Type: {88 OS << " type " << A.getAsType();89 break;90 }91 default:92 break;93 }94 }95 96 template <typename... T> void Visit(T...) {}97};98 99class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> {100 101 NodeTreePrinter MyNodeRecorder;102 103public:104 TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {}105 NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; }106};107 108template <typename... NodeType> std::string dumpASTString(NodeType &&... N) {109 std::string Buffer;110 llvm::raw_string_ostream OS(Buffer);111 112 TestASTDumper Dumper(OS);113 114 OS << "\n";115 116 Dumper.Visit(std::forward<NodeType &&>(N)...);117 118 return Buffer;119}120 121template <typename... NodeType>122std::string dumpASTString(TraversalKind TK, NodeType &&... N) {123 std::string Buffer;124 llvm::raw_string_ostream OS(Buffer);125 126 TestASTDumper Dumper(OS);127 Dumper.SetTraversalKind(TK);128 129 OS << "\n";130 131 Dumper.Visit(std::forward<NodeType &&>(N)...);132 133 return Buffer;134}135 136const FunctionDecl *getFunctionNode(clang::ASTUnit *AST,137 const std::string &Name) {138 auto Result = ast_matchers::match(functionDecl(hasName(Name)).bind("fn"),139 AST->getASTContext());140 EXPECT_EQ(Result.size(), 1u);141 return Result[0].getNodeAs<FunctionDecl>("fn");142}143 144template <typename T> struct Verifier {145 static void withDynNode(T Node, const std::string &DumpString) {146 EXPECT_EQ(dumpASTString(DynTypedNode::create(Node)), DumpString);147 }148};149 150template <typename T> struct Verifier<T *> {151 static void withDynNode(T *Node, const std::string &DumpString) {152 EXPECT_EQ(dumpASTString(DynTypedNode::create(*Node)), DumpString);153 }154};155 156template <typename T>157void verifyWithDynNode(T Node, const std::string &DumpString) {158 EXPECT_EQ(dumpASTString(Node), DumpString);159 160 Verifier<T>::withDynNode(Node, DumpString);161}162 163TEST(Traverse, Dump) {164 165 auto AST = buildASTFromCode(R"cpp(166struct A {167 int m_number;168 169 /// CTor170 A() : m_number(42) {}171 172 [[nodiscard]] const int func() {173 return 42;174 }175 176};177 178template<typename T>179struct templ180{181};182 183template<>184struct templ<int>185{186};187 188void parmvardecl_attr(struct A __attribute__((address_space(19)))*);189 190)cpp");191 192 const FunctionDecl *Func = getFunctionNode(AST.get(), "func");193 194 verifyWithDynNode(Func,195 R"cpp(196CXXMethodDecl 'func'197|-CompoundStmt198| `-ReturnStmt199| `-IntegerLiteral200`-WarnUnusedResultAttr201)cpp");202 203 Stmt *Body = Func->getBody();204 205 verifyWithDynNode(Body,206 R"cpp(207CompoundStmt208`-ReturnStmt209 `-IntegerLiteral210)cpp");211 212 QualType QT = Func->getType();213 214 verifyWithDynNode(QT,215 R"cpp(216FunctionProtoType217`-QualType const218 `-BuiltinType219)cpp");220 221 const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A");222 223 verifyWithDynNode(CTorFunc->getType(),224 R"cpp(225FunctionProtoType226`-BuiltinType227)cpp");228 229 Attr *A = *Func->attr_begin();230 231 {232 std::string expectedString = R"cpp(233WarnUnusedResultAttr234)cpp";235 236 EXPECT_EQ(dumpASTString(A), expectedString);237 }238 239 auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc);240 const CXXCtorInitializer *Init = *CTor->init_begin();241 242 verifyWithDynNode(Init,243 R"cpp(244CXXCtorInitializer 'm_number'245`-IntegerLiteral246)cpp");247 248 const comments::FullComment *Comment =249 AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc);250 {251 std::string expectedString = R"cpp(252FullComment253`-ParagraphComment254 `-TextComment255)cpp";256 EXPECT_EQ(dumpASTString(Comment, Comment), expectedString);257 }258 259 auto Result = ast_matchers::match(260 classTemplateSpecializationDecl(hasName("templ")).bind("fn"),261 AST->getASTContext());262 EXPECT_EQ(Result.size(), 1u);263 auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn");264 265 TemplateArgument TA = Templ->getTemplateArgs()[0];266 267 verifyWithDynNode(TA,268 R"cpp(269TemplateArgument type int270`-BuiltinType271)cpp");272 273 Func = getFunctionNode(AST.get(), "parmvardecl_attr");274 275 const auto *Parm = Func->getParamDecl(0);276 const auto TL = Parm->getTypeSourceInfo()->getTypeLoc();277 ASSERT_TRUE(TL.getType()->isPointerType());278 279 const auto ATL = TL.getNextTypeLoc().getAs<AttributedTypeLoc>();280 const auto *AS = cast<AddressSpaceAttr>(ATL.getAttr());281 EXPECT_EQ(toTargetAddressSpace(static_cast<LangAS>(AS->getAddressSpace())),282 19u);283}284 285TEST(Traverse, IgnoreUnlessSpelledInSourceVars) {286 287 auto AST = buildASTFromCodeWithArgs(R"cpp(288 289struct String290{291 String(const char*, int = -1) {}292 293 int overloaded() const;294 int& overloaded();295};296 297void stringConstruct()298{299 String s = "foo";300 s = "bar";301}302 303void overloadCall()304{305 String s = "foo";306 (s).overloaded();307}308 309struct C1 {};310struct C2 { operator C1(); };311 312void conversionOperator()313{314 C2* c2;315 C1 c1 = (*c2);316}317 318template <unsigned alignment>319void template_test() {320 static_assert(alignment, "");321}322void actual_template_test() {323 template_test<4>();324}325 326struct OneParamCtor {327 explicit OneParamCtor(int);328};329struct TwoParamCtor {330 explicit TwoParamCtor(int, int);331};332 333void varDeclCtors() {334 {335 auto var1 = OneParamCtor(5);336 auto var2 = TwoParamCtor(6, 7);337 }338 {339 OneParamCtor var3(5);340 TwoParamCtor var4(6, 7);341 }342 int i = 0;343 {344 auto var5 = OneParamCtor(i);345 auto var6 = TwoParamCtor(i, 7);346 }347 {348 OneParamCtor var7(i);349 TwoParamCtor var8(i, 7);350 }351}352 353)cpp", {"-std=c++14"});354 355 {356 auto FN =357 ast_matchers::match(functionDecl(hasName("stringConstruct")).bind("fn"),358 AST->getASTContext());359 EXPECT_EQ(FN.size(), 1u);360 361 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")),362 R"cpp(363FunctionDecl 'stringConstruct'364`-CompoundStmt365 |-DeclStmt366 | `-VarDecl 's'367 | `-ExprWithCleanups368 | `-CXXConstructExpr369 | `-MaterializeTemporaryExpr370 | `-ImplicitCastExpr371 | `-CXXConstructExpr372 | |-ImplicitCastExpr373 | | `-StringLiteral374 | `-CXXDefaultArgExpr375 | `-UnaryOperator376 | `-IntegerLiteral377 `-ExprWithCleanups378 `-CXXOperatorCallExpr379 |-ImplicitCastExpr380 | `-DeclRefExpr 'operator='381 |-DeclRefExpr 's'382 `-MaterializeTemporaryExpr383 `-CXXConstructExpr384 |-ImplicitCastExpr385 | `-StringLiteral386 `-CXXDefaultArgExpr387 `-UnaryOperator388 `-IntegerLiteral389)cpp");390 391 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,392 FN[0].getNodeAs<Decl>("fn")),393 R"cpp(394FunctionDecl 'stringConstruct'395`-CompoundStmt396 |-DeclStmt397 | `-VarDecl 's'398 | `-StringLiteral399 `-CXXOperatorCallExpr400 |-DeclRefExpr 'operator='401 |-DeclRefExpr 's'402 `-StringLiteral403)cpp");404 }405 406 {407 auto FN =408 ast_matchers::match(functionDecl(hasName("overloadCall")).bind("fn"),409 AST->getASTContext());410 EXPECT_EQ(FN.size(), 1u);411 412 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")),413 R"cpp(414FunctionDecl 'overloadCall'415`-CompoundStmt416 |-DeclStmt417 | `-VarDecl 's'418 | `-ExprWithCleanups419 | `-CXXConstructExpr420 | `-MaterializeTemporaryExpr421 | `-ImplicitCastExpr422 | `-CXXConstructExpr423 | |-ImplicitCastExpr424 | | `-StringLiteral425 | `-CXXDefaultArgExpr426 | `-UnaryOperator427 | `-IntegerLiteral428 `-CXXMemberCallExpr429 `-MemberExpr430 `-ParenExpr431 `-DeclRefExpr 's'432)cpp");433 434 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,435 FN[0].getNodeAs<Decl>("fn")),436 R"cpp(437FunctionDecl 'overloadCall'438`-CompoundStmt439 |-DeclStmt440 | `-VarDecl 's'441 | `-StringLiteral442 `-CXXMemberCallExpr443 `-MemberExpr444 `-DeclRefExpr 's'445)cpp");446 }447 448 {449 auto FN = ast_matchers::match(450 functionDecl(hasName("conversionOperator"),451 hasDescendant(varDecl(hasName("c1")).bind("var"))),452 AST->getASTContext());453 EXPECT_EQ(FN.size(), 1u);454 455 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("var")),456 R"cpp(457VarDecl 'c1'458`-ExprWithCleanups459 `-CXXConstructExpr460 `-MaterializeTemporaryExpr461 `-ImplicitCastExpr462 `-CXXMemberCallExpr463 `-MemberExpr464 `-ParenExpr465 `-UnaryOperator466 `-ImplicitCastExpr467 `-DeclRefExpr 'c2'468)cpp");469 470 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,471 FN[0].getNodeAs<Decl>("var")),472 R"cpp(473VarDecl 'c1'474`-UnaryOperator475 `-DeclRefExpr 'c2'476)cpp");477 }478 479 {480 auto FN = ast_matchers::match(481 functionDecl(hasName("template_test"),482 hasDescendant(staticAssertDecl().bind("staticAssert"))),483 AST->getASTContext());484 EXPECT_EQ(FN.size(), 2u);485 486 EXPECT_EQ(dumpASTString(TK_AsIs, FN[1].getNodeAs<Decl>("staticAssert")),487 R"cpp(488StaticAssertDecl489|-ImplicitCastExpr490| `-SubstNonTypeTemplateParmExpr491| |-NonTypeTemplateParmDecl 'alignment'492| `-IntegerLiteral493`-StringLiteral494)cpp");495 496 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,497 FN[1].getNodeAs<Decl>("staticAssert")),498 R"cpp(499StaticAssertDecl500|-IntegerLiteral501`-StringLiteral502)cpp");503 }504 505 auto varChecker = [&AST](StringRef varName, StringRef SemanticDump,506 StringRef SyntacticDump) {507 auto FN = ast_matchers::match(508 functionDecl(509 hasName("varDeclCtors"),510 forEachDescendant(varDecl(hasName(varName)).bind("varDeclCtor"))),511 AST->getASTContext());512 EXPECT_EQ(FN.size(), 1u);513 514 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("varDeclCtor")),515 SemanticDump);516 517 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,518 FN[0].getNodeAs<Decl>("varDeclCtor")),519 SyntacticDump);520 };521 522 varChecker("var1",523 R"cpp(524VarDecl 'var1'525`-ExprWithCleanups526 `-CXXConstructExpr527 `-MaterializeTemporaryExpr528 `-CXXFunctionalCastExpr529 `-CXXConstructExpr530 `-IntegerLiteral531)cpp",532 R"cpp(533VarDecl 'var1'534`-CXXConstructExpr535 `-IntegerLiteral536)cpp");537 538 varChecker("var2",539 R"cpp(540VarDecl 'var2'541`-ExprWithCleanups542 `-CXXConstructExpr543 `-MaterializeTemporaryExpr544 `-CXXTemporaryObjectExpr545 |-IntegerLiteral546 `-IntegerLiteral547)cpp",548 R"cpp(549VarDecl 'var2'550`-CXXTemporaryObjectExpr551 |-IntegerLiteral552 `-IntegerLiteral553)cpp");554 555 varChecker("var3",556 R"cpp(557VarDecl 'var3'558`-CXXConstructExpr559 `-IntegerLiteral560)cpp",561 R"cpp(562VarDecl 'var3'563`-CXXConstructExpr564 `-IntegerLiteral565)cpp");566 567 varChecker("var4",568 R"cpp(569VarDecl 'var4'570`-CXXConstructExpr571 |-IntegerLiteral572 `-IntegerLiteral573)cpp",574 R"cpp(575VarDecl 'var4'576`-CXXConstructExpr577 |-IntegerLiteral578 `-IntegerLiteral579)cpp");580 581 varChecker("var5",582 R"cpp(583VarDecl 'var5'584`-ExprWithCleanups585 `-CXXConstructExpr586 `-MaterializeTemporaryExpr587 `-CXXFunctionalCastExpr588 `-CXXConstructExpr589 `-ImplicitCastExpr590 `-DeclRefExpr 'i'591)cpp",592 R"cpp(593VarDecl 'var5'594`-CXXConstructExpr595 `-DeclRefExpr 'i'596)cpp");597 598 varChecker("var6",599 R"cpp(600VarDecl 'var6'601`-ExprWithCleanups602 `-CXXConstructExpr603 `-MaterializeTemporaryExpr604 `-CXXTemporaryObjectExpr605 |-ImplicitCastExpr606 | `-DeclRefExpr 'i'607 `-IntegerLiteral608)cpp",609 R"cpp(610VarDecl 'var6'611`-CXXTemporaryObjectExpr612 |-DeclRefExpr 'i'613 `-IntegerLiteral614)cpp");615 616 varChecker("var7",617 R"cpp(618VarDecl 'var7'619`-CXXConstructExpr620 `-ImplicitCastExpr621 `-DeclRefExpr 'i'622)cpp",623 R"cpp(624VarDecl 'var7'625`-CXXConstructExpr626 `-DeclRefExpr 'i'627)cpp");628 629 varChecker("var8",630 R"cpp(631VarDecl 'var8'632`-CXXConstructExpr633 |-ImplicitCastExpr634 | `-DeclRefExpr 'i'635 `-IntegerLiteral636)cpp",637 R"cpp(638VarDecl 'var8'639`-CXXConstructExpr640 |-DeclRefExpr 'i'641 `-IntegerLiteral642)cpp");643}644 645TEST(Traverse, IgnoreUnlessSpelledInSourceStructs) {646 auto AST = buildASTFromCode(R"cpp(647 648struct MyStruct {649 MyStruct();650 MyStruct(int i) {651 MyStruct();652 }653 ~MyStruct();654};655 656)cpp");657 658 auto BN = ast_matchers::match(659 cxxConstructorDecl(hasName("MyStruct"),660 hasParameter(0, parmVarDecl(hasType(isInteger()))))661 .bind("ctor"),662 AST->getASTContext());663 EXPECT_EQ(BN.size(), 1u);664 665 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,666 BN[0].getNodeAs<Decl>("ctor")),667 R"cpp(668CXXConstructorDecl 'MyStruct'669|-ParmVarDecl 'i'670`-CompoundStmt671 `-CXXTemporaryObjectExpr672)cpp");673 674 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("ctor")),675 R"cpp(676CXXConstructorDecl 'MyStruct'677|-ParmVarDecl 'i'678`-CompoundStmt679 `-ExprWithCleanups680 `-CXXBindTemporaryExpr681 `-CXXTemporaryObjectExpr682)cpp");683}684 685TEST(Traverse, IgnoreUnlessSpelledInSourceReturnStruct) {686 687 auto AST = buildASTFromCode(R"cpp(688struct Retval {689 Retval() {}690 ~Retval() {}691};692 693Retval someFun();694 695void foo()696{697 someFun();698}699)cpp");700 701 auto BN = ast_matchers::match(functionDecl(hasName("foo")).bind("fn"),702 AST->getASTContext());703 EXPECT_EQ(BN.size(), 1u);704 705 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,706 BN[0].getNodeAs<Decl>("fn")),707 R"cpp(708FunctionDecl 'foo'709`-CompoundStmt710 `-CallExpr711 `-DeclRefExpr 'someFun'712)cpp");713 714 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),715 R"cpp(716FunctionDecl 'foo'717`-CompoundStmt718 `-ExprWithCleanups719 `-CXXBindTemporaryExpr720 `-CallExpr721 `-ImplicitCastExpr722 `-DeclRefExpr 'someFun'723)cpp");724}725 726TEST(Traverse, IgnoreUnlessSpelledInSourceReturns) {727 728 auto AST = buildASTFromCodeWithArgs(R"cpp(729 730struct A731{732};733 734struct B735{736 B(int);737 B(A const& a);738 B();739};740 741struct C742{743 operator B();744};745 746B func1() {747 return 42;748}749 750B func2() {751 return B{42};752}753 754B func3() {755 return B(42);756}757 758B func4() {759 return B();760}761 762B func5() {763 return B{};764}765 766B func6() {767 return C();768}769 770B func7() {771 return A();772}773 774B func8() {775 return C{};776}777 778B func9() {779 return A{};780}781 782B func10() {783 A a;784 return a;785}786 787B func11() {788 B b;789 return b;790}791 792B func12() {793 C c;794 return c;795}796 797)cpp", {"-std=c++14"});798 799 auto getFunctionNode = [&AST](const std::string &name) {800 auto BN = ast_matchers::match(functionDecl(hasName(name)).bind("fn"),801 AST->getASTContext());802 EXPECT_EQ(BN.size(), 1u);803 return BN[0].getNodeAs<Decl>("fn");804 };805 806 {807 auto FN = getFunctionNode("func1");808 llvm::StringRef Expected = R"cpp(809FunctionDecl 'func1'810`-CompoundStmt811 `-ReturnStmt812 `-ExprWithCleanups813 `-CXXConstructExpr814 `-MaterializeTemporaryExpr815 `-ImplicitCastExpr816 `-CXXConstructExpr817 `-IntegerLiteral818)cpp";819 820 EXPECT_EQ(dumpASTString(TK_AsIs, FN), Expected);821 822 Expected = R"cpp(823FunctionDecl 'func1'824`-CompoundStmt825 `-ReturnStmt826 `-IntegerLiteral827)cpp";828 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, FN), Expected);829 }830 831 llvm::StringRef Expected = R"cpp(832FunctionDecl 'func2'833`-CompoundStmt834 `-ReturnStmt835 `-CXXTemporaryObjectExpr836 `-IntegerLiteral837)cpp";838 EXPECT_EQ(839 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func2")),840 Expected);841 842 Expected = R"cpp(843FunctionDecl 'func3'844`-CompoundStmt845 `-ReturnStmt846 `-CXXConstructExpr847 `-IntegerLiteral848)cpp";849 EXPECT_EQ(850 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func3")),851 Expected);852 853 Expected = R"cpp(854FunctionDecl 'func4'855`-CompoundStmt856 `-ReturnStmt857 `-CXXTemporaryObjectExpr858)cpp";859 EXPECT_EQ(860 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func4")),861 Expected);862 863 Expected = R"cpp(864FunctionDecl 'func5'865`-CompoundStmt866 `-ReturnStmt867 `-CXXTemporaryObjectExpr868)cpp";869 EXPECT_EQ(870 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func5")),871 Expected);872 873 Expected = R"cpp(874FunctionDecl 'func6'875`-CompoundStmt876 `-ReturnStmt877 `-CXXTemporaryObjectExpr878)cpp";879 EXPECT_EQ(880 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func6")),881 Expected);882 883 Expected = R"cpp(884FunctionDecl 'func7'885`-CompoundStmt886 `-ReturnStmt887 `-CXXTemporaryObjectExpr888)cpp";889 EXPECT_EQ(890 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func7")),891 Expected);892 893 Expected = R"cpp(894FunctionDecl 'func8'895`-CompoundStmt896 `-ReturnStmt897 `-CXXFunctionalCastExpr898 `-InitListExpr899)cpp";900 EXPECT_EQ(901 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func8")),902 Expected);903 904 Expected = R"cpp(905FunctionDecl 'func9'906`-CompoundStmt907 `-ReturnStmt908 `-CXXFunctionalCastExpr909 `-InitListExpr910)cpp";911 EXPECT_EQ(912 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func9")),913 Expected);914 915 Expected = R"cpp(916FunctionDecl 'func10'917`-CompoundStmt918 |-DeclStmt919 | `-VarDecl 'a'920 | `-CXXConstructExpr921 `-ReturnStmt922 `-DeclRefExpr 'a'923)cpp";924 EXPECT_EQ(925 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func10")),926 Expected);927 928 Expected = R"cpp(929FunctionDecl 'func11'930`-CompoundStmt931 |-DeclStmt932 | `-VarDecl 'b'933 | `-CXXConstructExpr934 `-ReturnStmt935 `-DeclRefExpr 'b'936)cpp";937 EXPECT_EQ(938 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func11")),939 Expected);940 941 Expected = R"cpp(942FunctionDecl 'func12'943`-CompoundStmt944 |-DeclStmt945 | `-VarDecl 'c'946 | `-CXXConstructExpr947 `-ReturnStmt948 `-DeclRefExpr 'c'949)cpp";950 EXPECT_EQ(951 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func12")),952 Expected);953}954 955TEST(Traverse, LambdaUnlessSpelledInSource) {956 957 auto AST =958 buildASTFromCodeWithArgs(R"cpp(959 960void captures() {961 int a = 0;962 int b = 0;963 int d = 0;964 int f = 0;965 966 [a, &b, c = d, &e = f](int g, int h = 42) {};967}968 969void templated() {970 int a = 0;971 [a]<typename T>(T t) {};972}973 974struct SomeStruct {975 int a = 0;976 void capture_this() {977 [this]() {};978 }979 void capture_this_copy() {980 [self = *this]() {};981 }982};983)cpp",984 {"-Wno-unused-value", "-Wno-c++2a-extensions"});985 986 auto getLambdaNode = [&AST](const std::string &name) {987 auto BN = ast_matchers::match(988 lambdaExpr(hasAncestor(functionDecl(hasName(name)))).bind("lambda"),989 AST->getASTContext());990 EXPECT_EQ(BN.size(), 1u);991 return BN[0].getNodeAs<LambdaExpr>("lambda");992 };993 994 {995 auto L = getLambdaNode("captures");996 997 llvm::StringRef Expected = R"cpp(998LambdaExpr999|-DeclRefExpr 'a'1000|-DeclRefExpr 'b'1001|-VarDecl 'c'1002| `-DeclRefExpr 'd'1003|-VarDecl 'e'1004| `-DeclRefExpr 'f'1005|-ParmVarDecl 'g'1006|-ParmVarDecl 'h'1007| `-IntegerLiteral1008`-CompoundStmt1009)cpp";1010 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);1011 1012 Expected = R"cpp(1013LambdaExpr1014|-CXXRecordDecl ''1015| |-CXXMethodDecl 'operator()'1016| | |-ParmVarDecl 'g'1017| | |-ParmVarDecl 'h'1018| | | `-IntegerLiteral1019| | `-CompoundStmt1020| |-FieldDecl ''1021| |-FieldDecl ''1022| |-FieldDecl ''1023| |-FieldDecl ''1024| `-CXXDestructorDecl '~(lambda at input.cc:9:3)'1025|-ImplicitCastExpr1026| `-DeclRefExpr 'a'1027|-DeclRefExpr 'b'1028|-ImplicitCastExpr1029| `-DeclRefExpr 'd'1030|-DeclRefExpr 'f'1031`-CompoundStmt1032)cpp";1033 EXPECT_EQ(dumpASTString(TK_AsIs, L), Expected);1034 }1035 1036 {1037 auto L = getLambdaNode("templated");1038 1039 llvm::StringRef Expected = R"cpp(1040LambdaExpr1041|-DeclRefExpr 'a'1042|-TemplateTypeParmDecl 'T'1043|-ParmVarDecl 't'1044`-CompoundStmt1045)cpp";1046 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);1047 }1048 1049 {1050 auto L = getLambdaNode("capture_this");1051 1052 llvm::StringRef Expected = R"cpp(1053LambdaExpr1054|-CXXThisExpr1055`-CompoundStmt1056)cpp";1057 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);1058 }1059 1060 {1061 auto L = getLambdaNode("capture_this_copy");1062 1063 llvm::StringRef Expected = R"cpp(1064LambdaExpr1065|-VarDecl 'self'1066| `-UnaryOperator1067| `-CXXThisExpr1068`-CompoundStmt1069)cpp";1070 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);1071 }1072}1073 1074TEST(Traverse, IgnoreUnlessSpelledInSourceImplicit) {1075 {1076 auto AST = buildASTFromCode(R"cpp(1077int i = 0;1078)cpp");1079 const auto *TUDecl = AST->getASTContext().getTranslationUnitDecl();1080 1081 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, TUDecl),1082 R"cpp(1083TranslationUnitDecl1084`-VarDecl 'i'1085 `-IntegerLiteral1086)cpp");1087 }1088 1089 auto AST2 = buildASTFromCodeWithArgs(R"cpp(1090struct Simple {1091};1092struct Other {1093};1094 1095struct Record : Simple, Other {1096 Record() : Simple(), m_i(42) {}1097private:1098 int m_i;1099 int m_i2 = 42;1100 Simple m_s;1101};1102 1103struct NonTrivial {1104 NonTrivial() {}1105 NonTrivial(NonTrivial&) {}1106 NonTrivial& operator=(NonTrivial&) { return *this; }1107 1108 ~NonTrivial() {}1109};1110 1111struct ContainsArray {1112 NonTrivial arr[2];1113 int irr[2];1114 ContainsArray& operator=(ContainsArray &) = default;1115};1116 1117void copyIt()1118{1119 ContainsArray ca;1120 ContainsArray ca2;1121 ca2 = ca;1122}1123 1124void forLoop()1125{1126 int arr[2];1127 for (auto i : arr)1128 {1129 1130 }1131 for (auto& a = arr; auto i : a)1132 {1133 1134 }1135}1136 1137struct DefaultedAndDeleted {1138 NonTrivial nt;1139 DefaultedAndDeleted() = default;1140 ~DefaultedAndDeleted() = default;1141 DefaultedAndDeleted(DefaultedAndDeleted &) = default;1142 DefaultedAndDeleted& operator=(DefaultedAndDeleted &) = default;1143 DefaultedAndDeleted(DefaultedAndDeleted &&) = delete;1144 DefaultedAndDeleted& operator=(DefaultedAndDeleted &&) = delete;1145};1146 1147void copyIt2()1148{1149 DefaultedAndDeleted ca;1150 DefaultedAndDeleted ca2;1151 ca2 = ca;1152}1153 1154void hasDefaultArg(int i, int j = 0)1155{1156}1157void callDefaultArg()1158{1159 hasDefaultArg(42);1160}1161 1162void decomposition()1163{1164 int arr[3];1165 auto &[f, s, t] = arr;1166 1167 f = 42;1168}1169 1170typedef __typeof(sizeof(int)) size_t;1171 1172struct Pair1173{1174 int x, y;1175};1176 1177// Tuple-like structure with a `get` method that has a default argument.1178struct Pair21179{1180 int x, y;1181};1182 1183// Note: these utilities are required to force binding to tuple like structure1184namespace std1185{1186 template <typename E>1187 struct tuple_size1188 {1189 };1190 1191 template <>1192 struct tuple_size<Pair>1193 {1194 static constexpr size_t value = 2;1195 };1196 1197 template <>1198 struct tuple_size<Pair2>1199 {1200 static constexpr size_t value = 2;1201 };1202 1203 template <size_t I, class T>1204 struct tuple_element1205 {1206 using type = int;1207 };1208 1209};1210 1211template <size_t I>1212int &&get(Pair &&p);1213 1214template <size_t I>1215int &&get(Pair2 &&p, int unused = 0);1216 1217void decompTuple()1218{1219 Pair p{1, 2};1220 auto [a, b] = p;1221 1222 a = 3;1223 1224 auto [c, d] = Pair2{3, 4};1225}1226 1227)cpp",1228 {"-std=c++20"});1229 1230 {1231 auto BN = ast_matchers::match(1232 cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),1233 AST2->getASTContext());1234 EXPECT_EQ(BN.size(), 1u);1235 1236 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1237 R"cpp(1238CXXRecordDecl 'Record'1239|-CXXRecordDecl 'Record'1240|-CXXConstructorDecl 'Record'1241| |-CXXCtorInitializer 'Simple'1242| | `-CXXConstructExpr1243| |-CXXCtorInitializer 'Other'1244| | `-CXXConstructExpr1245| |-CXXCtorInitializer 'm_i'1246| | `-IntegerLiteral1247| |-CXXCtorInitializer 'm_i2'1248| | `-CXXDefaultInitExpr1249| | `-IntegerLiteral1250| |-CXXCtorInitializer 'm_s'1251| | `-CXXConstructExpr1252| `-CompoundStmt1253|-AccessSpecDecl1254|-FieldDecl 'm_i'1255|-FieldDecl 'm_i2'1256| `-IntegerLiteral1257`-FieldDecl 'm_s'1258)cpp");1259 1260 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1261 BN[0].getNodeAs<Decl>("rec")),1262 R"cpp(1263CXXRecordDecl 'Record'1264|-CXXConstructorDecl 'Record'1265| |-CXXCtorInitializer 'Simple'1266| | `-CXXConstructExpr1267| |-CXXCtorInitializer 'm_i'1268| | `-IntegerLiteral1269| `-CompoundStmt1270|-AccessSpecDecl1271|-FieldDecl 'm_i'1272|-FieldDecl 'm_i2'1273| `-IntegerLiteral1274`-FieldDecl 'm_s'1275)cpp");1276 }1277 {1278 auto BN = ast_matchers::match(1279 cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))1280 .bind("rec"),1281 AST2->getASTContext());1282 EXPECT_EQ(BN.size(), 1u);1283 1284 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1285 R"cpp(1286CXXRecordDecl 'ContainsArray'1287|-CXXRecordDecl 'ContainsArray'1288|-FieldDecl 'arr'1289|-FieldDecl 'irr'1290|-CXXMethodDecl 'operator='1291| |-ParmVarDecl ''1292| `-CompoundStmt1293| |-ForStmt1294| | |-DeclStmt1295| | | `-VarDecl '__i0'1296| | | `-IntegerLiteral1297| | |-<<<NULL>>>1298| | |-BinaryOperator1299| | | |-ImplicitCastExpr1300| | | | `-DeclRefExpr '__i0'1301| | | `-IntegerLiteral1302| | |-UnaryOperator1303| | | `-DeclRefExpr '__i0'1304| | `-CXXMemberCallExpr1305| | |-MemberExpr1306| | | `-ArraySubscriptExpr1307| | | |-ImplicitCastExpr1308| | | | `-MemberExpr1309| | | | `-CXXThisExpr1310| | | `-ImplicitCastExpr1311| | | `-DeclRefExpr '__i0'1312| | `-ArraySubscriptExpr1313| | |-ImplicitCastExpr1314| | | `-MemberExpr1315| | | `-DeclRefExpr ''1316| | `-ImplicitCastExpr1317| | `-DeclRefExpr '__i0'1318| |-CallExpr1319| | |-ImplicitCastExpr1320| | | `-DeclRefExpr '__builtin_memcpy'1321| | |-ImplicitCastExpr1322| | | `-UnaryOperator1323| | | `-MemberExpr1324| | | `-CXXThisExpr1325| | |-ImplicitCastExpr1326| | | `-UnaryOperator1327| | | `-MemberExpr1328| | | `-DeclRefExpr ''1329| | `-IntegerLiteral1330| `-ReturnStmt1331| `-UnaryOperator1332| `-CXXThisExpr1333|-CXXConstructorDecl 'ContainsArray'1334| `-ParmVarDecl ''1335|-CXXDestructorDecl '~ContainsArray'1336| `-CompoundStmt1337`-CXXConstructorDecl 'ContainsArray'1338 |-CXXCtorInitializer 'arr'1339 | `-CXXConstructExpr1340 `-CompoundStmt1341)cpp");1342 1343 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1344 BN[0].getNodeAs<Decl>("rec")),1345 R"cpp(1346CXXRecordDecl 'ContainsArray'1347|-FieldDecl 'arr'1348|-FieldDecl 'irr'1349`-CXXMethodDecl 'operator='1350 `-ParmVarDecl ''1351)cpp");1352 }1353 {1354 auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),1355 AST2->getASTContext());1356 EXPECT_EQ(BN.size(), 1u);1357 1358 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("func")),1359 R"cpp(1360FunctionDecl 'forLoop'1361`-CompoundStmt1362 |-DeclStmt1363 | `-VarDecl 'arr'1364 |-CXXForRangeStmt1365 | |-<<<NULL>>>1366 | |-DeclStmt1367 | | `-VarDecl '__range1'1368 | | `-DeclRefExpr 'arr'1369 | |-DeclStmt1370 | | `-VarDecl '__begin1'1371 | | `-ImplicitCastExpr1372 | | `-DeclRefExpr '__range1'1373 | |-DeclStmt1374 | | `-VarDecl '__end1'1375 | | `-BinaryOperator1376 | | |-ImplicitCastExpr1377 | | | `-DeclRefExpr '__range1'1378 | | `-IntegerLiteral1379 | |-BinaryOperator1380 | | |-ImplicitCastExpr1381 | | | `-DeclRefExpr '__begin1'1382 | | `-ImplicitCastExpr1383 | | `-DeclRefExpr '__end1'1384 | |-UnaryOperator1385 | | `-DeclRefExpr '__begin1'1386 | |-DeclStmt1387 | | `-VarDecl 'i'1388 | | `-ImplicitCastExpr1389 | | `-UnaryOperator1390 | | `-ImplicitCastExpr1391 | | `-DeclRefExpr '__begin1'1392 | `-CompoundStmt1393 `-CXXForRangeStmt1394 |-DeclStmt1395 | `-VarDecl 'a'1396 | `-DeclRefExpr 'arr'1397 |-DeclStmt1398 | `-VarDecl '__range1'1399 | `-DeclRefExpr 'a'1400 |-DeclStmt1401 | `-VarDecl '__begin1'1402 | `-ImplicitCastExpr1403 | `-DeclRefExpr '__range1'1404 |-DeclStmt1405 | `-VarDecl '__end1'1406 | `-BinaryOperator1407 | |-ImplicitCastExpr1408 | | `-DeclRefExpr '__range1'1409 | `-IntegerLiteral1410 |-BinaryOperator1411 | |-ImplicitCastExpr1412 | | `-DeclRefExpr '__begin1'1413 | `-ImplicitCastExpr1414 | `-DeclRefExpr '__end1'1415 |-UnaryOperator1416 | `-DeclRefExpr '__begin1'1417 |-DeclStmt1418 | `-VarDecl 'i'1419 | `-ImplicitCastExpr1420 | `-UnaryOperator1421 | `-ImplicitCastExpr1422 | `-DeclRefExpr '__begin1'1423 `-CompoundStmt1424)cpp");1425 1426 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1427 BN[0].getNodeAs<Decl>("func")),1428 R"cpp(1429FunctionDecl 'forLoop'1430`-CompoundStmt1431 |-DeclStmt1432 | `-VarDecl 'arr'1433 |-CXXForRangeStmt1434 | |-<<<NULL>>>1435 | |-VarDecl 'i'1436 | |-DeclRefExpr 'arr'1437 | `-CompoundStmt1438 `-CXXForRangeStmt1439 |-DeclStmt1440 | `-VarDecl 'a'1441 | `-DeclRefExpr 'arr'1442 |-VarDecl 'i'1443 |-DeclRefExpr 'a'1444 `-CompoundStmt1445)cpp");1446 }1447 {1448 auto BN = ast_matchers::match(1449 cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))1450 .bind("rec"),1451 AST2->getASTContext());1452 EXPECT_EQ(BN.size(), 1u);1453 1454 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1455 R"cpp(1456CXXRecordDecl 'DefaultedAndDeleted'1457|-CXXRecordDecl 'DefaultedAndDeleted'1458|-FieldDecl 'nt'1459|-CXXConstructorDecl 'DefaultedAndDeleted'1460| |-CXXCtorInitializer 'nt'1461| | `-CXXConstructExpr1462| `-CompoundStmt1463|-CXXDestructorDecl '~DefaultedAndDeleted'1464| `-CompoundStmt1465|-CXXConstructorDecl 'DefaultedAndDeleted'1466| `-ParmVarDecl ''1467|-CXXMethodDecl 'operator='1468| |-ParmVarDecl ''1469| `-CompoundStmt1470| |-CXXMemberCallExpr1471| | |-MemberExpr1472| | | `-MemberExpr1473| | | `-CXXThisExpr1474| | `-MemberExpr1475| | `-DeclRefExpr ''1476| `-ReturnStmt1477| `-UnaryOperator1478| `-CXXThisExpr1479|-CXXConstructorDecl 'DefaultedAndDeleted'1480| `-ParmVarDecl ''1481`-CXXMethodDecl 'operator='1482 `-ParmVarDecl ''1483)cpp");1484 1485 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1486 BN[0].getNodeAs<Decl>("rec")),1487 R"cpp(1488CXXRecordDecl 'DefaultedAndDeleted'1489|-FieldDecl 'nt'1490|-CXXConstructorDecl 'DefaultedAndDeleted'1491|-CXXDestructorDecl '~DefaultedAndDeleted'1492|-CXXConstructorDecl 'DefaultedAndDeleted'1493| `-ParmVarDecl ''1494|-CXXMethodDecl 'operator='1495| `-ParmVarDecl ''1496|-CXXConstructorDecl 'DefaultedAndDeleted'1497| `-ParmVarDecl ''1498`-CXXMethodDecl 'operator='1499 `-ParmVarDecl ''1500)cpp");1501 }1502 {1503 auto BN = ast_matchers::match(1504 callExpr(callee(functionDecl(hasName("hasDefaultArg"))))1505 .bind("funcCall"),1506 AST2->getASTContext());1507 EXPECT_EQ(BN.size(), 1u);1508 1509 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<CallExpr>("funcCall")),1510 R"cpp(1511CallExpr1512|-ImplicitCastExpr1513| `-DeclRefExpr 'hasDefaultArg'1514|-IntegerLiteral1515`-CXXDefaultArgExpr1516 `-IntegerLiteral1517)cpp");1518 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1519 BN[0].getNodeAs<CallExpr>("funcCall")),1520 R"cpp(1521CallExpr1522|-DeclRefExpr 'hasDefaultArg'1523`-IntegerLiteral1524)cpp");1525 }1526 1527 {1528 auto FN = ast_matchers::match(1529 functionDecl(hasName("decomposition"),1530 hasDescendant(decompositionDecl().bind("decomp"))),1531 AST2->getASTContext());1532 EXPECT_EQ(FN.size(), 1u);1533 1534 EXPECT_EQ(1535 dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")),1536 R"cpp(1537DecompositionDecl ''1538|-DeclRefExpr 'arr'1539|-BindingDecl 'f'1540| `-ArraySubscriptExpr1541| |-ImplicitCastExpr1542| | `-DeclRefExpr ''1543| `-IntegerLiteral1544|-BindingDecl 's'1545| `-ArraySubscriptExpr1546| |-ImplicitCastExpr1547| | `-DeclRefExpr ''1548| `-IntegerLiteral1549`-BindingDecl 't'1550 `-ArraySubscriptExpr1551 |-ImplicitCastExpr1552 | `-DeclRefExpr ''1553 `-IntegerLiteral1554)cpp");1555 1556 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1557 FN[0].getNodeAs<DecompositionDecl>("decomp")),1558 R"cpp(1559DecompositionDecl ''1560|-DeclRefExpr 'arr'1561|-BindingDecl 'f'1562|-BindingDecl 's'1563`-BindingDecl 't'1564)cpp");1565 }1566 1567 {1568 auto FN = ast_matchers::match(1569 functionDecl(hasName("decompTuple"),1570 hasDescendant(decompositionDecl().bind("decomp"))),1571 AST2->getASTContext());1572 EXPECT_EQ(FN.size(), 1u);1573 1574 EXPECT_EQ(1575 dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")),1576 R"cpp(1577DecompositionDecl ''1578|-CXXConstructExpr1579| `-ImplicitCastExpr1580| `-DeclRefExpr 'p'1581|-BindingDecl 'a'1582| |-VarDecl 'a'1583| | `-CallExpr1584| | |-ImplicitCastExpr1585| | | `-DeclRefExpr 'get'1586| | `-ImplicitCastExpr1587| | `-DeclRefExpr ''1588| `-DeclRefExpr 'a'1589`-BindingDecl 'b'1590 |-VarDecl 'b'1591 | `-CallExpr1592 | |-ImplicitCastExpr1593 | | `-DeclRefExpr 'get'1594 | `-ImplicitCastExpr1595 | `-DeclRefExpr ''1596 `-DeclRefExpr 'b'1597)cpp");1598 1599 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1600 FN[0].getNodeAs<DecompositionDecl>("decomp")),1601 R"cpp(1602DecompositionDecl ''1603|-DeclRefExpr 'p'1604|-BindingDecl 'a'1605`-BindingDecl 'b'1606)cpp");1607 }1608 1609 {1610 auto FN = ast_matchers::match(1611 functionDecl(hasName("decompTuple"),1612 hasDescendant(callExpr(hasAncestor(varDecl(1613 hasName("a"),1614 hasAncestor(bindingDecl()))))1615 .bind("decomp_call"))),1616 AST2->getASTContext());1617 EXPECT_EQ(FN.size(), 1u);1618 1619 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<CallExpr>("decomp_call")),1620 R"cpp(1621CallExpr1622|-ImplicitCastExpr1623| `-DeclRefExpr 'get'1624`-ImplicitCastExpr1625 `-DeclRefExpr ''1626)cpp");1627 1628 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1629 FN[0].getNodeAs<CallExpr>("decomp_call")),1630 R"cpp(1631DeclRefExpr ''1632)cpp");1633 }1634 1635 {1636 auto FN = ast_matchers::match(1637 functionDecl(hasName("decompTuple"),1638 hasDescendant(callExpr(hasAncestor(varDecl(1639 hasName("c"),1640 hasAncestor(bindingDecl()))))1641 .bind("decomp_call_with_default"))),1642 AST2->getASTContext());1643 EXPECT_EQ(FN.size(), 1u);1644 1645 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<CallExpr>(1646 "decomp_call_with_default")),1647 R"cpp(1648CallExpr1649|-ImplicitCastExpr1650| `-DeclRefExpr 'get'1651|-ImplicitCastExpr1652| `-DeclRefExpr ''1653`-CXXDefaultArgExpr1654 `-IntegerLiteral1655)cpp");1656 1657 EXPECT_EQ(1658 dumpASTString(TK_IgnoreUnlessSpelledInSource,1659 FN[0].getNodeAs<CallExpr>("decomp_call_with_default")),1660 R"cpp(1661DeclRefExpr ''1662)cpp");1663 }1664}1665 1666TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {1667 1668 auto AST = buildASTFromCode(R"cpp(1669template<typename T>1670struct TemplStruct {1671 TemplStruct() {}1672 ~TemplStruct() {}1673 1674private:1675 T m_t;1676};1677 1678template<typename T>1679T timesTwo(T input)1680{1681 return input * 2;1682}1683 1684void instantiate()1685{1686 TemplStruct<int> ti;1687 TemplStruct<double> td;1688 (void)timesTwo<int>(2);1689 (void)timesTwo<double>(2);1690}1691 1692template class TemplStruct<float>;1693 1694extern template class TemplStruct<long>;1695 1696template<> class TemplStruct<bool> {1697 TemplStruct() {}1698 ~TemplStruct() {}1699 1700 void foo() {}1701private:1702 bool m_t;1703};1704 1705// Explicit instantiation of template functions do not appear in the AST1706template float timesTwo(float);1707 1708template<> bool timesTwo<bool>(bool) {1709 return true;1710}1711)cpp");1712 {1713 auto BN = ast_matchers::match(1714 classTemplateDecl(hasName("TemplStruct")).bind("rec"),1715 AST->getASTContext());1716 EXPECT_EQ(BN.size(), 1u);1717 1718 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1719 BN[0].getNodeAs<Decl>("rec")),1720 R"cpp(1721ClassTemplateDecl 'TemplStruct'1722|-TemplateTypeParmDecl 'T'1723`-CXXRecordDecl 'TemplStruct'1724 |-CXXConstructorDecl 'TemplStruct<T>'1725 | `-CompoundStmt1726 |-CXXDestructorDecl '~TemplStruct<T>'1727 | `-CompoundStmt1728 |-AccessSpecDecl1729 `-FieldDecl 'm_t'1730)cpp");1731 1732 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1733 R"cpp(1734ClassTemplateDecl 'TemplStruct'1735|-TemplateTypeParmDecl 'T'1736|-CXXRecordDecl 'TemplStruct'1737| |-CXXRecordDecl 'TemplStruct'1738| |-CXXConstructorDecl 'TemplStruct<T>'1739| | `-CompoundStmt1740| |-CXXDestructorDecl '~TemplStruct<T>'1741| | `-CompoundStmt1742| |-AccessSpecDecl1743| `-FieldDecl 'm_t'1744|-ClassTemplateSpecializationDecl 'TemplStruct'1745| |-TemplateArgument type int1746| | `-BuiltinType1747| |-CXXRecordDecl 'TemplStruct'1748| |-CXXConstructorDecl 'TemplStruct'1749| | `-CompoundStmt1750| |-CXXDestructorDecl '~TemplStruct'1751| | `-CompoundStmt1752| |-AccessSpecDecl1753| |-FieldDecl 'm_t'1754| `-CXXConstructorDecl 'TemplStruct'1755| `-ParmVarDecl ''1756|-ClassTemplateSpecializationDecl 'TemplStruct'1757| |-TemplateArgument type double1758| | `-BuiltinType1759| |-CXXRecordDecl 'TemplStruct'1760| |-CXXConstructorDecl 'TemplStruct'1761| | `-CompoundStmt1762| |-CXXDestructorDecl '~TemplStruct'1763| | `-CompoundStmt1764| |-AccessSpecDecl1765| |-FieldDecl 'm_t'1766| `-CXXConstructorDecl 'TemplStruct'1767| `-ParmVarDecl ''1768|-ClassTemplateSpecializationDecl 'TemplStruct'1769| |-TemplateArgument type float1770| | `-BuiltinType1771| |-CXXRecordDecl 'TemplStruct'1772| |-CXXConstructorDecl 'TemplStruct'1773| | `-CompoundStmt1774| |-CXXDestructorDecl '~TemplStruct'1775| | `-CompoundStmt1776| |-AccessSpecDecl1777| `-FieldDecl 'm_t'1778|-ClassTemplateSpecializationDecl 'TemplStruct'1779| |-TemplateArgument type long1780| | `-BuiltinType1781| |-CXXRecordDecl 'TemplStruct'1782| |-CXXConstructorDecl 'TemplStruct'1783| |-CXXDestructorDecl '~TemplStruct'1784| |-AccessSpecDecl1785| `-FieldDecl 'm_t'1786`-ClassTemplateSpecializationDecl 'TemplStruct'1787 |-TemplateArgument type _Bool1788 | `-BuiltinType1789 |-CXXRecordDecl 'TemplStruct'1790 |-CXXConstructorDecl 'TemplStruct'1791 | `-CompoundStmt1792 |-CXXDestructorDecl '~TemplStruct'1793 | `-CompoundStmt1794 |-CXXMethodDecl 'foo'1795 | `-CompoundStmt1796 |-AccessSpecDecl1797 `-FieldDecl 'm_t'1798)cpp");1799 }1800 {1801 auto BN = ast_matchers::match(1802 classTemplateSpecializationDecl(1803 hasTemplateArgument(1804 0, templateArgument(refersToType(asString("_Bool")))))1805 .bind("templSpec"),1806 AST->getASTContext());1807 EXPECT_EQ(BN.size(), 1u);1808 1809 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("templSpec")),1810 R"cpp(1811ClassTemplateSpecializationDecl 'TemplStruct'1812|-TemplateArgument type _Bool1813| `-BuiltinType1814|-CXXRecordDecl 'TemplStruct'1815|-CXXConstructorDecl 'TemplStruct'1816| `-CompoundStmt1817|-CXXDestructorDecl '~TemplStruct'1818| `-CompoundStmt1819|-CXXMethodDecl 'foo'1820| `-CompoundStmt1821|-AccessSpecDecl1822`-FieldDecl 'm_t'1823)cpp");1824 1825 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1826 BN[0].getNodeAs<Decl>("templSpec")),1827 R"cpp(1828ClassTemplateSpecializationDecl 'TemplStruct'1829|-TemplateArgument type _Bool1830| `-BuiltinType1831|-CXXConstructorDecl 'TemplStruct'1832| `-CompoundStmt1833|-CXXDestructorDecl '~TemplStruct'1834| `-CompoundStmt1835|-CXXMethodDecl 'foo'1836| `-CompoundStmt1837|-AccessSpecDecl1838`-FieldDecl 'm_t'1839)cpp");1840 }1841 {1842 auto BN = ast_matchers::match(1843 functionTemplateDecl(hasName("timesTwo")).bind("fn"),1844 AST->getASTContext());1845 EXPECT_EQ(BN.size(), 1u);1846 1847 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1848 BN[0].getNodeAs<Decl>("fn")),1849 R"cpp(1850FunctionTemplateDecl 'timesTwo'1851|-TemplateTypeParmDecl 'T'1852`-FunctionDecl 'timesTwo'1853 |-ParmVarDecl 'input'1854 `-CompoundStmt1855 `-ReturnStmt1856 `-BinaryOperator1857 |-DeclRefExpr 'input'1858 `-IntegerLiteral1859)cpp");1860 1861 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),1862 R"cpp(1863FunctionTemplateDecl 'timesTwo'1864|-TemplateTypeParmDecl 'T'1865|-FunctionDecl 'timesTwo'1866| |-ParmVarDecl 'input'1867| `-CompoundStmt1868| `-ReturnStmt1869| `-BinaryOperator1870| |-DeclRefExpr 'input'1871| `-IntegerLiteral1872|-FunctionDecl 'timesTwo'1873| |-TemplateArgument type int1874| | `-BuiltinType1875| |-ParmVarDecl 'input'1876| `-CompoundStmt1877| `-ReturnStmt1878| `-BinaryOperator1879| |-ImplicitCastExpr1880| | `-DeclRefExpr 'input'1881| `-IntegerLiteral1882|-FunctionDecl 'timesTwo'1883| |-TemplateArgument type double1884| | `-BuiltinType1885| |-ParmVarDecl 'input'1886| `-CompoundStmt1887| `-ReturnStmt1888| `-BinaryOperator1889| |-ImplicitCastExpr1890| | `-DeclRefExpr 'input'1891| `-ImplicitCastExpr1892| `-IntegerLiteral1893|-FunctionDecl 'timesTwo'1894| |-TemplateArgument type float1895| | `-BuiltinType1896| |-ParmVarDecl 'input'1897| `-CompoundStmt1898| `-ReturnStmt1899| `-BinaryOperator1900| |-ImplicitCastExpr1901| | `-DeclRefExpr 'input'1902| `-ImplicitCastExpr1903| `-IntegerLiteral1904|-FunctionDecl 'timesTwo'1905| |-TemplateArgument type _Bool1906| | `-BuiltinType1907| |-ParmVarDecl ''1908| `-CompoundStmt1909| `-ReturnStmt1910| `-CXXBoolLiteralExpr1911`-FunctionDecl 'timesTwo'1912 |-TemplateArgument type _Bool1913 | `-BuiltinType1914 `-ParmVarDecl 'input'1915)cpp");1916 }1917 {1918 auto BN = ast_matchers::match(1919 classTemplateSpecializationDecl(1920 hasName("TemplStruct"),1921 hasTemplateArgument(1922 0, templateArgument(refersToType(asString("float")))),1923 hasParent(translationUnitDecl()))1924 .bind("rec"),1925 AST->getASTContext());1926 EXPECT_EQ(BN.size(), 1u);1927 1928 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,1929 BN[0].getNodeAs<Decl>("rec")),1930 R"cpp(1931ClassTemplateSpecializationDecl 'TemplStruct'1932`-TemplateArgument type float1933 `-BuiltinType1934)cpp");1935 1936 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),1937 R"cpp(1938ClassTemplateSpecializationDecl 'TemplStruct'1939|-TemplateArgument type float1940| `-BuiltinType1941|-CXXRecordDecl 'TemplStruct'1942|-CXXConstructorDecl 'TemplStruct'1943| `-CompoundStmt1944|-CXXDestructorDecl '~TemplStruct'1945| `-CompoundStmt1946|-AccessSpecDecl1947`-FieldDecl 'm_t'1948)cpp");1949 }1950}1951 1952TEST(Traverse, CXXRewrittenBinaryOperator) {1953 1954 auto AST = buildASTFromCodeWithArgs(R"cpp(1955namespace std {1956struct strong_ordering {1957 int n;1958 constexpr operator int() const { return n; }1959 static const strong_ordering equal, greater, less;1960};1961constexpr strong_ordering strong_ordering::equal = {0};1962constexpr strong_ordering strong_ordering::greater = {1};1963constexpr strong_ordering strong_ordering::less = {-1};1964}1965 1966struct HasSpaceshipMem {1967 int a;1968 constexpr auto operator<=>(const HasSpaceshipMem&) const = default;1969};1970 1971void binop()1972{1973 HasSpaceshipMem hs1, hs2;1974 if (hs1 < hs2)1975 return;1976}1977)cpp",1978 {"-std=c++20"});1979 {1980 auto BN = ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"),1981 AST->getASTContext());1982 EXPECT_EQ(BN.size(), 1u);1983 1984 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Stmt>("binop")),1985 R"cpp(1986CXXRewrittenBinaryOperator1987`-BinaryOperator1988 |-ImplicitCastExpr1989 | `-CXXMemberCallExpr1990 | `-MemberExpr1991 | `-ImplicitCastExpr1992 | `-MaterializeTemporaryExpr1993 | `-CXXOperatorCallExpr1994 | |-ImplicitCastExpr1995 | | `-DeclRefExpr 'operator<=>'1996 | |-ImplicitCastExpr1997 | | `-DeclRefExpr 'hs1'1998 | `-ImplicitCastExpr1999 | `-DeclRefExpr 'hs2'2000 `-IntegerLiteral2001)cpp");2002 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,2003 BN[0].getNodeAs<Stmt>("binop")),2004 R"cpp(2005CXXRewrittenBinaryOperator2006|-DeclRefExpr 'hs1'2007`-DeclRefExpr 'hs2'2008)cpp");2009 }2010}2011 2012TEST(Traverse, CatchStatements) {2013 2014 auto AST = buildASTFromCode(R"cpp(2015void test()2016{2017 try2018 {2019 int a;2020 }2021 catch (...)2022 {2023 int b;2024 }2025 2026 try2027 {2028 int a;2029 }2030 catch (const int&)2031 {2032 int b;2033 }2034}2035)cpp");2036 2037 auto BN =2038 ast_matchers::match(cxxCatchStmt().bind("catch"), AST->getASTContext());2039 EXPECT_EQ(BN.size(), 2u);2040 const auto *catchWithoutDecl = BN[0].getNodeAs<Stmt>("catch");2041 2042 llvm::StringRef Expected = R"cpp(2043CXXCatchStmt2044|-<<<NULL>>>2045`-CompoundStmt2046 `-DeclStmt2047 `-VarDecl 'b'2048)cpp";2049 EXPECT_EQ(dumpASTString(TK_AsIs, catchWithoutDecl), Expected);2050 2051 Expected = R"cpp(2052CXXCatchStmt2053|-<<<NULL>>>2054`-CompoundStmt2055 `-DeclStmt2056 `-VarDecl 'b'2057)cpp";2058 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, catchWithoutDecl),2059 Expected);2060 2061 const auto *catchWithDecl = BN[1].getNodeAs<Stmt>("catch");2062 2063 Expected = R"cpp(2064CXXCatchStmt2065|-VarDecl ''2066`-CompoundStmt2067 `-DeclStmt2068 `-VarDecl 'b'2069)cpp";2070 EXPECT_EQ(dumpASTString(TK_AsIs, catchWithDecl), Expected);2071 2072 Expected = R"cpp(2073CXXCatchStmt2074|-VarDecl ''2075`-CompoundStmt2076 `-DeclStmt2077 `-VarDecl 'b'2078)cpp";2079 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, catchWithDecl),2080 Expected);2081}2082 2083} // namespace clang2084