jcking1034 updated this revision to Diff 383823. jcking1034 marked 4 inline comments as done. jcking1034 added a comment.
Update missed names; remove original implementations of `hasAnyCapture`. 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/docs/ReleaseNotes.rst 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 clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -563,26 +563,6 @@ 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, MatchesMethodsOnLambda) { StringRef Code = R"cpp( struct A { Index: clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -2237,6 +2237,65 @@ 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_BindsToCaptureOfVarDecl) { + if (!GetParam().isCXX11OrLater()) { + return; + } + auto matcher = lambdaExpr( + hasAnyCapture(lambdaCapture(capturesVar(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(capturesVar( + 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_DoesNotBindToCaptureOfVarDecl) { + if (!GetParam().isCXX11OrLater()) { + return; + } + auto matcher = lambdaExpr( + hasAnyCapture(lambdaCapture(capturesVar(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(capturesVar(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, CapturesThis) { + if (!GetParam().isCXX11OrLater()) { + return; + } + auto matcher = lambdaExpr(hasAnyCapture(lambdaCapture(capturesThis()))); + 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(), capturesVar(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); @@ -157,6 +156,8 @@ REGISTER_MATCHER(builtinType); REGISTER_MATCHER(cStyleCastExpr); REGISTER_MATCHER(callExpr); + REGISTER_MATCHER(capturesThis); + REGISTER_MATCHER(capturesVar); REGISTER_MATCHER(caseStmt); REGISTER_MATCHER(castExpr); REGISTER_MATCHER(characterLiteral); @@ -264,6 +265,7 @@ REGISTER_MATCHER(hasAnyBase); REGISTER_MATCHER(hasAnyBinding); REGISTER_MATCHER(hasAnyBody); + REGISTER_MATCHER(hasAnyCapture); REGISTER_MATCHER(hasAnyClause); REGISTER_MATCHER(hasAnyConstructorInitializer); REGISTER_MATCHER(hasAnyDeclaration); @@ -465,6 +467,7 @@ REGISTER_MATCHER(lValueReferenceType); REGISTER_MATCHER(labelDecl); REGISTER_MATCHER(labelStmt); + REGISTER_MATCHER(lambdaCapture); REGISTER_MATCHER(lambdaExpr); REGISTER_MATCHER(linkageSpecDecl); REGISTER_MATCHER(materializeTemporaryExpr); 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,50 +4590,66 @@ return false; } -/// Matches any capture of a lambda expression. +extern const internal::VariadicAllOfMatcher<LambdaCapture> lambdaCapture; + +/// Matches any capture in a lambda expression. /// /// Given /// \code /// void foo() { -/// int x; -/// auto f = [x](){}; +/// int t = 5; +/// auto f = [=](){ return t; }; /// } /// \endcode -/// lambdaExpr(hasAnyCapture(anything())) -/// matches [x](){}; -AST_MATCHER_P_OVERLOAD(LambdaExpr, hasAnyCapture, internal::Matcher<VarDecl>, - InnerMatcher, 0) { +/// lambdaExpr(hasAnyCapture(lambdaCapture())) and +/// lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t"))))) +/// both match `[=](){ return t; }`. +AST_MATCHER_P(LambdaExpr, hasAnyCapture, LambdaCaptureMatcher, InnerMatcher) { 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; - } + clang::ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(Capture, Finder, &Result)) { + *Builder = std::move(Result); + return true; } } return false; } -/// Matches any capture of 'this' in a lambda expression. +/// Matches a `LambdaCapture` that refers to the specified `VarDecl` /// /// Given /// \code -/// struct foo { -/// void bar() { -/// auto f = [this](){}; -/// } +/// void foo() { +/// int x; +/// auto f = [x](){}; +/// auto g = [x = 1](){}; /// } /// \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(); - }); +/// In the matcher +/// lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))), +/// capturesVar(hasName("x")) matches `int x` and `x = 1`. +AST_MATCHER_P(LambdaCapture, capturesVar, 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(capturesThis()))) +/// matches `[this]() { return cc; }`. +AST_MATCHER(LambdaCapture, capturesThis) { return Node.capturesThis(); } + /// Matches a constructor call expression which uses list initialization. AST_MATCHER(CXXConstructExpr, isListInitialization) { return Node.isListInitialization(); 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/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -218,6 +218,13 @@ matcher or the ``hasReturnTypeLoc`` matcher. The addition of these matchers was made possible by changes to the handling of ``TypeLoc`` nodes that allows them to enjoy the same static type checking as other AST node kinds. +- ``LambdaCapture`` AST Matchers are now available. These matchers allow for + the binding of ``LambdaCapture`` nodes, and include the ``lambdaCapture``, + ``capturesVar``, and ``capturesThis`` matchers. In addition, the + ``hasAnyCapture`` matcher has been updated to accept an inner matcher of + type ``Matcher<LambdaCapture>`` - its original interface accepted an inner + matcher of type ``Matcher<CXXThisExpr>`` or ``Matcher<VarDecl>``, but did + not allow for the binding of ``LambdaCapture`` nodes. clang-format ------------ 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,42 @@ <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('capturesThis0')"><a name="capturesThis0Anchor">capturesThis</a></td><td></td></tr> +<tr><td colspan="4" class="doc" id="capturesThis0"><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(capturesThis()))) + matches `[this]() { return cc; }`. +</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_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 in a lambda expression. + +Given + void foo() { + int t = 5; + auto f = [=](){ return t; }; + } +lambdaExpr(hasAnyCapture(lambdaCapture())) and +lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("t"))))) + both match `[=](){ 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,30 +8354,18 @@ </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. +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>></td><td class="name" onclick="toggle('capturesVar0')"><a name="capturesVar0Anchor">capturesVar</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="capturesVar0"><pre>Matches a `LambdaCapture` that refers to the specified `VarDecl` Given void foo() { int x; auto f = [x](){}; + auto g = [x = 1](){}; } -lambdaExpr(hasAnyCapture(anything())) - matches [x](){}; +In the matcher +lambdaExpr(hasAnyCapture(lambdaCapture(capturesVar(hasName("x")))), +capturesVar(hasName("x")) matches `int x` and `x = 1`. </pre></td></tr>
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits