diff --git a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h --- a/clang/include/clang/ASTMatchers/ASTMatchersInternal.h +++ b/clang/include/clang/ASTMatchers/ASTMatchersInternal.h @@ -723,6 +723,8 @@ 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 --- a/clang/lib/ASTMatchers/ASTMatchFinder.cpp +++ b/clang/lib/ASTMatchers/ASTMatchFinder.cpp @@ -475,6 +475,58 @@ } } return true; + } else if (auto *LE = dyn_cast(S)) { + + for (unsigned I = 0, N = LE->capture_size(); I != N; ++I) { + const auto *C = LE->capture_begin() + I; + { + ASTNodeNotSpelledInSourceScope RAII( + this, TraversingASTNodeNotSpelledInSource || !C->isExplicit()); + TraverseLambdaCapture(LE, C, LE->capture_init_begin()[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(); + + if (auto *TPL = LE->getTemplateParameterList()) { + for (NamedDecl *D : *TPL) { + TraverseDecl(D); + } + if (Expr *RequiresClause = TPL->getRequiresClause()) { + TraverseStmt(RequiresClause); + } + } + + if (LE->hasExplicitParameters()) { + // Visit parameters. + for (unsigned I = 0, N = Proto.getNumParams(); I != N; ++I) + TraverseDecl(Proto.getParam(I)); + } + + 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::dataTraverseNode(S, Queue); } @@ -617,6 +669,9 @@ bool IsMatchingInASTNodeNotSpelledInSource() const override { return TraversingASTNodeNotSpelledInSource; } + bool IsMatchingInASTNodeNotAsIs() const override { + return TraversingASTNodeNotAsIs; + } bool TraverseTemplateInstantiations(ClassTemplateDecl *D) { ASTNodeNotSpelledInSourceScope RAII(this, true); @@ -638,6 +693,7 @@ private: bool TraversingASTNodeNotSpelledInSource = false; + bool TraversingASTNodeNotAsIs = false; bool TraversingASTChildrenNotSpelledInSource = false; struct ASTNodeNotSpelledInSourceScope { @@ -654,6 +710,18 @@ 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 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -293,6 +293,10 @@ Finder->IsMatchingInASTNodeNotSpelledInSource()) return false; + if (!Finder->isTraversalIgnoringImplicitNodes() && + Finder->IsMatchingInASTNodeNotAsIs()) + return false; + auto N = Finder->getASTContext().getParentMapContext().traverseIgnored(DynNode); @@ -317,6 +321,10 @@ 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 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -3065,6 +3065,33 @@ 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) {