[ASTMatchers] Avoid pathological traversal over nested lambdas

Differential Revision: https://reviews.llvm.org/D95573
This commit is contained in:
Stephen Kelly 2021-01-27 23:47:05 +00:00
parent 39ecfe6143
commit 6f0df3cddb
3 changed files with 89 additions and 2 deletions

View File

@ -186,6 +186,9 @@ public:
/// code, e.g., implicit constructors and destructors.
bool shouldVisitImplicitCode() const { return false; }
/// Return whether this visitor should recurse into lambda body
bool shouldVisitLambdaBody() const { return true; }
/// Return whether this visitor should traverse post-order.
bool shouldTraversePostOrder() const { return false; }
@ -2057,6 +2060,14 @@ bool RecursiveASTVisitor<Derived>::TraverseFunctionHelper(FunctionDecl *D) {
// by clang.
(!D->isDefaulted() || getDerived().shouldVisitImplicitCode());
if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
if (const CXXRecordDecl *RD = MD->getParent()) {
if (RD->isLambda()) {
VisitBody = VisitBody && getDerived().shouldVisitLambdaBody();
}
}
}
if (VisitBody) {
TRY_TO(TraverseStmt(D->getBody())); // Function body.
}

View File

@ -556,9 +556,9 @@ public:
if (LE->hasExplicitResultType())
TraverseTypeLoc(Proto.getReturnLoc());
TraverseStmt(LE->getTrailingRequiresClause());
TraverseStmt(LE->getBody());
}
TraverseStmt(LE->getBody());
return true;
}
return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue);
@ -697,6 +697,10 @@ public:
bool shouldVisitTemplateInstantiations() const { return true; }
bool shouldVisitImplicitCode() const { return true; }
// We visit the lambda body explicitly, so instruct the RAV
// to not visit it on our behalf too.
bool shouldVisitLambdaBody() const { return false; }
bool IsMatchingInASTNodeNotSpelledInSource() const override {
return TraversingASTNodeNotSpelledInSource;
}

View File

@ -3853,6 +3853,78 @@ void binop()
}
}
TEST(IgnoringImpCasts, PathologicalLambda) {
// Test that deeply nested lambdas are not a performance penalty
StringRef Code = R"cpp(
void f() {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
[] {
int i = 42;
(void)i;
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}();
}
)cpp";
EXPECT_TRUE(matches(Code, integerLiteral(equals(42))));
EXPECT_TRUE(matches(Code, functionDecl(hasDescendant(integerLiteral(equals(42))))));
}
TEST(IgnoringImpCasts, MatchesImpCasts) {
// This test checks that ignoringImpCasts matches when implicit casts are
// present and its inner matcher alone does not match.