Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / clang / unittests / AST / ASTTraverserTest.cpp
blob362f37655a0ae4bd575b3068b947feb7335bd81d
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 //===----------------------------------------------------------------------===//
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"
18 using namespace clang::tooling;
19 using namespace clang::ast_matchers;
21 namespace clang {
23 class NodeTreePrinter : public TextTreeStructure {
24 llvm::raw_ostream &OS;
26 public:
27 NodeTreePrinter(llvm::raw_ostream &OS)
28 : TextTreeStructure(OS, /* showColors */ false), OS(OS) {}
30 void Visit(const Decl *D) {
31 OS << D->getDeclKindName() << "Decl";
32 if (auto *ND = dyn_cast<NamedDecl>(D)) {
33 OS << " '" << ND->getDeclName() << "'";
37 void Visit(const Stmt *S) {
38 if (!S) {
39 OS << "<<<NULL>>>";
40 return;
42 OS << S->getStmtClassName();
43 if (auto *E = dyn_cast<DeclRefExpr>(S)) {
44 OS << " '" << E->getDecl()->getDeclName() << "'";
48 void Visit(QualType QT) {
49 OS << "QualType " << QT.split().Quals.getAsString();
52 void Visit(const Type *T) { OS << T->getTypeClassName() << "Type"; }
54 void Visit(const comments::Comment *C, const comments::FullComment *FC) {
55 OS << C->getCommentKindName();
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() << "'";
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"
75 OS << "Attr";
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;
87 default:
88 break;
92 template <typename... T> void Visit(T...) {}
95 class TestASTDumper : public ASTNodeTraverser<TestASTDumper, NodeTreePrinter> {
97 NodeTreePrinter MyNodeRecorder;
99 public:
100 TestASTDumper(llvm::raw_ostream &OS) : MyNodeRecorder(OS) {}
101 NodeTreePrinter &doGetNodeDelegate() { return MyNodeRecorder; }
104 template <typename... NodeType> std::string dumpASTString(NodeType &&... N) {
105 std::string Buffer;
106 llvm::raw_string_ostream OS(Buffer);
108 TestASTDumper Dumper(OS);
110 OS << "\n";
112 Dumper.Visit(std::forward<NodeType &&>(N)...);
114 return Buffer;
117 template <typename... NodeType>
118 std::string dumpASTString(TraversalKind TK, NodeType &&... N) {
119 std::string Buffer;
120 llvm::raw_string_ostream OS(Buffer);
122 TestASTDumper Dumper(OS);
123 Dumper.SetTraversalKind(TK);
125 OS << "\n";
127 Dumper.Visit(std::forward<NodeType &&>(N)...);
129 return Buffer;
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");
140 template <typename T> struct Verifier {
141 static void withDynNode(T Node, const std::string &DumpString) {
142 EXPECT_EQ(dumpASTString(DynTypedNode::create(Node)), DumpString);
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);
152 template <typename T>
153 void verifyWithDynNode(T Node, const std::string &DumpString) {
154 EXPECT_EQ(dumpASTString(Node), DumpString);
156 Verifier<T>::withDynNode(Node, DumpString);
159 TEST(Traverse, Dump) {
161 auto AST = buildASTFromCode(R"cpp(
162 struct A {
163 int m_number;
165 /// CTor
166 A() : m_number(42) {}
168 [[nodiscard]] const int func() {
169 return 42;
174 template<typename T>
175 struct templ
179 template<>
180 struct templ<int>
184 void parmvardecl_attr(struct A __attribute__((address_space(19)))*);
186 )cpp");
188 const FunctionDecl *Func = getFunctionNode(AST.get(), "func");
190 verifyWithDynNode(Func,
191 R"cpp(
192 CXXMethodDecl 'func'
193 |-CompoundStmt
194 | `-ReturnStmt
195 | `-IntegerLiteral
196 `-WarnUnusedResultAttr
197 )cpp");
199 Stmt *Body = Func->getBody();
201 verifyWithDynNode(Body,
202 R"cpp(
203 CompoundStmt
204 `-ReturnStmt
205 `-IntegerLiteral
206 )cpp");
208 QualType QT = Func->getType();
210 verifyWithDynNode(QT,
211 R"cpp(
212 FunctionProtoType
213 `-QualType const
214 `-BuiltinType
215 )cpp");
217 const FunctionDecl *CTorFunc = getFunctionNode(AST.get(), "A");
219 verifyWithDynNode(CTorFunc->getType(),
220 R"cpp(
221 FunctionProtoType
222 `-BuiltinType
223 )cpp");
225 Attr *A = *Func->attr_begin();
228 std::string expectedString = R"cpp(
229 WarnUnusedResultAttr
230 )cpp";
232 EXPECT_EQ(dumpASTString(A), expectedString);
235 auto *CTor = dyn_cast<CXXConstructorDecl>(CTorFunc);
236 const CXXCtorInitializer *Init = *CTor->init_begin();
238 verifyWithDynNode(Init,
239 R"cpp(
240 CXXCtorInitializer 'm_number'
241 `-IntegerLiteral
242 )cpp");
244 const comments::FullComment *Comment =
245 AST->getASTContext().getLocalCommentForDeclUncached(CTorFunc);
247 std::string expectedString = R"cpp(
248 FullComment
249 `-ParagraphComment
250 `-TextComment
251 )cpp";
252 EXPECT_EQ(dumpASTString(Comment, Comment), expectedString);
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");
261 TemplateArgument TA = Templ->getTemplateArgs()[0];
263 verifyWithDynNode(TA,
264 R"cpp(
265 TemplateArgument type int
266 `-BuiltinType
267 )cpp");
269 Func = getFunctionNode(AST.get(), "parmvardecl_attr");
271 const auto *Parm = Func->getParamDecl(0);
272 const auto TL = Parm->getTypeSourceInfo()->getTypeLoc();
273 ASSERT_TRUE(TL.getType()->isPointerType());
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);
281 TEST(Traverse, IgnoreUnlessSpelledInSourceVars) {
283 auto AST = buildASTFromCodeWithArgs(R"cpp(
285 struct String
287 String(const char*, int = -1) {}
289 int overloaded() const;
290 int& overloaded();
293 void stringConstruct()
295 String s = "foo";
296 s = "bar";
299 void overloadCall()
301 String s = "foo";
302 (s).overloaded();
305 struct C1 {};
306 struct C2 { operator C1(); };
308 void conversionOperator()
310 C2* c2;
311 C1 c1 = (*c2);
314 template <unsigned alignment>
315 void template_test() {
316 static_assert(alignment, "");
318 void actual_template_test() {
319 template_test<4>();
322 struct OneParamCtor {
323 explicit OneParamCtor(int);
325 struct TwoParamCtor {
326 explicit TwoParamCtor(int, int);
329 void varDeclCtors() {
331 auto var1 = OneParamCtor(5);
332 auto var2 = TwoParamCtor(6, 7);
335 OneParamCtor var3(5);
336 TwoParamCtor var4(6, 7);
338 int i = 0;
340 auto var5 = OneParamCtor(i);
341 auto var6 = TwoParamCtor(i, 7);
344 OneParamCtor var7(i);
345 TwoParamCtor var8(i, 7);
349 )cpp", {"-std=c++14"});
352 auto FN =
353 ast_matchers::match(functionDecl(hasName("stringConstruct")).bind("fn"),
354 AST->getASTContext());
355 EXPECT_EQ(FN.size(), 1u);
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");
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");
399 auto FN =
400 ast_matchers::match(functionDecl(hasName("overloadCall")).bind("fn"),
401 AST->getASTContext());
402 EXPECT_EQ(FN.size(), 1u);
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");
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");
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);
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");
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");
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);
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");
486 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
487 FN[1].getNodeAs<Decl>("staticAssert")),
488 R"cpp(
489 StaticAssertDecl
490 |-IntegerLiteral
491 `-StringLiteral
492 )cpp");
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);
504 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("varDeclCtor")),
505 SemanticDump);
507 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
508 FN[0].getNodeAs<Decl>("varDeclCtor")),
509 SyntacticDump);
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");
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");
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");
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");
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");
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");
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");
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");
635 TEST(Traverse, IgnoreUnlessSpelledInSourceStructs) {
636 auto AST = buildASTFromCode(R"cpp(
638 struct MyStruct {
639 MyStruct();
640 MyStruct(int i) {
641 MyStruct();
643 ~MyStruct();
646 )cpp");
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);
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");
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");
675 TEST(Traverse, IgnoreUnlessSpelledInSourceReturnStruct) {
677 auto AST = buildASTFromCode(R"cpp(
678 struct Retval {
679 Retval() {}
680 ~Retval() {}
683 Retval someFun();
685 void foo()
687 someFun();
689 )cpp");
691 auto BN = ast_matchers::match(functionDecl(hasName("foo")).bind("fn"),
692 AST->getASTContext());
693 EXPECT_EQ(BN.size(), 1u);
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");
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");
716 TEST(Traverse, IgnoreUnlessSpelledInSourceReturns) {
718 auto AST = buildASTFromCodeWithArgs(R"cpp(
720 struct A
724 struct B
726 B(int);
727 B(A const& a);
728 B();
731 struct C
733 operator B();
736 B func1() {
737 return 42;
740 B func2() {
741 return B{42};
744 B func3() {
745 return B(42);
748 B func4() {
749 return B();
752 B func5() {
753 return B{};
756 B func6() {
757 return C();
760 B func7() {
761 return A();
764 B func8() {
765 return C{};
768 B func9() {
769 return A{};
772 B func10() {
773 A a;
774 return a;
777 B func11() {
778 B b;
779 return b;
782 B func12() {
783 C c;
784 return c;
787 )cpp", {"-std=c++14"});
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");
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";
810 EXPECT_EQ(dumpASTString(TK_AsIs, FN), Expected);
812 Expected = R"cpp(
813 FunctionDecl 'func1'
814 `-CompoundStmt
815 `-ReturnStmt
816 `-IntegerLiteral
817 )cpp";
818 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, FN), Expected);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
945 TEST(Traverse, LambdaUnlessSpelledInSource) {
947 auto AST =
948 buildASTFromCodeWithArgs(R"cpp(
950 void captures() {
951 int a = 0;
952 int b = 0;
953 int d = 0;
954 int f = 0;
956 [a, &b, c = d, &e = f](int g, int h = 42) {};
959 void templated() {
960 int a = 0;
961 [a]<typename T>(T t) {};
964 struct SomeStruct {
965 int a = 0;
966 void capture_this() {
967 [this]() {};
969 void capture_this_copy() {
970 [self = *this]() {};
973 )cpp",
974 {"-Wno-unused-value", "-Wno-c++2a-extensions"});
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");
985 auto L = getLambdaNode("captures");
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);
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 '~(lambda at input.cc:9:3)'
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);
1027 auto L = getLambdaNode("templated");
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);
1040 auto L = getLambdaNode("capture_this");
1042 llvm::StringRef Expected = R"cpp(
1043 LambdaExpr
1044 |-CXXThisExpr
1045 `-CompoundStmt
1046 )cpp";
1047 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1051 auto L = getLambdaNode("capture_this_copy");
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);
1064 TEST(Traverse, IgnoreUnlessSpelledInSourceImplicit) {
1066 auto AST = buildASTFromCode(R"cpp(
1067 int i = 0;
1068 )cpp");
1069 const auto *TUDecl = AST->getASTContext().getTranslationUnitDecl();
1071 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, TUDecl),
1072 R"cpp(
1073 TranslationUnitDecl
1074 `-VarDecl 'i'
1075 `-IntegerLiteral
1076 )cpp");
1079 auto AST2 = buildASTFromCodeWithArgs(R"cpp(
1080 struct Simple {
1082 struct Other {
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;
1093 struct NonTrivial {
1094 NonTrivial() {}
1095 NonTrivial(NonTrivial&) {}
1096 NonTrivial& operator=(NonTrivial&) { return *this; }
1098 ~NonTrivial() {}
1101 struct ContainsArray {
1102 NonTrivial arr[2];
1103 int irr[2];
1104 ContainsArray& operator=(ContainsArray &) = default;
1107 void copyIt()
1109 ContainsArray ca;
1110 ContainsArray ca2;
1111 ca2 = ca;
1114 void forLoop()
1116 int arr[2];
1117 for (auto i : arr)
1121 for (auto& a = arr; auto i : a)
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;
1137 void copyIt2()
1139 DefaultedAndDeleted ca;
1140 DefaultedAndDeleted ca2;
1141 ca2 = ca;
1144 void hasDefaultArg(int i, int j = 0)
1147 void callDefaultArg()
1149 hasDefaultArg(42);
1152 void decomposition()
1154 int arr[3];
1155 auto &[f, s, t] = arr;
1157 f = 42;
1160 typedef __typeof(sizeof(int)) size_t;
1162 struct Pair
1164 int x, y;
1167 // Note: these utilities are required to force binding to tuple like structure
1168 namespace std
1170 template <typename E>
1171 struct tuple_size
1175 template <>
1176 struct tuple_size<Pair>
1178 static constexpr size_t value = 2;
1181 template <size_t I, class T>
1182 struct tuple_element
1184 using type = int;
1189 template <size_t I>
1190 int &&get(Pair &&p);
1192 void decompTuple()
1194 Pair p{1, 2};
1195 auto [a, b] = p;
1197 a = 3;
1200 )cpp",
1201 {"-std=c++20"});
1204 auto BN = ast_matchers::match(
1205 cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),
1206 AST2->getASTContext());
1207 EXPECT_EQ(BN.size(), 1u);
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 'Simple'
1215 | | `-CXXConstructExpr
1216 | |-CXXCtorInitializer '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");
1232 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1233 BN[0].getNodeAs<Decl>("rec")),
1234 R"cpp(
1235 CXXRecordDecl 'Record'
1236 |-CXXConstructorDecl 'Record'
1237 | |-CXXCtorInitializer '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");
1250 auto BN = ast_matchers::match(
1251 cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))
1252 .bind("rec"),
1253 AST2->getASTContext());
1254 EXPECT_EQ(BN.size(), 1u);
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");
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");
1326 auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),
1327 AST2->getASTContext());
1328 EXPECT_EQ(BN.size(), 1u);
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");
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");
1420 auto BN = ast_matchers::match(
1421 cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))
1422 .bind("rec"),
1423 AST2->getASTContext());
1424 EXPECT_EQ(BN.size(), 1u);
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");
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");
1475 auto BN = ast_matchers::match(
1476 callExpr(callee(functionDecl(hasName("hasDefaultArg"))))
1477 .bind("funcCall"),
1478 AST2->getASTContext());
1479 EXPECT_EQ(BN.size(), 1u);
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");
1499 auto FN = ast_matchers::match(
1500 functionDecl(hasName("decomposition"),
1501 hasDescendant(decompositionDecl().bind("decomp"))),
1502 AST2->getASTContext());
1503 EXPECT_EQ(FN.size(), 1u);
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");
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");
1539 auto FN = ast_matchers::match(
1540 functionDecl(hasName("decompTuple"),
1541 hasDescendant(decompositionDecl().bind("decomp"))),
1542 AST2->getASTContext());
1543 EXPECT_EQ(FN.size(), 1u);
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");
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");
1581 TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {
1583 auto AST = buildASTFromCode(R"cpp(
1584 template<typename T>
1585 struct TemplStruct {
1586 TemplStruct() {}
1587 ~TemplStruct() {}
1589 private:
1590 T m_t;
1593 template<typename T>
1594 T timesTwo(T input)
1596 return input * 2;
1599 void instantiate()
1601 TemplStruct<int> ti;
1602 TemplStruct<double> td;
1603 (void)timesTwo<int>(2);
1604 (void)timesTwo<double>(2);
1607 template class TemplStruct<float>;
1609 extern template class TemplStruct<long>;
1611 template<> class TemplStruct<bool> {
1612 TemplStruct() {}
1613 ~TemplStruct() {}
1615 void foo() {}
1616 private:
1617 bool m_t;
1620 // Explicit instantiation of template functions do not appear in the AST
1621 template float timesTwo(float);
1623 template<> bool timesTwo<bool>(bool) {
1624 return true;
1626 )cpp");
1628 auto BN = ast_matchers::match(
1629 classTemplateDecl(hasName("TemplStruct")).bind("rec"),
1630 AST->getASTContext());
1631 EXPECT_EQ(BN.size(), 1u);
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");
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");
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);
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");
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");
1757 auto BN = ast_matchers::match(
1758 functionTemplateDecl(hasName("timesTwo")).bind("fn"),
1759 AST->getASTContext());
1760 EXPECT_EQ(BN.size(), 1u);
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");
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");
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);
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");
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");
1867 TEST(Traverse, CXXRewrittenBinaryOperator) {
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;
1876 constexpr strong_ordering strong_ordering::equal = {0};
1877 constexpr strong_ordering strong_ordering::greater = {1};
1878 constexpr strong_ordering strong_ordering::less = {-1};
1881 struct HasSpaceshipMem {
1882 int a;
1883 constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
1886 void binop()
1888 HasSpaceshipMem hs1, hs2;
1889 if (hs1 < hs2)
1890 return;
1892 )cpp",
1893 {"-std=c++20"});
1895 auto BN = ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"),
1896 AST->getASTContext());
1897 EXPECT_EQ(BN.size(), 1u);
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");
1927 } // namespace clang