steveire created this revision.
steveire added a reviewer: aaron.ballman.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D71680
Files:
clang/include/clang/AST/ASTNodeTraverser.h
clang/lib/ASTMatchers/ASTMatchFinder.cpp
clang/unittests/AST/ASTTraverserTest.cpp
clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1751,6 +1751,17 @@
return c;
}
+void func13() {
+ int a = 0;
+ int c = 0;
+
+ [a, b = c](int d) { int e = d; };
+}
+
+void func14() {
+ [] <typename TemplateType> (TemplateType t, TemplateType u) { int e = t + u; };
+}
+
)cpp";
EXPECT_TRUE(matches(
@@ -1821,6 +1832,23 @@
returnStmt(forFunction(functionDecl(hasName("func12"))),
hasReturnValue(
declRefExpr(to(varDecl(hasName("c")))))))));
+
+ EXPECT_TRUE(matches(
+ Code,
+ traverse(
+ ast_type_traits::TK_IgnoreUnlessSpelledInSource,
+ lambdaExpr(forFunction(functionDecl(hasName("func13"))),
+ has(compoundStmt(hasDescendant(varDecl(hasName("e"))))),
+ has(declRefExpr(to(varDecl(hasName("a"))))),
+ has(varDecl(hasName("b"), hasInitializer(declRefExpr(to(
+ varDecl(hasName("c"))))))),
+ has(parmVarDecl(hasName("d")))))));
+
+ EXPECT_TRUE(matches(
+ Code, traverse(ast_type_traits::TK_IgnoreUnlessSpelledInSource,
+ lambdaExpr(
+ forFunction(functionDecl(hasName("func14"))),
+ has(templateTypeParmDecl(hasName("TemplateType")))))));
}
TEST(IgnoringImpCasts, MatchesImpCasts) {
Index: clang/unittests/AST/ASTTraverserTest.cpp
===================================================================
--- clang/unittests/AST/ASTTraverserTest.cpp
+++ clang/unittests/AST/ASTTraverserTest.cpp
@@ -30,14 +30,14 @@
void Visit(const Decl *D) {
OS << D->getDeclKindName() << "Decl";
if (auto *ND = dyn_cast<NamedDecl>(D)) {
- OS << " '" << ND->getDeclName() << "'";
+ OS << " '" << ND->getNameAsString() << "'";
}
}
void Visit(const Stmt *S) {
OS << S->getStmtClassName();
if (auto *E = dyn_cast<DeclRefExpr>(S)) {
- OS << " '" << E->getDecl()->getDeclName() << "'";
+ OS << " '" << E->getDecl()->getNameAsString() << "'";
}
}
@@ -479,4 +479,116 @@
)cpp");
}
+TEST(Traverse, LambdaUnlessSpelledInSource) {
+
+ auto AST =
+ buildASTFromCodeWithArgs(R"cpp(
+
+void captures() {
+ int a = 0;
+ int b = 0;
+ int d = 0;
+ int f = 0;
+
+ [a, &b, c = d, &e = f](int g, int h = 42) {};
+}
+
+void templated() {
+ int a = 0;
+ [a]<typename T>(T t) {};
+}
+
+struct SomeStruct {
+ int a = 0;
+ void capture_this() {
+ [this]() {};
+ }
+ void capture_this_copy() {
+ [self = *this]() {};
+ }
+};
+)cpp",
+ {"-Wno-unused-value", "-Wno-c++2a-extensions"});
+
+ auto getLambdaNode = [&AST](const std::string &name) {
+ auto BN = ast_matchers::match(
+ lambdaExpr(hasAncestor(functionDecl(hasName(name)))).bind("lambda"),
+ AST->getASTContext());
+ EXPECT_EQ(BN.size(), 1u);
+ return BN[0].getNodeAs<LambdaExpr>("lambda");
+ };
+
+ {
+ auto L = getLambdaNode("captures");
+
+ EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
+ R"cpp(
+LambdaExpr
+|-DeclRefExpr 'a'
+|-DeclRefExpr 'b'
+|-VarDecl 'c'
+| `-DeclRefExpr 'd'
+|-VarDecl 'e'
+| `-DeclRefExpr 'f'
+|-ParmVarDecl 'g'
+|-ParmVarDecl 'h'
+| `-IntegerLiteral
+`-CompoundStmt
+)cpp");
+
+ EXPECT_EQ(dumpASTString(ast_type_traits::TK_AsIs, L),
+ R"cpp(
+LambdaExpr
+`-CXXRecordDecl ''
+ |-CXXMethodDecl 'operator()'
+ | |-ParmVarDecl 'g'
+ | |-ParmVarDecl 'h'
+ | | `-IntegerLiteral
+ | `-CompoundStmt
+ |-FieldDecl ''
+ |-FieldDecl ''
+ |-FieldDecl ''
+ |-FieldDecl ''
+ `-CXXDestructorDecl '~'
+)cpp");
+ }
+
+ {
+ auto L = getLambdaNode("templated");
+
+ EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
+ R"cpp(
+LambdaExpr
+|-DeclRefExpr 'a'
+|-TemplateTypeParmDecl 'T'
+|-ParmVarDecl 't'
+`-CompoundStmt
+)cpp");
+ }
+
+ {
+ auto L = getLambdaNode("capture_this");
+
+ EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
+ R"cpp(
+LambdaExpr
+|-CXXThisExpr
+`-CompoundStmt
+)cpp");
+ }
+
+ {
+ auto L = getLambdaNode("capture_this_copy");
+
+ EXPECT_EQ(dumpASTString(ast_type_traits::TK_IgnoreUnlessSpelledInSource, L),
+ R"cpp(
+LambdaExpr
+|-VarDecl 'self'
+| `-UnaryOperator
+| `-CXXThisExpr
+`-CompoundStmt
+)cpp");
+ }
+}
+
} // namespace clang
Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -145,7 +145,9 @@
ScopedIncrement ScopedDepth(&CurrentDepth);
Stmt *StmtToTraverse = StmtNode;
- if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
+ if (auto *ExprNode = dyn_cast_or_null<LambdaExpr>(StmtNode))
+ StmtToTraverse = ExprNode;
+ else if (auto *ExprNode = dyn_cast_or_null<Expr>(StmtNode))
StmtToTraverse = Finder->getASTContext().traverseIgnored(ExprNode);
if (Traversal ==
ast_type_traits::TraversalKind::TK_IgnoreImplicitCastsAndParentheses) {
@@ -203,6 +205,42 @@
ScopedIncrement ScopedDepth(&CurrentDepth);
return traverse(*CtorInit);
}
+ bool TraverseLambdaExpr(LambdaExpr *Node) {
+ if (!Node)
+ return true;
+ ScopedIncrement ScopedDepth(&CurrentDepth);
+
+ for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
+ const auto *C = Node->capture_begin() + I;
+ if (!C->isExplicit())
+ continue;
+ if (Node->isInitCapture(C) && !match(*C->getCapturedVar())) {
+ return false;
+ } else if (!match(*Node->capture_init_begin()[I])) {
+ return false;
+ }
+ }
+ auto *TPL = Node->getTemplateParameterList();
+ if (TPL) {
+ for (const auto *TP : *TPL) {
+ if (!match(*TP)) {
+ return false;
+ }
+ }
+ }
+
+ auto CallOp = Node->getCallOperator();
+ for (auto *P : CallOp->parameters()) {
+ if (!match(*P)) {
+ return false;
+ }
+ }
+
+ if (!match(*Node->getBody()))
+ return false;
+
+ return false;
+ }
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
Index: clang/include/clang/AST/ASTNodeTraverser.h
===================================================================
--- clang/include/clang/AST/ASTNodeTraverser.h
+++ clang/include/clang/AST/ASTNodeTraverser.h
@@ -128,7 +128,8 @@
ConstStmtVisitor<Derived>::Visit(S);
// Some statements have custom mechanisms for dumping their children.
- if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S)) {
+ if (isa<DeclStmt>(S) || isa<GenericSelectionExpr>(S) ||
+ isa<LambdaExpr>(S)) {
return;
}
@@ -646,7 +647,24 @@
}
void VisitLambdaExpr(const LambdaExpr *Node) {
- Visit(Node->getLambdaClass());
+ if (Traversal == ast_type_traits::TK_IgnoreUnlessSpelledInSource) {
+ for (unsigned I = 0, N = Node->capture_size(); I != N; ++I) {
+ const auto *C = Node->capture_begin() + I;
+ if (!C->isExplicit())
+ continue;
+ if (Node->isInitCapture(C))
+ Visit(C->getCapturedVar());
+ else
+ Visit(Node->capture_init_begin()[I]);
+ }
+ dumpTemplateParameters(Node->getTemplateParameterList());
+ auto CallOp = Node->getCallOperator();
+ for (auto *P : CallOp->parameters())
+ Visit(P);
+ Visit(Node->getBody());
+ } else {
+ return Visit(Node->getLambdaClass());
+ }
}
void VisitSizeOfPackExpr(const SizeOfPackExpr *Node) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits