1 //===- unittests/AST/ASTTraverserTest.h------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
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"
18 using namespace clang::tooling
;
19 using namespace clang::ast_matchers
;
23 class NodeTreePrinter
: public TextTreeStructure
{
24 llvm::raw_ostream
&OS
;
27 NodeTreePrinter(llvm::raw_ostream
&OS
)
28 : TextTreeStructure(OS
, /* showColors */ false), OS(OS
) {}
30 void Visit(const Decl
*D
) {
31 OS
<< D
->getDeclKindName() << "Decl";
32 if (auto *ND
= dyn_cast
<NamedDecl
>(D
)) {
33 OS
<< " '" << ND
->getDeclName() << "'";
37 void Visit(const Stmt
*S
) {
42 OS
<< S
->getStmtClassName();
43 if (auto *E
= dyn_cast
<DeclRefExpr
>(S
)) {
44 OS
<< " '" << E
->getDecl()->getDeclName() << "'";
48 void Visit(QualType QT
) {
49 OS
<< "QualType " << QT
.split().Quals
.getAsString();
52 void Visit(const Type
*T
) { OS
<< T
->getTypeClassName() << "Type"; }
54 void Visit(const comments::Comment
*C
, const comments::FullComment
*FC
) {
55 OS
<< C
->getCommentKindName();
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() << "'";
67 void Visit(const Attr
*A
) {
68 switch (A
->getKind()) {
73 #include "clang/Basic/AttrList.inc"
78 void Visit(const OMPClause
*C
) { OS
<< "OMPClause"; }
79 void Visit(const TemplateArgument
&A
, SourceRange R
= {},
80 const Decl
*From
= nullptr, const char *Label
= nullptr) {
81 OS
<< "TemplateArgument";
82 switch (A
.getKind()) {
83 case TemplateArgument::Type
: {
84 OS
<< " type " << A
.getAsType();
92 template <typename
... T
> void Visit(T
...) {}
95 class TestASTDumper
: public ASTNodeTraverser
<TestASTDumper
, NodeTreePrinter
> {
97 NodeTreePrinter MyNodeRecorder
;
100 TestASTDumper(llvm::raw_ostream
&OS
) : MyNodeRecorder(OS
) {}
101 NodeTreePrinter
&doGetNodeDelegate() { return MyNodeRecorder
; }
104 template <typename
... NodeType
> std::string
dumpASTString(NodeType
&&... N
) {
106 llvm::raw_string_ostream
OS(Buffer
);
108 TestASTDumper
Dumper(OS
);
112 Dumper
.Visit(std::forward
<NodeType
&&>(N
)...);
117 template <typename
... NodeType
>
118 std::string
dumpASTString(TraversalKind TK
, NodeType
&&... N
) {
120 llvm::raw_string_ostream
OS(Buffer
);
122 TestASTDumper
Dumper(OS
);
123 Dumper
.SetTraversalKind(TK
);
127 Dumper
.Visit(std::forward
<NodeType
&&>(N
)...);
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");
140 template <typename T
> struct Verifier
{
141 static void withDynNode(T Node
, const std::string
&DumpString
) {
142 EXPECT_EQ(dumpASTString(DynTypedNode::create(Node
)), DumpString
);
146 template <typename T
> struct Verifier
<T
*> {
147 static void withDynNode(T
*Node
, const std::string
&DumpString
) {
148 EXPECT_EQ(dumpASTString(DynTypedNode::create(*Node
)), DumpString
);
152 template <typename T
>
153 void verifyWithDynNode(T Node
, const std::string
&DumpString
) {
154 EXPECT_EQ(dumpASTString(Node
), DumpString
);
156 Verifier
<T
>::withDynNode(Node
, DumpString
);
159 TEST(Traverse
, Dump
) {
161 auto AST
= buildASTFromCode(R
"cpp(
166 A() : m_number(42) {}
168 [[nodiscard]] const int func() {
184 void parmvardecl_attr(struct A __attribute__((address_space(19)))*);
188 const FunctionDecl
*Func
= getFunctionNode(AST
.get(), "func");
190 verifyWithDynNode(Func
,
196 `-WarnUnusedResultAttr
199 Stmt
*Body
= Func
->getBody();
201 verifyWithDynNode(Body
,
208 QualType QT
= Func
->getType();
210 verifyWithDynNode(QT
,
217 const FunctionDecl
*CTorFunc
= getFunctionNode(AST
.get(), "A");
219 verifyWithDynNode(CTorFunc
->getType(),
225 Attr
*A
= *Func
->attr_begin();
228 std::string expectedString
= R
"cpp(
232 EXPECT_EQ(dumpASTString(A
), expectedString
);
235 auto *CTor
= dyn_cast
<CXXConstructorDecl
>(CTorFunc
);
236 const CXXCtorInitializer
*Init
= *CTor
->init_begin();
238 verifyWithDynNode(Init
,
240 CXXCtorInitializer 'm_number'
244 const comments::FullComment
*Comment
=
245 AST
->getASTContext().getLocalCommentForDeclUncached(CTorFunc
);
247 std::string expectedString
= R
"cpp(
252 EXPECT_EQ(dumpASTString(Comment
, Comment
), expectedString
);
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");
261 TemplateArgument TA
= Templ
->getTemplateArgs()[0];
263 verifyWithDynNode(TA
,
265 TemplateArgument type int
269 Func
= getFunctionNode(AST
.get(), "parmvardecl_attr");
271 const auto *Parm
= Func
->getParamDecl(0);
272 const auto TL
= Parm
->getTypeSourceInfo()->getTypeLoc();
273 ASSERT_TRUE(TL
.getType()->isPointerType());
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())),
281 TEST(Traverse
, IgnoreUnlessSpelledInSourceVars
) {
283 auto AST
= buildASTFromCodeWithArgs(R
"cpp(
287 String(const char*, int = -1) {}
289 int overloaded() const;
293 void stringConstruct()
306 struct C2 { operator C1(); };
308 void conversionOperator()
314 template <unsigned alignment>
315 void template_test() {
316 static_assert(alignment, "");
318 void actual_template_test() {
322 struct OneParamCtor {
323 explicit OneParamCtor(int);
325 struct TwoParamCtor {
326 explicit TwoParamCtor(int, int);
329 void varDeclCtors() {
331 auto var1 = OneParamCtor(5);
332 auto var2 = TwoParamCtor(6, 7);
335 OneParamCtor var3(5);
336 TwoParamCtor var4(6, 7);
340 auto var5 = OneParamCtor(i);
341 auto var6 = TwoParamCtor(i, 7);
344 OneParamCtor var7(i);
345 TwoParamCtor var8(i, 7);
349 )cpp", {"-std=c++14"});
353 ast_matchers::match(functionDecl(hasName("stringConstruct")).bind("fn"),
354 AST
->getASTContext());
355 EXPECT_EQ(FN
.size(), 1u);
357 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<Decl
>("fn")),
359 FunctionDecl 'stringConstruct'
365 | `-MaterializeTemporaryExpr
370 | `-CXXDefaultArgExpr
372 `-CXXOperatorCallExpr
374 | `-DeclRefExpr 'operator='
376 `-MaterializeTemporaryExpr
383 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
384 FN
[0].getNodeAs
<Decl
>("fn")),
386 FunctionDecl 'stringConstruct'
391 `-CXXOperatorCallExpr
392 |-DeclRefExpr 'operator='
400 ast_matchers::match(functionDecl(hasName("overloadCall")).bind("fn"),
401 AST
->getASTContext());
402 EXPECT_EQ(FN
.size(), 1u);
404 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<Decl
>("fn")),
406 FunctionDecl 'overloadCall'
412 | `-MaterializeTemporaryExpr
417 | `-CXXDefaultArgExpr
424 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
425 FN
[0].getNodeAs
<Decl
>("fn")),
427 FunctionDecl 'overloadCall'
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);
445 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<Decl
>("var")),
450 `-MaterializeTemporaryExpr
460 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
461 FN
[0].getNodeAs
<Decl
>("var")),
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);
476 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[1].getNodeAs
<Decl
>("staticAssert")),
480 | `-SubstNonTypeTemplateParmExpr
481 | |-NonTypeTemplateParmDecl 'alignment'
486 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
487 FN
[1].getNodeAs
<Decl
>("staticAssert")),
495 auto varChecker
= [&AST
](StringRef varName
, StringRef SemanticDump
,
496 StringRef SyntacticDump
) {
497 auto FN
= ast_matchers::match(
499 hasName("varDeclCtors"),
500 forEachDescendant(varDecl(hasName(varName
)).bind("varDeclCtor"))),
501 AST
->getASTContext());
502 EXPECT_EQ(FN
.size(), 1u);
504 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<Decl
>("varDeclCtor")),
507 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
508 FN
[0].getNodeAs
<Decl
>("varDeclCtor")),
517 `-MaterializeTemporaryExpr
518 `-CXXFunctionalCastExpr
533 `-MaterializeTemporaryExpr
534 `-CXXTemporaryObjectExpr
540 `-CXXTemporaryObjectExpr
576 `-MaterializeTemporaryExpr
577 `-CXXFunctionalCastExpr
593 `-MaterializeTemporaryExpr
594 `-CXXTemporaryObjectExpr
601 `-CXXTemporaryObjectExpr
635 TEST(Traverse
, IgnoreUnlessSpelledInSourceStructs
) {
636 auto AST
= buildASTFromCode(R
"cpp(
648 auto BN
= ast_matchers::match(
649 cxxConstructorDecl(hasName("MyStruct"),
650 hasParameter(0, parmVarDecl(hasType(isInteger()))))
652 AST
->getASTContext());
653 EXPECT_EQ(BN
.size(), 1u);
655 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
656 BN
[0].getNodeAs
<Decl
>("ctor")),
658 CXXConstructorDecl 'MyStruct'
661 `-CXXTemporaryObjectExpr
664 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("ctor")),
666 CXXConstructorDecl 'MyStruct'
670 `-CXXBindTemporaryExpr
671 `-CXXTemporaryObjectExpr
675 TEST(Traverse
, IgnoreUnlessSpelledInSourceReturnStruct
) {
677 auto AST
= buildASTFromCode(R
"cpp(
691 auto BN
= ast_matchers::match(functionDecl(hasName("foo")).bind("fn"),
692 AST
->getASTContext());
693 EXPECT_EQ(BN
.size(), 1u);
695 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
696 BN
[0].getNodeAs
<Decl
>("fn")),
701 `-DeclRefExpr 'someFun'
704 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("fn")),
709 `-CXXBindTemporaryExpr
712 `-DeclRefExpr 'someFun'
716 TEST(Traverse
, IgnoreUnlessSpelledInSourceReturns
) {
718 auto AST
= buildASTFromCodeWithArgs(R
"cpp(
787 )cpp", {"-std=c++14"});
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");
797 auto FN
= getFunctionNode("func1");
798 llvm::StringRef Expected
= R
"cpp(
804 `-MaterializeTemporaryExpr
810 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
), Expected
);
818 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, FN
), Expected
);
821 llvm::StringRef Expected
= R
"cpp(
825 `-CXXTemporaryObjectExpr
829 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func2")),
840 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func3")),
847 `-CXXTemporaryObjectExpr
850 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func4")),
857 `-CXXTemporaryObjectExpr
860 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func5")),
867 `-CXXTemporaryObjectExpr
870 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func6")),
877 `-CXXTemporaryObjectExpr
880 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func7")),
887 `-CXXFunctionalCastExpr
891 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func8")),
898 `-CXXFunctionalCastExpr
902 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func9")),
906 FunctionDecl 'func10'
915 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func10")),
919 FunctionDecl 'func11'
928 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func11")),
932 FunctionDecl 'func12'
941 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func12")),
945 TEST(Traverse
, LambdaUnlessSpelledInSource
) {
948 buildASTFromCodeWithArgs(R
"cpp(
956 [a, &b, c = d, &e = f](int g, int h = 42) {};
961 [a]<typename T>(T t) {};
966 void capture_this() {
969 void capture_this_copy() {
974 {"-Wno-unused-value", "-Wno-c++2a-extensions"});
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");
985 auto L
= getLambdaNode("captures");
987 llvm::StringRef Expected
= R
"cpp(
1000 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, L
), Expected
);
1005 | |-CXXMethodDecl 'operator()'
1006 | | |-ParmVarDecl 'g'
1007 | | |-ParmVarDecl 'h'
1008 | | | `-IntegerLiteral
1014 | `-CXXDestructorDecl '~(lambda at input.cc:9:3)'
1023 EXPECT_EQ(dumpASTString(TK_AsIs
, L
), Expected
);
1027 auto L
= getLambdaNode("templated");
1029 llvm::StringRef Expected
= R
"cpp(
1032 |-TemplateTypeParmDecl 'T'
1036 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, L
), Expected
);
1040 auto L
= getLambdaNode("capture_this");
1042 llvm::StringRef Expected
= R
"cpp(
1047 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, L
), Expected
);
1051 auto L
= getLambdaNode("capture_this_copy");
1053 llvm::StringRef Expected
= R
"cpp(
1060 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, L
), Expected
);
1064 TEST(Traverse
, IgnoreUnlessSpelledInSourceImplicit
) {
1066 auto AST
= buildASTFromCode(R
"cpp(
1069 const auto *TUDecl
= AST
->getASTContext().getTranslationUnitDecl();
1071 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, TUDecl
),
1079 auto AST2
= buildASTFromCodeWithArgs(R
"cpp(
1085 struct Record : Simple, Other {
1086 Record() : Simple(), m_i(42) {}
1095 NonTrivial(NonTrivial&) {}
1096 NonTrivial& operator=(NonTrivial&) { return *this; }
1101 struct ContainsArray {
1104 ContainsArray& operator=(ContainsArray &) = default;
1121 for (auto& a = arr; auto i : a)
1127 struct DefaultedAndDeleted {
1129 DefaultedAndDeleted() = default;
1130 ~DefaultedAndDeleted() = default;
1131 DefaultedAndDeleted(DefaultedAndDeleted &) = default;
1132 DefaultedAndDeleted& operator=(DefaultedAndDeleted &) = default;
1133 DefaultedAndDeleted(DefaultedAndDeleted &&) = delete;
1134 DefaultedAndDeleted& operator=(DefaultedAndDeleted &&) = delete;
1139 DefaultedAndDeleted ca;
1140 DefaultedAndDeleted ca2;
1144 void hasDefaultArg(int i, int j = 0)
1147 void callDefaultArg()
1152 void decomposition()
1155 auto &[f, s, t] = arr;
1160 typedef __typeof(sizeof(int)) size_t;
1167 // Note: these utilities are required to force binding to tuple like structure
1170 template <typename E>
1176 struct tuple_size<Pair>
1178 static constexpr size_t value = 2;
1181 template <size_t I, class T>
1182 struct tuple_element
1190 int &&get(Pair &&p);
1204 auto BN
= ast_matchers::match(
1205 cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),
1206 AST2
->getASTContext());
1207 EXPECT_EQ(BN
.size(), 1u);
1209 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1211 CXXRecordDecl 'Record'
1212 |-CXXRecordDecl 'Record'
1213 |-CXXConstructorDecl 'Record'
1214 | |-CXXCtorInitializer 'Simple'
1215 | | `-CXXConstructExpr
1216 | |-CXXCtorInitializer 'Other'
1217 | | `-CXXConstructExpr
1218 | |-CXXCtorInitializer 'm_i'
1219 | | `-IntegerLiteral
1220 | |-CXXCtorInitializer 'm_i2'
1221 | | `-CXXDefaultInitExpr
1222 | |-CXXCtorInitializer 'm_s'
1223 | | `-CXXConstructExpr
1232 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1233 BN
[0].getNodeAs
<Decl
>("rec")),
1235 CXXRecordDecl 'Record'
1236 |-CXXConstructorDecl 'Record'
1237 | |-CXXCtorInitializer 'Simple'
1238 | | `-CXXConstructExpr
1239 | |-CXXCtorInitializer 'm_i'
1240 | | `-IntegerLiteral
1250 auto BN
= ast_matchers::match(
1251 cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))
1253 AST2
->getASTContext());
1254 EXPECT_EQ(BN
.size(), 1u);
1256 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1258 CXXRecordDecl 'ContainsArray'
1259 |-CXXRecordDecl 'ContainsArray'
1262 |-CXXMethodDecl 'operator='
1267 | | | `-VarDecl '__i0'
1268 | | | `-IntegerLiteral
1270 | | |-BinaryOperator
1271 | | | |-ImplicitCastExpr
1272 | | | | `-DeclRefExpr '__i0'
1273 | | | `-IntegerLiteral
1275 | | | `-DeclRefExpr '__i0'
1276 | | `-CXXMemberCallExpr
1278 | | | `-ArraySubscriptExpr
1279 | | | |-ImplicitCastExpr
1280 | | | | `-MemberExpr
1281 | | | | `-CXXThisExpr
1282 | | | `-ImplicitCastExpr
1283 | | | `-DeclRefExpr '__i0'
1284 | | `-ArraySubscriptExpr
1285 | | |-ImplicitCastExpr
1287 | | | `-DeclRefExpr ''
1288 | | `-ImplicitCastExpr
1289 | | `-DeclRefExpr '__i0'
1291 | | |-ImplicitCastExpr
1292 | | | `-DeclRefExpr '__builtin_memcpy'
1293 | | |-ImplicitCastExpr
1294 | | | `-UnaryOperator
1297 | | |-ImplicitCastExpr
1298 | | | `-UnaryOperator
1300 | | | `-DeclRefExpr ''
1301 | | `-IntegerLiteral
1305 |-CXXConstructorDecl 'ContainsArray'
1307 |-CXXDestructorDecl '~ContainsArray'
1309 `-CXXConstructorDecl 'ContainsArray'
1310 |-CXXCtorInitializer 'arr'
1311 | `-CXXConstructExpr
1315 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1316 BN
[0].getNodeAs
<Decl
>("rec")),
1318 CXXRecordDecl 'ContainsArray'
1321 `-CXXMethodDecl 'operator='
1326 auto BN
= ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),
1327 AST2
->getASTContext());
1328 EXPECT_EQ(BN
.size(), 1u);
1330 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("func")),
1332 FunctionDecl 'forLoop'
1339 | | `-VarDecl '__range1'
1340 | | `-DeclRefExpr 'arr'
1342 | | `-VarDecl '__begin1'
1343 | | `-ImplicitCastExpr
1344 | | `-DeclRefExpr '__range1'
1346 | | `-VarDecl '__end1'
1347 | | `-BinaryOperator
1348 | | |-ImplicitCastExpr
1349 | | | `-DeclRefExpr '__range1'
1350 | | `-IntegerLiteral
1352 | | |-ImplicitCastExpr
1353 | | | `-DeclRefExpr '__begin1'
1354 | | `-ImplicitCastExpr
1355 | | `-DeclRefExpr '__end1'
1357 | | `-DeclRefExpr '__begin1'
1360 | | `-ImplicitCastExpr
1362 | | `-ImplicitCastExpr
1363 | | `-DeclRefExpr '__begin1'
1368 | `-DeclRefExpr 'arr'
1370 | `-VarDecl '__range1'
1373 | `-VarDecl '__begin1'
1374 | `-ImplicitCastExpr
1375 | `-DeclRefExpr '__range1'
1377 | `-VarDecl '__end1'
1379 | |-ImplicitCastExpr
1380 | | `-DeclRefExpr '__range1'
1383 | |-ImplicitCastExpr
1384 | | `-DeclRefExpr '__begin1'
1385 | `-ImplicitCastExpr
1386 | `-DeclRefExpr '__end1'
1388 | `-DeclRefExpr '__begin1'
1391 | `-ImplicitCastExpr
1393 | `-ImplicitCastExpr
1394 | `-DeclRefExpr '__begin1'
1398 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1399 BN
[0].getNodeAs
<Decl
>("func")),
1401 FunctionDecl 'forLoop'
1408 | |-DeclRefExpr 'arr'
1413 | `-DeclRefExpr 'arr'
1420 auto BN
= ast_matchers::match(
1421 cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))
1423 AST2
->getASTContext());
1424 EXPECT_EQ(BN
.size(), 1u);
1426 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1428 CXXRecordDecl 'DefaultedAndDeleted'
1429 |-CXXRecordDecl 'DefaultedAndDeleted'
1431 |-CXXConstructorDecl 'DefaultedAndDeleted'
1432 | |-CXXCtorInitializer 'nt'
1433 | | `-CXXConstructExpr
1435 |-CXXDestructorDecl '~DefaultedAndDeleted'
1437 |-CXXConstructorDecl 'DefaultedAndDeleted'
1439 |-CXXMethodDecl 'operator='
1442 | |-CXXMemberCallExpr
1447 | | `-DeclRefExpr ''
1451 |-CXXConstructorDecl 'DefaultedAndDeleted'
1453 `-CXXMethodDecl 'operator='
1457 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1458 BN
[0].getNodeAs
<Decl
>("rec")),
1460 CXXRecordDecl 'DefaultedAndDeleted'
1462 |-CXXConstructorDecl 'DefaultedAndDeleted'
1463 |-CXXDestructorDecl '~DefaultedAndDeleted'
1464 |-CXXConstructorDecl 'DefaultedAndDeleted'
1466 |-CXXMethodDecl 'operator='
1468 |-CXXConstructorDecl 'DefaultedAndDeleted'
1470 `-CXXMethodDecl 'operator='
1475 auto BN
= ast_matchers::match(
1476 callExpr(callee(functionDecl(hasName("hasDefaultArg"))))
1478 AST2
->getASTContext());
1479 EXPECT_EQ(BN
.size(), 1u);
1481 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<CallExpr
>("funcCall")),
1485 | `-DeclRefExpr 'hasDefaultArg'
1489 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1490 BN
[0].getNodeAs
<CallExpr
>("funcCall")),
1493 |-DeclRefExpr 'hasDefaultArg'
1499 auto FN
= ast_matchers::match(
1500 functionDecl(hasName("decomposition"),
1501 hasDescendant(decompositionDecl().bind("decomp"))),
1502 AST2
->getASTContext());
1503 EXPECT_EQ(FN
.size(), 1u);
1506 dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<DecompositionDecl
>("decomp")),
1508 DecompositionDecl ''
1511 | `-ArraySubscriptExpr
1512 | |-ImplicitCastExpr
1513 | | `-DeclRefExpr ''
1516 | `-ArraySubscriptExpr
1517 | |-ImplicitCastExpr
1518 | | `-DeclRefExpr ''
1521 `-ArraySubscriptExpr
1527 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1528 FN
[0].getNodeAs
<DecompositionDecl
>("decomp")),
1530 DecompositionDecl ''
1539 auto FN
= ast_matchers::match(
1540 functionDecl(hasName("decompTuple"),
1541 hasDescendant(decompositionDecl().bind("decomp"))),
1542 AST2
->getASTContext());
1543 EXPECT_EQ(FN
.size(), 1u);
1546 dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<DecompositionDecl
>("decomp")),
1548 DecompositionDecl ''
1550 | `-ImplicitCastExpr
1555 | | |-ImplicitCastExpr
1556 | | | `-DeclRefExpr 'get'
1557 | | `-ImplicitCastExpr
1558 | | `-DeclRefExpr ''
1563 | |-ImplicitCastExpr
1564 | | `-DeclRefExpr 'get'
1565 | `-ImplicitCastExpr
1570 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1571 FN
[0].getNodeAs
<DecompositionDecl
>("decomp")),
1573 DecompositionDecl ''
1581 TEST(Traverse
, IgnoreUnlessSpelledInSourceTemplateInstantiations
) {
1583 auto AST
= buildASTFromCode(R
"cpp(
1584 template<typename T>
1585 struct TemplStruct {
1593 template<typename T>
1601 TemplStruct<int> ti;
1602 TemplStruct<double> td;
1603 (void)timesTwo<int>(2);
1604 (void)timesTwo<double>(2);
1607 template class TemplStruct<float>;
1609 extern template class TemplStruct<long>;
1611 template<> class TemplStruct<bool> {
1620 // Explicit instantiation of template functions do not appear in the AST
1621 template float timesTwo(float);
1623 template<> bool timesTwo<bool>(bool) {
1628 auto BN
= ast_matchers::match(
1629 classTemplateDecl(hasName("TemplStruct")).bind("rec"),
1630 AST
->getASTContext());
1631 EXPECT_EQ(BN
.size(), 1u);
1633 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1634 BN
[0].getNodeAs
<Decl
>("rec")),
1636 ClassTemplateDecl 'TemplStruct'
1637 |-TemplateTypeParmDecl 'T'
1638 `-CXXRecordDecl 'TemplStruct'
1639 |-CXXConstructorDecl 'TemplStruct<T>'
1641 |-CXXDestructorDecl '~TemplStruct<T>'
1647 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1649 ClassTemplateDecl 'TemplStruct'
1650 |-TemplateTypeParmDecl 'T'
1651 |-CXXRecordDecl 'TemplStruct'
1652 | |-CXXRecordDecl 'TemplStruct'
1653 | |-CXXConstructorDecl 'TemplStruct<T>'
1655 | |-CXXDestructorDecl '~TemplStruct<T>'
1659 |-ClassTemplateSpecializationDecl 'TemplStruct'
1660 | |-TemplateArgument type int
1662 | |-CXXRecordDecl 'TemplStruct'
1663 | |-CXXConstructorDecl 'TemplStruct'
1665 | |-CXXDestructorDecl '~TemplStruct'
1669 | `-CXXConstructorDecl 'TemplStruct'
1671 |-ClassTemplateSpecializationDecl 'TemplStruct'
1672 | |-TemplateArgument type double
1674 | |-CXXRecordDecl 'TemplStruct'
1675 | |-CXXConstructorDecl 'TemplStruct'
1677 | |-CXXDestructorDecl '~TemplStruct'
1681 | `-CXXConstructorDecl 'TemplStruct'
1683 |-ClassTemplateSpecializationDecl 'TemplStruct'
1684 | |-TemplateArgument type float
1686 | |-CXXRecordDecl 'TemplStruct'
1687 | |-CXXConstructorDecl 'TemplStruct'
1689 | |-CXXDestructorDecl '~TemplStruct'
1693 |-ClassTemplateSpecializationDecl 'TemplStruct'
1694 | |-TemplateArgument type long
1696 | |-CXXRecordDecl 'TemplStruct'
1697 | |-CXXConstructorDecl 'TemplStruct'
1698 | |-CXXDestructorDecl '~TemplStruct'
1701 `-ClassTemplateSpecializationDecl 'TemplStruct'
1702 |-TemplateArgument type _Bool
1704 |-CXXRecordDecl 'TemplStruct'
1705 |-CXXConstructorDecl 'TemplStruct'
1707 |-CXXDestructorDecl '~TemplStruct'
1709 |-CXXMethodDecl 'foo'
1716 auto BN
= ast_matchers::match(
1717 classTemplateSpecializationDecl(
1718 hasTemplateArgument(
1719 0, templateArgument(refersToType(asString("_Bool")))))
1721 AST
->getASTContext());
1722 EXPECT_EQ(BN
.size(), 1u);
1724 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("templSpec")),
1726 ClassTemplateSpecializationDecl 'TemplStruct'
1727 |-TemplateArgument type _Bool
1729 |-CXXRecordDecl 'TemplStruct'
1730 |-CXXConstructorDecl 'TemplStruct'
1732 |-CXXDestructorDecl '~TemplStruct'
1734 |-CXXMethodDecl 'foo'
1740 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1741 BN
[0].getNodeAs
<Decl
>("templSpec")),
1743 ClassTemplateSpecializationDecl 'TemplStruct'
1744 |-TemplateArgument type _Bool
1746 |-CXXConstructorDecl 'TemplStruct'
1748 |-CXXDestructorDecl '~TemplStruct'
1750 |-CXXMethodDecl 'foo'
1757 auto BN
= ast_matchers::match(
1758 functionTemplateDecl(hasName("timesTwo")).bind("fn"),
1759 AST
->getASTContext());
1760 EXPECT_EQ(BN
.size(), 1u);
1762 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1763 BN
[0].getNodeAs
<Decl
>("fn")),
1765 FunctionTemplateDecl 'timesTwo'
1766 |-TemplateTypeParmDecl 'T'
1767 `-FunctionDecl 'timesTwo'
1768 |-ParmVarDecl 'input'
1772 |-DeclRefExpr 'input'
1776 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("fn")),
1778 FunctionTemplateDecl 'timesTwo'
1779 |-TemplateTypeParmDecl 'T'
1780 |-FunctionDecl 'timesTwo'
1781 | |-ParmVarDecl 'input'
1785 | |-DeclRefExpr 'input'
1787 |-FunctionDecl 'timesTwo'
1788 | |-TemplateArgument type int
1790 | |-ParmVarDecl 'input'
1794 | |-ImplicitCastExpr
1795 | | `-DeclRefExpr 'input'
1797 |-FunctionDecl 'timesTwo'
1798 | |-TemplateArgument type double
1800 | |-ParmVarDecl 'input'
1804 | |-ImplicitCastExpr
1805 | | `-DeclRefExpr 'input'
1806 | `-ImplicitCastExpr
1808 |-FunctionDecl 'timesTwo'
1809 | |-TemplateArgument type float
1811 | |-ParmVarDecl 'input'
1815 | |-ImplicitCastExpr
1816 | | `-DeclRefExpr 'input'
1817 | `-ImplicitCastExpr
1819 |-FunctionDecl 'timesTwo'
1820 | |-TemplateArgument type _Bool
1825 | `-CXXBoolLiteralExpr
1826 `-FunctionDecl 'timesTwo'
1827 |-TemplateArgument type _Bool
1829 `-ParmVarDecl 'input'
1833 auto BN
= ast_matchers::match(
1834 classTemplateSpecializationDecl(
1835 hasName("TemplStruct"),
1836 hasTemplateArgument(
1837 0, templateArgument(refersToType(asString("float")))),
1838 hasParent(translationUnitDecl()))
1840 AST
->getASTContext());
1841 EXPECT_EQ(BN
.size(), 1u);
1843 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1844 BN
[0].getNodeAs
<Decl
>("rec")),
1846 ClassTemplateSpecializationDecl 'TemplStruct'
1847 `-TemplateArgument type float
1851 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1853 ClassTemplateSpecializationDecl 'TemplStruct'
1854 |-TemplateArgument type float
1856 |-CXXRecordDecl 'TemplStruct'
1857 |-CXXConstructorDecl 'TemplStruct'
1859 |-CXXDestructorDecl '~TemplStruct'
1867 TEST(Traverse
, CXXRewrittenBinaryOperator
) {
1869 auto AST
= buildASTFromCodeWithArgs(R
"cpp(
1871 struct strong_ordering {
1873 constexpr operator int() const { return n; }
1874 static const strong_ordering equal, greater, less;
1876 constexpr strong_ordering strong_ordering::equal = {0};
1877 constexpr strong_ordering strong_ordering::greater = {1};
1878 constexpr strong_ordering strong_ordering::less = {-1};
1881 struct HasSpaceshipMem {
1883 constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
1888 HasSpaceshipMem hs1, hs2;
1895 auto BN
= ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"),
1896 AST
->getASTContext());
1897 EXPECT_EQ(BN
.size(), 1u);
1899 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Stmt
>("binop")),
1901 CXXRewrittenBinaryOperator
1904 | `-CXXMemberCallExpr
1906 | `-ImplicitCastExpr
1907 | `-MaterializeTemporaryExpr
1908 | `-CXXOperatorCallExpr
1909 | |-ImplicitCastExpr
1910 | | `-DeclRefExpr 'operator<=>'
1911 | |-ImplicitCastExpr
1912 | | `-DeclRefExpr 'hs1'
1913 | `-ImplicitCastExpr
1914 | `-DeclRefExpr 'hs2'
1917 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1918 BN
[0].getNodeAs
<Stmt
>("binop")),
1920 CXXRewrittenBinaryOperator
1927 } // namespace clang