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-exception 6 // 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 18 using namespace clang::tooling; 19 using namespace clang::ast_matchers; 20 21 namespace clang { 22 23 class NodeTreePrinter : public TextTreeStructure { 24 llvm::raw_ostream &OS; 25 26 public: 27 NodeTreePrinter(llvm::raw_ostream &OS) 28 : TextTreeStructure(OS, /* showColors */ false), OS(OS) {} 29 30 void Visit(const Decl *D) { 31 OS << D->getDeclKindName() << "Decl"; 32 if (auto *ND = dyn_cast<NamedDecl>(D)) { 33 OS << " '" << ND->getDeclName() << "'"; 34 } 35 } 36 37 void Visit(const Stmt *S) { 38 if (!S) { 39 OS << "<<<NULL>>>"; 40 return; 41 } 42 OS << S->getStmtClassName(); 43 if (auto *E = dyn_cast<DeclRefExpr>(S)) { 44 OS << " '" << E->getDecl()->getDeclName() << "'"; 45 } 46 } 47 48 void Visit(QualType QT) { 49 OS << "QualType " << QT.split().Quals.getAsString(); 50 } 51 52 void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; } 53 54 void Visit(const comments::Comment *C, const comments::FullComment *FC) { 55 OS << C->getCommentKindName(); 56 } 57 58 void Visit(const CXXCtorInitializer *Init) { 59 OS << "CXXCtorInitializer"; 60 if (const auto *F = Init->getAnyMember()) { 61 OS << " '" << F->getNameAsString() << "'"; 62 } else if (auto const *TSI = Init->getTypeSourceInfo()) { 63 OS << " '" << TSI->getType() << "'"; 64 } 65 } 66 67 void Visit(const Attr *A) { 68 switch (A->getKind()) { 69 #define ATTR(X) \ 70 case attr::X: \ 71 OS << #X; \ 72 break; 73 #include "clang/Basic/AttrList.inc" 74 } 75 OS << "Attr"; 76 } 77 78 void Visit(const OMPClause *C) { OS << "OMPClause"; } 79 void Visit(const TemplateArgument &A, SourceRange R = {}, 80 const Decl *From = nullptr, const char *Label = nullptr) { 81 OS << "TemplateArgument"; 82 switch (A.getKind()) { 83 case TemplateArgument::Type: { 84 OS << " type " << A.getAsType(); 85 break; 86 } 87 default: 88 break; 89 } 90 } 91 92 template <typename... T> void Visit(T...) {} 93 }; 94 95 class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> { 96 97 NodeTreePrinter MyNodeRecorder; 98 99 public: 100 TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {} 101 NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; } 102 }; 103 104 template <typename... NodeType> std::string dumpASTString(NodeType &&... N) { 105 std::string Buffer; 106 llvm::raw_string_ostream OS(Buffer); 107 108 TestASTDumper Dumper(OS); 109 110 OS << "\n"; 111 112 Dumper.Visit(std::forward<NodeType &&>(N)...); 113 114 return Buffer; 115 } 116 117 template <typename... NodeType> 118 std::string dumpASTString(TraversalKind TK, NodeType &&... N) { 119 std::string Buffer; 120 llvm::raw_string_ostream OS(Buffer); 121 122 TestASTDumper Dumper(OS); 123 Dumper.SetTraversalKind(TK); 124 125 OS << "\n"; 126 127 Dumper.Visit(std::forward<NodeType &&>(N)...); 128 129 return Buffer; 130 } 131 132 const FunctionDecl *getFunctionNode(clang::ASTUnit *AST, 133 const std::string &Name) { 134 auto Result = ast_matchers::match(functionDecl(hasName(Name)).bind("fn"), 135 AST->getASTContext()); 136 EXPECT_EQ(Result.size(), 1u); 137 return Result[0].getNodeAs<FunctionDecl>("fn"); 138 } 139 140 template <typename T> struct Verifier { 141 static void withDynNode(T Node, const std::string &DumpString) { 142 EXPECT_EQ(dumpASTString(DynTypedNode::create(Node)), DumpString); 143 } 144 }; 145 146 template <typename T> struct Verifier<T *> { 147 static void withDynNode(T *Node, const std::string &DumpString) { 148 EXPECT_EQ(dumpASTString(DynTypedNode::create(*Node)), DumpString); 149 } 150 }; 151 152 template <typename T> 153 void verifyWithDynNode(T Node, const std::string &DumpString) { 154 EXPECT_EQ(dumpASTString(Node), DumpString); 155 156 Verifier<T>::withDynNode(Node, DumpString); 157 } 158 159 TEST(Traverse, Dump) { 160 161 auto AST = buildASTFromCode(R"cpp( 162 struct A { 163 int m_number; 164 165 /// CTor 166 A() : m_number(42) {} 167 168 [[nodiscard]] const int func() { 169 return 42; 170 } 171 172 }; 173 174 template<typename T> 175 struct templ 176 { 177 }; 178 179 template<> 180 struct templ<int> 181 { 182 }; 183 184 void parmvardecl_attr(struct A __attribute__((address_space(19)))*); 185 186 )cpp"); 187 188 const FunctionDecl *Func = getFunctionNode(AST.get(), "func"); 189 190 verifyWithDynNode(Func, 191 R"cpp( 192 CXXMethodDecl 'func' 193 |-CompoundStmt 194 | `-ReturnStmt 195 | `-IntegerLiteral 196 `-WarnUnusedResultAttr 197 )cpp"); 198 199 Stmt *Body = Func->getBody(); 200 201 verifyWithDynNode(Body, 202 R"cpp( 203 CompoundStmt 204 `-ReturnStmt 205 `-IntegerLiteral 206 )cpp"); 207 208 QualType QT = Func->getType(); 209 210 verifyWithDynNode(QT, 211 R"cpp( 212 FunctionProtoType 213 `-QualType const 214 `-BuiltinType 215 )cpp"); 216 217 const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A"); 218 219 verifyWithDynNode(CTorFunc->getType(), 220 R"cpp( 221 FunctionProtoType 222 `-BuiltinType 223 )cpp"); 224 225 Attr *A = *Func->attr_begin(); 226 227 { 228 std::string expectedString = R"cpp( 229 WarnUnusedResultAttr 230 )cpp"; 231 232 EXPECT_EQ(dumpASTString(A), expectedString); 233 } 234 235 auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc); 236 const CXXCtorInitializer *Init = *CTor->init_begin(); 237 238 verifyWithDynNode(Init, 239 R"cpp( 240 CXXCtorInitializer 'm_number' 241 `-IntegerLiteral 242 )cpp"); 243 244 const comments::FullComment *Comment = 245 AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc); 246 { 247 std::string expectedString = R"cpp( 248 FullComment 249 `-ParagraphComment 250 `-TextComment 251 )cpp"; 252 EXPECT_EQ(dumpASTString(Comment, Comment), expectedString); 253 } 254 255 auto Result = ast_matchers::match( 256 classTemplateSpecializationDecl(hasName("templ")).bind("fn"), 257 AST->getASTContext()); 258 EXPECT_EQ(Result.size(), 1u); 259 auto Templ = Result[0].getNodeAs<ClassTemplateSpecializationDecl>("fn"); 260 261 TemplateArgument TA = Templ->getTemplateArgs()[0]; 262 263 verifyWithDynNode(TA, 264 R"cpp( 265 TemplateArgument type int 266 `-BuiltinType 267 )cpp"); 268 269 Func = getFunctionNode(AST.get(), "parmvardecl_attr"); 270 271 const auto *Parm = Func->getParamDecl(0); 272 const auto TL = Parm->getTypeSourceInfo()->getTypeLoc(); 273 ASSERT_TRUE(TL.getType()->isPointerType()); 274 275 const auto ATL = TL.getNextTypeLoc().getAs<AttributedTypeLoc>(); 276 const auto *AS = cast<AddressSpaceAttr>(ATL.getAttr()); 277 EXPECT_EQ(toTargetAddressSpace(static_cast<LangAS>(AS->getAddressSpace())), 278 19u); 279 } 280 281 TEST(Traverse, IgnoreUnlessSpelledInSourceVars) { 282 283 auto AST = buildASTFromCode(R"cpp( 284 285 struct String 286 { 287 String(const char*, int = -1) {} 288 289 int overloaded() const; 290 int& overloaded(); 291 }; 292 293 void stringConstruct() 294 { 295 String s = "foo"; 296 s = "bar"; 297 } 298 299 void overloadCall() 300 { 301 String s = "foo"; 302 (s).overloaded(); 303 } 304 305 struct C1 {}; 306 struct C2 { operator C1(); }; 307 308 void conversionOperator() 309 { 310 C2* c2; 311 C1 c1 = (*c2); 312 } 313 314 template <unsigned alignment> 315 void template_test() { 316 static_assert(alignment, ""); 317 } 318 void actual_template_test() { 319 template_test<4>(); 320 } 321 322 struct OneParamCtor { 323 explicit OneParamCtor(int); 324 }; 325 struct TwoParamCtor { 326 explicit TwoParamCtor(int, int); 327 }; 328 329 void varDeclCtors() { 330 { 331 auto var1 = OneParamCtor(5); 332 auto var2 = TwoParamCtor(6, 7); 333 } 334 { 335 OneParamCtor var3(5); 336 TwoParamCtor var4(6, 7); 337 } 338 int i = 0; 339 { 340 auto var5 = OneParamCtor(i); 341 auto var6 = TwoParamCtor(i, 7); 342 } 343 { 344 OneParamCtor var7(i); 345 TwoParamCtor var8(i, 7); 346 } 347 } 348 349 )cpp"); 350 351 { 352 auto FN = 353 ast_matchers::match(functionDecl(hasName("stringConstruct")).bind("fn"), 354 AST->getASTContext()); 355 EXPECT_EQ(FN.size(), 1u); 356 357 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")), 358 R"cpp( 359 FunctionDecl 'stringConstruct' 360 `-CompoundStmt 361 |-DeclStmt 362 | `-VarDecl 's' 363 | `-ExprWithCleanups 364 | `-CXXConstructExpr 365 | `-MaterializeTemporaryExpr 366 | `-ImplicitCastExpr 367 | `-CXXConstructExpr 368 | |-ImplicitCastExpr 369 | | `-StringLiteral 370 | `-CXXDefaultArgExpr 371 `-ExprWithCleanups 372 `-CXXOperatorCallExpr 373 |-ImplicitCastExpr 374 | `-DeclRefExpr 'operator=' 375 |-DeclRefExpr 's' 376 `-MaterializeTemporaryExpr 377 `-CXXConstructExpr 378 |-ImplicitCastExpr 379 | `-StringLiteral 380 `-CXXDefaultArgExpr 381 )cpp"); 382 383 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 384 FN[0].getNodeAs<Decl>("fn")), 385 R"cpp( 386 FunctionDecl 'stringConstruct' 387 `-CompoundStmt 388 |-DeclStmt 389 | `-VarDecl 's' 390 | `-StringLiteral 391 `-CXXOperatorCallExpr 392 |-DeclRefExpr 'operator=' 393 |-DeclRefExpr 's' 394 `-StringLiteral 395 )cpp"); 396 } 397 398 { 399 auto FN = 400 ast_matchers::match(functionDecl(hasName("overloadCall")).bind("fn"), 401 AST->getASTContext()); 402 EXPECT_EQ(FN.size(), 1u); 403 404 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")), 405 R"cpp( 406 FunctionDecl 'overloadCall' 407 `-CompoundStmt 408 |-DeclStmt 409 | `-VarDecl 's' 410 | `-ExprWithCleanups 411 | `-CXXConstructExpr 412 | `-MaterializeTemporaryExpr 413 | `-ImplicitCastExpr 414 | `-CXXConstructExpr 415 | |-ImplicitCastExpr 416 | | `-StringLiteral 417 | `-CXXDefaultArgExpr 418 `-CXXMemberCallExpr 419 `-MemberExpr 420 `-ParenExpr 421 `-DeclRefExpr 's' 422 )cpp"); 423 424 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 425 FN[0].getNodeAs<Decl>("fn")), 426 R"cpp( 427 FunctionDecl 'overloadCall' 428 `-CompoundStmt 429 |-DeclStmt 430 | `-VarDecl 's' 431 | `-StringLiteral 432 `-CXXMemberCallExpr 433 `-MemberExpr 434 `-DeclRefExpr 's' 435 )cpp"); 436 } 437 438 { 439 auto FN = ast_matchers::match( 440 functionDecl(hasName("conversionOperator"), 441 hasDescendant(varDecl(hasName("c1")).bind("var"))), 442 AST->getASTContext()); 443 EXPECT_EQ(FN.size(), 1u); 444 445 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("var")), 446 R"cpp( 447 VarDecl 'c1' 448 `-ExprWithCleanups 449 `-CXXConstructExpr 450 `-MaterializeTemporaryExpr 451 `-ImplicitCastExpr 452 `-CXXMemberCallExpr 453 `-MemberExpr 454 `-ParenExpr 455 `-UnaryOperator 456 `-ImplicitCastExpr 457 `-DeclRefExpr 'c2' 458 )cpp"); 459 460 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 461 FN[0].getNodeAs<Decl>("var")), 462 R"cpp( 463 VarDecl 'c1' 464 `-UnaryOperator 465 `-DeclRefExpr 'c2' 466 )cpp"); 467 } 468 469 { 470 auto FN = ast_matchers::match( 471 functionDecl(hasName("template_test"), 472 hasDescendant(staticAssertDecl().bind("staticAssert"))), 473 AST->getASTContext()); 474 EXPECT_EQ(FN.size(), 2u); 475 476 EXPECT_EQ(dumpASTString(TK_AsIs, FN[1].getNodeAs<Decl>("staticAssert")), 477 R"cpp( 478 StaticAssertDecl 479 |-ImplicitCastExpr 480 | `-SubstNonTypeTemplateParmExpr 481 | |-NonTypeTemplateParmDecl 'alignment' 482 | `-IntegerLiteral 483 `-StringLiteral 484 )cpp"); 485 486 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 487 FN[1].getNodeAs<Decl>("staticAssert")), 488 R"cpp( 489 StaticAssertDecl 490 |-IntegerLiteral 491 `-StringLiteral 492 )cpp"); 493 } 494 495 auto varChecker = [&AST](StringRef varName, StringRef SemanticDump, 496 StringRef SyntacticDump) { 497 auto FN = ast_matchers::match( 498 functionDecl( 499 hasName("varDeclCtors"), 500 forEachDescendant(varDecl(hasName(varName)).bind("varDeclCtor"))), 501 AST->getASTContext()); 502 EXPECT_EQ(FN.size(), 1u); 503 504 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("varDeclCtor")), 505 SemanticDump); 506 507 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 508 FN[0].getNodeAs<Decl>("varDeclCtor")), 509 SyntacticDump); 510 }; 511 512 varChecker("var1", 513 R"cpp( 514 VarDecl 'var1' 515 `-ExprWithCleanups 516 `-CXXConstructExpr 517 `-MaterializeTemporaryExpr 518 `-CXXFunctionalCastExpr 519 `-CXXConstructExpr 520 `-IntegerLiteral 521 )cpp", 522 R"cpp( 523 VarDecl 'var1' 524 `-CXXConstructExpr 525 `-IntegerLiteral 526 )cpp"); 527 528 varChecker("var2", 529 R"cpp( 530 VarDecl 'var2' 531 `-ExprWithCleanups 532 `-CXXConstructExpr 533 `-MaterializeTemporaryExpr 534 `-CXXTemporaryObjectExpr 535 |-IntegerLiteral 536 `-IntegerLiteral 537 )cpp", 538 R"cpp( 539 VarDecl 'var2' 540 `-CXXTemporaryObjectExpr 541 |-IntegerLiteral 542 `-IntegerLiteral 543 )cpp"); 544 545 varChecker("var3", 546 R"cpp( 547 VarDecl 'var3' 548 `-CXXConstructExpr 549 `-IntegerLiteral 550 )cpp", 551 R"cpp( 552 VarDecl 'var3' 553 `-CXXConstructExpr 554 `-IntegerLiteral 555 )cpp"); 556 557 varChecker("var4", 558 R"cpp( 559 VarDecl 'var4' 560 `-CXXConstructExpr 561 |-IntegerLiteral 562 `-IntegerLiteral 563 )cpp", 564 R"cpp( 565 VarDecl 'var4' 566 `-CXXConstructExpr 567 |-IntegerLiteral 568 `-IntegerLiteral 569 )cpp"); 570 571 varChecker("var5", 572 R"cpp( 573 VarDecl 'var5' 574 `-ExprWithCleanups 575 `-CXXConstructExpr 576 `-MaterializeTemporaryExpr 577 `-CXXFunctionalCastExpr 578 `-CXXConstructExpr 579 `-ImplicitCastExpr 580 `-DeclRefExpr 'i' 581 )cpp", 582 R"cpp( 583 VarDecl 'var5' 584 `-CXXConstructExpr 585 `-DeclRefExpr 'i' 586 )cpp"); 587 588 varChecker("var6", 589 R"cpp( 590 VarDecl 'var6' 591 `-ExprWithCleanups 592 `-CXXConstructExpr 593 `-MaterializeTemporaryExpr 594 `-CXXTemporaryObjectExpr 595 |-ImplicitCastExpr 596 | `-DeclRefExpr 'i' 597 `-IntegerLiteral 598 )cpp", 599 R"cpp( 600 VarDecl 'var6' 601 `-CXXTemporaryObjectExpr 602 |-DeclRefExpr 'i' 603 `-IntegerLiteral 604 )cpp"); 605 606 varChecker("var7", 607 R"cpp( 608 VarDecl 'var7' 609 `-CXXConstructExpr 610 `-ImplicitCastExpr 611 `-DeclRefExpr 'i' 612 )cpp", 613 R"cpp( 614 VarDecl 'var7' 615 `-CXXConstructExpr 616 `-DeclRefExpr 'i' 617 )cpp"); 618 619 varChecker("var8", 620 R"cpp( 621 VarDecl 'var8' 622 `-CXXConstructExpr 623 |-ImplicitCastExpr 624 | `-DeclRefExpr 'i' 625 `-IntegerLiteral 626 )cpp", 627 R"cpp( 628 VarDecl 'var8' 629 `-CXXConstructExpr 630 |-DeclRefExpr 'i' 631 `-IntegerLiteral 632 )cpp"); 633 } 634 635 TEST(Traverse, IgnoreUnlessSpelledInSourceStructs) { 636 auto AST = buildASTFromCode(R"cpp( 637 638 struct MyStruct { 639 MyStruct(); 640 MyStruct(int i) { 641 MyStruct(); 642 } 643 ~MyStruct(); 644 }; 645 646 )cpp"); 647 648 auto BN = ast_matchers::match( 649 cxxConstructorDecl(hasName("MyStruct"), 650 hasParameter(0, parmVarDecl(hasType(isInteger())))) 651 .bind("ctor"), 652 AST->getASTContext()); 653 EXPECT_EQ(BN.size(), 1u); 654 655 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 656 BN[0].getNodeAs<Decl>("ctor")), 657 R"cpp( 658 CXXConstructorDecl 'MyStruct' 659 |-ParmVarDecl 'i' 660 `-CompoundStmt 661 `-CXXTemporaryObjectExpr 662 )cpp"); 663 664 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("ctor")), 665 R"cpp( 666 CXXConstructorDecl 'MyStruct' 667 |-ParmVarDecl 'i' 668 `-CompoundStmt 669 `-ExprWithCleanups 670 `-CXXBindTemporaryExpr 671 `-CXXTemporaryObjectExpr 672 )cpp"); 673 } 674 675 TEST(Traverse, IgnoreUnlessSpelledInSourceReturnStruct) { 676 677 auto AST = buildASTFromCode(R"cpp( 678 struct Retval { 679 Retval() {} 680 ~Retval() {} 681 }; 682 683 Retval someFun(); 684 685 void foo() 686 { 687 someFun(); 688 } 689 )cpp"); 690 691 auto BN = ast_matchers::match(functionDecl(hasName("foo")).bind("fn"), 692 AST->getASTContext()); 693 EXPECT_EQ(BN.size(), 1u); 694 695 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 696 BN[0].getNodeAs<Decl>("fn")), 697 R"cpp( 698 FunctionDecl 'foo' 699 `-CompoundStmt 700 `-CallExpr 701 `-DeclRefExpr 'someFun' 702 )cpp"); 703 704 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")), 705 R"cpp( 706 FunctionDecl 'foo' 707 `-CompoundStmt 708 `-ExprWithCleanups 709 `-CXXBindTemporaryExpr 710 `-CallExpr 711 `-ImplicitCastExpr 712 `-DeclRefExpr 'someFun' 713 )cpp"); 714 } 715 716 TEST(Traverse, IgnoreUnlessSpelledInSourceReturns) { 717 718 auto AST = buildASTFromCode(R"cpp( 719 720 struct A 721 { 722 }; 723 724 struct B 725 { 726 B(int); 727 B(A const& a); 728 B(); 729 }; 730 731 struct C 732 { 733 operator B(); 734 }; 735 736 B func1() { 737 return 42; 738 } 739 740 B func2() { 741 return B{42}; 742 } 743 744 B func3() { 745 return B(42); 746 } 747 748 B func4() { 749 return B(); 750 } 751 752 B func5() { 753 return B{}; 754 } 755 756 B func6() { 757 return C(); 758 } 759 760 B func7() { 761 return A(); 762 } 763 764 B func8() { 765 return C{}; 766 } 767 768 B func9() { 769 return A{}; 770 } 771 772 B func10() { 773 A a; 774 return a; 775 } 776 777 B func11() { 778 B b; 779 return b; 780 } 781 782 B func12() { 783 C c; 784 return c; 785 } 786 787 )cpp"); 788 789 auto getFunctionNode = [&AST](const std::string &name) { 790 auto BN = ast_matchers::match(functionDecl(hasName(name)).bind("fn"), 791 AST->getASTContext()); 792 EXPECT_EQ(BN.size(), 1u); 793 return BN[0].getNodeAs<Decl>("fn"); 794 }; 795 796 { 797 auto FN = getFunctionNode("func1"); 798 llvm::StringRef Expected = R"cpp( 799 FunctionDecl 'func1' 800 `-CompoundStmt 801 `-ReturnStmt 802 `-ExprWithCleanups 803 `-CXXConstructExpr 804 `-MaterializeTemporaryExpr 805 `-ImplicitCastExpr 806 `-CXXConstructExpr 807 `-IntegerLiteral 808 )cpp"; 809 810 EXPECT_EQ(dumpASTString(TK_AsIs, FN), Expected); 811 812 Expected = R"cpp( 813 FunctionDecl 'func1' 814 `-CompoundStmt 815 `-ReturnStmt 816 `-IntegerLiteral 817 )cpp"; 818 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, FN), Expected); 819 } 820 821 llvm::StringRef Expected = R"cpp( 822 FunctionDecl 'func2' 823 `-CompoundStmt 824 `-ReturnStmt 825 `-CXXTemporaryObjectExpr 826 `-IntegerLiteral 827 )cpp"; 828 EXPECT_EQ( 829 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func2")), 830 Expected); 831 832 Expected = R"cpp( 833 FunctionDecl 'func3' 834 `-CompoundStmt 835 `-ReturnStmt 836 `-CXXConstructExpr 837 `-IntegerLiteral 838 )cpp"; 839 EXPECT_EQ( 840 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func3")), 841 Expected); 842 843 Expected = R"cpp( 844 FunctionDecl 'func4' 845 `-CompoundStmt 846 `-ReturnStmt 847 `-CXXTemporaryObjectExpr 848 )cpp"; 849 EXPECT_EQ( 850 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func4")), 851 Expected); 852 853 Expected = R"cpp( 854 FunctionDecl 'func5' 855 `-CompoundStmt 856 `-ReturnStmt 857 `-CXXTemporaryObjectExpr 858 )cpp"; 859 EXPECT_EQ( 860 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func5")), 861 Expected); 862 863 Expected = R"cpp( 864 FunctionDecl 'func6' 865 `-CompoundStmt 866 `-ReturnStmt 867 `-CXXTemporaryObjectExpr 868 )cpp"; 869 EXPECT_EQ( 870 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func6")), 871 Expected); 872 873 Expected = R"cpp( 874 FunctionDecl 'func7' 875 `-CompoundStmt 876 `-ReturnStmt 877 `-CXXTemporaryObjectExpr 878 )cpp"; 879 EXPECT_EQ( 880 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func7")), 881 Expected); 882 883 Expected = R"cpp( 884 FunctionDecl 'func8' 885 `-CompoundStmt 886 `-ReturnStmt 887 `-CXXFunctionalCastExpr 888 `-InitListExpr 889 )cpp"; 890 EXPECT_EQ( 891 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func8")), 892 Expected); 893 894 Expected = R"cpp( 895 FunctionDecl 'func9' 896 `-CompoundStmt 897 `-ReturnStmt 898 `-CXXFunctionalCastExpr 899 `-InitListExpr 900 )cpp"; 901 EXPECT_EQ( 902 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func9")), 903 Expected); 904 905 Expected = R"cpp( 906 FunctionDecl 'func10' 907 `-CompoundStmt 908 |-DeclStmt 909 | `-VarDecl 'a' 910 | `-CXXConstructExpr 911 `-ReturnStmt 912 `-DeclRefExpr 'a' 913 )cpp"; 914 EXPECT_EQ( 915 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func10")), 916 Expected); 917 918 Expected = R"cpp( 919 FunctionDecl 'func11' 920 `-CompoundStmt 921 |-DeclStmt 922 | `-VarDecl 'b' 923 | `-CXXConstructExpr 924 `-ReturnStmt 925 `-DeclRefExpr 'b' 926 )cpp"; 927 EXPECT_EQ( 928 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func11")), 929 Expected); 930 931 Expected = R"cpp( 932 FunctionDecl 'func12' 933 `-CompoundStmt 934 |-DeclStmt 935 | `-VarDecl 'c' 936 | `-CXXConstructExpr 937 `-ReturnStmt 938 `-DeclRefExpr 'c' 939 )cpp"; 940 EXPECT_EQ( 941 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func12")), 942 Expected); 943 } 944 945 TEST(Traverse, LambdaUnlessSpelledInSource) { 946 947 auto AST = 948 buildASTFromCodeWithArgs(R"cpp( 949 950 void captures() { 951 int a = 0; 952 int b = 0; 953 int d = 0; 954 int f = 0; 955 956 [a, &b, c = d, &e = f](int g, int h = 42) {}; 957 } 958 959 void templated() { 960 int a = 0; 961 [a]<typename T>(T t) {}; 962 } 963 964 struct SomeStruct { 965 int a = 0; 966 void capture_this() { 967 [this]() {}; 968 } 969 void capture_this_copy() { 970 [self = *this]() {}; 971 } 972 }; 973 )cpp", 974 {"-Wno-unused-value", "-Wno-c++2a-extensions"}); 975 976 auto getLambdaNode = [&AST](const std::string &name) { 977 auto BN = ast_matchers::match( 978 lambdaExpr(hasAncestor(functionDecl(hasName(name)))).bind("lambda"), 979 AST->getASTContext()); 980 EXPECT_EQ(BN.size(), 1u); 981 return BN[0].getNodeAs<LambdaExpr>("lambda"); 982 }; 983 984 { 985 auto L = getLambdaNode("captures"); 986 987 llvm::StringRef Expected = R"cpp( 988 LambdaExpr 989 |-DeclRefExpr 'a' 990 |-DeclRefExpr 'b' 991 |-VarDecl 'c' 992 | `-DeclRefExpr 'd' 993 |-VarDecl 'e' 994 | `-DeclRefExpr 'f' 995 |-ParmVarDecl 'g' 996 |-ParmVarDecl 'h' 997 | `-IntegerLiteral 998 `-CompoundStmt 999 )cpp"; 1000 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected); 1001 1002 Expected = R"cpp( 1003 LambdaExpr 1004 |-CXXRecordDecl '' 1005 | |-CXXMethodDecl 'operator()' 1006 | | |-ParmVarDecl 'g' 1007 | | |-ParmVarDecl 'h' 1008 | | | `-IntegerLiteral 1009 | | `-CompoundStmt 1010 | |-FieldDecl '' 1011 | |-FieldDecl '' 1012 | |-FieldDecl '' 1013 | |-FieldDecl '' 1014 | `-CXXDestructorDecl '~' 1015 |-ImplicitCastExpr 1016 | `-DeclRefExpr 'a' 1017 |-DeclRefExpr 'b' 1018 |-ImplicitCastExpr 1019 | `-DeclRefExpr 'd' 1020 |-DeclRefExpr 'f' 1021 `-CompoundStmt 1022 )cpp"; 1023 EXPECT_EQ(dumpASTString(TK_AsIs, L), Expected); 1024 } 1025 1026 { 1027 auto L = getLambdaNode("templated"); 1028 1029 llvm::StringRef Expected = R"cpp( 1030 LambdaExpr 1031 |-DeclRefExpr 'a' 1032 |-TemplateTypeParmDecl 'T' 1033 |-ParmVarDecl 't' 1034 `-CompoundStmt 1035 )cpp"; 1036 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected); 1037 } 1038 1039 { 1040 auto L = getLambdaNode("capture_this"); 1041 1042 llvm::StringRef Expected = R"cpp( 1043 LambdaExpr 1044 |-CXXThisExpr 1045 `-CompoundStmt 1046 )cpp"; 1047 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected); 1048 } 1049 1050 { 1051 auto L = getLambdaNode("capture_this_copy"); 1052 1053 llvm::StringRef Expected = R"cpp( 1054 LambdaExpr 1055 |-VarDecl 'self' 1056 | `-UnaryOperator 1057 | `-CXXThisExpr 1058 `-CompoundStmt 1059 )cpp"; 1060 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected); 1061 } 1062 } 1063 1064 TEST(Traverse, IgnoreUnlessSpelledInSourceImplicit) { 1065 { 1066 auto AST = buildASTFromCode(R"cpp( 1067 int i = 0; 1068 )cpp"); 1069 const auto *TUDecl = AST->getASTContext().getTranslationUnitDecl(); 1070 1071 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, TUDecl), 1072 R"cpp( 1073 TranslationUnitDecl 1074 `-VarDecl 'i' 1075 `-IntegerLiteral 1076 )cpp"); 1077 } 1078 1079 auto AST2 = buildASTFromCodeWithArgs(R"cpp( 1080 struct Simple { 1081 }; 1082 struct Other { 1083 }; 1084 1085 struct Record : Simple, Other { 1086 Record() : Simple(), m_i(42) {} 1087 private: 1088 int m_i; 1089 int m_i2 = 42; 1090 Simple m_s; 1091 }; 1092 1093 struct NonTrivial { 1094 NonTrivial() {} 1095 NonTrivial(NonTrivial&) {} 1096 NonTrivial& operator=(NonTrivial&) { return *this; } 1097 1098 ~NonTrivial() {} 1099 }; 1100 1101 struct ContainsArray { 1102 NonTrivial arr[2]; 1103 int irr[2]; 1104 ContainsArray& operator=(ContainsArray &) = default; 1105 }; 1106 1107 void copyIt() 1108 { 1109 ContainsArray ca; 1110 ContainsArray ca2; 1111 ca2 = ca; 1112 } 1113 1114 void forLoop() 1115 { 1116 int arr[2]; 1117 for (auto i : arr) 1118 { 1119 1120 } 1121 for (auto& a = arr; auto i : a) 1122 { 1123 1124 } 1125 } 1126 1127 struct DefaultedAndDeleted { 1128 NonTrivial nt; 1129 DefaultedAndDeleted() = default; 1130 ~DefaultedAndDeleted() = default; 1131 DefaultedAndDeleted(DefaultedAndDeleted &) = default; 1132 DefaultedAndDeleted& operator=(DefaultedAndDeleted &) = default; 1133 DefaultedAndDeleted(DefaultedAndDeleted &&) = delete; 1134 DefaultedAndDeleted& operator=(DefaultedAndDeleted &&) = delete; 1135 }; 1136 1137 void copyIt2() 1138 { 1139 DefaultedAndDeleted ca; 1140 DefaultedAndDeleted ca2; 1141 ca2 = ca; 1142 } 1143 1144 void hasDefaultArg(int i, int j = 0) 1145 { 1146 } 1147 void callDefaultArg() 1148 { 1149 hasDefaultArg(42); 1150 } 1151 1152 void decomposition() 1153 { 1154 int arr[3]; 1155 auto &[f, s, t] = arr; 1156 1157 f = 42; 1158 } 1159 1160 typedef __typeof(sizeof(int)) size_t; 1161 1162 struct Pair 1163 { 1164 int x, y; 1165 }; 1166 1167 // Note: these utilities are required to force binding to tuple like structure 1168 namespace std 1169 { 1170 template <typename E> 1171 struct tuple_size 1172 { 1173 }; 1174 1175 template <> 1176 struct tuple_size<Pair> 1177 { 1178 static constexpr size_t value = 2; 1179 }; 1180 1181 template <size_t I, class T> 1182 struct tuple_element 1183 { 1184 using type = int; 1185 }; 1186 1187 }; 1188 1189 template <size_t I> 1190 int &&get(Pair &&p); 1191 1192 void decompTuple() 1193 { 1194 Pair p{1, 2}; 1195 auto [a, b] = p; 1196 1197 a = 3; 1198 } 1199 1200 )cpp", 1201 {"-std=c++20"}); 1202 1203 { 1204 auto BN = ast_matchers::match( 1205 cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"), 1206 AST2->getASTContext()); 1207 EXPECT_EQ(BN.size(), 1u); 1208 1209 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1210 R"cpp( 1211 CXXRecordDecl 'Record' 1212 |-CXXRecordDecl 'Record' 1213 |-CXXConstructorDecl 'Record' 1214 | |-CXXCtorInitializer 'struct Simple' 1215 | | `-CXXConstructExpr 1216 | |-CXXCtorInitializer 'struct Other' 1217 | | `-CXXConstructExpr 1218 | |-CXXCtorInitializer 'm_i' 1219 | | `-IntegerLiteral 1220 | |-CXXCtorInitializer 'm_i2' 1221 | | `-CXXDefaultInitExpr 1222 | |-CXXCtorInitializer 'm_s' 1223 | | `-CXXConstructExpr 1224 | `-CompoundStmt 1225 |-AccessSpecDecl 1226 |-FieldDecl 'm_i' 1227 |-FieldDecl 'm_i2' 1228 | `-IntegerLiteral 1229 `-FieldDecl 'm_s' 1230 )cpp"); 1231 1232 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1233 BN[0].getNodeAs<Decl>("rec")), 1234 R"cpp( 1235 CXXRecordDecl 'Record' 1236 |-CXXConstructorDecl 'Record' 1237 | |-CXXCtorInitializer 'struct Simple' 1238 | | `-CXXConstructExpr 1239 | |-CXXCtorInitializer 'm_i' 1240 | | `-IntegerLiteral 1241 | `-CompoundStmt 1242 |-AccessSpecDecl 1243 |-FieldDecl 'm_i' 1244 |-FieldDecl 'm_i2' 1245 | `-IntegerLiteral 1246 `-FieldDecl 'm_s' 1247 )cpp"); 1248 } 1249 { 1250 auto BN = ast_matchers::match( 1251 cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit())) 1252 .bind("rec"), 1253 AST2->getASTContext()); 1254 EXPECT_EQ(BN.size(), 1u); 1255 1256 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1257 R"cpp( 1258 CXXRecordDecl 'ContainsArray' 1259 |-CXXRecordDecl 'ContainsArray' 1260 |-FieldDecl 'arr' 1261 |-FieldDecl 'irr' 1262 |-CXXMethodDecl 'operator=' 1263 | |-ParmVarDecl '' 1264 | `-CompoundStmt 1265 | |-ForStmt 1266 | | |-DeclStmt 1267 | | | `-VarDecl '__i0' 1268 | | | `-IntegerLiteral 1269 | | |-<<<NULL>>> 1270 | | |-BinaryOperator 1271 | | | |-ImplicitCastExpr 1272 | | | | `-DeclRefExpr '__i0' 1273 | | | `-IntegerLiteral 1274 | | |-UnaryOperator 1275 | | | `-DeclRefExpr '__i0' 1276 | | `-CXXMemberCallExpr 1277 | | |-MemberExpr 1278 | | | `-ArraySubscriptExpr 1279 | | | |-ImplicitCastExpr 1280 | | | | `-MemberExpr 1281 | | | | `-CXXThisExpr 1282 | | | `-ImplicitCastExpr 1283 | | | `-DeclRefExpr '__i0' 1284 | | `-ArraySubscriptExpr 1285 | | |-ImplicitCastExpr 1286 | | | `-MemberExpr 1287 | | | `-DeclRefExpr '' 1288 | | `-ImplicitCastExpr 1289 | | `-DeclRefExpr '__i0' 1290 | |-CallExpr 1291 | | |-ImplicitCastExpr 1292 | | | `-DeclRefExpr '__builtin_memcpy' 1293 | | |-ImplicitCastExpr 1294 | | | `-UnaryOperator 1295 | | | `-MemberExpr 1296 | | | `-CXXThisExpr 1297 | | |-ImplicitCastExpr 1298 | | | `-UnaryOperator 1299 | | | `-MemberExpr 1300 | | | `-DeclRefExpr '' 1301 | | `-IntegerLiteral 1302 | `-ReturnStmt 1303 | `-UnaryOperator 1304 | `-CXXThisExpr 1305 |-CXXConstructorDecl 'ContainsArray' 1306 | `-ParmVarDecl '' 1307 |-CXXDestructorDecl '~ContainsArray' 1308 | `-CompoundStmt 1309 `-CXXConstructorDecl 'ContainsArray' 1310 |-CXXCtorInitializer 'arr' 1311 | `-CXXConstructExpr 1312 `-CompoundStmt 1313 )cpp"); 1314 1315 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1316 BN[0].getNodeAs<Decl>("rec")), 1317 R"cpp( 1318 CXXRecordDecl 'ContainsArray' 1319 |-FieldDecl 'arr' 1320 |-FieldDecl 'irr' 1321 `-CXXMethodDecl 'operator=' 1322 `-ParmVarDecl '' 1323 )cpp"); 1324 } 1325 { 1326 auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"), 1327 AST2->getASTContext()); 1328 EXPECT_EQ(BN.size(), 1u); 1329 1330 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("func")), 1331 R"cpp( 1332 FunctionDecl 'forLoop' 1333 `-CompoundStmt 1334 |-DeclStmt 1335 | `-VarDecl 'arr' 1336 |-CXXForRangeStmt 1337 | |-<<<NULL>>> 1338 | |-DeclStmt 1339 | | `-VarDecl '__range1' 1340 | | `-DeclRefExpr 'arr' 1341 | |-DeclStmt 1342 | | `-VarDecl '__begin1' 1343 | | `-ImplicitCastExpr 1344 | | `-DeclRefExpr '__range1' 1345 | |-DeclStmt 1346 | | `-VarDecl '__end1' 1347 | | `-BinaryOperator 1348 | | |-ImplicitCastExpr 1349 | | | `-DeclRefExpr '__range1' 1350 | | `-IntegerLiteral 1351 | |-BinaryOperator 1352 | | |-ImplicitCastExpr 1353 | | | `-DeclRefExpr '__begin1' 1354 | | `-ImplicitCastExpr 1355 | | `-DeclRefExpr '__end1' 1356 | |-UnaryOperator 1357 | | `-DeclRefExpr '__begin1' 1358 | |-DeclStmt 1359 | | `-VarDecl 'i' 1360 | | `-ImplicitCastExpr 1361 | | `-UnaryOperator 1362 | | `-ImplicitCastExpr 1363 | | `-DeclRefExpr '__begin1' 1364 | `-CompoundStmt 1365 `-CXXForRangeStmt 1366 |-DeclStmt 1367 | `-VarDecl 'a' 1368 | `-DeclRefExpr 'arr' 1369 |-DeclStmt 1370 | `-VarDecl '__range1' 1371 | `-DeclRefExpr 'a' 1372 |-DeclStmt 1373 | `-VarDecl '__begin1' 1374 | `-ImplicitCastExpr 1375 | `-DeclRefExpr '__range1' 1376 |-DeclStmt 1377 | `-VarDecl '__end1' 1378 | `-BinaryOperator 1379 | |-ImplicitCastExpr 1380 | | `-DeclRefExpr '__range1' 1381 | `-IntegerLiteral 1382 |-BinaryOperator 1383 | |-ImplicitCastExpr 1384 | | `-DeclRefExpr '__begin1' 1385 | `-ImplicitCastExpr 1386 | `-DeclRefExpr '__end1' 1387 |-UnaryOperator 1388 | `-DeclRefExpr '__begin1' 1389 |-DeclStmt 1390 | `-VarDecl 'i' 1391 | `-ImplicitCastExpr 1392 | `-UnaryOperator 1393 | `-ImplicitCastExpr 1394 | `-DeclRefExpr '__begin1' 1395 `-CompoundStmt 1396 )cpp"); 1397 1398 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1399 BN[0].getNodeAs<Decl>("func")), 1400 R"cpp( 1401 FunctionDecl 'forLoop' 1402 `-CompoundStmt 1403 |-DeclStmt 1404 | `-VarDecl 'arr' 1405 |-CXXForRangeStmt 1406 | |-<<<NULL>>> 1407 | |-VarDecl 'i' 1408 | |-DeclRefExpr 'arr' 1409 | `-CompoundStmt 1410 `-CXXForRangeStmt 1411 |-DeclStmt 1412 | `-VarDecl 'a' 1413 | `-DeclRefExpr 'arr' 1414 |-VarDecl 'i' 1415 |-DeclRefExpr 'a' 1416 `-CompoundStmt 1417 )cpp"); 1418 } 1419 { 1420 auto BN = ast_matchers::match( 1421 cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit())) 1422 .bind("rec"), 1423 AST2->getASTContext()); 1424 EXPECT_EQ(BN.size(), 1u); 1425 1426 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1427 R"cpp( 1428 CXXRecordDecl 'DefaultedAndDeleted' 1429 |-CXXRecordDecl 'DefaultedAndDeleted' 1430 |-FieldDecl 'nt' 1431 |-CXXConstructorDecl 'DefaultedAndDeleted' 1432 | |-CXXCtorInitializer 'nt' 1433 | | `-CXXConstructExpr 1434 | `-CompoundStmt 1435 |-CXXDestructorDecl '~DefaultedAndDeleted' 1436 | `-CompoundStmt 1437 |-CXXConstructorDecl 'DefaultedAndDeleted' 1438 | `-ParmVarDecl '' 1439 |-CXXMethodDecl 'operator=' 1440 | |-ParmVarDecl '' 1441 | `-CompoundStmt 1442 | |-CXXMemberCallExpr 1443 | | |-MemberExpr 1444 | | | `-MemberExpr 1445 | | | `-CXXThisExpr 1446 | | `-MemberExpr 1447 | | `-DeclRefExpr '' 1448 | `-ReturnStmt 1449 | `-UnaryOperator 1450 | `-CXXThisExpr 1451 |-CXXConstructorDecl 'DefaultedAndDeleted' 1452 | `-ParmVarDecl '' 1453 `-CXXMethodDecl 'operator=' 1454 `-ParmVarDecl '' 1455 )cpp"); 1456 1457 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1458 BN[0].getNodeAs<Decl>("rec")), 1459 R"cpp( 1460 CXXRecordDecl 'DefaultedAndDeleted' 1461 |-FieldDecl 'nt' 1462 |-CXXConstructorDecl 'DefaultedAndDeleted' 1463 |-CXXDestructorDecl '~DefaultedAndDeleted' 1464 |-CXXConstructorDecl 'DefaultedAndDeleted' 1465 | `-ParmVarDecl '' 1466 |-CXXMethodDecl 'operator=' 1467 | `-ParmVarDecl '' 1468 |-CXXConstructorDecl 'DefaultedAndDeleted' 1469 | `-ParmVarDecl '' 1470 `-CXXMethodDecl 'operator=' 1471 `-ParmVarDecl '' 1472 )cpp"); 1473 } 1474 { 1475 auto BN = ast_matchers::match( 1476 callExpr(callee(functionDecl(hasName("hasDefaultArg")))) 1477 .bind("funcCall"), 1478 AST2->getASTContext()); 1479 EXPECT_EQ(BN.size(), 1u); 1480 1481 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<CallExpr>("funcCall")), 1482 R"cpp( 1483 CallExpr 1484 |-ImplicitCastExpr 1485 | `-DeclRefExpr 'hasDefaultArg' 1486 |-IntegerLiteral 1487 `-CXXDefaultArgExpr 1488 )cpp"); 1489 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1490 BN[0].getNodeAs<CallExpr>("funcCall")), 1491 R"cpp( 1492 CallExpr 1493 |-DeclRefExpr 'hasDefaultArg' 1494 `-IntegerLiteral 1495 )cpp"); 1496 } 1497 1498 { 1499 auto FN = ast_matchers::match( 1500 functionDecl(hasName("decomposition"), 1501 hasDescendant(decompositionDecl().bind("decomp"))), 1502 AST2->getASTContext()); 1503 EXPECT_EQ(FN.size(), 1u); 1504 1505 EXPECT_EQ( 1506 dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")), 1507 R"cpp( 1508 DecompositionDecl '' 1509 |-DeclRefExpr 'arr' 1510 |-BindingDecl 'f' 1511 | `-ArraySubscriptExpr 1512 | |-ImplicitCastExpr 1513 | | `-DeclRefExpr '' 1514 | `-IntegerLiteral 1515 |-BindingDecl 's' 1516 | `-ArraySubscriptExpr 1517 | |-ImplicitCastExpr 1518 | | `-DeclRefExpr '' 1519 | `-IntegerLiteral 1520 `-BindingDecl 't' 1521 `-ArraySubscriptExpr 1522 |-ImplicitCastExpr 1523 | `-DeclRefExpr '' 1524 `-IntegerLiteral 1525 )cpp"); 1526 1527 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1528 FN[0].getNodeAs<DecompositionDecl>("decomp")), 1529 R"cpp( 1530 DecompositionDecl '' 1531 |-DeclRefExpr 'arr' 1532 |-BindingDecl 'f' 1533 |-BindingDecl 's' 1534 `-BindingDecl 't' 1535 )cpp"); 1536 } 1537 1538 { 1539 auto FN = ast_matchers::match( 1540 functionDecl(hasName("decompTuple"), 1541 hasDescendant(decompositionDecl().bind("decomp"))), 1542 AST2->getASTContext()); 1543 EXPECT_EQ(FN.size(), 1u); 1544 1545 EXPECT_EQ( 1546 dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")), 1547 R"cpp( 1548 DecompositionDecl '' 1549 |-CXXConstructExpr 1550 | `-ImplicitCastExpr 1551 | `-DeclRefExpr 'p' 1552 |-BindingDecl 'a' 1553 | |-VarDecl 'a' 1554 | | `-CallExpr 1555 | | |-ImplicitCastExpr 1556 | | | `-DeclRefExpr 'get' 1557 | | `-ImplicitCastExpr 1558 | | `-DeclRefExpr '' 1559 | `-DeclRefExpr 'a' 1560 `-BindingDecl 'b' 1561 |-VarDecl 'b' 1562 | `-CallExpr 1563 | |-ImplicitCastExpr 1564 | | `-DeclRefExpr 'get' 1565 | `-ImplicitCastExpr 1566 | `-DeclRefExpr '' 1567 `-DeclRefExpr 'b' 1568 )cpp"); 1569 1570 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1571 FN[0].getNodeAs<DecompositionDecl>("decomp")), 1572 R"cpp( 1573 DecompositionDecl '' 1574 |-DeclRefExpr 'p' 1575 |-BindingDecl 'a' 1576 `-BindingDecl 'b' 1577 )cpp"); 1578 } 1579 } 1580 1581 TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) { 1582 1583 auto AST = buildASTFromCode(R"cpp( 1584 template<typename T> 1585 struct TemplStruct { 1586 TemplStruct() {} 1587 ~TemplStruct() {} 1588 1589 private: 1590 T m_t; 1591 }; 1592 1593 template<typename T> 1594 T timesTwo(T input) 1595 { 1596 return input * 2; 1597 } 1598 1599 void instantiate() 1600 { 1601 TemplStruct<int> ti; 1602 TemplStruct<double> td; 1603 (void)timesTwo<int>(2); 1604 (void)timesTwo<double>(2); 1605 } 1606 1607 template class TemplStruct<float>; 1608 1609 extern template class TemplStruct<long>; 1610 1611 template<> class TemplStruct<bool> { 1612 TemplStruct() {} 1613 ~TemplStruct() {} 1614 1615 void foo() {} 1616 private: 1617 bool m_t; 1618 }; 1619 1620 // Explicit instantiation of template functions do not appear in the AST 1621 template float timesTwo(float); 1622 1623 template<> bool timesTwo<bool>(bool) { 1624 return true; 1625 } 1626 )cpp"); 1627 { 1628 auto BN = ast_matchers::match( 1629 classTemplateDecl(hasName("TemplStruct")).bind("rec"), 1630 AST->getASTContext()); 1631 EXPECT_EQ(BN.size(), 1u); 1632 1633 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1634 BN[0].getNodeAs<Decl>("rec")), 1635 R"cpp( 1636 ClassTemplateDecl 'TemplStruct' 1637 |-TemplateTypeParmDecl 'T' 1638 `-CXXRecordDecl 'TemplStruct' 1639 |-CXXConstructorDecl 'TemplStruct<T>' 1640 | `-CompoundStmt 1641 |-CXXDestructorDecl '~TemplStruct<T>' 1642 | `-CompoundStmt 1643 |-AccessSpecDecl 1644 `-FieldDecl 'm_t' 1645 )cpp"); 1646 1647 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1648 R"cpp( 1649 ClassTemplateDecl 'TemplStruct' 1650 |-TemplateTypeParmDecl 'T' 1651 |-CXXRecordDecl 'TemplStruct' 1652 | |-CXXRecordDecl 'TemplStruct' 1653 | |-CXXConstructorDecl 'TemplStruct<T>' 1654 | | `-CompoundStmt 1655 | |-CXXDestructorDecl '~TemplStruct<T>' 1656 | | `-CompoundStmt 1657 | |-AccessSpecDecl 1658 | `-FieldDecl 'm_t' 1659 |-ClassTemplateSpecializationDecl 'TemplStruct' 1660 | |-TemplateArgument type int 1661 | | `-BuiltinType 1662 | |-CXXRecordDecl 'TemplStruct' 1663 | |-CXXConstructorDecl 'TemplStruct' 1664 | | `-CompoundStmt 1665 | |-CXXDestructorDecl '~TemplStruct' 1666 | | `-CompoundStmt 1667 | |-AccessSpecDecl 1668 | |-FieldDecl 'm_t' 1669 | `-CXXConstructorDecl 'TemplStruct' 1670 | `-ParmVarDecl '' 1671 |-ClassTemplateSpecializationDecl 'TemplStruct' 1672 | |-TemplateArgument type double 1673 | | `-BuiltinType 1674 | |-CXXRecordDecl 'TemplStruct' 1675 | |-CXXConstructorDecl 'TemplStruct' 1676 | | `-CompoundStmt 1677 | |-CXXDestructorDecl '~TemplStruct' 1678 | | `-CompoundStmt 1679 | |-AccessSpecDecl 1680 | |-FieldDecl 'm_t' 1681 | `-CXXConstructorDecl 'TemplStruct' 1682 | `-ParmVarDecl '' 1683 |-ClassTemplateSpecializationDecl 'TemplStruct' 1684 | |-TemplateArgument type float 1685 | | `-BuiltinType 1686 | |-CXXRecordDecl 'TemplStruct' 1687 | |-CXXConstructorDecl 'TemplStruct' 1688 | | `-CompoundStmt 1689 | |-CXXDestructorDecl '~TemplStruct' 1690 | | `-CompoundStmt 1691 | |-AccessSpecDecl 1692 | `-FieldDecl 'm_t' 1693 |-ClassTemplateSpecializationDecl 'TemplStruct' 1694 | |-TemplateArgument type long 1695 | | `-BuiltinType 1696 | |-CXXRecordDecl 'TemplStruct' 1697 | |-CXXConstructorDecl 'TemplStruct' 1698 | |-CXXDestructorDecl '~TemplStruct' 1699 | |-AccessSpecDecl 1700 | `-FieldDecl 'm_t' 1701 `-ClassTemplateSpecializationDecl 'TemplStruct' 1702 |-TemplateArgument type _Bool 1703 | `-BuiltinType 1704 |-CXXRecordDecl 'TemplStruct' 1705 |-CXXConstructorDecl 'TemplStruct' 1706 | `-CompoundStmt 1707 |-CXXDestructorDecl '~TemplStruct' 1708 | `-CompoundStmt 1709 |-CXXMethodDecl 'foo' 1710 | `-CompoundStmt 1711 |-AccessSpecDecl 1712 `-FieldDecl 'm_t' 1713 )cpp"); 1714 } 1715 { 1716 auto BN = ast_matchers::match( 1717 classTemplateSpecializationDecl( 1718 hasTemplateArgument( 1719 0, templateArgument(refersToType(asString("_Bool"))))) 1720 .bind("templSpec"), 1721 AST->getASTContext()); 1722 EXPECT_EQ(BN.size(), 1u); 1723 1724 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("templSpec")), 1725 R"cpp( 1726 ClassTemplateSpecializationDecl 'TemplStruct' 1727 |-TemplateArgument type _Bool 1728 | `-BuiltinType 1729 |-CXXRecordDecl 'TemplStruct' 1730 |-CXXConstructorDecl 'TemplStruct' 1731 | `-CompoundStmt 1732 |-CXXDestructorDecl '~TemplStruct' 1733 | `-CompoundStmt 1734 |-CXXMethodDecl 'foo' 1735 | `-CompoundStmt 1736 |-AccessSpecDecl 1737 `-FieldDecl 'm_t' 1738 )cpp"); 1739 1740 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1741 BN[0].getNodeAs<Decl>("templSpec")), 1742 R"cpp( 1743 ClassTemplateSpecializationDecl 'TemplStruct' 1744 |-TemplateArgument type _Bool 1745 | `-BuiltinType 1746 |-CXXConstructorDecl 'TemplStruct' 1747 | `-CompoundStmt 1748 |-CXXDestructorDecl '~TemplStruct' 1749 | `-CompoundStmt 1750 |-CXXMethodDecl 'foo' 1751 | `-CompoundStmt 1752 |-AccessSpecDecl 1753 `-FieldDecl 'm_t' 1754 )cpp"); 1755 } 1756 { 1757 auto BN = ast_matchers::match( 1758 functionTemplateDecl(hasName("timesTwo")).bind("fn"), 1759 AST->getASTContext()); 1760 EXPECT_EQ(BN.size(), 1u); 1761 1762 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1763 BN[0].getNodeAs<Decl>("fn")), 1764 R"cpp( 1765 FunctionTemplateDecl 'timesTwo' 1766 |-TemplateTypeParmDecl 'T' 1767 `-FunctionDecl 'timesTwo' 1768 |-ParmVarDecl 'input' 1769 `-CompoundStmt 1770 `-ReturnStmt 1771 `-BinaryOperator 1772 |-DeclRefExpr 'input' 1773 `-IntegerLiteral 1774 )cpp"); 1775 1776 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")), 1777 R"cpp( 1778 FunctionTemplateDecl 'timesTwo' 1779 |-TemplateTypeParmDecl 'T' 1780 |-FunctionDecl 'timesTwo' 1781 | |-ParmVarDecl 'input' 1782 | `-CompoundStmt 1783 | `-ReturnStmt 1784 | `-BinaryOperator 1785 | |-DeclRefExpr 'input' 1786 | `-IntegerLiteral 1787 |-FunctionDecl 'timesTwo' 1788 | |-TemplateArgument type int 1789 | | `-BuiltinType 1790 | |-ParmVarDecl 'input' 1791 | `-CompoundStmt 1792 | `-ReturnStmt 1793 | `-BinaryOperator 1794 | |-ImplicitCastExpr 1795 | | `-DeclRefExpr 'input' 1796 | `-IntegerLiteral 1797 |-FunctionDecl 'timesTwo' 1798 | |-TemplateArgument type double 1799 | | `-BuiltinType 1800 | |-ParmVarDecl 'input' 1801 | `-CompoundStmt 1802 | `-ReturnStmt 1803 | `-BinaryOperator 1804 | |-ImplicitCastExpr 1805 | | `-DeclRefExpr 'input' 1806 | `-ImplicitCastExpr 1807 | `-IntegerLiteral 1808 |-FunctionDecl 'timesTwo' 1809 | |-TemplateArgument type float 1810 | | `-BuiltinType 1811 | |-ParmVarDecl 'input' 1812 | `-CompoundStmt 1813 | `-ReturnStmt 1814 | `-BinaryOperator 1815 | |-ImplicitCastExpr 1816 | | `-DeclRefExpr 'input' 1817 | `-ImplicitCastExpr 1818 | `-IntegerLiteral 1819 |-FunctionDecl 'timesTwo' 1820 | |-TemplateArgument type _Bool 1821 | | `-BuiltinType 1822 | |-ParmVarDecl '' 1823 | `-CompoundStmt 1824 | `-ReturnStmt 1825 | `-CXXBoolLiteralExpr 1826 `-FunctionDecl 'timesTwo' 1827 |-TemplateArgument type _Bool 1828 | `-BuiltinType 1829 `-ParmVarDecl 'input' 1830 )cpp"); 1831 } 1832 { 1833 auto BN = ast_matchers::match( 1834 classTemplateSpecializationDecl( 1835 hasName("TemplStruct"), 1836 hasTemplateArgument( 1837 0, templateArgument(refersToType(asString("float")))), 1838 hasParent(translationUnitDecl())) 1839 .bind("rec"), 1840 AST->getASTContext()); 1841 EXPECT_EQ(BN.size(), 1u); 1842 1843 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1844 BN[0].getNodeAs<Decl>("rec")), 1845 R"cpp( 1846 ClassTemplateSpecializationDecl 'TemplStruct' 1847 `-TemplateArgument type float 1848 `-BuiltinType 1849 )cpp"); 1850 1851 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1852 R"cpp( 1853 ClassTemplateSpecializationDecl 'TemplStruct' 1854 |-TemplateArgument type float 1855 | `-BuiltinType 1856 |-CXXRecordDecl 'TemplStruct' 1857 |-CXXConstructorDecl 'TemplStruct' 1858 | `-CompoundStmt 1859 |-CXXDestructorDecl '~TemplStruct' 1860 | `-CompoundStmt 1861 |-AccessSpecDecl 1862 `-FieldDecl 'm_t' 1863 )cpp"); 1864 } 1865 } 1866 1867 TEST(Traverse, CXXRewrittenBinaryOperator) { 1868 1869 auto AST = buildASTFromCodeWithArgs(R"cpp( 1870 namespace std { 1871 struct strong_ordering { 1872 int n; 1873 constexpr operator int() const { return n; } 1874 static const strong_ordering equal, greater, less; 1875 }; 1876 constexpr strong_ordering strong_ordering::equal = {0}; 1877 constexpr strong_ordering strong_ordering::greater = {1}; 1878 constexpr strong_ordering strong_ordering::less = {-1}; 1879 } 1880 1881 struct HasSpaceshipMem { 1882 int a; 1883 constexpr auto operator<=>(const HasSpaceshipMem&) const = default; 1884 }; 1885 1886 void binop() 1887 { 1888 HasSpaceshipMem hs1, hs2; 1889 if (hs1 < hs2) 1890 return; 1891 } 1892 )cpp", 1893 {"-std=c++20"}); 1894 { 1895 auto BN = ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"), 1896 AST->getASTContext()); 1897 EXPECT_EQ(BN.size(), 1u); 1898 1899 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Stmt>("binop")), 1900 R"cpp( 1901 CXXRewrittenBinaryOperator 1902 `-BinaryOperator 1903 |-ImplicitCastExpr 1904 | `-CXXMemberCallExpr 1905 | `-MemberExpr 1906 | `-ImplicitCastExpr 1907 | `-MaterializeTemporaryExpr 1908 | `-CXXOperatorCallExpr 1909 | |-ImplicitCastExpr 1910 | | `-DeclRefExpr 'operator<=>' 1911 | |-ImplicitCastExpr 1912 | | `-DeclRefExpr 'hs1' 1913 | `-ImplicitCastExpr 1914 | `-DeclRefExpr 'hs2' 1915 `-IntegerLiteral 1916 )cpp"); 1917 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1918 BN[0].getNodeAs<Stmt>("binop")), 1919 R"cpp( 1920 CXXRewrittenBinaryOperator 1921 |-DeclRefExpr 'hs1' 1922 `-DeclRefExpr 'hs2' 1923 )cpp"); 1924 } 1925 } 1926 1927 } // namespace clang 1928