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().getAsString() << "'";
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().getAsString();
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 OS.str();
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 OS.str();
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 = 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 
TEST(Traverse,IgnoreUnlessSpelledInSourceStructs)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 
TEST(Traverse,IgnoreUnlessSpelledInSourceReturnStruct)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 
TEST(Traverse,IgnoreUnlessSpelledInSourceReturns)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 
TEST(Traverse,LambdaUnlessSpelledInSource)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 
TEST(Traverse,IgnoreUnlessSpelledInSourceImplicit)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 )cpp",
1152                                        {"-std=c++20"});
1153 
1154   {
1155     auto BN = ast_matchers::match(
1156         cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),
1157         AST2->getASTContext());
1158     EXPECT_EQ(BN.size(), 1u);
1159 
1160     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1161               R"cpp(
1162 CXXRecordDecl 'Record'
1163 |-CXXRecordDecl 'Record'
1164 |-CXXConstructorDecl 'Record'
1165 | |-CXXCtorInitializer 'struct Simple'
1166 | | `-CXXConstructExpr
1167 | |-CXXCtorInitializer 'struct Other'
1168 | | `-CXXConstructExpr
1169 | |-CXXCtorInitializer 'm_i'
1170 | | `-IntegerLiteral
1171 | |-CXXCtorInitializer 'm_i2'
1172 | | `-CXXDefaultInitExpr
1173 | |-CXXCtorInitializer 'm_s'
1174 | | `-CXXConstructExpr
1175 | `-CompoundStmt
1176 |-AccessSpecDecl
1177 |-FieldDecl 'm_i'
1178 |-FieldDecl 'm_i2'
1179 | `-IntegerLiteral
1180 `-FieldDecl 'm_s'
1181 )cpp");
1182 
1183     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1184                             BN[0].getNodeAs<Decl>("rec")),
1185               R"cpp(
1186 CXXRecordDecl 'Record'
1187 |-CXXConstructorDecl 'Record'
1188 | |-CXXCtorInitializer 'struct Simple'
1189 | | `-CXXConstructExpr
1190 | |-CXXCtorInitializer 'm_i'
1191 | | `-IntegerLiteral
1192 | `-CompoundStmt
1193 |-AccessSpecDecl
1194 |-FieldDecl 'm_i'
1195 |-FieldDecl 'm_i2'
1196 | `-IntegerLiteral
1197 `-FieldDecl 'm_s'
1198 )cpp");
1199   }
1200   {
1201     auto BN = ast_matchers::match(
1202         cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))
1203             .bind("rec"),
1204         AST2->getASTContext());
1205     EXPECT_EQ(BN.size(), 1u);
1206 
1207     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1208               R"cpp(
1209 CXXRecordDecl 'ContainsArray'
1210 |-CXXRecordDecl 'ContainsArray'
1211 |-FieldDecl 'arr'
1212 |-FieldDecl 'irr'
1213 |-CXXMethodDecl 'operator='
1214 | |-ParmVarDecl ''
1215 | `-CompoundStmt
1216 |   |-ForStmt
1217 |   | |-DeclStmt
1218 |   | | `-VarDecl '__i0'
1219 |   | |   `-IntegerLiteral
1220 |   | |-<<<NULL>>>
1221 |   | |-BinaryOperator
1222 |   | | |-ImplicitCastExpr
1223 |   | | | `-DeclRefExpr '__i0'
1224 |   | | `-IntegerLiteral
1225 |   | |-UnaryOperator
1226 |   | | `-DeclRefExpr '__i0'
1227 |   | `-CXXMemberCallExpr
1228 |   |   |-MemberExpr
1229 |   |   | `-ArraySubscriptExpr
1230 |   |   |   |-ImplicitCastExpr
1231 |   |   |   | `-MemberExpr
1232 |   |   |   |   `-CXXThisExpr
1233 |   |   |   `-ImplicitCastExpr
1234 |   |   |     `-DeclRefExpr '__i0'
1235 |   |   `-ArraySubscriptExpr
1236 |   |     |-ImplicitCastExpr
1237 |   |     | `-MemberExpr
1238 |   |     |   `-DeclRefExpr ''
1239 |   |     `-ImplicitCastExpr
1240 |   |       `-DeclRefExpr '__i0'
1241 |   |-CallExpr
1242 |   | |-ImplicitCastExpr
1243 |   | | `-DeclRefExpr '__builtin_memcpy'
1244 |   | |-ImplicitCastExpr
1245 |   | | `-UnaryOperator
1246 |   | |   `-MemberExpr
1247 |   | |     `-CXXThisExpr
1248 |   | |-ImplicitCastExpr
1249 |   | | `-UnaryOperator
1250 |   | |   `-MemberExpr
1251 |   | |     `-DeclRefExpr ''
1252 |   | `-IntegerLiteral
1253 |   `-ReturnStmt
1254 |     `-UnaryOperator
1255 |       `-CXXThisExpr
1256 |-CXXConstructorDecl 'ContainsArray'
1257 | `-ParmVarDecl ''
1258 |-CXXDestructorDecl '~ContainsArray'
1259 | `-CompoundStmt
1260 `-CXXConstructorDecl 'ContainsArray'
1261   |-CXXCtorInitializer 'arr'
1262   | `-CXXConstructExpr
1263   `-CompoundStmt
1264 )cpp");
1265 
1266     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1267                             BN[0].getNodeAs<Decl>("rec")),
1268               R"cpp(
1269 CXXRecordDecl 'ContainsArray'
1270 |-FieldDecl 'arr'
1271 |-FieldDecl 'irr'
1272 `-CXXMethodDecl 'operator='
1273   `-ParmVarDecl ''
1274 )cpp");
1275   }
1276   {
1277     auto BN = ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),
1278                                   AST2->getASTContext());
1279     EXPECT_EQ(BN.size(), 1u);
1280 
1281     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("func")),
1282               R"cpp(
1283 FunctionDecl 'forLoop'
1284 `-CompoundStmt
1285   |-DeclStmt
1286   | `-VarDecl 'arr'
1287   |-CXXForRangeStmt
1288   | |-<<<NULL>>>
1289   | |-DeclStmt
1290   | | `-VarDecl '__range1'
1291   | |   `-DeclRefExpr 'arr'
1292   | |-DeclStmt
1293   | | `-VarDecl '__begin1'
1294   | |   `-ImplicitCastExpr
1295   | |     `-DeclRefExpr '__range1'
1296   | |-DeclStmt
1297   | | `-VarDecl '__end1'
1298   | |   `-BinaryOperator
1299   | |     |-ImplicitCastExpr
1300   | |     | `-DeclRefExpr '__range1'
1301   | |     `-IntegerLiteral
1302   | |-BinaryOperator
1303   | | |-ImplicitCastExpr
1304   | | | `-DeclRefExpr '__begin1'
1305   | | `-ImplicitCastExpr
1306   | |   `-DeclRefExpr '__end1'
1307   | |-UnaryOperator
1308   | | `-DeclRefExpr '__begin1'
1309   | |-DeclStmt
1310   | | `-VarDecl 'i'
1311   | |   `-ImplicitCastExpr
1312   | |     `-UnaryOperator
1313   | |       `-ImplicitCastExpr
1314   | |         `-DeclRefExpr '__begin1'
1315   | `-CompoundStmt
1316   `-CXXForRangeStmt
1317     |-DeclStmt
1318     | `-VarDecl 'a'
1319     |   `-DeclRefExpr 'arr'
1320     |-DeclStmt
1321     | `-VarDecl '__range1'
1322     |   `-DeclRefExpr 'a'
1323     |-DeclStmt
1324     | `-VarDecl '__begin1'
1325     |   `-ImplicitCastExpr
1326     |     `-DeclRefExpr '__range1'
1327     |-DeclStmt
1328     | `-VarDecl '__end1'
1329     |   `-BinaryOperator
1330     |     |-ImplicitCastExpr
1331     |     | `-DeclRefExpr '__range1'
1332     |     `-IntegerLiteral
1333     |-BinaryOperator
1334     | |-ImplicitCastExpr
1335     | | `-DeclRefExpr '__begin1'
1336     | `-ImplicitCastExpr
1337     |   `-DeclRefExpr '__end1'
1338     |-UnaryOperator
1339     | `-DeclRefExpr '__begin1'
1340     |-DeclStmt
1341     | `-VarDecl 'i'
1342     |   `-ImplicitCastExpr
1343     |     `-UnaryOperator
1344     |       `-ImplicitCastExpr
1345     |         `-DeclRefExpr '__begin1'
1346     `-CompoundStmt
1347 )cpp");
1348 
1349     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1350                             BN[0].getNodeAs<Decl>("func")),
1351               R"cpp(
1352 FunctionDecl 'forLoop'
1353 `-CompoundStmt
1354   |-DeclStmt
1355   | `-VarDecl 'arr'
1356   |-CXXForRangeStmt
1357   | |-<<<NULL>>>
1358   | |-VarDecl 'i'
1359   | |-DeclRefExpr 'arr'
1360   | `-CompoundStmt
1361   `-CXXForRangeStmt
1362     |-DeclStmt
1363     | `-VarDecl 'a'
1364     |   `-DeclRefExpr 'arr'
1365     |-VarDecl 'i'
1366     |-DeclRefExpr 'a'
1367     `-CompoundStmt
1368 )cpp");
1369   }
1370   {
1371     auto BN = ast_matchers::match(
1372         cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))
1373             .bind("rec"),
1374         AST2->getASTContext());
1375     EXPECT_EQ(BN.size(), 1u);
1376 
1377     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1378               R"cpp(
1379 CXXRecordDecl 'DefaultedAndDeleted'
1380 |-CXXRecordDecl 'DefaultedAndDeleted'
1381 |-FieldDecl 'nt'
1382 |-CXXConstructorDecl 'DefaultedAndDeleted'
1383 | |-CXXCtorInitializer 'nt'
1384 | | `-CXXConstructExpr
1385 | `-CompoundStmt
1386 |-CXXDestructorDecl '~DefaultedAndDeleted'
1387 | `-CompoundStmt
1388 |-CXXConstructorDecl 'DefaultedAndDeleted'
1389 | `-ParmVarDecl ''
1390 |-CXXMethodDecl 'operator='
1391 | |-ParmVarDecl ''
1392 | `-CompoundStmt
1393 |   |-CXXMemberCallExpr
1394 |   | |-MemberExpr
1395 |   | | `-MemberExpr
1396 |   | |   `-CXXThisExpr
1397 |   | `-MemberExpr
1398 |   |   `-DeclRefExpr ''
1399 |   `-ReturnStmt
1400 |     `-UnaryOperator
1401 |       `-CXXThisExpr
1402 |-CXXConstructorDecl 'DefaultedAndDeleted'
1403 | `-ParmVarDecl ''
1404 `-CXXMethodDecl 'operator='
1405   `-ParmVarDecl ''
1406 )cpp");
1407 
1408     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1409                             BN[0].getNodeAs<Decl>("rec")),
1410               R"cpp(
1411 CXXRecordDecl 'DefaultedAndDeleted'
1412 |-FieldDecl 'nt'
1413 |-CXXConstructorDecl 'DefaultedAndDeleted'
1414 |-CXXDestructorDecl '~DefaultedAndDeleted'
1415 |-CXXConstructorDecl 'DefaultedAndDeleted'
1416 | `-ParmVarDecl ''
1417 |-CXXMethodDecl 'operator='
1418 | `-ParmVarDecl ''
1419 |-CXXConstructorDecl 'DefaultedAndDeleted'
1420 | `-ParmVarDecl ''
1421 `-CXXMethodDecl 'operator='
1422   `-ParmVarDecl ''
1423 )cpp");
1424   }
1425   {
1426     auto BN = ast_matchers::match(
1427         callExpr(callee(functionDecl(hasName("hasDefaultArg"))))
1428             .bind("funcCall"),
1429         AST2->getASTContext());
1430     EXPECT_EQ(BN.size(), 1u);
1431 
1432     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<CallExpr>("funcCall")),
1433               R"cpp(
1434 CallExpr
1435 |-ImplicitCastExpr
1436 | `-DeclRefExpr 'hasDefaultArg'
1437 |-IntegerLiteral
1438 `-CXXDefaultArgExpr
1439 )cpp");
1440     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1441                             BN[0].getNodeAs<CallExpr>("funcCall")),
1442               R"cpp(
1443 CallExpr
1444 |-DeclRefExpr 'hasDefaultArg'
1445 `-IntegerLiteral
1446 )cpp");
1447   }
1448 }
1449 
TEST(Traverse,IgnoreUnlessSpelledInSourceTemplateInstantiations)1450 TEST(Traverse, IgnoreUnlessSpelledInSourceTemplateInstantiations) {
1451 
1452   auto AST = buildASTFromCode(R"cpp(
1453 template<typename T>
1454 struct TemplStruct {
1455   TemplStruct() {}
1456   ~TemplStruct() {}
1457 
1458 private:
1459   T m_t;
1460 };
1461 
1462 template<typename T>
1463 T timesTwo(T input)
1464 {
1465   return input * 2;
1466 }
1467 
1468 void instantiate()
1469 {
1470   TemplStruct<int> ti;
1471   TemplStruct<double> td;
1472   (void)timesTwo<int>(2);
1473   (void)timesTwo<double>(2);
1474 }
1475 
1476 template class TemplStruct<float>;
1477 
1478 extern template class TemplStruct<long>;
1479 
1480 template<> class TemplStruct<bool> {
1481   TemplStruct() {}
1482   ~TemplStruct() {}
1483 
1484   void foo() {}
1485 private:
1486   bool m_t;
1487 };
1488 
1489 // Explicit instantiation of template functions do not appear in the AST
1490 template float timesTwo(float);
1491 
1492 template<> bool timesTwo<bool>(bool) {
1493   return true;
1494 }
1495 )cpp");
1496   {
1497     auto BN = ast_matchers::match(
1498         classTemplateDecl(hasName("TemplStruct")).bind("rec"),
1499         AST->getASTContext());
1500     EXPECT_EQ(BN.size(), 1u);
1501 
1502     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1503                             BN[0].getNodeAs<Decl>("rec")),
1504               R"cpp(
1505 ClassTemplateDecl 'TemplStruct'
1506 |-TemplateTypeParmDecl 'T'
1507 `-CXXRecordDecl 'TemplStruct'
1508   |-CXXConstructorDecl 'TemplStruct<T>'
1509   | `-CompoundStmt
1510   |-CXXDestructorDecl '~TemplStruct<T>'
1511   | `-CompoundStmt
1512   |-AccessSpecDecl
1513   `-FieldDecl 'm_t'
1514 )cpp");
1515 
1516     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1517               R"cpp(
1518 ClassTemplateDecl 'TemplStruct'
1519 |-TemplateTypeParmDecl 'T'
1520 |-CXXRecordDecl 'TemplStruct'
1521 | |-CXXRecordDecl 'TemplStruct'
1522 | |-CXXConstructorDecl 'TemplStruct<T>'
1523 | | `-CompoundStmt
1524 | |-CXXDestructorDecl '~TemplStruct<T>'
1525 | | `-CompoundStmt
1526 | |-AccessSpecDecl
1527 | `-FieldDecl 'm_t'
1528 |-ClassTemplateSpecializationDecl 'TemplStruct'
1529 | |-TemplateArgument type int
1530 | | `-BuiltinType
1531 | |-CXXRecordDecl 'TemplStruct'
1532 | |-CXXConstructorDecl 'TemplStruct'
1533 | | `-CompoundStmt
1534 | |-CXXDestructorDecl '~TemplStruct'
1535 | | `-CompoundStmt
1536 | |-AccessSpecDecl
1537 | |-FieldDecl 'm_t'
1538 | `-CXXConstructorDecl 'TemplStruct'
1539 |   `-ParmVarDecl ''
1540 |-ClassTemplateSpecializationDecl 'TemplStruct'
1541 | |-TemplateArgument type double
1542 | | `-BuiltinType
1543 | |-CXXRecordDecl 'TemplStruct'
1544 | |-CXXConstructorDecl 'TemplStruct'
1545 | | `-CompoundStmt
1546 | |-CXXDestructorDecl '~TemplStruct'
1547 | | `-CompoundStmt
1548 | |-AccessSpecDecl
1549 | |-FieldDecl 'm_t'
1550 | `-CXXConstructorDecl 'TemplStruct'
1551 |   `-ParmVarDecl ''
1552 |-ClassTemplateSpecializationDecl 'TemplStruct'
1553 | |-TemplateArgument type float
1554 | | `-BuiltinType
1555 | |-CXXRecordDecl 'TemplStruct'
1556 | |-CXXConstructorDecl 'TemplStruct'
1557 | | `-CompoundStmt
1558 | |-CXXDestructorDecl '~TemplStruct'
1559 | | `-CompoundStmt
1560 | |-AccessSpecDecl
1561 | `-FieldDecl 'm_t'
1562 |-ClassTemplateSpecializationDecl 'TemplStruct'
1563 | |-TemplateArgument type long
1564 | | `-BuiltinType
1565 | |-CXXRecordDecl 'TemplStruct'
1566 | |-CXXConstructorDecl 'TemplStruct'
1567 | |-CXXDestructorDecl '~TemplStruct'
1568 | |-AccessSpecDecl
1569 | `-FieldDecl 'm_t'
1570 `-ClassTemplateSpecializationDecl 'TemplStruct'
1571   |-TemplateArgument type _Bool
1572   | `-BuiltinType
1573   |-CXXRecordDecl 'TemplStruct'
1574   |-CXXConstructorDecl 'TemplStruct'
1575   | `-CompoundStmt
1576   |-CXXDestructorDecl '~TemplStruct'
1577   | `-CompoundStmt
1578   |-CXXMethodDecl 'foo'
1579   | `-CompoundStmt
1580   |-AccessSpecDecl
1581   `-FieldDecl 'm_t'
1582 )cpp");
1583   }
1584   {
1585     auto BN = ast_matchers::match(
1586         classTemplateSpecializationDecl(
1587             hasTemplateArgument(
1588                 0, templateArgument(refersToType(asString("_Bool")))))
1589             .bind("templSpec"),
1590         AST->getASTContext());
1591     EXPECT_EQ(BN.size(), 1u);
1592 
1593     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("templSpec")),
1594               R"cpp(
1595 ClassTemplateSpecializationDecl 'TemplStruct'
1596 |-TemplateArgument type _Bool
1597 | `-BuiltinType
1598 |-CXXRecordDecl 'TemplStruct'
1599 |-CXXConstructorDecl 'TemplStruct'
1600 | `-CompoundStmt
1601 |-CXXDestructorDecl '~TemplStruct'
1602 | `-CompoundStmt
1603 |-CXXMethodDecl 'foo'
1604 | `-CompoundStmt
1605 |-AccessSpecDecl
1606 `-FieldDecl 'm_t'
1607 )cpp");
1608 
1609     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1610                             BN[0].getNodeAs<Decl>("templSpec")),
1611               R"cpp(
1612 ClassTemplateSpecializationDecl 'TemplStruct'
1613 |-TemplateArgument type _Bool
1614 | `-BuiltinType
1615 |-CXXConstructorDecl 'TemplStruct'
1616 | `-CompoundStmt
1617 |-CXXDestructorDecl '~TemplStruct'
1618 | `-CompoundStmt
1619 |-CXXMethodDecl 'foo'
1620 | `-CompoundStmt
1621 |-AccessSpecDecl
1622 `-FieldDecl 'm_t'
1623 )cpp");
1624   }
1625   {
1626     auto BN = ast_matchers::match(
1627         functionTemplateDecl(hasName("timesTwo")).bind("fn"),
1628         AST->getASTContext());
1629     EXPECT_EQ(BN.size(), 1u);
1630 
1631     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1632                             BN[0].getNodeAs<Decl>("fn")),
1633               R"cpp(
1634 FunctionTemplateDecl 'timesTwo'
1635 |-TemplateTypeParmDecl 'T'
1636 `-FunctionDecl 'timesTwo'
1637   |-ParmVarDecl 'input'
1638   `-CompoundStmt
1639     `-ReturnStmt
1640       `-BinaryOperator
1641         |-DeclRefExpr 'input'
1642         `-IntegerLiteral
1643 )cpp");
1644 
1645     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("fn")),
1646               R"cpp(
1647 FunctionTemplateDecl 'timesTwo'
1648 |-TemplateTypeParmDecl 'T'
1649 |-FunctionDecl 'timesTwo'
1650 | |-ParmVarDecl 'input'
1651 | `-CompoundStmt
1652 |   `-ReturnStmt
1653 |     `-BinaryOperator
1654 |       |-DeclRefExpr 'input'
1655 |       `-IntegerLiteral
1656 |-FunctionDecl 'timesTwo'
1657 | |-TemplateArgument type int
1658 | | `-BuiltinType
1659 | |-ParmVarDecl 'input'
1660 | `-CompoundStmt
1661 |   `-ReturnStmt
1662 |     `-BinaryOperator
1663 |       |-ImplicitCastExpr
1664 |       | `-DeclRefExpr 'input'
1665 |       `-IntegerLiteral
1666 |-FunctionDecl 'timesTwo'
1667 | |-TemplateArgument type double
1668 | | `-BuiltinType
1669 | |-ParmVarDecl 'input'
1670 | `-CompoundStmt
1671 |   `-ReturnStmt
1672 |     `-BinaryOperator
1673 |       |-ImplicitCastExpr
1674 |       | `-DeclRefExpr 'input'
1675 |       `-ImplicitCastExpr
1676 |         `-IntegerLiteral
1677 |-FunctionDecl 'timesTwo'
1678 | |-TemplateArgument type float
1679 | | `-BuiltinType
1680 | |-ParmVarDecl 'input'
1681 | `-CompoundStmt
1682 |   `-ReturnStmt
1683 |     `-BinaryOperator
1684 |       |-ImplicitCastExpr
1685 |       | `-DeclRefExpr 'input'
1686 |       `-ImplicitCastExpr
1687 |         `-IntegerLiteral
1688 |-FunctionDecl 'timesTwo'
1689 | |-TemplateArgument type _Bool
1690 | | `-BuiltinType
1691 | |-ParmVarDecl ''
1692 | `-CompoundStmt
1693 |   `-ReturnStmt
1694 |     `-CXXBoolLiteralExpr
1695 `-FunctionDecl 'timesTwo'
1696   |-TemplateArgument type _Bool
1697   | `-BuiltinType
1698   `-ParmVarDecl 'input'
1699 )cpp");
1700   }
1701   {
1702     auto BN = ast_matchers::match(
1703         classTemplateSpecializationDecl(
1704             hasName("TemplStruct"),
1705             hasTemplateArgument(
1706                 0, templateArgument(refersToType(asString("float")))),
1707             hasParent(translationUnitDecl()))
1708             .bind("rec"),
1709         AST->getASTContext());
1710     EXPECT_EQ(BN.size(), 1u);
1711 
1712     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1713                             BN[0].getNodeAs<Decl>("rec")),
1714               R"cpp(
1715 ClassTemplateSpecializationDecl 'TemplStruct'
1716 `-TemplateArgument type float
1717   `-BuiltinType
1718 )cpp");
1719 
1720     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Decl>("rec")),
1721               R"cpp(
1722 ClassTemplateSpecializationDecl 'TemplStruct'
1723 |-TemplateArgument type float
1724 | `-BuiltinType
1725 |-CXXRecordDecl 'TemplStruct'
1726 |-CXXConstructorDecl 'TemplStruct'
1727 | `-CompoundStmt
1728 |-CXXDestructorDecl '~TemplStruct'
1729 | `-CompoundStmt
1730 |-AccessSpecDecl
1731 `-FieldDecl 'm_t'
1732 )cpp");
1733   }
1734 }
1735 
TEST(Traverse,CXXRewrittenBinaryOperator)1736 TEST(Traverse, CXXRewrittenBinaryOperator) {
1737 
1738   auto AST = buildASTFromCodeWithArgs(R"cpp(
1739 namespace std {
1740 struct strong_ordering {
1741   int n;
1742   constexpr operator int() const { return n; }
1743   static const strong_ordering equal, greater, less;
1744 };
1745 constexpr strong_ordering strong_ordering::equal = {0};
1746 constexpr strong_ordering strong_ordering::greater = {1};
1747 constexpr strong_ordering strong_ordering::less = {-1};
1748 }
1749 
1750 struct HasSpaceshipMem {
1751   int a;
1752   constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
1753 };
1754 
1755 void binop()
1756 {
1757     HasSpaceshipMem hs1, hs2;
1758     if (hs1 < hs2)
1759         return;
1760 }
1761 )cpp",
1762                                       {"-std=c++20"});
1763   {
1764     auto BN = ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"),
1765                                   AST->getASTContext());
1766     EXPECT_EQ(BN.size(), 1u);
1767 
1768     EXPECT_EQ(dumpASTString(TK_AsIs, BN[0].getNodeAs<Stmt>("binop")),
1769               R"cpp(
1770 CXXRewrittenBinaryOperator
1771 `-BinaryOperator
1772   |-ImplicitCastExpr
1773   | `-CXXMemberCallExpr
1774   |   `-MemberExpr
1775   |     `-ImplicitCastExpr
1776   |       `-MaterializeTemporaryExpr
1777   |         `-CXXOperatorCallExpr
1778   |           |-ImplicitCastExpr
1779   |           | `-DeclRefExpr 'operator<=>'
1780   |           |-ImplicitCastExpr
1781   |           | `-DeclRefExpr 'hs1'
1782   |           `-ImplicitCastExpr
1783   |             `-DeclRefExpr 'hs2'
1784   `-IntegerLiteral
1785 )cpp");
1786     EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource,
1787                             BN[0].getNodeAs<Stmt>("binop")),
1788               R"cpp(
1789 CXXRewrittenBinaryOperator
1790 |-DeclRefExpr 'hs1'
1791 `-DeclRefExpr 'hs2'
1792 )cpp");
1793   }
1794 }
1795 
1796 } // namespace clang
1797