Author: Stephen Kelly Date: 2021-01-05T14:39:46Z New Revision: c3a21e5de3dc3f55e4d219afd55dec518159d356
URL: https://github.com/llvm/llvm-project/commit/c3a21e5de3dc3f55e4d219afd55dec518159d356 DIFF: https://github.com/llvm/llvm-project/commit/c3a21e5de3dc3f55e4d219afd55dec518159d356.diff LOG: [ASTMatchers] Ensure that we can match inside lambdas Because we don't know in ASTMatchFinder whether we're matching in AsIs or IgnoreUnlessSpelledInSource mode, we need to traverse the lambda twice, but store whether we're matching in nodes spelled in source or not. Differential Revision: https://reviews.llvm.org/D93688 Added: Modified: clang/include/clang/ASTMatchers/ASTMatchersInternal.h clang/lib/ASTMatchers/ASTMatchFinder.cpp clang/lib/ASTMatchers/ASTMatchersInternal.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Removed: ################################################################################ diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h index 46de4093272d..f49728d1f50e 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -723,6 +723,8 @@ class ASTMatchFinder { virtual bool IsMatchingInASTNodeNotSpelledInSource() const = 0; + virtual bool IsMatchingInASTNodeNotAsIs() const = 0; + bool isTraversalIgnoringImplicitNodes() const; protected: diff --git a/clang/lib/ASTMatchers/ASTMatchFinder.cpp b/clang/lib/ASTMatchers/ASTMatchFinder.cpp index 762885fa0052..af21e2283d8b 100644 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -475,6 +475,55 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, } } return true; + } else if (auto *LE = dyn_cast<LambdaExpr>(S)) { + for (auto I : llvm::zip(LE->captures(), LE->capture_inits())) { + auto C = std::get<0>(I); + ASTNodeNotSpelledInSourceScope RAII( + this, TraversingASTNodeNotSpelledInSource || !C.isExplicit()); + TraverseLambdaCapture(LE, &C, std::get<1>(I)); + } + + { + ASTNodeNotSpelledInSourceScope RAII(this, true); + TraverseDecl(LE->getLambdaClass()); + } + { + ASTNodeNotAsIsSourceScope RAII(this, true); + + // We need to poke around to find the bits that might be explicitly + // written. + TypeLoc TL = LE->getCallOperator()->getTypeSourceInfo()->getTypeLoc(); + FunctionProtoTypeLoc Proto = TL.getAsAdjusted<FunctionProtoTypeLoc>(); + + if (auto *TPL = LE->getTemplateParameterList()) { + for (NamedDecl *D : *TPL) { + TraverseDecl(D); + } + if (Expr *RequiresClause = TPL->getRequiresClause()) { + TraverseStmt(RequiresClause); + } + } + + if (LE->hasExplicitParameters()) { + // Visit parameters. + for (ParmVarDecl *Param : Proto.getParams()) + TraverseDecl(Param); + } + + const auto *T = Proto.getTypePtr(); + for (const auto &E : T->exceptions()) + TraverseType(E); + + if (Expr *NE = T->getNoexceptExpr()) + TraverseStmt(NE, Queue); + + if (LE->hasExplicitResultType()) + TraverseTypeLoc(Proto.getReturnLoc()); + TraverseStmt(LE->getTrailingRequiresClause()); + + TraverseStmt(LE->getBody()); + } + return true; } return RecursiveASTVisitor<MatchASTVisitor>::dataTraverseNode(S, Queue); } @@ -617,6 +666,9 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, bool IsMatchingInASTNodeNotSpelledInSource() const override { return TraversingASTNodeNotSpelledInSource; } + bool IsMatchingInASTNodeNotAsIs() const override { + return TraversingASTNodeNotAsIs; + } bool TraverseTemplateInstantiations(ClassTemplateDecl *D) { ASTNodeNotSpelledInSourceScope RAII(this, true); @@ -638,6 +690,7 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, private: bool TraversingASTNodeNotSpelledInSource = false; + bool TraversingASTNodeNotAsIs = false; bool TraversingASTChildrenNotSpelledInSource = false; struct ASTNodeNotSpelledInSourceScope { @@ -654,6 +707,18 @@ class MatchASTVisitor : public RecursiveASTVisitor<MatchASTVisitor>, bool MB; }; + struct ASTNodeNotAsIsSourceScope { + ASTNodeNotAsIsSourceScope(MatchASTVisitor *V, bool B) + : MV(V), MB(V->TraversingASTNodeNotAsIs) { + V->TraversingASTNodeNotAsIs = B; + } + ~ASTNodeNotAsIsSourceScope() { MV->TraversingASTNodeNotAsIs = MB; } + + private: + MatchASTVisitor *MV; + bool MB; + }; + struct ASTChildrenNotSpelledInSource { ASTChildrenNotSpelledInSource(MatchASTVisitor *V, bool B) : MV(V), MB(V->TraversingASTChildrenNotSpelledInSource) { diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 3c19bceb079e..eb0fffcc3c37 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -293,6 +293,10 @@ bool DynTypedMatcher::matches(const DynTypedNode &DynNode, Finder->IsMatchingInASTNodeNotSpelledInSource()) return false; + if (!Finder->isTraversalIgnoringImplicitNodes() && + Finder->IsMatchingInASTNodeNotAsIs()) + return false; + auto N = Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); @@ -317,6 +321,10 @@ bool DynTypedMatcher::matchesNoKindCheck(const DynTypedNode &DynNode, Finder->IsMatchingInASTNodeNotSpelledInSource()) return false; + if (!Finder->isTraversalIgnoringImplicitNodes() && + Finder->IsMatchingInASTNodeNotAsIs()) + return false; + auto N = Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp index a3a3a911b85c..1dc5179ce857 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -3065,6 +3065,33 @@ void func14() { traverse(TK_IgnoreUnlessSpelledInSource, functionDecl(hasName("func14"), hasDescendant(floatLiteral()))), langCxx20OrLater())); + + Code = R"cpp( +void foo() { + int explicit_captured = 0; + int implicit_captured = 0; + auto l = [&, explicit_captured](int i) { + if (i || explicit_captured || implicit_captured) return; + }; +} +)cpp"; + + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, ifStmt()))); + EXPECT_TRUE( + matches(Code, traverse(TK_IgnoreUnlessSpelledInSource, ifStmt()))); + + auto lambdaExplicitCapture = declRefExpr( + to(varDecl(hasName("explicit_captured"))), unless(hasAncestor(ifStmt()))); + auto lambdaImplicitCapture = declRefExpr( + to(varDecl(hasName("implicit_captured"))), unless(hasAncestor(ifStmt()))); + + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, lambdaExplicitCapture))); + EXPECT_TRUE(matches( + Code, traverse(TK_IgnoreUnlessSpelledInSource, lambdaExplicitCapture))); + + EXPECT_TRUE(matches(Code, traverse(TK_AsIs, lambdaImplicitCapture))); + EXPECT_FALSE(matches( + Code, traverse(TK_IgnoreUnlessSpelledInSource, lambdaImplicitCapture))); } TEST(IgnoringImpCasts, MatchesImpCasts) { _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits