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().getAsString() << "'"; 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().getAsString(); 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 )cpp", 1161 {"-std=c++20"}); 1162 1163 { 1164 auto BN = ast_matchers::match( 1165 cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"), 1166 AST2->getASTContext()); 1167 EXPECT_EQ(BN.size(), 1u); 1168 1169 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1170 R"cpp( 1171 CXXRecordDecl 'Record' 1172 |-CXXRecordDecl 'Record' 1173 |-CXXConstructorDecl 'Record' 1174 | |-CXXCtorInitializer 'struct Simple' 1175 | | `-CXXConstructExpr 1176 | |-CXXCtorInitializer 'struct Other' 1177 | | `-CXXConstructExpr 1178 | |-CXXCtorInitializer 'm_i' 1179 | | `-IntegerLiteral 1180 | |-CXXCtorInitializer 'm_i2' 1181 | | `-CXXDefaultInitExpr 1182 | |-CXXCtorInitializer 'm_s' 1183 | | `-CXXConstructExpr 1184 | `-CompoundStmt 1185 |-AccessSpecDecl 1186 |-FieldDecl 'm_i' 1187 |-FieldDecl 'm_i2' 1188 | `-IntegerLiteral 1189 `-FieldDecl 'm_s' 1190 )cpp"); 1191 1192 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1193 BN[0].getNodeAs<Decl>("rec")), 1194 R"cpp( 1195 CXXRecordDecl 'Record' 1196 |-CXXConstructorDecl 'Record' 1197 | |-CXXCtorInitializer 'struct Simple' 1198 | | `-CXXConstructExpr 1199 | |-CXXCtorInitializer 'm_i' 1200 | | `-IntegerLiteral 1201 | `-CompoundStmt 1202 |-AccessSpecDecl 1203 |-FieldDecl 'm_i' 1204 |-FieldDecl 'm_i2' 1205 | `-IntegerLiteral 1206 `-FieldDecl 'm_s' 1207 )cpp"); 1208 } 1209 { 1210 auto BN = ast_matchers::match( 1211 cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit())) 1212 .bind("rec"), 1213 AST2->getASTContext()); 1214 EXPECT_EQ(BN.size(), 1u); 1215 1216 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1217 R"cpp( 1218 CXXRecordDecl 'ContainsArray' 1219 |-CXXRecordDecl 'ContainsArray' 1220 |-FieldDecl 'arr' 1221 |-FieldDecl 'irr' 1222 |-CXXMethodDecl 'operator=' 1223 | |-ParmVarDecl '' 1224 | `-CompoundStmt 1225 | |-ForStmt 1226 | | |-DeclStmt 1227 | | | `-VarDecl '__i0' 1228 | | | `-IntegerLiteral 1229 | | |-<<<NULL>>> 1230 | | |-BinaryOperator 1231 | | | |-ImplicitCastExpr 1232 | | | | `-DeclRefExpr '__i0' 1233 | | | `-IntegerLiteral 1234 | | |-UnaryOperator 1235 | | | `-DeclRefExpr '__i0' 1236 | | `-CXXMemberCallExpr 1237 | | |-MemberExpr 1238 | | | `-ArraySubscriptExpr 1239 | | | |-ImplicitCastExpr 1240 | | | | `-MemberExpr 1241 | | | | `-CXXThisExpr 1242 | | | `-ImplicitCastExpr 1243 | | | `-DeclRefExpr '__i0' 1244 | | `-ArraySubscriptExpr 1245 | | |-ImplicitCastExpr 1246 | | | `-MemberExpr 1247 | | | `-DeclRefExpr '' 1248 | | `-ImplicitCastExpr 1249 | | `-DeclRefExpr '__i0' 1250 | |-CallExpr 1251 | | |-ImplicitCastExpr 1252 | | | `-DeclRefExpr '__builtin_memcpy' 1253 | | |-ImplicitCastExpr 1254 | | | `-UnaryOperator 1255 | | | `-MemberExpr 1256 | | | `-CXXThisExpr 1257 | | |-ImplicitCastExpr 1258 | | | `-UnaryOperator 1259 | | | `-MemberExpr 1260 | | | `-DeclRefExpr '' 1261 | | `-IntegerLiteral 1262 | `-ReturnStmt 1263 | `-UnaryOperator 1264 | `-CXXThisExpr 1265 |-CXXConstructorDecl 'ContainsArray' 1266 | `-ParmVarDecl '' 1267 |-CXXDestructorDecl '~ContainsArray' 1268 | `-CompoundStmt 1269 `-CXXConstructorDecl 'ContainsArray' 1270 |-CXXCtorInitializer 'arr' 1271 | `-CXXConstructExpr 1272 `-CompoundStmt 1273 )cpp"); 1274 1275 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1276 BN[0].getNodeAs<Decl>("rec")), 1277 R"cpp( 1278 CXXRecordDecl 'ContainsArray' 1279 |-FieldDecl 'arr' 1280 |-FieldDecl 'irr' 1281 `-CXXMethodDecl 'operator=' 1282 `-ParmVarDecl '' 1283 )cpp"); 1284 } 1285 { 1286 auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"), 1287 AST2->getASTContext()); 1288 EXPECT_EQ(BN.size(), 1u); 1289 1290 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("func")), 1291 R"cpp( 1292 FunctionDecl 'forLoop' 1293 `-CompoundStmt 1294 |-DeclStmt 1295 | `-VarDecl 'arr' 1296 |-CXXForRangeStmt 1297 | |-<<<NULL>>> 1298 | |-DeclStmt 1299 | | `-VarDecl '__range1' 1300 | | `-DeclRefExpr 'arr' 1301 | |-DeclStmt 1302 | | `-VarDecl '__begin1' 1303 | | `-ImplicitCastExpr 1304 | | `-DeclRefExpr '__range1' 1305 | |-DeclStmt 1306 | | `-VarDecl '__end1' 1307 | | `-BinaryOperator 1308 | | |-ImplicitCastExpr 1309 | | | `-DeclRefExpr '__range1' 1310 | | `-IntegerLiteral 1311 | |-BinaryOperator 1312 | | |-ImplicitCastExpr 1313 | | | `-DeclRefExpr '__begin1' 1314 | | `-ImplicitCastExpr 1315 | | `-DeclRefExpr '__end1' 1316 | |-UnaryOperator 1317 | | `-DeclRefExpr '__begin1' 1318 | |-DeclStmt 1319 | | `-VarDecl 'i' 1320 | | `-ImplicitCastExpr 1321 | | `-UnaryOperator 1322 | | `-ImplicitCastExpr 1323 | | `-DeclRefExpr '__begin1' 1324 | `-CompoundStmt 1325 `-CXXForRangeStmt 1326 |-DeclStmt 1327 | `-VarDecl 'a' 1328 | `-DeclRefExpr 'arr' 1329 |-DeclStmt 1330 | `-VarDecl '__range1' 1331 | `-DeclRefExpr 'a' 1332 |-DeclStmt 1333 | `-VarDecl '__begin1' 1334 | `-ImplicitCastExpr 1335 | `-DeclRefExpr '__range1' 1336 |-DeclStmt 1337 | `-VarDecl '__end1' 1338 | `-BinaryOperator 1339 | |-ImplicitCastExpr 1340 | | `-DeclRefExpr '__range1' 1341 | `-IntegerLiteral 1342 |-BinaryOperator 1343 | |-ImplicitCastExpr 1344 | | `-DeclRefExpr '__begin1' 1345 | `-ImplicitCastExpr 1346 | `-DeclRefExpr '__end1' 1347 |-UnaryOperator 1348 | `-DeclRefExpr '__begin1' 1349 |-DeclStmt 1350 | `-VarDecl 'i' 1351 | `-ImplicitCastExpr 1352 | `-UnaryOperator 1353 | `-ImplicitCastExpr 1354 | `-DeclRefExpr '__begin1' 1355 `-CompoundStmt 1356 )cpp"); 1357 1358 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1359 BN[0].getNodeAs<Decl>("func")), 1360 R"cpp( 1361 FunctionDecl 'forLoop' 1362 `-CompoundStmt 1363 |-DeclStmt 1364 | `-VarDecl 'arr' 1365 |-CXXForRangeStmt 1366 | |-<<<NULL>>> 1367 | |-VarDecl 'i' 1368 | |-DeclRefExpr 'arr' 1369 | `-CompoundStmt 1370 `-CXXForRangeStmt 1371 |-DeclStmt 1372 | `-VarDecl 'a' 1373 | `-DeclRefExpr 'arr' 1374 |-VarDecl 'i' 1375 |-DeclRefExpr 'a' 1376 `-CompoundStmt 1377 )cpp"); 1378 } 1379 { 1380 auto BN = ast_matchers::match( 1381 cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit())) 1382 .bind("rec"), 1383 AST2->getASTContext()); 1384 EXPECT_EQ(BN.size(), 1u); 1385 1386 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1387 R"cpp( 1388 CXXRecordDecl 'DefaultedAndDeleted' 1389 |-CXXRecordDecl 'DefaultedAndDeleted' 1390 |-FieldDecl 'nt' 1391 |-CXXConstructorDecl 'DefaultedAndDeleted' 1392 | |-CXXCtorInitializer 'nt' 1393 | | `-CXXConstructExpr 1394 | `-CompoundStmt 1395 |-CXXDestructorDecl '~DefaultedAndDeleted' 1396 | `-CompoundStmt 1397 |-CXXConstructorDecl 'DefaultedAndDeleted' 1398 | `-ParmVarDecl '' 1399 |-CXXMethodDecl 'operator=' 1400 | |-ParmVarDecl '' 1401 | `-CompoundStmt 1402 | |-CXXMemberCallExpr 1403 | | |-MemberExpr 1404 | | | `-MemberExpr 1405 | | | `-CXXThisExpr 1406 | | `-MemberExpr 1407 | | `-DeclRefExpr '' 1408 | `-ReturnStmt 1409 | `-UnaryOperator 1410 | `-CXXThisExpr 1411 |-CXXConstructorDecl 'DefaultedAndDeleted' 1412 | `-ParmVarDecl '' 1413 `-CXXMethodDecl 'operator=' 1414 `-ParmVarDecl '' 1415 )cpp"); 1416 1417 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1418 BN[0].getNodeAs<Decl>("rec")), 1419 R"cpp( 1420 CXXRecordDecl 'DefaultedAndDeleted' 1421 |-FieldDecl 'nt' 1422 |-CXXConstructorDecl 'DefaultedAndDeleted' 1423 |-CXXDestructorDecl '~DefaultedAndDeleted' 1424 |-CXXConstructorDecl 'DefaultedAndDeleted' 1425 | `-ParmVarDecl '' 1426 |-CXXMethodDecl 'operator=' 1427 | `-ParmVarDecl '' 1428 |-CXXConstructorDecl 'DefaultedAndDeleted' 1429 | `-ParmVarDecl '' 1430 `-CXXMethodDecl 'operator=' 1431 `-ParmVarDecl '' 1432 )cpp"); 1433 } 1434 { 1435 auto BN = ast_matchers::match( 1436 callExpr(callee(functionDecl(hasName("hasDefaultArg")))) 1437 .bind("funcCall"), 1438 AST2->getASTContext()); 1439 EXPECT_EQ(BN.size(), 1u); 1440 1441 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<CallExpr>("funcCall")), 1442 R"cpp( 1443 CallExpr 1444 |-ImplicitCastExpr 1445 | `-DeclRefExpr 'hasDefaultArg' 1446 |-IntegerLiteral 1447 `-CXXDefaultArgExpr 1448 )cpp"); 1449 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1450 BN[0].getNodeAs<CallExpr>("funcCall")), 1451 R"cpp( 1452 CallExpr 1453 |-DeclRefExpr 'hasDefaultArg' 1454 `-IntegerLiteral 1455 )cpp"); 1456 } 1457 1458 { 1459 auto FN = ast_matchers::match( 1460 functionDecl(hasName("decomposition"), 1461 hasDescendant(decompositionDecl().bind("decomp"))), 1462 AST2->getASTContext()); 1463 EXPECT_EQ(FN.size(), 1u); 1464 1465 EXPECT_EQ( 1466 dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")), 1467 R"cpp( 1468 DecompositionDecl '' 1469 |-DeclRefExpr 'arr' 1470 |-BindingDecl 'f' 1471 | `-ArraySubscriptExpr 1472 | |-ImplicitCastExpr 1473 | | `-DeclRefExpr '' 1474 | `-IntegerLiteral 1475 |-BindingDecl 's' 1476 | `-ArraySubscriptExpr 1477 | |-ImplicitCastExpr 1478 | | `-DeclRefExpr '' 1479 | `-IntegerLiteral 1480 `-BindingDecl 't' 1481 `-ArraySubscriptExpr 1482 |-ImplicitCastExpr 1483 | `-DeclRefExpr '' 1484 `-IntegerLiteral 1485 )cpp"); 1486 1487 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1488 FN[0].getNodeAs<DecompositionDecl>("decomp")), 1489 R"cpp( 1490 DecompositionDecl '' 1491 |-DeclRefExpr 'arr' 1492 |-BindingDecl 'f' 1493 |-BindingDecl 's' 1494 `-BindingDecl 't' 1495 )cpp"); 1496 } 1497 } 1498 1499 TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) { 1500 1501 auto AST = buildASTFromCode(R"cpp( 1502 template<typename T> 1503 struct TemplStruct { 1504 TemplStruct() {} 1505 ~TemplStruct() {} 1506 1507 private: 1508 T m_t; 1509 }; 1510 1511 template<typename T> 1512 T timesTwo(T input) 1513 { 1514 return input * 2; 1515 } 1516 1517 void instantiate() 1518 { 1519 TemplStruct<int> ti; 1520 TemplStruct<double> td; 1521 (void)timesTwo<int>(2); 1522 (void)timesTwo<double>(2); 1523 } 1524 1525 template class TemplStruct<float>; 1526 1527 extern template class TemplStruct<long>; 1528 1529 template<> class TemplStruct<bool> { 1530 TemplStruct() {} 1531 ~TemplStruct() {} 1532 1533 void foo() {} 1534 private: 1535 bool m_t; 1536 }; 1537 1538 // Explicit instantiation of template functions do not appear in the AST 1539 template float timesTwo(float); 1540 1541 template<> bool timesTwo<bool>(bool) { 1542 return true; 1543 } 1544 )cpp"); 1545 { 1546 auto BN = ast_matchers::match( 1547 classTemplateDecl(hasName("TemplStruct")).bind("rec"), 1548 AST->getASTContext()); 1549 EXPECT_EQ(BN.size(), 1u); 1550 1551 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1552 BN[0].getNodeAs<Decl>("rec")), 1553 R"cpp( 1554 ClassTemplateDecl 'TemplStruct' 1555 |-TemplateTypeParmDecl 'T' 1556 `-CXXRecordDecl 'TemplStruct' 1557 |-CXXConstructorDecl 'TemplStruct<T>' 1558 | `-CompoundStmt 1559 |-CXXDestructorDecl '~TemplStruct<T>' 1560 | `-CompoundStmt 1561 |-AccessSpecDecl 1562 `-FieldDecl 'm_t' 1563 )cpp"); 1564 1565 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1566 R"cpp( 1567 ClassTemplateDecl 'TemplStruct' 1568 |-TemplateTypeParmDecl 'T' 1569 |-CXXRecordDecl 'TemplStruct' 1570 | |-CXXRecordDecl 'TemplStruct' 1571 | |-CXXConstructorDecl 'TemplStruct<T>' 1572 | | `-CompoundStmt 1573 | |-CXXDestructorDecl '~TemplStruct<T>' 1574 | | `-CompoundStmt 1575 | |-AccessSpecDecl 1576 | `-FieldDecl 'm_t' 1577 |-ClassTemplateSpecializationDecl 'TemplStruct' 1578 | |-TemplateArgument type int 1579 | | `-BuiltinType 1580 | |-CXXRecordDecl 'TemplStruct' 1581 | |-CXXConstructorDecl 'TemplStruct' 1582 | | `-CompoundStmt 1583 | |-CXXDestructorDecl '~TemplStruct' 1584 | | `-CompoundStmt 1585 | |-AccessSpecDecl 1586 | |-FieldDecl 'm_t' 1587 | `-CXXConstructorDecl 'TemplStruct' 1588 | `-ParmVarDecl '' 1589 |-ClassTemplateSpecializationDecl 'TemplStruct' 1590 | |-TemplateArgument type double 1591 | | `-BuiltinType 1592 | |-CXXRecordDecl 'TemplStruct' 1593 | |-CXXConstructorDecl 'TemplStruct' 1594 | | `-CompoundStmt 1595 | |-CXXDestructorDecl '~TemplStruct' 1596 | | `-CompoundStmt 1597 | |-AccessSpecDecl 1598 | |-FieldDecl 'm_t' 1599 | `-CXXConstructorDecl 'TemplStruct' 1600 | `-ParmVarDecl '' 1601 |-ClassTemplateSpecializationDecl 'TemplStruct' 1602 | |-TemplateArgument type float 1603 | | `-BuiltinType 1604 | |-CXXRecordDecl 'TemplStruct' 1605 | |-CXXConstructorDecl 'TemplStruct' 1606 | | `-CompoundStmt 1607 | |-CXXDestructorDecl '~TemplStruct' 1608 | | `-CompoundStmt 1609 | |-AccessSpecDecl 1610 | `-FieldDecl 'm_t' 1611 |-ClassTemplateSpecializationDecl 'TemplStruct' 1612 | |-TemplateArgument type long 1613 | | `-BuiltinType 1614 | |-CXXRecordDecl 'TemplStruct' 1615 | |-CXXConstructorDecl 'TemplStruct' 1616 | |-CXXDestructorDecl '~TemplStruct' 1617 | |-AccessSpecDecl 1618 | `-FieldDecl 'm_t' 1619 `-ClassTemplateSpecializationDecl 'TemplStruct' 1620 |-TemplateArgument type _Bool 1621 | `-BuiltinType 1622 |-CXXRecordDecl 'TemplStruct' 1623 |-CXXConstructorDecl 'TemplStruct' 1624 | `-CompoundStmt 1625 |-CXXDestructorDecl '~TemplStruct' 1626 | `-CompoundStmt 1627 |-CXXMethodDecl 'foo' 1628 | `-CompoundStmt 1629 |-AccessSpecDecl 1630 `-FieldDecl 'm_t' 1631 )cpp"); 1632 } 1633 { 1634 auto BN = ast_matchers::match( 1635 classTemplateSpecializationDecl( 1636 hasTemplateArgument( 1637 0, templateArgument(refersToType(asString("_Bool"))))) 1638 .bind("templSpec"), 1639 AST->getASTContext()); 1640 EXPECT_EQ(BN.size(), 1u); 1641 1642 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("templSpec")), 1643 R"cpp( 1644 ClassTemplateSpecializationDecl 'TemplStruct' 1645 |-TemplateArgument type _Bool 1646 | `-BuiltinType 1647 |-CXXRecordDecl 'TemplStruct' 1648 |-CXXConstructorDecl 'TemplStruct' 1649 | `-CompoundStmt 1650 |-CXXDestructorDecl '~TemplStruct' 1651 | `-CompoundStmt 1652 |-CXXMethodDecl 'foo' 1653 | `-CompoundStmt 1654 |-AccessSpecDecl 1655 `-FieldDecl 'm_t' 1656 )cpp"); 1657 1658 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1659 BN[0].getNodeAs<Decl>("templSpec")), 1660 R"cpp( 1661 ClassTemplateSpecializationDecl 'TemplStruct' 1662 |-TemplateArgument type _Bool 1663 | `-BuiltinType 1664 |-CXXConstructorDecl 'TemplStruct' 1665 | `-CompoundStmt 1666 |-CXXDestructorDecl '~TemplStruct' 1667 | `-CompoundStmt 1668 |-CXXMethodDecl 'foo' 1669 | `-CompoundStmt 1670 |-AccessSpecDecl 1671 `-FieldDecl 'm_t' 1672 )cpp"); 1673 } 1674 { 1675 auto BN = ast_matchers::match( 1676 functionTemplateDecl(hasName("timesTwo")).bind("fn"), 1677 AST->getASTContext()); 1678 EXPECT_EQ(BN.size(), 1u); 1679 1680 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1681 BN[0].getNodeAs<Decl>("fn")), 1682 R"cpp( 1683 FunctionTemplateDecl 'timesTwo' 1684 |-TemplateTypeParmDecl 'T' 1685 `-FunctionDecl 'timesTwo' 1686 |-ParmVarDecl 'input' 1687 `-CompoundStmt 1688 `-ReturnStmt 1689 `-BinaryOperator 1690 |-DeclRefExpr 'input' 1691 `-IntegerLiteral 1692 )cpp"); 1693 1694 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")), 1695 R"cpp( 1696 FunctionTemplateDecl 'timesTwo' 1697 |-TemplateTypeParmDecl 'T' 1698 |-FunctionDecl 'timesTwo' 1699 | |-ParmVarDecl 'input' 1700 | `-CompoundStmt 1701 | `-ReturnStmt 1702 | `-BinaryOperator 1703 | |-DeclRefExpr 'input' 1704 | `-IntegerLiteral 1705 |-FunctionDecl 'timesTwo' 1706 | |-TemplateArgument type int 1707 | | `-BuiltinType 1708 | |-ParmVarDecl 'input' 1709 | `-CompoundStmt 1710 | `-ReturnStmt 1711 | `-BinaryOperator 1712 | |-ImplicitCastExpr 1713 | | `-DeclRefExpr 'input' 1714 | `-IntegerLiteral 1715 |-FunctionDecl 'timesTwo' 1716 | |-TemplateArgument type double 1717 | | `-BuiltinType 1718 | |-ParmVarDecl 'input' 1719 | `-CompoundStmt 1720 | `-ReturnStmt 1721 | `-BinaryOperator 1722 | |-ImplicitCastExpr 1723 | | `-DeclRefExpr 'input' 1724 | `-ImplicitCastExpr 1725 | `-IntegerLiteral 1726 |-FunctionDecl 'timesTwo' 1727 | |-TemplateArgument type float 1728 | | `-BuiltinType 1729 | |-ParmVarDecl 'input' 1730 | `-CompoundStmt 1731 | `-ReturnStmt 1732 | `-BinaryOperator 1733 | |-ImplicitCastExpr 1734 | | `-DeclRefExpr 'input' 1735 | `-ImplicitCastExpr 1736 | `-IntegerLiteral 1737 |-FunctionDecl 'timesTwo' 1738 | |-TemplateArgument type _Bool 1739 | | `-BuiltinType 1740 | |-ParmVarDecl '' 1741 | `-CompoundStmt 1742 | `-ReturnStmt 1743 | `-CXXBoolLiteralExpr 1744 `-FunctionDecl 'timesTwo' 1745 |-TemplateArgument type _Bool 1746 | `-BuiltinType 1747 `-ParmVarDecl 'input' 1748 )cpp"); 1749 } 1750 { 1751 auto BN = ast_matchers::match( 1752 classTemplateSpecializationDecl( 1753 hasName("TemplStruct"), 1754 hasTemplateArgument( 1755 0, templateArgument(refersToType(asString("float")))), 1756 hasParent(translationUnitDecl())) 1757 .bind("rec"), 1758 AST->getASTContext()); 1759 EXPECT_EQ(BN.size(), 1u); 1760 1761 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1762 BN[0].getNodeAs<Decl>("rec")), 1763 R"cpp( 1764 ClassTemplateSpecializationDecl 'TemplStruct' 1765 `-TemplateArgument type float 1766 `-BuiltinType 1767 )cpp"); 1768 1769 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")), 1770 R"cpp( 1771 ClassTemplateSpecializationDecl 'TemplStruct' 1772 |-TemplateArgument type float 1773 | `-BuiltinType 1774 |-CXXRecordDecl 'TemplStruct' 1775 |-CXXConstructorDecl 'TemplStruct' 1776 | `-CompoundStmt 1777 |-CXXDestructorDecl '~TemplStruct' 1778 | `-CompoundStmt 1779 |-AccessSpecDecl 1780 `-FieldDecl 'm_t' 1781 )cpp"); 1782 } 1783 } 1784 1785 TEST(Traverse, CXXRewrittenBinaryOperator) { 1786 1787 auto AST = buildASTFromCodeWithArgs(R"cpp( 1788 namespace std { 1789 struct strong_ordering { 1790 int n; 1791 constexpr operator int() const { return n; } 1792 static const strong_ordering equal, greater, less; 1793 }; 1794 constexpr strong_ordering strong_ordering::equal = {0}; 1795 constexpr strong_ordering strong_ordering::greater = {1}; 1796 constexpr strong_ordering strong_ordering::less = {-1}; 1797 } 1798 1799 struct HasSpaceshipMem { 1800 int a; 1801 constexpr auto operator<=>(const HasSpaceshipMem&) const = default; 1802 }; 1803 1804 void binop() 1805 { 1806 HasSpaceshipMem hs1, hs2; 1807 if (hs1 < hs2) 1808 return; 1809 } 1810 )cpp", 1811 {"-std=c++20"}); 1812 { 1813 auto BN = ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"), 1814 AST->getASTContext()); 1815 EXPECT_EQ(BN.size(), 1u); 1816 1817 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Stmt>("binop")), 1818 R"cpp( 1819 CXXRewrittenBinaryOperator 1820 `-BinaryOperator 1821 |-ImplicitCastExpr 1822 | `-CXXMemberCallExpr 1823 | `-MemberExpr 1824 | `-ImplicitCastExpr 1825 | `-MaterializeTemporaryExpr 1826 | `-CXXOperatorCallExpr 1827 | |-ImplicitCastExpr 1828 | | `-DeclRefExpr 'operator<=>' 1829 | |-ImplicitCastExpr 1830 | | `-DeclRefExpr 'hs1' 1831 | `-ImplicitCastExpr 1832 | `-DeclRefExpr 'hs2' 1833 `-IntegerLiteral 1834 )cpp"); 1835 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, 1836 BN[0].getNodeAs<Stmt>("binop")), 1837 R"cpp( 1838 CXXRewrittenBinaryOperator 1839 |-DeclRefExpr 'hs1' 1840 `-DeclRefExpr 'hs2' 1841 )cpp"); 1842 } 1843 } 1844 1845 } // namespace clang 1846