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
374 `-CXXOperatorCallExpr
376 | `-DeclRefExpr 'operator='
378 `-MaterializeTemporaryExpr
387 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
388 FN
[0].getNodeAs
<Decl
>("fn")),
390 FunctionDecl 'stringConstruct'
395 `-CXXOperatorCallExpr
396 |-DeclRefExpr 'operator='
404 ast_matchers::match(functionDecl(hasName("overloadCall")).bind("fn"),
405 AST
->getASTContext());
406 EXPECT_EQ(FN
.size(), 1u);
408 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<Decl
>("fn")),
410 FunctionDecl 'overloadCall'
416 | `-MaterializeTemporaryExpr
421 | `-CXXDefaultArgExpr
430 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
431 FN
[0].getNodeAs
<Decl
>("fn")),
433 FunctionDecl 'overloadCall'
445 auto FN
= ast_matchers::match(
446 functionDecl(hasName("conversionOperator"),
447 hasDescendant(varDecl(hasName("c1")).bind("var"))),
448 AST
->getASTContext());
449 EXPECT_EQ(FN
.size(), 1u);
451 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<Decl
>("var")),
456 `-MaterializeTemporaryExpr
466 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
467 FN
[0].getNodeAs
<Decl
>("var")),
476 auto FN
= ast_matchers::match(
477 functionDecl(hasName("template_test"),
478 hasDescendant(staticAssertDecl().bind("staticAssert"))),
479 AST
->getASTContext());
480 EXPECT_EQ(FN
.size(), 2u);
482 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[1].getNodeAs
<Decl
>("staticAssert")),
486 | `-SubstNonTypeTemplateParmExpr
487 | |-NonTypeTemplateParmDecl 'alignment'
492 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
493 FN
[1].getNodeAs
<Decl
>("staticAssert")),
501 auto varChecker
= [&AST
](StringRef varName
, StringRef SemanticDump
,
502 StringRef SyntacticDump
) {
503 auto FN
= ast_matchers::match(
505 hasName("varDeclCtors"),
506 forEachDescendant(varDecl(hasName(varName
)).bind("varDeclCtor"))),
507 AST
->getASTContext());
508 EXPECT_EQ(FN
.size(), 1u);
510 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<Decl
>("varDeclCtor")),
513 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
514 FN
[0].getNodeAs
<Decl
>("varDeclCtor")),
523 `-MaterializeTemporaryExpr
524 `-CXXFunctionalCastExpr
539 `-MaterializeTemporaryExpr
540 `-CXXTemporaryObjectExpr
546 `-CXXTemporaryObjectExpr
582 `-MaterializeTemporaryExpr
583 `-CXXFunctionalCastExpr
599 `-MaterializeTemporaryExpr
600 `-CXXTemporaryObjectExpr
607 `-CXXTemporaryObjectExpr
641 TEST(Traverse
, IgnoreUnlessSpelledInSourceStructs
) {
642 auto AST
= buildASTFromCode(R
"cpp(
654 auto BN
= ast_matchers::match(
655 cxxConstructorDecl(hasName("MyStruct"),
656 hasParameter(0, parmVarDecl(hasType(isInteger()))))
658 AST
->getASTContext());
659 EXPECT_EQ(BN
.size(), 1u);
661 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
662 BN
[0].getNodeAs
<Decl
>("ctor")),
664 CXXConstructorDecl 'MyStruct'
667 `-CXXTemporaryObjectExpr
670 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("ctor")),
672 CXXConstructorDecl 'MyStruct'
676 `-CXXBindTemporaryExpr
677 `-CXXTemporaryObjectExpr
681 TEST(Traverse
, IgnoreUnlessSpelledInSourceReturnStruct
) {
683 auto AST
= buildASTFromCode(R
"cpp(
697 auto BN
= ast_matchers::match(functionDecl(hasName("foo")).bind("fn"),
698 AST
->getASTContext());
699 EXPECT_EQ(BN
.size(), 1u);
701 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
702 BN
[0].getNodeAs
<Decl
>("fn")),
707 `-DeclRefExpr 'someFun'
710 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("fn")),
715 `-CXXBindTemporaryExpr
718 `-DeclRefExpr 'someFun'
722 TEST(Traverse
, IgnoreUnlessSpelledInSourceReturns
) {
724 auto AST
= buildASTFromCodeWithArgs(R
"cpp(
793 )cpp", {"-std=c++14"});
795 auto getFunctionNode
= [&AST
](const std::string
&name
) {
796 auto BN
= ast_matchers::match(functionDecl(hasName(name
)).bind("fn"),
797 AST
->getASTContext());
798 EXPECT_EQ(BN
.size(), 1u);
799 return BN
[0].getNodeAs
<Decl
>("fn");
803 auto FN
= getFunctionNode("func1");
804 llvm::StringRef Expected
= R
"cpp(
810 `-MaterializeTemporaryExpr
816 EXPECT_EQ(dumpASTString(TK_AsIs
, FN
), Expected
);
824 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, FN
), Expected
);
827 llvm::StringRef Expected
= R
"cpp(
831 `-CXXTemporaryObjectExpr
835 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func2")),
846 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func3")),
853 `-CXXTemporaryObjectExpr
856 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func4")),
863 `-CXXTemporaryObjectExpr
866 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func5")),
873 `-CXXTemporaryObjectExpr
876 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func6")),
883 `-CXXTemporaryObjectExpr
886 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func7")),
893 `-CXXFunctionalCastExpr
897 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func8")),
904 `-CXXFunctionalCastExpr
908 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func9")),
912 FunctionDecl 'func10'
921 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func10")),
925 FunctionDecl 'func11'
934 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func11")),
938 FunctionDecl 'func12'
947 dumpASTString(TK_IgnoreUnlessSpelledInSource
, getFunctionNode("func12")),
951 TEST(Traverse
, LambdaUnlessSpelledInSource
) {
954 buildASTFromCodeWithArgs(R
"cpp(
962 [a, &b, c = d, &e = f](int g, int h = 42) {};
967 [a]<typename T>(T t) {};
972 void capture_this() {
975 void capture_this_copy() {
980 {"-Wno-unused-value", "-Wno-c++2a-extensions"});
982 auto getLambdaNode
= [&AST
](const std::string
&name
) {
983 auto BN
= ast_matchers::match(
984 lambdaExpr(hasAncestor(functionDecl(hasName(name
)))).bind("lambda"),
985 AST
->getASTContext());
986 EXPECT_EQ(BN
.size(), 1u);
987 return BN
[0].getNodeAs
<LambdaExpr
>("lambda");
991 auto L
= getLambdaNode("captures");
993 llvm::StringRef Expected
= R
"cpp(
1006 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, L
), Expected
);
1011 | |-CXXMethodDecl 'operator()'
1012 | | |-ParmVarDecl 'g'
1013 | | |-ParmVarDecl 'h'
1014 | | | `-IntegerLiteral
1020 | `-CXXDestructorDecl '~(lambda at input.cc:9:3)'
1029 EXPECT_EQ(dumpASTString(TK_AsIs
, L
), Expected
);
1033 auto L
= getLambdaNode("templated");
1035 llvm::StringRef Expected
= R
"cpp(
1038 |-TemplateTypeParmDecl 'T'
1042 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, L
), Expected
);
1046 auto L
= getLambdaNode("capture_this");
1048 llvm::StringRef Expected
= R
"cpp(
1053 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, L
), Expected
);
1057 auto L
= getLambdaNode("capture_this_copy");
1059 llvm::StringRef Expected
= R
"cpp(
1066 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, L
), Expected
);
1070 TEST(Traverse
, IgnoreUnlessSpelledInSourceImplicit
) {
1072 auto AST
= buildASTFromCode(R
"cpp(
1075 const auto *TUDecl
= AST
->getASTContext().getTranslationUnitDecl();
1077 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
, TUDecl
),
1085 auto AST2
= buildASTFromCodeWithArgs(R
"cpp(
1091 struct Record : Simple, Other {
1092 Record() : Simple(), m_i(42) {}
1101 NonTrivial(NonTrivial&) {}
1102 NonTrivial& operator=(NonTrivial&) { return *this; }
1107 struct ContainsArray {
1110 ContainsArray& operator=(ContainsArray &) = default;
1127 for (auto& a = arr; auto i : a)
1133 struct DefaultedAndDeleted {
1135 DefaultedAndDeleted() = default;
1136 ~DefaultedAndDeleted() = default;
1137 DefaultedAndDeleted(DefaultedAndDeleted &) = default;
1138 DefaultedAndDeleted& operator=(DefaultedAndDeleted &) = default;
1139 DefaultedAndDeleted(DefaultedAndDeleted &&) = delete;
1140 DefaultedAndDeleted& operator=(DefaultedAndDeleted &&) = delete;
1145 DefaultedAndDeleted ca;
1146 DefaultedAndDeleted ca2;
1150 void hasDefaultArg(int i, int j = 0)
1153 void callDefaultArg()
1158 void decomposition()
1161 auto &[f, s, t] = arr;
1166 typedef __typeof(sizeof(int)) size_t;
1173 // Note: these utilities are required to force binding to tuple like structure
1176 template <typename E>
1182 struct tuple_size<Pair>
1184 static constexpr size_t value = 2;
1187 template <size_t I, class T>
1188 struct tuple_element
1196 int &&get(Pair &&p);
1210 auto BN
= ast_matchers::match(
1211 cxxRecordDecl(hasName("Record"), unless(isImplicit())).bind("rec"),
1212 AST2
->getASTContext());
1213 EXPECT_EQ(BN
.size(), 1u);
1215 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1217 CXXRecordDecl 'Record'
1218 |-CXXRecordDecl 'Record'
1219 |-CXXConstructorDecl 'Record'
1220 | |-CXXCtorInitializer 'Simple'
1221 | | `-CXXConstructExpr
1222 | |-CXXCtorInitializer 'Other'
1223 | | `-CXXConstructExpr
1224 | |-CXXCtorInitializer 'm_i'
1225 | | `-IntegerLiteral
1226 | |-CXXCtorInitializer 'm_i2'
1227 | | `-CXXDefaultInitExpr
1228 | | `-IntegerLiteral
1229 | |-CXXCtorInitializer 'm_s'
1230 | | `-CXXConstructExpr
1239 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1240 BN
[0].getNodeAs
<Decl
>("rec")),
1242 CXXRecordDecl 'Record'
1243 |-CXXConstructorDecl 'Record'
1244 | |-CXXCtorInitializer 'Simple'
1245 | | `-CXXConstructExpr
1246 | |-CXXCtorInitializer 'm_i'
1247 | | `-IntegerLiteral
1257 auto BN
= ast_matchers::match(
1258 cxxRecordDecl(hasName("ContainsArray"), unless(isImplicit()))
1260 AST2
->getASTContext());
1261 EXPECT_EQ(BN
.size(), 1u);
1263 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1265 CXXRecordDecl 'ContainsArray'
1266 |-CXXRecordDecl 'ContainsArray'
1269 |-CXXMethodDecl 'operator='
1274 | | | `-VarDecl '__i0'
1275 | | | `-IntegerLiteral
1277 | | |-BinaryOperator
1278 | | | |-ImplicitCastExpr
1279 | | | | `-DeclRefExpr '__i0'
1280 | | | `-IntegerLiteral
1282 | | | `-DeclRefExpr '__i0'
1283 | | `-CXXMemberCallExpr
1285 | | | `-ArraySubscriptExpr
1286 | | | |-ImplicitCastExpr
1287 | | | | `-MemberExpr
1288 | | | | `-CXXThisExpr
1289 | | | `-ImplicitCastExpr
1290 | | | `-DeclRefExpr '__i0'
1291 | | `-ArraySubscriptExpr
1292 | | |-ImplicitCastExpr
1294 | | | `-DeclRefExpr ''
1295 | | `-ImplicitCastExpr
1296 | | `-DeclRefExpr '__i0'
1298 | | |-ImplicitCastExpr
1299 | | | `-DeclRefExpr '__builtin_memcpy'
1300 | | |-ImplicitCastExpr
1301 | | | `-UnaryOperator
1304 | | |-ImplicitCastExpr
1305 | | | `-UnaryOperator
1307 | | | `-DeclRefExpr ''
1308 | | `-IntegerLiteral
1312 |-CXXConstructorDecl 'ContainsArray'
1314 |-CXXDestructorDecl '~ContainsArray'
1316 `-CXXConstructorDecl 'ContainsArray'
1317 |-CXXCtorInitializer 'arr'
1318 | `-CXXConstructExpr
1322 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1323 BN
[0].getNodeAs
<Decl
>("rec")),
1325 CXXRecordDecl 'ContainsArray'
1328 `-CXXMethodDecl 'operator='
1333 auto BN
= ast_matchers::match(functionDecl(hasName("forLoop")).bind("func"),
1334 AST2
->getASTContext());
1335 EXPECT_EQ(BN
.size(), 1u);
1337 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("func")),
1339 FunctionDecl 'forLoop'
1346 | | `-VarDecl '__range1'
1347 | | `-DeclRefExpr 'arr'
1349 | | `-VarDecl '__begin1'
1350 | | `-ImplicitCastExpr
1351 | | `-DeclRefExpr '__range1'
1353 | | `-VarDecl '__end1'
1354 | | `-BinaryOperator
1355 | | |-ImplicitCastExpr
1356 | | | `-DeclRefExpr '__range1'
1357 | | `-IntegerLiteral
1359 | | |-ImplicitCastExpr
1360 | | | `-DeclRefExpr '__begin1'
1361 | | `-ImplicitCastExpr
1362 | | `-DeclRefExpr '__end1'
1364 | | `-DeclRefExpr '__begin1'
1367 | | `-ImplicitCastExpr
1369 | | `-ImplicitCastExpr
1370 | | `-DeclRefExpr '__begin1'
1375 | `-DeclRefExpr 'arr'
1377 | `-VarDecl '__range1'
1380 | `-VarDecl '__begin1'
1381 | `-ImplicitCastExpr
1382 | `-DeclRefExpr '__range1'
1384 | `-VarDecl '__end1'
1386 | |-ImplicitCastExpr
1387 | | `-DeclRefExpr '__range1'
1390 | |-ImplicitCastExpr
1391 | | `-DeclRefExpr '__begin1'
1392 | `-ImplicitCastExpr
1393 | `-DeclRefExpr '__end1'
1395 | `-DeclRefExpr '__begin1'
1398 | `-ImplicitCastExpr
1400 | `-ImplicitCastExpr
1401 | `-DeclRefExpr '__begin1'
1405 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1406 BN
[0].getNodeAs
<Decl
>("func")),
1408 FunctionDecl 'forLoop'
1415 | |-DeclRefExpr 'arr'
1420 | `-DeclRefExpr 'arr'
1427 auto BN
= ast_matchers::match(
1428 cxxRecordDecl(hasName("DefaultedAndDeleted"), unless(isImplicit()))
1430 AST2
->getASTContext());
1431 EXPECT_EQ(BN
.size(), 1u);
1433 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1435 CXXRecordDecl 'DefaultedAndDeleted'
1436 |-CXXRecordDecl 'DefaultedAndDeleted'
1438 |-CXXConstructorDecl 'DefaultedAndDeleted'
1439 | |-CXXCtorInitializer 'nt'
1440 | | `-CXXConstructExpr
1442 |-CXXDestructorDecl '~DefaultedAndDeleted'
1444 |-CXXConstructorDecl 'DefaultedAndDeleted'
1446 |-CXXMethodDecl 'operator='
1449 | |-CXXMemberCallExpr
1454 | | `-DeclRefExpr ''
1458 |-CXXConstructorDecl 'DefaultedAndDeleted'
1460 `-CXXMethodDecl 'operator='
1464 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1465 BN
[0].getNodeAs
<Decl
>("rec")),
1467 CXXRecordDecl 'DefaultedAndDeleted'
1469 |-CXXConstructorDecl 'DefaultedAndDeleted'
1470 |-CXXDestructorDecl '~DefaultedAndDeleted'
1471 |-CXXConstructorDecl 'DefaultedAndDeleted'
1473 |-CXXMethodDecl 'operator='
1475 |-CXXConstructorDecl 'DefaultedAndDeleted'
1477 `-CXXMethodDecl 'operator='
1482 auto BN
= ast_matchers::match(
1483 callExpr(callee(functionDecl(hasName("hasDefaultArg"))))
1485 AST2
->getASTContext());
1486 EXPECT_EQ(BN
.size(), 1u);
1488 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<CallExpr
>("funcCall")),
1492 | `-DeclRefExpr 'hasDefaultArg'
1497 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1498 BN
[0].getNodeAs
<CallExpr
>("funcCall")),
1501 |-DeclRefExpr 'hasDefaultArg'
1507 auto FN
= ast_matchers::match(
1508 functionDecl(hasName("decomposition"),
1509 hasDescendant(decompositionDecl().bind("decomp"))),
1510 AST2
->getASTContext());
1511 EXPECT_EQ(FN
.size(), 1u);
1514 dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<DecompositionDecl
>("decomp")),
1516 DecompositionDecl ''
1519 | `-ArraySubscriptExpr
1520 | |-ImplicitCastExpr
1521 | | `-DeclRefExpr ''
1524 | `-ArraySubscriptExpr
1525 | |-ImplicitCastExpr
1526 | | `-DeclRefExpr ''
1529 `-ArraySubscriptExpr
1535 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1536 FN
[0].getNodeAs
<DecompositionDecl
>("decomp")),
1538 DecompositionDecl ''
1547 auto FN
= ast_matchers::match(
1548 functionDecl(hasName("decompTuple"),
1549 hasDescendant(decompositionDecl().bind("decomp"))),
1550 AST2
->getASTContext());
1551 EXPECT_EQ(FN
.size(), 1u);
1554 dumpASTString(TK_AsIs
, FN
[0].getNodeAs
<DecompositionDecl
>("decomp")),
1556 DecompositionDecl ''
1558 | `-ImplicitCastExpr
1563 | | |-ImplicitCastExpr
1564 | | | `-DeclRefExpr 'get'
1565 | | `-ImplicitCastExpr
1566 | | `-DeclRefExpr ''
1571 | |-ImplicitCastExpr
1572 | | `-DeclRefExpr 'get'
1573 | `-ImplicitCastExpr
1578 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1579 FN
[0].getNodeAs
<DecompositionDecl
>("decomp")),
1581 DecompositionDecl ''
1589 TEST(Traverse
, IgnoreUnlessSpelledInSourceTemplateInstantiations
) {
1591 auto AST
= buildASTFromCode(R
"cpp(
1592 template<typename T>
1593 struct TemplStruct {
1601 template<typename T>
1609 TemplStruct<int> ti;
1610 TemplStruct<double> td;
1611 (void)timesTwo<int>(2);
1612 (void)timesTwo<double>(2);
1615 template class TemplStruct<float>;
1617 extern template class TemplStruct<long>;
1619 template<> class TemplStruct<bool> {
1628 // Explicit instantiation of template functions do not appear in the AST
1629 template float timesTwo(float);
1631 template<> bool timesTwo<bool>(bool) {
1636 auto BN
= ast_matchers::match(
1637 classTemplateDecl(hasName("TemplStruct")).bind("rec"),
1638 AST
->getASTContext());
1639 EXPECT_EQ(BN
.size(), 1u);
1641 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1642 BN
[0].getNodeAs
<Decl
>("rec")),
1644 ClassTemplateDecl 'TemplStruct'
1645 |-TemplateTypeParmDecl 'T'
1646 `-CXXRecordDecl 'TemplStruct'
1647 |-CXXConstructorDecl 'TemplStruct<T>'
1649 |-CXXDestructorDecl '~TemplStruct<T>'
1655 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1657 ClassTemplateDecl 'TemplStruct'
1658 |-TemplateTypeParmDecl 'T'
1659 |-CXXRecordDecl 'TemplStruct'
1660 | |-CXXRecordDecl 'TemplStruct'
1661 | |-CXXConstructorDecl 'TemplStruct<T>'
1663 | |-CXXDestructorDecl '~TemplStruct<T>'
1667 |-ClassTemplateSpecializationDecl 'TemplStruct'
1668 | |-TemplateArgument type int
1670 | |-CXXRecordDecl 'TemplStruct'
1671 | |-CXXConstructorDecl 'TemplStruct'
1673 | |-CXXDestructorDecl '~TemplStruct'
1677 | `-CXXConstructorDecl 'TemplStruct'
1679 |-ClassTemplateSpecializationDecl 'TemplStruct'
1680 | |-TemplateArgument type double
1682 | |-CXXRecordDecl 'TemplStruct'
1683 | |-CXXConstructorDecl 'TemplStruct'
1685 | |-CXXDestructorDecl '~TemplStruct'
1689 | `-CXXConstructorDecl 'TemplStruct'
1691 |-ClassTemplateSpecializationDecl 'TemplStruct'
1692 | |-TemplateArgument type float
1694 | |-CXXRecordDecl 'TemplStruct'
1695 | |-CXXConstructorDecl 'TemplStruct'
1697 | |-CXXDestructorDecl '~TemplStruct'
1701 |-ClassTemplateSpecializationDecl 'TemplStruct'
1702 | |-TemplateArgument type long
1704 | |-CXXRecordDecl 'TemplStruct'
1705 | |-CXXConstructorDecl 'TemplStruct'
1706 | |-CXXDestructorDecl '~TemplStruct'
1709 `-ClassTemplateSpecializationDecl 'TemplStruct'
1710 |-TemplateArgument type _Bool
1712 |-CXXRecordDecl 'TemplStruct'
1713 |-CXXConstructorDecl 'TemplStruct'
1715 |-CXXDestructorDecl '~TemplStruct'
1717 |-CXXMethodDecl 'foo'
1724 auto BN
= ast_matchers::match(
1725 classTemplateSpecializationDecl(
1726 hasTemplateArgument(
1727 0, templateArgument(refersToType(asString("_Bool")))))
1729 AST
->getASTContext());
1730 EXPECT_EQ(BN
.size(), 1u);
1732 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("templSpec")),
1734 ClassTemplateSpecializationDecl 'TemplStruct'
1735 |-TemplateArgument type _Bool
1737 |-CXXRecordDecl 'TemplStruct'
1738 |-CXXConstructorDecl 'TemplStruct'
1740 |-CXXDestructorDecl '~TemplStruct'
1742 |-CXXMethodDecl 'foo'
1748 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1749 BN
[0].getNodeAs
<Decl
>("templSpec")),
1751 ClassTemplateSpecializationDecl 'TemplStruct'
1752 |-TemplateArgument type _Bool
1754 |-CXXConstructorDecl 'TemplStruct'
1756 |-CXXDestructorDecl '~TemplStruct'
1758 |-CXXMethodDecl 'foo'
1765 auto BN
= ast_matchers::match(
1766 functionTemplateDecl(hasName("timesTwo")).bind("fn"),
1767 AST
->getASTContext());
1768 EXPECT_EQ(BN
.size(), 1u);
1770 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1771 BN
[0].getNodeAs
<Decl
>("fn")),
1773 FunctionTemplateDecl 'timesTwo'
1774 |-TemplateTypeParmDecl 'T'
1775 `-FunctionDecl 'timesTwo'
1776 |-ParmVarDecl 'input'
1780 |-DeclRefExpr 'input'
1784 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("fn")),
1786 FunctionTemplateDecl 'timesTwo'
1787 |-TemplateTypeParmDecl 'T'
1788 |-FunctionDecl 'timesTwo'
1789 | |-ParmVarDecl 'input'
1793 | |-DeclRefExpr 'input'
1795 |-FunctionDecl 'timesTwo'
1796 | |-TemplateArgument type int
1798 | |-ParmVarDecl 'input'
1802 | |-ImplicitCastExpr
1803 | | `-DeclRefExpr 'input'
1805 |-FunctionDecl 'timesTwo'
1806 | |-TemplateArgument type double
1808 | |-ParmVarDecl 'input'
1812 | |-ImplicitCastExpr
1813 | | `-DeclRefExpr 'input'
1814 | `-ImplicitCastExpr
1816 |-FunctionDecl 'timesTwo'
1817 | |-TemplateArgument type float
1819 | |-ParmVarDecl 'input'
1823 | |-ImplicitCastExpr
1824 | | `-DeclRefExpr 'input'
1825 | `-ImplicitCastExpr
1827 |-FunctionDecl 'timesTwo'
1828 | |-TemplateArgument type _Bool
1833 | `-CXXBoolLiteralExpr
1834 `-FunctionDecl 'timesTwo'
1835 |-TemplateArgument type _Bool
1837 `-ParmVarDecl 'input'
1841 auto BN
= ast_matchers::match(
1842 classTemplateSpecializationDecl(
1843 hasName("TemplStruct"),
1844 hasTemplateArgument(
1845 0, templateArgument(refersToType(asString("float")))),
1846 hasParent(translationUnitDecl()))
1848 AST
->getASTContext());
1849 EXPECT_EQ(BN
.size(), 1u);
1851 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1852 BN
[0].getNodeAs
<Decl
>("rec")),
1854 ClassTemplateSpecializationDecl 'TemplStruct'
1855 `-TemplateArgument type float
1859 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Decl
>("rec")),
1861 ClassTemplateSpecializationDecl 'TemplStruct'
1862 |-TemplateArgument type float
1864 |-CXXRecordDecl 'TemplStruct'
1865 |-CXXConstructorDecl 'TemplStruct'
1867 |-CXXDestructorDecl '~TemplStruct'
1875 TEST(Traverse
, CXXRewrittenBinaryOperator
) {
1877 auto AST
= buildASTFromCodeWithArgs(R
"cpp(
1879 struct strong_ordering {
1881 constexpr operator int() const { return n; }
1882 static const strong_ordering equal, greater, less;
1884 constexpr strong_ordering strong_ordering::equal = {0};
1885 constexpr strong_ordering strong_ordering::greater = {1};
1886 constexpr strong_ordering strong_ordering::less = {-1};
1889 struct HasSpaceshipMem {
1891 constexpr auto operator<=>(const HasSpaceshipMem&) const = default;
1896 HasSpaceshipMem hs1, hs2;
1903 auto BN
= ast_matchers::match(cxxRewrittenBinaryOperator().bind("binop"),
1904 AST
->getASTContext());
1905 EXPECT_EQ(BN
.size(), 1u);
1907 EXPECT_EQ(dumpASTString(TK_AsIs
, BN
[0].getNodeAs
<Stmt
>("binop")),
1909 CXXRewrittenBinaryOperator
1912 | `-CXXMemberCallExpr
1914 | `-ImplicitCastExpr
1915 | `-MaterializeTemporaryExpr
1916 | `-CXXOperatorCallExpr
1917 | |-ImplicitCastExpr
1918 | | `-DeclRefExpr 'operator<=>'
1919 | |-ImplicitCastExpr
1920 | | `-DeclRefExpr 'hs1'
1921 | `-ImplicitCastExpr
1922 | `-DeclRefExpr 'hs2'
1925 EXPECT_EQ(dumpASTString(TK_IgnoreUnlessSpelledInSource
,
1926 BN
[0].getNodeAs
<Stmt
>("binop")),
1928 CXXRewrittenBinaryOperator
1935 } // namespace clang