rhiro updated this revision to Diff 237389. rhiro added a comment. Fixed the condition for the varDecl case and made the cxxThisExpr more concise.
- Condition on `capturesVariable` instead of `capturesThis` and switch the loop in the cxxThisExpr overload to use llvm::any_of instead of an explicit loop. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D72414/new/ https://reviews.llvm.org/D72414 Files: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ 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 " Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ 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); Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ 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<VarDecl>, + 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<CXXThisExpr>, 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(); Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -5098,15 +5098,15 @@ <tr><td colspan="4" class="doc" id="hasInitStatement2"><pre>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 @@ <tr><td colspan="4" class="doc" id="hasInitStatement0"><pre>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 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaExpr.html">LambdaExpr</a>></td><td class="name" onclick="toggle('hasAnyCapture1')"><a name="hasAnyCapture1Anchor">hasAnyCapture</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXThisExpr.html">CXXThisExpr</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasAnyCapture1"><pre>Matches any capture of 'this' in a lambda expression. + +Given + struct foo { + void bar() { + auto f = [this](){}; + } + } +lambdaExpr(hasAnyCapture(cxxThisExpr())) + matches [this](){}; +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaExpr.html">LambdaExpr</a>></td><td class="name" onclick="toggle('hasAnyCapture0')"><a name="hasAnyCapture0Anchor">hasAnyCapture</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasAnyCapture0"><pre>Matches any capture of a lambda expression. + +Given + void foo() { + int x; + auto f = [x](){}; + } +lambdaExpr(hasAnyCapture(anything())) + matches [x](){}; +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1MemberExpr.html">MemberExpr</a>></td><td class="name" onclick="toggle('hasDeclaration7')"><a name="hasDeclaration7Anchor">hasDeclaration</a></td><td>const Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasDeclaration7"><pre>Matches a node if the declaration associated with that node matches the given matcher. @@ -7005,15 +7032,15 @@ <tr><td colspan="4" class="doc" id="hasInitStatement1"><pre>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 @@ </pre></td></tr> +<tr><td>Matcher<T></td><td class="name" onclick="toggle('traverse1')"><a name="traverse1Anchor">traverse</a></td><td>ast_type_traits::TraversalKind TK, const BindableMatcher<T> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="traverse1"><pre></pre></td></tr> + + <tr><td>Matcher<T></td><td class="name" onclick="toggle('traverse0')"><a name="traverse0Anchor">traverse</a></td><td>ast_type_traits::TraversalKind TK, const Matcher<T> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="traverse0"><pre>Causes all nested matchers to be matched with the specified traversal kind.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits