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

source code of clang/unittests/AST/ASTTraverserTest.cpp