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