Revert "[llvm] Improve llvm.objectsize computation by computing GEP, alloca and mallo...
[llvm-project.git] / clang / unittests / AST / ASTTraverserTest.cpp
blob8b6e3e90c0ea67b54d1ee5c28d868bbb3d14c068
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 | `-UnaryOperator
372 | `-IntegerLiteral
373 `-ExprWithCleanups
374 `-CXXOperatorCallExpr
375 |-ImplicitCastExpr
376 | `-DeclRefExpr 'operator='
377 |-DeclRefExpr 's'
378 `-MaterializeTemporaryExpr
379 `-CXXConstructExpr
380 |-ImplicitCastExpr
381 | `-StringLiteral
382 `-CXXDefaultArgExpr
383 `-UnaryOperator
384 `-IntegerLiteral
385 )cpp");
387 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
388 FN[0].getNodeAs<Decl>("fn")),
389 R"cpp(
390 FunctionDecl 'stringConstruct'
391 `-CompoundStmt
392 |-DeclStmt
393 | `-VarDecl 's'
394 | `-StringLiteral
395 `-CXXOperatorCallExpr
396 |-DeclRefExpr 'operator='
397 |-DeclRefExpr 's'
398 `-StringLiteral
399 )cpp");
403 auto FN =
404 ast_matchers::match(functionDecl(hasName("overloadCall")).bind("fn"),
405 AST->getASTContext());
406 EXPECT_EQ(FN.size(), 1u);
408 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("fn")),
409 R"cpp(
410 FunctionDecl 'overloadCall'
411 `-CompoundStmt
412 |-DeclStmt
413 | `-VarDecl 's'
414 | `-ExprWithCleanups
415 | `-CXXConstructExpr
416 | `-MaterializeTemporaryExpr
417 | `-ImplicitCastExpr
418 | `-CXXConstructExpr
419 | |-ImplicitCastExpr
420 | | `-StringLiteral
421 | `-CXXDefaultArgExpr
422 | `-UnaryOperator
423 | `-IntegerLiteral
424 `-CXXMemberCallExpr
425 `-MemberExpr
426 `-ParenExpr
427 `-DeclRefExpr 's'
428 )cpp");
430 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
431 FN[0].getNodeAs<Decl>("fn")),
432 R"cpp(
433 FunctionDecl 'overloadCall'
434 `-CompoundStmt
435 |-DeclStmt
436 | `-VarDecl 's'
437 | `-StringLiteral
438 `-CXXMemberCallExpr
439 `-MemberExpr
440 `-DeclRefExpr 's'
441 )cpp");
445 auto FN = ast_matchers::match(
446 functionDecl(hasName("conversionOperator"),
447 hasDescendant(varDecl(hasName("c1")).bind("var"))),
448 AST->getASTContext());
449 EXPECT_EQ(FN.size(), 1u);
451 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("var")),
452 R"cpp(
453 VarDecl 'c1'
454 `-ExprWithCleanups
455 `-CXXConstructExpr
456 `-MaterializeTemporaryExpr
457 `-ImplicitCastExpr
458 `-CXXMemberCallExpr
459 `-MemberExpr
460 `-ParenExpr
461 `-UnaryOperator
462 `-ImplicitCastExpr
463 `-DeclRefExpr 'c2'
464 )cpp");
466 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
467 FN[0].getNodeAs<Decl>("var")),
468 R"cpp(
469 VarDecl 'c1'
470 `-UnaryOperator
471 `-DeclRefExpr 'c2'
472 )cpp");
476 auto FN = ast_matchers::match(
477 functionDecl(hasName("template_test"),
478 hasDescendant(staticAssertDecl().bind("staticAssert"))),
479 AST->getASTContext());
480 EXPECT_EQ(FN.size(), 2u);
482 EXPECT_EQ(dumpASTString(TK_AsIs, FN[1].getNodeAs<Decl>("staticAssert")),
483 R"cpp(
484 StaticAssertDecl
485 |-ImplicitCastExpr
486 | `-SubstNonTypeTemplateParmExpr
487 | |-NonTypeTemplateParmDecl 'alignment'
488 | `-IntegerLiteral
489 `-StringLiteral
490 )cpp");
492 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
493 FN[1].getNodeAs<Decl>("staticAssert")),
494 R"cpp(
495 StaticAssertDecl
496 |-IntegerLiteral
497 `-StringLiteral
498 )cpp");
501 auto varChecker = [&AST](StringRef varName, StringRef SemanticDump,
502 StringRef SyntacticDump) {
503 auto FN = ast_matchers::match(
504 functionDecl(
505 hasName("varDeclCtors"),
506 forEachDescendant(varDecl(hasName(varName)).bind("varDeclCtor"))),
507 AST->getASTContext());
508 EXPECT_EQ(FN.size(), 1u);
510 EXPECT_EQ(dumpASTString(TK_AsIs, FN[0].getNodeAs<Decl>("varDeclCtor")),
511 SemanticDump);
513 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
514 FN[0].getNodeAs<Decl>("varDeclCtor")),
515 SyntacticDump);
518 varChecker("var1",
519 R"cpp(
520 VarDecl 'var1'
521 `-ExprWithCleanups
522 `-CXXConstructExpr
523 `-MaterializeTemporaryExpr
524 `-CXXFunctionalCastExpr
525 `-CXXConstructExpr
526 `-IntegerLiteral
527 )cpp",
528 R"cpp(
529 VarDecl 'var1'
530 `-CXXConstructExpr
531 `-IntegerLiteral
532 )cpp");
534 varChecker("var2",
535 R"cpp(
536 VarDecl 'var2'
537 `-ExprWithCleanups
538 `-CXXConstructExpr
539 `-MaterializeTemporaryExpr
540 `-CXXTemporaryObjectExpr
541 |-IntegerLiteral
542 `-IntegerLiteral
543 )cpp",
544 R"cpp(
545 VarDecl 'var2'
546 `-CXXTemporaryObjectExpr
547 |-IntegerLiteral
548 `-IntegerLiteral
549 )cpp");
551 varChecker("var3",
552 R"cpp(
553 VarDecl 'var3'
554 `-CXXConstructExpr
555 `-IntegerLiteral
556 )cpp",
557 R"cpp(
558 VarDecl 'var3'
559 `-CXXConstructExpr
560 `-IntegerLiteral
561 )cpp");
563 varChecker("var4",
564 R"cpp(
565 VarDecl 'var4'
566 `-CXXConstructExpr
567 |-IntegerLiteral
568 `-IntegerLiteral
569 )cpp",
570 R"cpp(
571 VarDecl 'var4'
572 `-CXXConstructExpr
573 |-IntegerLiteral
574 `-IntegerLiteral
575 )cpp");
577 varChecker("var5",
578 R"cpp(
579 VarDecl 'var5'
580 `-ExprWithCleanups
581 `-CXXConstructExpr
582 `-MaterializeTemporaryExpr
583 `-CXXFunctionalCastExpr
584 `-CXXConstructExpr
585 `-ImplicitCastExpr
586 `-DeclRefExpr 'i'
587 )cpp",
588 R"cpp(
589 VarDecl 'var5'
590 `-CXXConstructExpr
591 `-DeclRefExpr 'i'
592 )cpp");
594 varChecker("var6",
595 R"cpp(
596 VarDecl 'var6'
597 `-ExprWithCleanups
598 `-CXXConstructExpr
599 `-MaterializeTemporaryExpr
600 `-CXXTemporaryObjectExpr
601 |-ImplicitCastExpr
602 | `-DeclRefExpr 'i'
603 `-IntegerLiteral
604 )cpp",
605 R"cpp(
606 VarDecl 'var6'
607 `-CXXTemporaryObjectExpr
608 |-DeclRefExpr 'i'
609 `-IntegerLiteral
610 )cpp");
612 varChecker("var7",
613 R"cpp(
614 VarDecl 'var7'
615 `-CXXConstructExpr
616 `-ImplicitCastExpr
617 `-DeclRefExpr 'i'
618 )cpp",
619 R"cpp(
620 VarDecl 'var7'
621 `-CXXConstructExpr
622 `-DeclRefExpr 'i'
623 )cpp");
625 varChecker("var8",
626 R"cpp(
627 VarDecl 'var8'
628 `-CXXConstructExpr
629 |-ImplicitCastExpr
630 | `-DeclRefExpr 'i'
631 `-IntegerLiteral
632 )cpp",
633 R"cpp(
634 VarDecl 'var8'
635 `-CXXConstructExpr
636 |-DeclRefExpr 'i'
637 `-IntegerLiteral
638 )cpp");
641 TEST(Traverse, IgnoreUnlessSpelledInSourceStructs) {
642 auto AST = buildASTFromCode(R"cpp(
644 struct MyStruct {
645 MyStruct();
646 MyStruct(int i) {
647 MyStruct();
649 ~MyStruct();
652 )cpp");
654 auto BN = ast_matchers::match(
655 cxxConstructorDecl(hasName("MyStruct"),
656 hasParameter(0, parmVarDecl(hasType(isInteger()))))
657 .bind("ctor"),
658 AST->getASTContext());
659 EXPECT_EQ(BN.size(), 1u);
661 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
662 BN[0].getNodeAs<Decl>("ctor")),
663 R"cpp(
664 CXXConstructorDecl 'MyStruct'
665 |-ParmVarDecl 'i'
666 `-CompoundStmt
667 `-CXXTemporaryObjectExpr
668 )cpp");
670 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("ctor")),
671 R"cpp(
672 CXXConstructorDecl 'MyStruct'
673 |-ParmVarDecl 'i'
674 `-CompoundStmt
675 `-ExprWithCleanups
676 `-CXXBindTemporaryExpr
677 `-CXXTemporaryObjectExpr
678 )cpp");
681 TEST(Traverse, IgnoreUnlessSpelledInSourceReturnStruct) {
683 auto AST = buildASTFromCode(R"cpp(
684 struct Retval {
685 Retval() {}
686 ~Retval() {}
689 Retval someFun();
691 void foo()
693 someFun();
695 )cpp");
697 auto BN = ast_matchers::match(functionDecl(hasName("foo")).bind("fn"),
698 AST->getASTContext());
699 EXPECT_EQ(BN.size(), 1u);
701 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
702 BN[0].getNodeAs<Decl>("fn")),
703 R"cpp(
704 FunctionDecl 'foo'
705 `-CompoundStmt
706 `-CallExpr
707 `-DeclRefExpr 'someFun'
708 )cpp");
710 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),
711 R"cpp(
712 FunctionDecl 'foo'
713 `-CompoundStmt
714 `-ExprWithCleanups
715 `-CXXBindTemporaryExpr
716 `-CallExpr
717 `-ImplicitCastExpr
718 `-DeclRefExpr 'someFun'
719 )cpp");
722 TEST(Traverse, IgnoreUnlessSpelledInSourceReturns) {
724 auto AST = buildASTFromCodeWithArgs(R"cpp(
726 struct A
730 struct B
732 B(int);
733 B(A const& a);
734 B();
737 struct C
739 operator B();
742 B func1() {
743 return 42;
746 B func2() {
747 return B{42};
750 B func3() {
751 return B(42);
754 B func4() {
755 return B();
758 B func5() {
759 return B{};
762 B func6() {
763 return C();
766 B func7() {
767 return A();
770 B func8() {
771 return C{};
774 B func9() {
775 return A{};
778 B func10() {
779 A a;
780 return a;
783 B func11() {
784 B b;
785 return b;
788 B func12() {
789 C c;
790 return c;
793 )cpp", {"-std=c++14"});
795 auto getFunctionNode = [&AST](const std::string &name) {
796 auto BN = ast_matchers::match(functionDecl(hasName(name)).bind("fn"),
797 AST->getASTContext());
798 EXPECT_EQ(BN.size(), 1u);
799 return BN[0].getNodeAs<Decl>("fn");
803 auto FN = getFunctionNode("func1");
804 llvm::StringRef Expected = R"cpp(
805 FunctionDecl 'func1'
806 `-CompoundStmt
807 `-ReturnStmt
808 `-ExprWithCleanups
809 `-CXXConstructExpr
810 `-MaterializeTemporaryExpr
811 `-ImplicitCastExpr
812 `-CXXConstructExpr
813 `-IntegerLiteral
814 )cpp";
816 EXPECT_EQ(dumpASTString(TK_AsIs, FN), Expected);
818 Expected = R"cpp(
819 FunctionDecl 'func1'
820 `-CompoundStmt
821 `-ReturnStmt
822 `-IntegerLiteral
823 )cpp";
824 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, FN), Expected);
827 llvm::StringRef Expected = R"cpp(
828 FunctionDecl 'func2'
829 `-CompoundStmt
830 `-ReturnStmt
831 `-CXXTemporaryObjectExpr
832 `-IntegerLiteral
833 )cpp";
834 EXPECT_EQ(
835 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func2")),
836 Expected);
838 Expected = R"cpp(
839 FunctionDecl 'func3'
840 `-CompoundStmt
841 `-ReturnStmt
842 `-CXXConstructExpr
843 `-IntegerLiteral
844 )cpp";
845 EXPECT_EQ(
846 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func3")),
847 Expected);
849 Expected = R"cpp(
850 FunctionDecl 'func4'
851 `-CompoundStmt
852 `-ReturnStmt
853 `-CXXTemporaryObjectExpr
854 )cpp";
855 EXPECT_EQ(
856 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func4")),
857 Expected);
859 Expected = R"cpp(
860 FunctionDecl 'func5'
861 `-CompoundStmt
862 `-ReturnStmt
863 `-CXXTemporaryObjectExpr
864 )cpp";
865 EXPECT_EQ(
866 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func5")),
867 Expected);
869 Expected = R"cpp(
870 FunctionDecl 'func6'
871 `-CompoundStmt
872 `-ReturnStmt
873 `-CXXTemporaryObjectExpr
874 )cpp";
875 EXPECT_EQ(
876 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func6")),
877 Expected);
879 Expected = R"cpp(
880 FunctionDecl 'func7'
881 `-CompoundStmt
882 `-ReturnStmt
883 `-CXXTemporaryObjectExpr
884 )cpp";
885 EXPECT_EQ(
886 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func7")),
887 Expected);
889 Expected = R"cpp(
890 FunctionDecl 'func8'
891 `-CompoundStmt
892 `-ReturnStmt
893 `-CXXFunctionalCastExpr
894 `-InitListExpr
895 )cpp";
896 EXPECT_EQ(
897 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func8")),
898 Expected);
900 Expected = R"cpp(
901 FunctionDecl 'func9'
902 `-CompoundStmt
903 `-ReturnStmt
904 `-CXXFunctionalCastExpr
905 `-InitListExpr
906 )cpp";
907 EXPECT_EQ(
908 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func9")),
909 Expected);
911 Expected = R"cpp(
912 FunctionDecl 'func10'
913 `-CompoundStmt
914 |-DeclStmt
915 | `-VarDecl 'a'
916 | `-CXXConstructExpr
917 `-ReturnStmt
918 `-DeclRefExpr 'a'
919 )cpp";
920 EXPECT_EQ(
921 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func10")),
922 Expected);
924 Expected = R"cpp(
925 FunctionDecl 'func11'
926 `-CompoundStmt
927 |-DeclStmt
928 | `-VarDecl 'b'
929 | `-CXXConstructExpr
930 `-ReturnStmt
931 `-DeclRefExpr 'b'
932 )cpp";
933 EXPECT_EQ(
934 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func11")),
935 Expected);
937 Expected = R"cpp(
938 FunctionDecl 'func12'
939 `-CompoundStmt
940 |-DeclStmt
941 | `-VarDecl 'c'
942 | `-CXXConstructExpr
943 `-ReturnStmt
944 `-DeclRefExpr 'c'
945 )cpp";
946 EXPECT_EQ(
947 dumpASTString(TK_IgnoreUnlessSpelledInSource, getFunctionNode("func12")),
948 Expected);
951 TEST(Traverse, LambdaUnlessSpelledInSource) {
953 auto AST =
954 buildASTFromCodeWithArgs(R"cpp(
956 void captures() {
957 int a = 0;
958 int b = 0;
959 int d = 0;
960 int f = 0;
962 [a, &b, c = d, &e = f](int g, int h = 42) {};
965 void templated() {
966 int a = 0;
967 [a]<typename T>(T t) {};
970 struct SomeStruct {
971 int a = 0;
972 void capture_this() {
973 [this]() {};
975 void capture_this_copy() {
976 [self = *this]() {};
979 )cpp",
980 {"-Wno-unused-value", "-Wno-c++2a-extensions"});
982 auto getLambdaNode = [&AST](const std::string &name) {
983 auto BN = ast_matchers::match(
984 lambdaExpr(hasAncestor(functionDecl(hasName(name)))).bind("lambda"),
985 AST->getASTContext());
986 EXPECT_EQ(BN.size(), 1u);
987 return BN[0].getNodeAs<LambdaExpr>("lambda");
991 auto L = getLambdaNode("captures");
993 llvm::StringRef Expected = R"cpp(
994 LambdaExpr
995 |-DeclRefExpr 'a'
996 |-DeclRefExpr 'b'
997 |-VarDecl 'c'
998 | `-DeclRefExpr 'd'
999 |-VarDecl 'e'
1000 | `-DeclRefExpr 'f'
1001 |-ParmVarDecl 'g'
1002 |-ParmVarDecl 'h'
1003 | `-IntegerLiteral
1004 `-CompoundStmt
1005 )cpp";
1006 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1008 Expected = R"cpp(
1009 LambdaExpr
1010 |-CXXRecordDecl ''
1011 | |-CXXMethodDecl 'operator()'
1012 | | |-ParmVarDecl 'g'
1013 | | |-ParmVarDecl 'h'
1014 | | | `-IntegerLiteral
1015 | | `-CompoundStmt
1016 | |-FieldDecl ''
1017 | |-FieldDecl ''
1018 | |-FieldDecl ''
1019 | |-FieldDecl ''
1020 | `-CXXDestructorDecl '~(lambda at input.cc:9:3)'
1021 |-ImplicitCastExpr
1022 | `-DeclRefExpr 'a'
1023 |-DeclRefExpr 'b'
1024 |-ImplicitCastExpr
1025 | `-DeclRefExpr 'd'
1026 |-DeclRefExpr 'f'
1027 `-CompoundStmt
1028 )cpp";
1029 EXPECT_EQ(dumpASTString(TK_AsIs, L), Expected);
1033 auto L = getLambdaNode("templated");
1035 llvm::StringRef Expected = R"cpp(
1036 LambdaExpr
1037 |-DeclRefExpr 'a'
1038 |-TemplateTypeParmDecl 'T'
1039 |-ParmVarDecl 't'
1040 `-CompoundStmt
1041 )cpp";
1042 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1046 auto L = getLambdaNode("capture_this");
1048 llvm::StringRef Expected = R"cpp(
1049 LambdaExpr
1050 |-CXXThisExpr
1051 `-CompoundStmt
1052 )cpp";
1053 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1057 auto L = getLambdaNode("capture_this_copy");
1059 llvm::StringRef Expected = R"cpp(
1060 LambdaExpr
1061 |-VarDecl 'self'
1062 | `-UnaryOperator
1063 | `-CXXThisExpr
1064 `-CompoundStmt
1065 )cpp";
1066 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, L), Expected);
1070 TEST(Traverse, IgnoreUnlessSpelledInSourceImplicit) {
1072 auto AST = buildASTFromCode(R"cpp(
1073 int i = 0;
1074 )cpp");
1075 const auto *TUDecl = AST->getASTContext().getTranslationUnitDecl();
1077 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource, TUDecl),
1078 R"cpp(
1079 TranslationUnitDecl
1080 `-VarDecl 'i'
1081 `-IntegerLiteral
1082 )cpp");
1085 auto AST2 = buildASTFromCodeWithArgs(R"cpp(
1086 struct Simple {
1088 struct Other {
1091 struct Record : Simple, Other {
1092 Record() : Simple(), m_i(42) {}
1093 private:
1094 int m_i;
1095 int m_i2 = 42;
1096 Simple m_s;
1099 struct NonTrivial {
1100 NonTrivial() {}
1101 NonTrivial(NonTrivial&) {}
1102 NonTrivial& operator=(NonTrivial&) { return *this; }
1104 ~NonTrivial() {}
1107 struct ContainsArray {
1108 NonTrivial arr[2];
1109 int irr[2];
1110 ContainsArray& operator=(ContainsArray &) = default;
1113 void copyIt()
1115 ContainsArray ca;
1116 ContainsArray ca2;
1117 ca2 = ca;
1120 void forLoop()
1122 int arr[2];
1123 for (auto i : arr)
1127 for (auto& a = arr; auto i : a)
1133 struct DefaultedAndDeleted {
1134 NonTrivial nt;
1135 DefaultedAndDeleted() = default;
1136 ~DefaultedAndDeleted() = default;
1137 DefaultedAndDeleted(DefaultedAndDeleted &) = default;
1138 DefaultedAndDeleted& operator=(DefaultedAndDeleted &) = default;
1139 DefaultedAndDeleted(DefaultedAndDeleted &&) = delete;
1140 DefaultedAndDeleted& operator=(DefaultedAndDeleted &&) = delete;
1143 void copyIt2()
1145 DefaultedAndDeleted ca;
1146 DefaultedAndDeleted ca2;
1147 ca2 = ca;
1150 void hasDefaultArg(int i, int j = 0)
1153 void callDefaultArg()
1155 hasDefaultArg(42);
1158 void decomposition()
1160 int arr[3];
1161 auto &[f, s, t] = arr;
1163 f = 42;
1166 typedef __typeof(sizeof(int)) size_t;
1168 struct Pair
1170 int x, y;
1173 // Note: these utilities are required to force binding to tuple like structure
1174 namespace std
1176 template <typename E>
1177 struct tuple_size
1181 template <>
1182 struct tuple_size<Pair>
1184 static constexpr size_t value = 2;
1187 template <size_t I, class T>
1188 struct tuple_element
1190 using type = int;
1195 template <size_t I>
1196 int &&get(Pair &&p);
1198 void decompTuple()
1200 Pair p{1, 2};
1201 auto [a, b] = p;
1203 a = 3;
1206 )cpp",
1207 {"-std=c++20"});
1210 auto BN = ast_matchers::match(
1211 cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),
1212 AST2->getASTContext());
1213 EXPECT_EQ(BN.size(), 1u);
1215 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1216 R"cpp(
1217 CXXRecordDecl 'Record'
1218 |-CXXRecordDecl 'Record'
1219 |-CXXConstructorDecl 'Record'
1220 | |-CXXCtorInitializer 'Simple'
1221 | | `-CXXConstructExpr
1222 | |-CXXCtorInitializer 'Other'
1223 | | `-CXXConstructExpr
1224 | |-CXXCtorInitializer 'm_i'
1225 | | `-IntegerLiteral
1226 | |-CXXCtorInitializer 'm_i2'
1227 | | `-CXXDefaultInitExpr
1228 | | `-IntegerLiteral
1229 | |-CXXCtorInitializer 'm_s'
1230 | | `-CXXConstructExpr
1231 | `-CompoundStmt
1232 |-AccessSpecDecl
1233 |-FieldDecl 'm_i'
1234 |-FieldDecl 'm_i2'
1235 | `-IntegerLiteral
1236 `-FieldDecl 'm_s'
1237 )cpp");
1239 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1240 BN[0].getNodeAs<Decl>("rec")),
1241 R"cpp(
1242 CXXRecordDecl 'Record'
1243 |-CXXConstructorDecl 'Record'
1244 | |-CXXCtorInitializer 'Simple'
1245 | | `-CXXConstructExpr
1246 | |-CXXCtorInitializer 'm_i'
1247 | | `-IntegerLiteral
1248 | `-CompoundStmt
1249 |-AccessSpecDecl
1250 |-FieldDecl 'm_i'
1251 |-FieldDecl 'm_i2'
1252 | `-IntegerLiteral
1253 `-FieldDecl 'm_s'
1254 )cpp");
1257 auto BN = ast_matchers::match(
1258 cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))
1259 .bind("rec"),
1260 AST2->getASTContext());
1261 EXPECT_EQ(BN.size(), 1u);
1263 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1264 R"cpp(
1265 CXXRecordDecl 'ContainsArray'
1266 |-CXXRecordDecl 'ContainsArray'
1267 |-FieldDecl 'arr'
1268 |-FieldDecl 'irr'
1269 |-CXXMethodDecl 'operator='
1270 | |-ParmVarDecl ''
1271 | `-CompoundStmt
1272 | |-ForStmt
1273 | | |-DeclStmt
1274 | | | `-VarDecl '__i0'
1275 | | | `-IntegerLiteral
1276 | | |-<<<NULL>>>
1277 | | |-BinaryOperator
1278 | | | |-ImplicitCastExpr
1279 | | | | `-DeclRefExpr '__i0'
1280 | | | `-IntegerLiteral
1281 | | |-UnaryOperator
1282 | | | `-DeclRefExpr '__i0'
1283 | | `-CXXMemberCallExpr
1284 | | |-MemberExpr
1285 | | | `-ArraySubscriptExpr
1286 | | | |-ImplicitCastExpr
1287 | | | | `-MemberExpr
1288 | | | | `-CXXThisExpr
1289 | | | `-ImplicitCastExpr
1290 | | | `-DeclRefExpr '__i0'
1291 | | `-ArraySubscriptExpr
1292 | | |-ImplicitCastExpr
1293 | | | `-MemberExpr
1294 | | | `-DeclRefExpr ''
1295 | | `-ImplicitCastExpr
1296 | | `-DeclRefExpr '__i0'
1297 | |-CallExpr
1298 | | |-ImplicitCastExpr
1299 | | | `-DeclRefExpr '__builtin_memcpy'
1300 | | |-ImplicitCastExpr
1301 | | | `-UnaryOperator
1302 | | | `-MemberExpr
1303 | | | `-CXXThisExpr
1304 | | |-ImplicitCastExpr
1305 | | | `-UnaryOperator
1306 | | | `-MemberExpr
1307 | | | `-DeclRefExpr ''
1308 | | `-IntegerLiteral
1309 | `-ReturnStmt
1310 | `-UnaryOperator
1311 | `-CXXThisExpr
1312 |-CXXConstructorDecl 'ContainsArray'
1313 | `-ParmVarDecl ''
1314 |-CXXDestructorDecl '~ContainsArray'
1315 | `-CompoundStmt
1316 `-CXXConstructorDecl 'ContainsArray'
1317 |-CXXCtorInitializer 'arr'
1318 | `-CXXConstructExpr
1319 `-CompoundStmt
1320 )cpp");
1322 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1323 BN[0].getNodeAs<Decl>("rec")),
1324 R"cpp(
1325 CXXRecordDecl 'ContainsArray'
1326 |-FieldDecl 'arr'
1327 |-FieldDecl 'irr'
1328 `-CXXMethodDecl 'operator='
1329 `-ParmVarDecl ''
1330 )cpp");
1333 auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),
1334 AST2->getASTContext());
1335 EXPECT_EQ(BN.size(), 1u);
1337 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("func")),
1338 R"cpp(
1339 FunctionDecl 'forLoop'
1340 `-CompoundStmt
1341 |-DeclStmt
1342 | `-VarDecl 'arr'
1343 |-CXXForRangeStmt
1344 | |-<<<NULL>>>
1345 | |-DeclStmt
1346 | | `-VarDecl '__range1'
1347 | | `-DeclRefExpr 'arr'
1348 | |-DeclStmt
1349 | | `-VarDecl '__begin1'
1350 | | `-ImplicitCastExpr
1351 | | `-DeclRefExpr '__range1'
1352 | |-DeclStmt
1353 | | `-VarDecl '__end1'
1354 | | `-BinaryOperator
1355 | | |-ImplicitCastExpr
1356 | | | `-DeclRefExpr '__range1'
1357 | | `-IntegerLiteral
1358 | |-BinaryOperator
1359 | | |-ImplicitCastExpr
1360 | | | `-DeclRefExpr '__begin1'
1361 | | `-ImplicitCastExpr
1362 | | `-DeclRefExpr '__end1'
1363 | |-UnaryOperator
1364 | | `-DeclRefExpr '__begin1'
1365 | |-DeclStmt
1366 | | `-VarDecl 'i'
1367 | | `-ImplicitCastExpr
1368 | | `-UnaryOperator
1369 | | `-ImplicitCastExpr
1370 | | `-DeclRefExpr '__begin1'
1371 | `-CompoundStmt
1372 `-CXXForRangeStmt
1373 |-DeclStmt
1374 | `-VarDecl 'a'
1375 | `-DeclRefExpr 'arr'
1376 |-DeclStmt
1377 | `-VarDecl '__range1'
1378 | `-DeclRefExpr 'a'
1379 |-DeclStmt
1380 | `-VarDecl '__begin1'
1381 | `-ImplicitCastExpr
1382 | `-DeclRefExpr '__range1'
1383 |-DeclStmt
1384 | `-VarDecl '__end1'
1385 | `-BinaryOperator
1386 | |-ImplicitCastExpr
1387 | | `-DeclRefExpr '__range1'
1388 | `-IntegerLiteral
1389 |-BinaryOperator
1390 | |-ImplicitCastExpr
1391 | | `-DeclRefExpr '__begin1'
1392 | `-ImplicitCastExpr
1393 | `-DeclRefExpr '__end1'
1394 |-UnaryOperator
1395 | `-DeclRefExpr '__begin1'
1396 |-DeclStmt
1397 | `-VarDecl 'i'
1398 | `-ImplicitCastExpr
1399 | `-UnaryOperator
1400 | `-ImplicitCastExpr
1401 | `-DeclRefExpr '__begin1'
1402 `-CompoundStmt
1403 )cpp");
1405 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1406 BN[0].getNodeAs<Decl>("func")),
1407 R"cpp(
1408 FunctionDecl 'forLoop'
1409 `-CompoundStmt
1410 |-DeclStmt
1411 | `-VarDecl 'arr'
1412 |-CXXForRangeStmt
1413 | |-<<<NULL>>>
1414 | |-VarDecl 'i'
1415 | |-DeclRefExpr 'arr'
1416 | `-CompoundStmt
1417 `-CXXForRangeStmt
1418 |-DeclStmt
1419 | `-VarDecl 'a'
1420 | `-DeclRefExpr 'arr'
1421 |-VarDecl 'i'
1422 |-DeclRefExpr 'a'
1423 `-CompoundStmt
1424 )cpp");
1427 auto BN = ast_matchers::match(
1428 cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))
1429 .bind("rec"),
1430 AST2->getASTContext());
1431 EXPECT_EQ(BN.size(), 1u);
1433 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1434 R"cpp(
1435 CXXRecordDecl 'DefaultedAndDeleted'
1436 |-CXXRecordDecl 'DefaultedAndDeleted'
1437 |-FieldDecl 'nt'
1438 |-CXXConstructorDecl 'DefaultedAndDeleted'
1439 | |-CXXCtorInitializer 'nt'
1440 | | `-CXXConstructExpr
1441 | `-CompoundStmt
1442 |-CXXDestructorDecl '~DefaultedAndDeleted'
1443 | `-CompoundStmt
1444 |-CXXConstructorDecl 'DefaultedAndDeleted'
1445 | `-ParmVarDecl ''
1446 |-CXXMethodDecl 'operator='
1447 | |-ParmVarDecl ''
1448 | `-CompoundStmt
1449 | |-CXXMemberCallExpr
1450 | | |-MemberExpr
1451 | | | `-MemberExpr
1452 | | | `-CXXThisExpr
1453 | | `-MemberExpr
1454 | | `-DeclRefExpr ''
1455 | `-ReturnStmt
1456 | `-UnaryOperator
1457 | `-CXXThisExpr
1458 |-CXXConstructorDecl 'DefaultedAndDeleted'
1459 | `-ParmVarDecl ''
1460 `-CXXMethodDecl 'operator='
1461 `-ParmVarDecl ''
1462 )cpp");
1464 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1465 BN[0].getNodeAs<Decl>("rec")),
1466 R"cpp(
1467 CXXRecordDecl 'DefaultedAndDeleted'
1468 |-FieldDecl 'nt'
1469 |-CXXConstructorDecl 'DefaultedAndDeleted'
1470 |-CXXDestructorDecl '~DefaultedAndDeleted'
1471 |-CXXConstructorDecl 'DefaultedAndDeleted'
1472 | `-ParmVarDecl ''
1473 |-CXXMethodDecl 'operator='
1474 | `-ParmVarDecl ''
1475 |-CXXConstructorDecl 'DefaultedAndDeleted'
1476 | `-ParmVarDecl ''
1477 `-CXXMethodDecl 'operator='
1478 `-ParmVarDecl ''
1479 )cpp");
1482 auto BN = ast_matchers::match(
1483 callExpr(callee(functionDecl(hasName("hasDefaultArg"))))
1484 .bind("funcCall"),
1485 AST2->getASTContext());
1486 EXPECT_EQ(BN.size(), 1u);
1488 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<CallExpr>("funcCall")),
1489 R"cpp(
1490 CallExpr
1491 |-ImplicitCastExpr
1492 | `-DeclRefExpr 'hasDefaultArg'
1493 |-IntegerLiteral
1494 `-CXXDefaultArgExpr
1495 `-IntegerLiteral
1496 )cpp");
1497 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1498 BN[0].getNodeAs<CallExpr>("funcCall")),
1499 R"cpp(
1500 CallExpr
1501 |-DeclRefExpr 'hasDefaultArg'
1502 `-IntegerLiteral
1503 )cpp");
1507 auto FN = ast_matchers::match(
1508 functionDecl(hasName("decomposition"),
1509 hasDescendant(decompositionDecl().bind("decomp"))),
1510 AST2->getASTContext());
1511 EXPECT_EQ(FN.size(), 1u);
1513 EXPECT_EQ(
1514 dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")),
1515 R"cpp(
1516 DecompositionDecl ''
1517 |-DeclRefExpr 'arr'
1518 |-BindingDecl 'f'
1519 | `-ArraySubscriptExpr
1520 | |-ImplicitCastExpr
1521 | | `-DeclRefExpr ''
1522 | `-IntegerLiteral
1523 |-BindingDecl 's'
1524 | `-ArraySubscriptExpr
1525 | |-ImplicitCastExpr
1526 | | `-DeclRefExpr ''
1527 | `-IntegerLiteral
1528 `-BindingDecl 't'
1529 `-ArraySubscriptExpr
1530 |-ImplicitCastExpr
1531 | `-DeclRefExpr ''
1532 `-IntegerLiteral
1533 )cpp");
1535 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1536 FN[0].getNodeAs<DecompositionDecl>("decomp")),
1537 R"cpp(
1538 DecompositionDecl ''
1539 |-DeclRefExpr 'arr'
1540 |-BindingDecl 'f'
1541 |-BindingDecl 's'
1542 `-BindingDecl 't'
1543 )cpp");
1547 auto FN = ast_matchers::match(
1548 functionDecl(hasName("decompTuple"),
1549 hasDescendant(decompositionDecl().bind("decomp"))),
1550 AST2->getASTContext());
1551 EXPECT_EQ(FN.size(), 1u);
1553 EXPECT_EQ(
1554 dumpASTString(TK_AsIs, FN[0].getNodeAs<DecompositionDecl>("decomp")),
1555 R"cpp(
1556 DecompositionDecl ''
1557 |-CXXConstructExpr
1558 | `-ImplicitCastExpr
1559 | `-DeclRefExpr 'p'
1560 |-BindingDecl 'a'
1561 | |-VarDecl 'a'
1562 | | `-CallExpr
1563 | | |-ImplicitCastExpr
1564 | | | `-DeclRefExpr 'get'
1565 | | `-ImplicitCastExpr
1566 | | `-DeclRefExpr ''
1567 | `-DeclRefExpr 'a'
1568 `-BindingDecl 'b'
1569 |-VarDecl 'b'
1570 | `-CallExpr
1571 | |-ImplicitCastExpr
1572 | | `-DeclRefExpr 'get'
1573 | `-ImplicitCastExpr
1574 | `-DeclRefExpr ''
1575 `-DeclRefExpr 'b'
1576 )cpp");
1578 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1579 FN[0].getNodeAs<DecompositionDecl>("decomp")),
1580 R"cpp(
1581 DecompositionDecl ''
1582 |-DeclRefExpr 'p'
1583 |-BindingDecl 'a'
1584 `-BindingDecl 'b'
1585 )cpp");
1589 TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {
1591 auto AST = buildASTFromCode(R"cpp(
1592 template<typename T>
1593 struct TemplStruct {
1594 TemplStruct() {}
1595 ~TemplStruct() {}
1597 private:
1598 T m_t;
1601 template<typename T>
1602 T timesTwo(T input)
1604 return input * 2;
1607 void instantiate()
1609 TemplStruct<int> ti;
1610 TemplStruct<double> td;
1611 (void)timesTwo<int>(2);
1612 (void)timesTwo<double>(2);
1615 template class TemplStruct<float>;
1617 extern template class TemplStruct<long>;
1619 template<> class TemplStruct<bool> {
1620 TemplStruct() {}
1621 ~TemplStruct() {}
1623 void foo() {}
1624 private:
1625 bool m_t;
1628 // Explicit instantiation of template functions do not appear in the AST
1629 template float timesTwo(float);
1631 template<> bool timesTwo<bool>(bool) {
1632 return true;
1634 )cpp");
1636 auto BN = ast_matchers::match(
1637 classTemplateDecl(hasName("TemplStruct")).bind("rec"),
1638 AST->getASTContext());
1639 EXPECT_EQ(BN.size(), 1u);
1641 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1642 BN[0].getNodeAs<Decl>("rec")),
1643 R"cpp(
1644 ClassTemplateDecl 'TemplStruct'
1645 |-TemplateTypeParmDecl 'T'
1646 `-CXXRecordDecl 'TemplStruct'
1647 |-CXXConstructorDecl 'TemplStruct<T>'
1648 | `-CompoundStmt
1649 |-CXXDestructorDecl '~TemplStruct<T>'
1650 | `-CompoundStmt
1651 |-AccessSpecDecl
1652 `-FieldDecl 'm_t'
1653 )cpp");
1655 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1656 R"cpp(
1657 ClassTemplateDecl 'TemplStruct'
1658 |-TemplateTypeParmDecl 'T'
1659 |-CXXRecordDecl 'TemplStruct'
1660 | |-CXXRecordDecl 'TemplStruct'
1661 | |-CXXConstructorDecl 'TemplStruct<T>'
1662 | | `-CompoundStmt
1663 | |-CXXDestructorDecl '~TemplStruct<T>'
1664 | | `-CompoundStmt
1665 | |-AccessSpecDecl
1666 | `-FieldDecl 'm_t'
1667 |-ClassTemplateSpecializationDecl 'TemplStruct'
1668 | |-TemplateArgument type int
1669 | | `-BuiltinType
1670 | |-CXXRecordDecl 'TemplStruct'
1671 | |-CXXConstructorDecl 'TemplStruct'
1672 | | `-CompoundStmt
1673 | |-CXXDestructorDecl '~TemplStruct'
1674 | | `-CompoundStmt
1675 | |-AccessSpecDecl
1676 | |-FieldDecl 'm_t'
1677 | `-CXXConstructorDecl 'TemplStruct'
1678 | `-ParmVarDecl ''
1679 |-ClassTemplateSpecializationDecl 'TemplStruct'
1680 | |-TemplateArgument type double
1681 | | `-BuiltinType
1682 | |-CXXRecordDecl 'TemplStruct'
1683 | |-CXXConstructorDecl 'TemplStruct'
1684 | | `-CompoundStmt
1685 | |-CXXDestructorDecl '~TemplStruct'
1686 | | `-CompoundStmt
1687 | |-AccessSpecDecl
1688 | |-FieldDecl 'm_t'
1689 | `-CXXConstructorDecl 'TemplStruct'
1690 | `-ParmVarDecl ''
1691 |-ClassTemplateSpecializationDecl 'TemplStruct'
1692 | |-TemplateArgument type float
1693 | | `-BuiltinType
1694 | |-CXXRecordDecl 'TemplStruct'
1695 | |-CXXConstructorDecl 'TemplStruct'
1696 | | `-CompoundStmt
1697 | |-CXXDestructorDecl '~TemplStruct'
1698 | | `-CompoundStmt
1699 | |-AccessSpecDecl
1700 | `-FieldDecl 'm_t'
1701 |-ClassTemplateSpecializationDecl 'TemplStruct'
1702 | |-TemplateArgument type long
1703 | | `-BuiltinType
1704 | |-CXXRecordDecl 'TemplStruct'
1705 | |-CXXConstructorDecl 'TemplStruct'
1706 | |-CXXDestructorDecl '~TemplStruct'
1707 | |-AccessSpecDecl
1708 | `-FieldDecl 'm_t'
1709 `-ClassTemplateSpecializationDecl 'TemplStruct'
1710 |-TemplateArgument type _Bool
1711 | `-BuiltinType
1712 |-CXXRecordDecl 'TemplStruct'
1713 |-CXXConstructorDecl 'TemplStruct'
1714 | `-CompoundStmt
1715 |-CXXDestructorDecl '~TemplStruct'
1716 | `-CompoundStmt
1717 |-CXXMethodDecl 'foo'
1718 | `-CompoundStmt
1719 |-AccessSpecDecl
1720 `-FieldDecl 'm_t'
1721 )cpp");
1724 auto BN = ast_matchers::match(
1725 classTemplateSpecializationDecl(
1726 hasTemplateArgument(
1727 0, templateArgument(refersToType(asString("_Bool")))))
1728 .bind("templSpec"),
1729 AST->getASTContext());
1730 EXPECT_EQ(BN.size(), 1u);
1732 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("templSpec")),
1733 R"cpp(
1734 ClassTemplateSpecializationDecl 'TemplStruct'
1735 |-TemplateArgument type _Bool
1736 | `-BuiltinType
1737 |-CXXRecordDecl 'TemplStruct'
1738 |-CXXConstructorDecl 'TemplStruct'
1739 | `-CompoundStmt
1740 |-CXXDestructorDecl '~TemplStruct'
1741 | `-CompoundStmt
1742 |-CXXMethodDecl 'foo'
1743 | `-CompoundStmt
1744 |-AccessSpecDecl
1745 `-FieldDecl 'm_t'
1746 )cpp");
1748 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1749 BN[0].getNodeAs<Decl>("templSpec")),
1750 R"cpp(
1751 ClassTemplateSpecializationDecl 'TemplStruct'
1752 |-TemplateArgument type _Bool
1753 | `-BuiltinType
1754 |-CXXConstructorDecl 'TemplStruct'
1755 | `-CompoundStmt
1756 |-CXXDestructorDecl '~TemplStruct'
1757 | `-CompoundStmt
1758 |-CXXMethodDecl 'foo'
1759 | `-CompoundStmt
1760 |-AccessSpecDecl
1761 `-FieldDecl 'm_t'
1762 )cpp");
1765 auto BN = ast_matchers::match(
1766 functionTemplateDecl(hasName("timesTwo")).bind("fn"),
1767 AST->getASTContext());
1768 EXPECT_EQ(BN.size(), 1u);
1770 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1771 BN[0].getNodeAs<Decl>("fn")),
1772 R"cpp(
1773 FunctionTemplateDecl 'timesTwo'
1774 |-TemplateTypeParmDecl 'T'
1775 `-FunctionDecl 'timesTwo'
1776 |-ParmVarDecl 'input'
1777 `-CompoundStmt
1778 `-ReturnStmt
1779 `-BinaryOperator
1780 |-DeclRefExpr 'input'
1781 `-IntegerLiteral
1782 )cpp");
1784 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),
1785 R"cpp(
1786 FunctionTemplateDecl 'timesTwo'
1787 |-TemplateTypeParmDecl 'T'
1788 |-FunctionDecl 'timesTwo'
1789 | |-ParmVarDecl 'input'
1790 | `-CompoundStmt
1791 | `-ReturnStmt
1792 | `-BinaryOperator
1793 | |-DeclRefExpr 'input'
1794 | `-IntegerLiteral
1795 |-FunctionDecl 'timesTwo'
1796 | |-TemplateArgument type int
1797 | | `-BuiltinType
1798 | |-ParmVarDecl 'input'
1799 | `-CompoundStmt
1800 | `-ReturnStmt
1801 | `-BinaryOperator
1802 | |-ImplicitCastExpr
1803 | | `-DeclRefExpr 'input'
1804 | `-IntegerLiteral
1805 |-FunctionDecl 'timesTwo'
1806 | |-TemplateArgument type double
1807 | | `-BuiltinType
1808 | |-ParmVarDecl 'input'
1809 | `-CompoundStmt
1810 | `-ReturnStmt
1811 | `-BinaryOperator
1812 | |-ImplicitCastExpr
1813 | | `-DeclRefExpr 'input'
1814 | `-ImplicitCastExpr
1815 | `-IntegerLiteral
1816 |-FunctionDecl 'timesTwo'
1817 | |-TemplateArgument type float
1818 | | `-BuiltinType
1819 | |-ParmVarDecl 'input'
1820 | `-CompoundStmt
1821 | `-ReturnStmt
1822 | `-BinaryOperator
1823 | |-ImplicitCastExpr
1824 | | `-DeclRefExpr 'input'
1825 | `-ImplicitCastExpr
1826 | `-IntegerLiteral
1827 |-FunctionDecl 'timesTwo'
1828 | |-TemplateArgument type _Bool
1829 | | `-BuiltinType
1830 | |-ParmVarDecl ''
1831 | `-CompoundStmt
1832 | `-ReturnStmt
1833 | `-CXXBoolLiteralExpr
1834 `-FunctionDecl 'timesTwo'
1835 |-TemplateArgument type _Bool
1836 | `-BuiltinType
1837 `-ParmVarDecl 'input'
1838 )cpp");
1841 auto BN = ast_matchers::match(
1842 classTemplateSpecializationDecl(
1843 hasName("TemplStruct"),
1844 hasTemplateArgument(
1845 0, templateArgument(refersToType(asString("float")))),
1846 hasParent(translationUnitDecl()))
1847 .bind("rec"),
1848 AST->getASTContext());
1849 EXPECT_EQ(BN.size(), 1u);
1851 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1852 BN[0].getNodeAs<Decl>("rec")),
1853 R"cpp(
1854 ClassTemplateSpecializationDecl 'TemplStruct'
1855 `-TemplateArgument type float
1856 `-BuiltinType
1857 )cpp");
1859 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1860 R"cpp(
1861 ClassTemplateSpecializationDecl 'TemplStruct'
1862 |-TemplateArgument type float
1863 | `-BuiltinType
1864 |-CXXRecordDecl 'TemplStruct'
1865 |-CXXConstructorDecl 'TemplStruct'
1866 | `-CompoundStmt
1867 |-CXXDestructorDecl '~TemplStruct'
1868 | `-CompoundStmt
1869 |-AccessSpecDecl
1870 `-FieldDecl 'm_t'
1871 )cpp");
1875 TEST(Traverse, CXXRewrittenBinaryOperator) {
1877 auto AST = buildASTFromCodeWithArgs(R"cpp(
1878 namespace std {
1879 struct strong_ordering {
1880 int n;
1881 constexpr operator int() const { return n; }
1882 static const strong_ordering equal, greater, less;
1884 constexpr strong_ordering strong_ordering::equal = {0};
1885 constexpr strong_ordering strong_ordering::greater = {1};
1886 constexpr strong_ordering strong_ordering::less = {-1};
1889 struct HasSpaceshipMem {
1890 int a;
1891 constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
1894 void binop()
1896 HasSpaceshipMem hs1, hs2;
1897 if (hs1 < hs2)
1898 return;
1900 )cpp",
1901 {"-std=c++20"});
1903 auto BN = ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"),
1904 AST->getASTContext());
1905 EXPECT_EQ(BN.size(), 1u);
1907 EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Stmt>("binop")),
1908 R"cpp(
1909 CXXRewrittenBinaryOperator
1910 `-BinaryOperator
1911 |-ImplicitCastExpr
1912 | `-CXXMemberCallExpr
1913 | `-MemberExpr
1914 | `-ImplicitCastExpr
1915 | `-MaterializeTemporaryExpr
1916 | `-CXXOperatorCallExpr
1917 | |-ImplicitCastExpr
1918 | | `-DeclRefExpr 'operator<=>'
1919 | |-ImplicitCastExpr
1920 | | `-DeclRefExpr 'hs1'
1921 | `-ImplicitCastExpr
1922 | `-DeclRefExpr 'hs2'
1923 `-IntegerLiteral
1924 )cpp");
1925 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1926 BN[0].getNodeAs<Stmt>("binop")),
1927 R"cpp(
1928 CXXRewrittenBinaryOperator
1929 |-DeclRefExpr 'hs1'
1930 `-DeclRefExpr 'hs2'
1931 )cpp");
1935 } // namespace clang