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