Author: Reid Date: 2020-01-10T15:49:43-05:00 New Revision: 4ffcec40acebae7161ac7426edc68290bbaca2b8
URL: https://github.com/llvm/llvm-project/commit/4ffcec40acebae7161ac7426edc68290bbaca2b8 DIFF: https://github.com/llvm/llvm-project/commit/4ffcec40acebae7161ac7426edc68290bbaca2b8.diff LOG: Implement new AST matcher hasAnyCapture to match on LambdaExpr captures. Accepts child matchers cxxThisExpr to match on capture of this and also on varDecl. Added: Modified: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Removed: ################################################################################ diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 05562c543c47..5bb181b04d3a 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -6390,6 +6390,33 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </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. @@ -7277,6 +7304,10 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2> </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. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 71cb85264bc2..9a5888b7572b 100644 --- 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" @@ -4044,6 +4045,50 @@ AST_POLYMORPHIC_MATCHER_P(hasAnyArgument, 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(); diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 475818bc3ae5..1c0930c5983a 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -105,6 +105,7 @@ RegistryMaps::RegistryMaps() { // 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 index ee7b3bfd5b1b..23447baf912b 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -454,6 +454,26 @@ TEST(Matcher, HasReceiver) { 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 " _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits