jcking1034 updated this revision to Diff 383458.
jcking1034 marked 2 inline comments as done.
jcking1034 added a comment.
Update matcher names for clarity.
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(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_DoesNotBindToCaptureReferringToVarDecl) {
+ 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, RefersToThis) {
+ 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);
@@ -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);
@@ -157,6 +163,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);
@@ -465,6 +473,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,8 +4590,73 @@
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](){};
+/// auto g = [x = 1](){};
+/// }
+/// \endcode
+/// In the matcher
+/// lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("x")))),
+/// refersToVarDecl(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(refersToThis())))
+/// matches `[this]() { return cc; }`.
+AST_MATCHER(LambdaCapture, capturesThis) { return Node.capturesThis(); }
+
/// Matches any capture of a lambda expression.
///
+/// Deprecated. Use the overload of `hasAnyCapture` which accepts an
+/// `InnerMatcher` of type `Matcher<LambdaCapture>`, in combination with the
+/// `lambdaCapture` and `refersToVarDecl` matchers, instead.
+///
/// Given
/// \code
/// void foo() {
@@ -4598,7 +4665,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()) {
@@ -4615,6 +4682,10 @@
/// Matches any capture of 'this' in a lambda expression.
///
+/// Deprecated. Use the overload of `hasAnyCapture` which accepts an
+/// `InnerMatcher` of type `Matcher<LambdaCapture>`, in combination with the
+/// `lambdaCapture` and `refersToThis` matchers, instead.
+///
/// Given
/// \code
/// struct foo {
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,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(refersToThis())))
+ 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,8 +8354,27 @@
</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('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](){};
+ }
+In the matcher
+lambdaExpr(hasAnyCapture(lambdaCapture(refersToVarDecl(hasName("x")))),
+refersToVarDecl(hasName("x")) matches `int x` and `x = 1`.
+</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.
+
+Deprecated. Use the overload of `hasAnyCapture` which accepts an
+`InnerMatcher` of type `Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>>`, in combination with the
+`lambdaCapture` and `refersToThis` matchers, instead.
Given
struct foo {
@@ -8328,8 +8387,12 @@
</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.
+
+Deprecated. Use the overload of `hasAnyCapture` which accepts an
+`InnerMatcher` of type `Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1LambdaCapture.html">LambdaCapture</a>>`, in combination with the
+`lambdaCapture` and `refersToVarDecl` matchers, instead.
Given
void foo() {
@@ -8337,7 +8400,7 @@
auto f = [x](){};
}
lambdaExpr(hasAnyCapture(anything()))
- matches [x](){};
+ matches `[x](){}`.
</pre></td></tr>
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits