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