jcking1034 updated this revision to Diff 382410. jcking1034 added a comment.
Update comments and tests Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D112491/new/ https://reviews.llvm.org/D112491 Files: clang/docs/LibASTMatchersReference.html clang/include/clang/AST/ASTTypeTraits.h clang/include/clang/ASTMatchers/ASTMatchers.h clang/lib/AST/ASTTypeTraits.cpp clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -2237,6 +2237,66 @@ varDecl(hasName("ss"), hasTypeLoc(elaboratedTypeLoc())))); } +TEST_P(ASTMatchersTest, LambdaCaptureTest) { + if (!GetParam().isCXX11OrLater()) { + return; + } + EXPECT_TRUE(matches("int main() { int cc; auto f = [cc](){ return cc; }; }", + lambdaExpr(hasAnyCapture(lambdaCapture())))); +} + +TEST_P(ASTMatchersTest, LambdaCaptureTest_BindsToCaptureReferringToVarDecl) { + if (!GetParam().isCXX11OrLater()) { + return; + } + auto matcher = lambdaExpr( + hasAnyCapture(lambdaCapture(refersToVarDecl(varDecl(hasName("cc")))))); + EXPECT_TRUE(matches("int main() { int cc; auto f = [cc](){ return cc; }; }", + matcher)); + EXPECT_TRUE(matches("int main() { int cc; auto f = [&cc](){ return cc; }; }", + matcher)); + EXPECT_TRUE( + matches("int main() { int cc; auto f = [=](){ return cc; }; }", matcher)); + EXPECT_TRUE( + matches("int main() { int cc; auto f = [&](){ return cc; }; }", matcher)); +} + +TEST_P(ASTMatchersTest, LambdaCaptureTest_BindsToCaptureWithInitializer) { + if (!GetParam().isCXX14OrLater()) { + return; + } + auto matcher = lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl( + varDecl(hasName("cc"), hasInitializer(integerLiteral(equals(1)))))))); + EXPECT_TRUE( + matches("int main() { auto lambda = [cc = 1] {return cc;}; }", matcher)); + EXPECT_TRUE( + matches("int main() { int cc = 2; auto lambda = [cc = 1] {return cc;}; }", + matcher)); +} + +TEST_P(ASTMatchersTest, + LambdaCaptureTest_DoesNotBindToCaptureReferringToVarDecl) { + if (!GetParam().isCXX11OrLater()) { + return; + } + auto matcher = lambdaExpr( + hasAnyCapture(lambdaCapture(refersToVarDecl(varDecl(hasName("cc")))))); + EXPECT_FALSE(matches("int main() { auto f = [](){ return 5; }; }", matcher)); + EXPECT_FALSE(matches("int main() { int xx; auto f = [xx](){ return xx; }; }", + matcher)); +} + +TEST_P(ASTMatchersTest, + LambdaCaptureTest_DoesNotBindToCaptureWithInitializerAndDifferentName) { + if (!GetParam().isCXX14OrLater()) { + return; + } + EXPECT_FALSE(matches( + "int main() { auto lambda = [xx = 1] {return xx;}; }", + lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(varDecl( + hasName("cc"), hasInitializer(integerLiteral(equals(1)))))))))); +} + TEST(ASTMatchersTestObjC, ObjCMessageExpr) { // Don't find ObjCMessageExpr where none are present. EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything()))); Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -4445,5 +4445,42 @@ cxxRecordDecl(hasName("Derived"), hasDirectBase(hasType(cxxRecordDecl(hasName("Base"))))))); } + +TEST_P(ASTMatchersTest, RefersToThis) { + if (!GetParam().isCXX11OrLater()) { + return; + } + auto matcher = lambdaExpr(hasAnyCapture(lambdaCapture(refersToThis()))); + EXPECT_TRUE(matches("class C { int cc; int f() { auto l = [this](){ return " + "cc; }; return l(); } };", + matcher)); + EXPECT_TRUE(matches("class C { int cc; int f() { auto l = [=](){ return cc; " + "}; return l(); } };", + matcher)); + EXPECT_TRUE(matches("class C { int cc; int f() { auto l = [&](){ return cc; " + "}; return l(); } };", + matcher)); + EXPECT_FALSE(matches("class C { int cc; int f() { auto l = [cc](){ return " + "cc; }; return l(); } };", + matcher)); + EXPECT_FALSE(matches("class C { int this; int f() { auto l = [this](){ " + "return this; }; return l(); } };", + matcher)); +} + +TEST_P(ASTMatchersTest, IsImplicit_LambdaCapture) { + if (!GetParam().isCXX11OrLater()) { + return; + } + auto matcher = lambdaExpr(hasAnyCapture( + lambdaCapture(isImplicit(), refersToVarDecl(varDecl(hasName("cc")))))); + EXPECT_TRUE( + matches("int main() { int cc; auto f = [&](){ return cc; }; }", matcher)); + EXPECT_TRUE( + matches("int main() { int cc; auto f = [=](){ return cc; }; }", matcher)); + EXPECT_FALSE(matches("int main() { int cc; auto f = [cc](){ return cc; }; }", + matcher)); +} + } // namespace ast_matchers } // namespace clang Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -106,7 +106,6 @@ std::make_unique<internal::MapAnyOfBuilderDescriptor>()); REGISTER_OVERLOADED_2(callee); - REGISTER_OVERLOADED_2(hasAnyCapture); REGISTER_OVERLOADED_2(hasPrefix); REGISTER_OVERLOADED_2(hasType); REGISTER_OVERLOADED_2(ignoringParens); @@ -125,6 +124,13 @@ }; REGISTER_MATCHER_OVERLOAD(equals); + std::unique_ptr<MatcherDescriptor> hasAnyCaptureCallbacks[] = { + MATCHER_OVERLOAD_ENTRY(hasAnyCapture, 0), + MATCHER_OVERLOAD_ENTRY(hasAnyCapture, 1), + MATCHER_OVERLOAD_ENTRY(hasAnyCapture, 2), + }; + REGISTER_MATCHER_OVERLOAD(hasAnyCapture); + REGISTER_REGEX_MATCHER(isExpansionInFileMatching); REGISTER_REGEX_MATCHER(matchesName); REGISTER_REGEX_MATCHER(matchesSelector); @@ -465,6 +471,7 @@ REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(labelDecl); REGISTER_MATCHER(labelStmt); + REGISTER_MATCHER(lambdaCapture); REGISTER_MATCHER(lambdaExpr); REGISTER_MATCHER(linkageSpecDecl); REGISTER_MATCHER(materializeTemporaryExpr); @@ -525,7 +532,9 @@ REGISTER_MATCHER(refersToDeclaration); REGISTER_MATCHER(refersToIntegralType); REGISTER_MATCHER(refersToTemplate); + REGISTER_MATCHER(refersToThis); REGISTER_MATCHER(refersToType); + REGISTER_MATCHER(refersToVarDecl); REGISTER_MATCHER(requiresZeroInitialization); REGISTER_MATCHER(returnStmt); REGISTER_MATCHER(returns); Index: clang/lib/AST/ASTTypeTraits.cpp =================================================================== --- clang/lib/AST/ASTTypeTraits.cpp +++ clang/lib/AST/ASTTypeTraits.cpp @@ -26,6 +26,7 @@ {NKI_None, "<None>"}, {NKI_None, "TemplateArgument"}, {NKI_None, "TemplateArgumentLoc"}, + {NKI_None, "LambdaCapture"}, {NKI_None, "TemplateName"}, {NKI_None, "NestedNameSpecifierLoc"}, {NKI_None, "QualType"}, Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -148,6 +148,7 @@ using CXXCtorInitializerMatcher = internal::Matcher<CXXCtorInitializer>; using TemplateArgumentMatcher = internal::Matcher<TemplateArgument>; using TemplateArgumentLocMatcher = internal::Matcher<TemplateArgumentLoc>; +using LambdaCaptureMatcher = internal::Matcher<LambdaCapture>; using AttrMatcher = internal::Matcher<Attr>; /// @} @@ -756,7 +757,8 @@ /// Matches an entity that has been implicitly added by the compiler (e.g. /// implicit default/copy constructors). AST_POLYMORPHIC_MATCHER(isImplicit, - AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Attr)) { + AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Attr, + LambdaCapture)) { return Node.isImplicit(); } @@ -4588,6 +4590,66 @@ return false; } +extern const internal::VariadicAllOfMatcher<LambdaCapture> lambdaCapture; + +/// Matches any capture in a lambda expression. +/// +/// Given +/// \code +/// void foo() { +/// int t = 5; +/// auto f = [=](){ return t; }; +/// } +/// \endcode +/// lambdaExpr(hasAnyCapture(lambdaCapture())) and +/// lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t"))))) +/// both match `[=](){ return t; }`. +AST_MATCHER_P_OVERLOAD(LambdaExpr, hasAnyCapture, LambdaCaptureMatcher, + InnerMatcher, 2) { + for (const LambdaCapture &Capture : Node.captures()) { + clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(Capture, Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +/// Matches a `LambdaCapture` that refers to the specified `VarDecl` +/// +/// Given +/// \code +/// void foo() { +/// int x; +/// auto f = [x](){}; +/// } +/// \endcode +/// In the matcher +/// lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("x")))), +/// refersToVarDecl(hasName("x")) matches `int x`. +AST_MATCHER_P(LambdaCapture, refersToVarDecl, internal::Matcher<VarDecl>, + InnerMatcher) { + auto *capturedVar = Node.getCapturedVar(); + return capturedVar && InnerMatcher.matches(*capturedVar, Finder, Builder); +} + +/// Matches a `LambdaCapture` that refers to 'this'. +/// +/// Given +/// \code +/// class C { +/// int cc; +/// int f() { +/// auto l = [this]() { return cc; }; +/// return l(); +/// } +/// }; +/// \endcode +/// lambdaExpr(hasAnyCapture(lambdaCapture(refersToThis()))) +/// matches `[this]() { return cc; }`. +AST_MATCHER(LambdaCapture, refersToThis) { return Node.capturesThis(); } + /// Matches any capture of a lambda expression. /// /// Given @@ -4598,7 +4660,7 @@ /// } /// \endcode /// lambdaExpr(hasAnyCapture(anything())) -/// matches [x](){}; +/// matches `[x](){}`. AST_MATCHER_P_OVERLOAD(LambdaExpr, hasAnyCapture, internal::Matcher<VarDecl>, InnerMatcher, 0) { for (const LambdaCapture &Capture : Node.captures()) { Index: clang/include/clang/AST/ASTTypeTraits.h =================================================================== --- clang/include/clang/AST/ASTTypeTraits.h +++ clang/include/clang/AST/ASTTypeTraits.h @@ -17,6 +17,7 @@ #include "clang/AST/ASTFwd.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TypeLoc.h" @@ -64,6 +65,7 @@ static ASTNodeKind getFromNode(const Stmt &S); static ASTNodeKind getFromNode(const Type &T); static ASTNodeKind getFromNode(const TypeLoc &T); + static ASTNodeKind getFromNode(const LambdaCapture &L); static ASTNodeKind getFromNode(const OMPClause &C); static ASTNodeKind getFromNode(const Attr &A); /// \} @@ -131,6 +133,7 @@ NKI_None, NKI_TemplateArgument, NKI_TemplateArgumentLoc, + NKI_LambdaCapture, NKI_TemplateName, NKI_NestedNameSpecifierLoc, NKI_QualType, @@ -197,6 +200,7 @@ KIND_TO_KIND_ID(CXXCtorInitializer) KIND_TO_KIND_ID(TemplateArgument) KIND_TO_KIND_ID(TemplateArgumentLoc) +KIND_TO_KIND_ID(LambdaCapture) KIND_TO_KIND_ID(TemplateName) KIND_TO_KIND_ID(NestedNameSpecifier) KIND_TO_KIND_ID(NestedNameSpecifierLoc) @@ -540,6 +544,10 @@ struct DynTypedNode::BaseConverter<TemplateArgumentLoc, void> : public ValueConverter<TemplateArgumentLoc> {}; +template <> +struct DynTypedNode::BaseConverter<LambdaCapture, void> + : public ValueConverter<LambdaCapture> {}; + template <> struct DynTypedNode::BaseConverter< TemplateName, void> : public ValueConverter<TemplateName> {}; Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -1190,6 +1190,10 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>></td><td class="name" onclick="toggle('lambdaCapture0')"><a name="lambdaCapture0Anchor">lambdaCapture</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="lambdaCapture0"><pre></pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('nestedNameSpecifierLoc0')"><a name="nestedNameSpecifierLoc0Anchor">nestedNameSpecifierLoc</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>>...</td></tr> <tr><td colspan="4" class="doc" id="nestedNameSpecifierLoc0"><pre>Same as nestedNameSpecifier but matches NestedNameSpecifierLoc. </pre></td></tr> @@ -4514,6 +4518,41 @@ <tr><td colspan="4" class="doc" id="equals9"><pre></pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>></td><td class="name" onclick="toggle('isImplicit2')"><a name="isImplicit2Anchor">isImplicit</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="isImplicit2"><pre>Matches an entity that has been implicitly added by the compiler (e.g. +implicit default/copy constructors). +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>></td><td class="name" onclick="toggle('refersToThis0')"><a name="refersToThis0Anchor">refersToThis</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="refersToThis0"><pre>Matches a `LambdaCapture` that refers to 'this'. + +Given +class C { + int cc; + int f() { + auto l = [this]() { return cc; }; + return l(); + } +}; +lambdaExpr(hasAnyCapture(lambdaCapture(refersToThis()))) + matches `[this]() { return cc; }`. +</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>LambdaCaptureMatcher InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasAnyCapture0"><pre>Matches any capture of a lambda expression. + +Given + void foo() { + int t = 5; + auto f = [=](){ return t; }; + } +lambdaExpr(hasAnyCapture(lambdaCapture())) + matches `[=](){ return t; }`. +</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('isArrow0')"><a name="isArrow0Anchor">isArrow</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isArrow0"><pre>Matches member expressions that are called with '->' as opposed to '.'. @@ -8314,8 +8353,21 @@ </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. +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>></td><td class="name" onclick="toggle('refersToVarDecl0')"><a name="refersToVarDecl0Anchor">refersToVarDecl</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="refersToVarDecl0"><pre>Matches a `LambdaCapture` that refers to the specified `VarDecl` + +Given + void foo() { + int x; + auto f = [x](){}; + } +lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("x")))) + matches `[x](){}`. +</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('hasAnyCapture2')"><a name="hasAnyCapture2Anchor">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="hasAnyCapture2"><pre>Matches any capture of 'this' in a lambda expression. Given struct foo { @@ -8328,8 +8380,8 @@ </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. +<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_1VarDecl.html">VarDecl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="hasAnyCapture1"><pre>Matches any capture of a lambda expression. Given void foo() { @@ -8337,7 +8389,7 @@ auto f = [x](){}; } lambdaExpr(hasAnyCapture(anything())) - matches [x](){}; + matches `[x](){}`. </pre></td></tr>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits