diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -5098,15 +5098,15 @@
Matches selection statements with initializer. Given: - void foo() { + void foo() { if (int i = foobar(); i > 0) {} switch (int i = foobar(); i) {} - for (auto& a = get_range(); auto& x : a) {} + for (auto& a = get_range(); auto& x : a) {} } - void bar() { + void bar() { if (foobar() > 0) {} switch (foobar()) {} - for (auto& x : get_range()) {} + for (auto& x : get_range()) {} } ifStmt(hasInitStatement(anything())) matches the if statement in foo but not in bar. @@ -6245,15 +6245,15 @@+ Matches selection statements with initializer. Given: - void foo() { + void foo() { if (int i = foobar(); i > 0) {} switch (int i = foobar(); i) {} - for (auto& a = get_range(); auto& x : a) {} + for (auto& a = get_range(); auto& x : a) {} } - void bar() { + void bar() { if (foobar() > 0) {} switch (foobar()) {} - for (auto& x : get_range()) {} + for (auto& x : get_range()) {} } ifStmt(hasInitStatement(anything())) matches the if statement in foo but not in bar. @@ -6364,6 +6364,33 @@+ Matcher<LambdaExpr> hasAnyCapture Matcher<CXXThisExpr> InnerMatcher + + + Matches any capture of 'this' in a lambda expression. + +Given + struct foo { + void bar() { + auto f = [this](){}; + } + } +lambdaExpr(hasAnyCapture(cxxThisExpr())) + matches [this](){}; ++ Matcher<LambdaExpr> hasAnyCapture Matcher<VarDecl> InnerMatcher + + Matches any capture of a lambda expression. + +Given + void foo() { + int x; + auto f = [x](){}; + } +lambdaExpr(hasAnyCapture(anything())) + matches [x](){}; +Matcher<MemberExpr> hasDeclaration const Matcher<Decl> InnerMatcher Matches a node if the declaration associated with that node matches the given matcher. @@ -7005,15 +7032,15 @@+ Matches selection statements with initializer. Given: - void foo() { + void foo() { if (int i = foobar(); i > 0) {} switch (int i = foobar(); i) {} - for (auto& a = get_range(); auto& x : a) {} + for (auto& a = get_range(); auto& x : a) {} } - void bar() { + void bar() { if (foobar() > 0) {} switch (foobar()) {} - for (auto& x : get_range()) {} + for (auto& x : get_range()) {} } ifStmt(hasInitStatement(anything())) matches the if statement in foo but not in bar. @@ -7251,6 +7278,10 @@+ Matcher<T> traverse ast_type_traits::TraversalKind TK, const BindableMatcher<T> InnerMatcher + + Matcher<T> traverse ast_type_traits::TraversalKind TK, const Matcher<T> InnerMatcher Causes all nested matchers to be matched with the specified traversal kind. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -55,6 +55,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/OperationKinds.h" @@ -4014,6 +4015,50 @@ return false; } +/// Matches any capture of a lambda expression. +/// +/// Given +/// \code +/// void foo() { +/// int x; +/// auto f = [x](){}; +/// } +/// \endcode +/// lambdaExpr(hasAnyCapture(anything())) +/// matches [x](){}; +AST_MATCHER_P_OVERLOAD(LambdaExpr, hasAnyCapture, internal::Matcher, + InnerMatcher, 0) { + for (const LambdaCapture &Capture : Node.captures()) { + if (Capture.capturesVariable()) { + BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(*Capture.getCapturedVar(), Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + } + return false; +} + +/// Matches any capture of 'this' in a lambda expression. +/// +/// Given +/// \code +/// struct foo { +/// void bar() { +/// auto f = [this](){}; +/// } +/// } +/// \endcode +/// lambdaExpr(hasAnyCapture(cxxThisExpr())) +/// matches [this](){}; +AST_MATCHER_P_OVERLOAD(LambdaExpr, hasAnyCapture, + internal::Matcher , InnerMatcher, 1) { + return llvm::any_of(Node.captures(), [](const LambdaCapture &LC) { + return LC.capturesThis(); + }); +} + /// Matches a constructor call expression which uses list initialization. AST_MATCHER(CXXConstructExpr, isListInitialization) { return Node.isListInitialization(); diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -105,6 +105,7 @@ // equalsNode REGISTER_OVERLOADED_2(callee); + REGISTER_OVERLOADED_2(hasAnyCapture); REGISTER_OVERLOADED_2(hasPrefix); REGISTER_OVERLOADED_2(hasType); REGISTER_OVERLOADED_2(ignoringParens); 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 @@ -454,6 +454,26 @@ objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x")))))))); } +TEST(Matcher, HasAnyCapture) { + auto HasCaptureX = lambdaExpr(hasAnyCapture(varDecl(hasName("x")))); + EXPECT_TRUE(matches("void f() { int x = 3; [x](){}; }", HasCaptureX)); + EXPECT_TRUE(matches("void f() { int x = 3; [&x](){}; }", HasCaptureX)); + EXPECT_TRUE(notMatches("void f() { [](){}; }", HasCaptureX)); + EXPECT_TRUE(notMatches("void f() { int z = 3; [&z](){}; }", HasCaptureX)); + EXPECT_TRUE( + notMatches("struct a { void f() { [this](){}; }; };", HasCaptureX)); +} + +TEST(Matcher, CapturesThis) { + auto HasCaptureThis = lambdaExpr(hasAnyCapture(cxxThisExpr())); + EXPECT_TRUE( + matches("struct a { void f() { [this](){}; }; };", HasCaptureThis)); + EXPECT_TRUE(notMatches("void f() { [](){}; }", HasCaptureThis)); + EXPECT_TRUE(notMatches("void f() { int x = 3; [x](){}; }", HasCaptureThis)); + EXPECT_TRUE(notMatches("void f() { int x = 3; [&x](){}; }", HasCaptureThis)); + EXPECT_TRUE(notMatches("void f() { int z = 3; [&z](){}; }", HasCaptureThis)); +} + TEST(Matcher, isClassMessage) { EXPECT_TRUE(matchesObjC( "@interface NSString +(NSString *) stringWithFormat; @end "