Skip to content

Commit 494b131

Browse files
committed
Customize simplified dumping and matching of LambdaExpr
Reviewers: aaron.ballman Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D71680
1 parent 44b4b83 commit 494b131

File tree

4 files changed

+204
-4
lines changed

4 files changed

+204
-4
lines changed

clang/include/clang/AST/ASTNodeTraverser.h

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,12 @@ class ASTNodeTraverser
128128
ConstStmtVisitor<Derived>::Visit(S);
129129

130130
// Some statements have custom mechanisms for dumping their children.
131-
if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S)) {
131+
if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S))
132+
return;
133+
134+
if (isa<LambdaExpr>(S) &&
135+
Traversal == ast_type_traits::TK_IgnoreUnlessSpelledInSource)
132136
return;
133-
}
134137

135138
for (const Stmt *SubStmt : S->children())
136139
Visit(SubStmt);
@@ -646,7 +649,23 @@ class ASTNodeTraverser
646649
}
647650

648651
void VisitLambdaExpr(const LambdaExpr *Node) {
649-
Visit(Node->getLambdaClass());
652+
if (Traversal == ast_type_traits::TK_IgnoreUnlessSpelledInSource) {
653+
for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
654+
const auto *C = Node->capture_begin() + I;
655+
if (!C->isExplicit())
656+
continue;
657+
if (Node->isInitCapture(C))
658+
Visit(C->getCapturedVar());
659+
else
660+
Visit(Node->capture_init_begin()[I]);
661+
}
662+
dumpTemplateParameters(Node->getTemplateParameterList());
663+
for (const auto *P : Node->getCallOperator()->parameters())
664+
Visit(P);
665+
Visit(Node->getBody());
666+
} else {
667+
return Visit(Node->getLambdaClass());
668+
}
650669
}
651670

652671
void VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {

clang/lib/ASTMatchers/ASTMatchFinder.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,9 @@ class MatchChildASTVisitor
145145

146146
ScopedIncrement ScopedDepth(&CurrentDepth);
147147
Stmt *StmtToTraverse = StmtNode;
148-
if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
148+
if (auto *ExprNode = dyn_cast_or_null<LambdaExpr>(StmtNode))
149+
StmtToTraverse = ExprNode;
150+
else if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
149151
StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode);
150152
if (Traversal ==
151153
ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
@@ -203,6 +205,38 @@ class MatchChildASTVisitor
203205
ScopedIncrement ScopedDepth(&CurrentDepth);
204206
return traverse(*CtorInit);
205207
}
208+
bool TraverseLambdaExpr(LambdaExpr *Node) {
209+
if (!Node)
210+
return true;
211+
ScopedIncrement ScopedDepth(&CurrentDepth);
212+
213+
for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
214+
const auto *C = Node->capture_begin() + I;
215+
if (!C->isExplicit())
216+
continue;
217+
if (Node->isInitCapture(C) && !match(*C->getCapturedVar()))
218+
return false;
219+
if (!match(*Node->capture_init_begin()[I]))
220+
return false;
221+
}
222+
223+
if (const auto *TPL = Node->getTemplateParameterList()) {
224+
for (const auto *TP : *TPL) {
225+
if (!match(*TP))
226+
return false;
227+
}
228+
}
229+
230+
for (const auto *P : Node->getCallOperator()->parameters()) {
231+
if (!match(*P))
232+
return false;
233+
}
234+
235+
if (!match(*Node->getBody()))
236+
return false;
237+
238+
return false;
239+
}
206240

207241
bool shouldVisitTemplateInstantiations() const { return true; }
208242
bool shouldVisitImplicitCode() const { return true; }

clang/unittests/AST/ASTTraverserTest.cpp

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,4 +479,123 @@ FunctionDecl 'func12'
479479
)cpp");
480480
}
481481

482+
TEST(Traverse, LambdaUnlessSpelledInSource) {
483+
484+
auto AST =
485+
buildASTFromCodeWithArgs(R"cpp(
486+
487+
void captures() {
488+
int a = 0;
489+
int b = 0;
490+
int d = 0;
491+
int f = 0;
492+
493+
[a, &b, c = d, &e = f](int g, int h = 42) {};
494+
}
495+
496+
void templated() {
497+
int a = 0;
498+
[a]<typename T>(T t) {};
499+
}
500+
501+
struct SomeStruct {
502+
int a = 0;
503+
void capture_this() {
504+
[this]() {};
505+
}
506+
void capture_this_copy() {
507+
[self = *this]() {};
508+
}
509+
};
510+
)cpp",
511+
{"-Wno-unused-value", "-Wno-c++2a-extensions"});
512+
513+
auto getLambdaNode = [&AST](const std::string &name) {
514+
auto BN = ast_matchers::match(
515+
lambdaExpr(hasAncestor(functionDecl(hasName(name)))).bind("lambda"),
516+
AST->getASTContext());
517+
EXPECT_EQ(BN.size(), 1u);
518+
return BN[0].getNodeAs<LambdaExpr>("lambda");
519+
};
520+
521+
{
522+
auto L = getLambdaNode("captures");
523+
524+
EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
525+
R"cpp(
526+
LambdaExpr
527+
|-DeclRefExpr 'a'
528+
|-DeclRefExpr 'b'
529+
|-VarDecl 'c'
530+
| `-DeclRefExpr 'd'
531+
|-VarDecl 'e'
532+
| `-DeclRefExpr 'f'
533+
|-ParmVarDecl 'g'
534+
|-ParmVarDecl 'h'
535+
| `-IntegerLiteral
536+
`-CompoundStmt
537+
)cpp");
538+
539+
EXPECT_EQ(dumpASTString(ast_type_traits::TK_AsIs, L),
540+
R"cpp(
541+
LambdaExpr
542+
|-CXXRecordDecl ''
543+
| |-CXXMethodDecl 'operator()'
544+
| | |-ParmVarDecl 'g'
545+
| | |-ParmVarDecl 'h'
546+
| | | `-IntegerLiteral
547+
| | `-CompoundStmt
548+
| |-FieldDecl ''
549+
| |-FieldDecl ''
550+
| |-FieldDecl ''
551+
| |-FieldDecl ''
552+
| `-CXXDestructorDecl '~'
553+
|-ImplicitCastExpr
554+
| `-DeclRefExpr 'a'
555+
|-DeclRefExpr 'b'
556+
|-ImplicitCastExpr
557+
| `-DeclRefExpr 'd'
558+
|-DeclRefExpr 'f'
559+
`-CompoundStmt
560+
)cpp");
561+
}
562+
563+
{
564+
auto L = getLambdaNode("templated");
565+
566+
EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
567+
R"cpp(
568+
LambdaExpr
569+
|-DeclRefExpr 'a'
570+
|-TemplateTypeParmDecl 'T'
571+
|-ParmVarDecl 't'
572+
`-CompoundStmt
573+
)cpp");
574+
}
575+
576+
{
577+
auto L = getLambdaNode("capture_this");
578+
579+
EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
580+
R"cpp(
581+
LambdaExpr
582+
|-CXXThisExpr
583+
`-CompoundStmt
584+
)cpp");
585+
}
586+
587+
{
588+
auto L = getLambdaNode("capture_this_copy");
589+
590+
EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
591+
R"cpp(
592+
LambdaExpr
593+
|-VarDecl 'self'
594+
| `-UnaryOperator
595+
| `-CXXThisExpr
596+
`-CompoundStmt
597+
)cpp");
598+
}
599+
}
600+
482601
} // namespace clang

clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1751,6 +1751,17 @@ B func12() {
17511751
return c;
17521752
}
17531753
1754+
void func13() {
1755+
int a = 0;
1756+
int c = 0;
1757+
1758+
[a, b = c](int d) { int e = d; };
1759+
}
1760+
1761+
void func14() {
1762+
[] <typename TemplateType> (TemplateType t, TemplateType u) { int e = t + u; };
1763+
}
1764+
17541765
)cpp";
17551766

17561767
EXPECT_TRUE(matches(
@@ -1821,6 +1832,23 @@ B func12() {
18211832
returnStmt(forFunction(functionDecl(hasName("func12"))),
18221833
hasReturnValue(
18231834
declRefExpr(to(varDecl(hasName("c")))))))));
1835+
1836+
EXPECT_TRUE(matches(
1837+
Code,
1838+
traverse(
1839+
ast_type_traits::TK_IgnoreUnlessSpelledInSource,
1840+
lambdaExpr(forFunction(functionDecl(hasName("func13"))),
1841+
has(compoundStmt(hasDescendant(varDecl(hasName("e"))))),
1842+
has(declRefExpr(to(varDecl(hasName("a"))))),
1843+
has(varDecl(hasName("b"), hasInitializer(declRefExpr(to(
1844+
varDecl(hasName("c"))))))),
1845+
has(parmVarDecl(hasName("d")))))));
1846+
1847+
EXPECT_TRUE(matches(
1848+
Code, traverse(ast_type_traits::TK_IgnoreUnlessSpelledInSource,
1849+
lambdaExpr(
1850+
forFunction(functionDecl(hasName("func14"))),
1851+
has(templateTypeParmDecl(hasName("TemplateType")))))));
18241852
}
18251853

18261854
TEST(IgnoringImpCasts, MatchesImpCasts) {

0 commit comments

Comments
 (0)