forked from OSchip/llvm-project
Add `isInitCapture` and `forEachLambdaCapture` matchers.
This contributes follow-up work from https://reviews.llvm.org/D112491, which allows for increased control over the matching of lambda captures. This also updates the documentation for the `lambdaCapture` matcher. Reviewed By: ymandel, aaron.ballman Differential Revision: https://reviews.llvm.org/D113575
This commit is contained in:
parent
0b5051cede
commit
9809c6c61c
|
@ -1191,7 +1191,17 @@ Example matches a
|
||||||
|
|
||||||
|
|
||||||
<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>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 colspan="4" class="doc" id="lambdaCapture0"><pre>Matches lambda captures.
|
||||||
|
|
||||||
|
Given
|
||||||
|
int main() {
|
||||||
|
int x;
|
||||||
|
auto f = [x](){};
|
||||||
|
auto g = [x = 1](){};
|
||||||
|
}
|
||||||
|
In the matcher `lambdaExpr(hasAnyCapture(lambdaCapture()))`,
|
||||||
|
`lambdaCapture()` matches `x` and `x=1`.
|
||||||
|
</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>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>
|
||||||
|
@ -4540,6 +4550,21 @@ implicit default/copy constructors).
|
||||||
</pre></td></tr>
|
</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('forEachLambdaCapture0')"><a name="forEachLambdaCapture0Anchor">forEachLambdaCapture</a></td><td>LambdaCaptureMatcher InnerMatcher</td></tr>
|
||||||
|
<tr><td colspan="4" class="doc" id="forEachLambdaCapture0"><pre>Matches each lambda capture in a lambda expression.
|
||||||
|
|
||||||
|
Given
|
||||||
|
int main() {
|
||||||
|
int x, y;
|
||||||
|
float z;
|
||||||
|
auto f = [=]() { return x + y + z; };
|
||||||
|
}
|
||||||
|
lambdaExpr(forEachLambdaCapture(
|
||||||
|
lambdaCapture(capturesVar(varDecl(hasType(isInteger()))))))
|
||||||
|
will trigger two matches, binding for 'x' and 'y' respectively.
|
||||||
|
</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>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.
|
<tr><td colspan="4" class="doc" id="hasAnyCapture0"><pre>Matches any capture in a lambda expression.
|
||||||
|
|
||||||
|
@ -5666,6 +5691,15 @@ varDecl(isExternC())
|
||||||
</pre></td></tr>
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
|
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isInitCapture0')"><a name="isInitCapture0Anchor">isInitCapture</a></td><td></td></tr>
|
||||||
|
<tr><td colspan="4" class="doc" id="isInitCapture0"><pre>Matches a variable serving as the implicit variable for a lambda init-
|
||||||
|
capture.
|
||||||
|
|
||||||
|
Example matches x (matcher = varDecl(isInitCapture()))
|
||||||
|
auto f = [x=3]() { return x; };
|
||||||
|
</pre></td></tr>
|
||||||
|
|
||||||
|
|
||||||
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isStaticLocal0')"><a name="isStaticLocal0Anchor">isStaticLocal</a></td><td></td></tr>
|
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1VarDecl.html">VarDecl</a>></td><td class="name" onclick="toggle('isStaticLocal0')"><a name="isStaticLocal0Anchor">isStaticLocal</a></td><td></td></tr>
|
||||||
<tr><td colspan="4" class="doc" id="isStaticLocal0"><pre>Matches a static variable with local scope.
|
<tr><td colspan="4" class="doc" id="isStaticLocal0"><pre>Matches a static variable with local scope.
|
||||||
|
|
||||||
|
|
|
@ -4205,6 +4205,45 @@ AST_MATCHER_P(
|
||||||
InnerMatcher.matches(*Initializer, Finder, Builder));
|
InnerMatcher.matches(*Initializer, Finder, Builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Matches a variable serving as the implicit variable for a lambda init-
|
||||||
|
/// capture.
|
||||||
|
///
|
||||||
|
/// Example matches x (matcher = varDecl(isInitCapture()))
|
||||||
|
/// \code
|
||||||
|
/// auto f = [x=3]() { return x; };
|
||||||
|
/// \endcode
|
||||||
|
AST_MATCHER(VarDecl, isInitCapture) { return Node.isInitCapture(); }
|
||||||
|
|
||||||
|
/// Matches each lambda capture in a lambda expression.
|
||||||
|
///
|
||||||
|
/// Given
|
||||||
|
/// \code
|
||||||
|
/// int main() {
|
||||||
|
/// int x, y;
|
||||||
|
/// float z;
|
||||||
|
/// auto f = [=]() { return x + y + z; };
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
/// lambdaExpr(forEachLambdaCapture(
|
||||||
|
/// lambdaCapture(capturesVar(varDecl(hasType(isInteger()))))))
|
||||||
|
/// will trigger two matches, binding for 'x' and 'y' respectively.
|
||||||
|
AST_MATCHER_P(LambdaExpr, forEachLambdaCapture, LambdaCaptureMatcher,
|
||||||
|
InnerMatcher) {
|
||||||
|
BoundNodesTreeBuilder Result;
|
||||||
|
bool Matched = false;
|
||||||
|
for (const auto &Capture : Node.captures()) {
|
||||||
|
if (Finder->isTraversalIgnoringImplicitNodes() && Capture.isImplicit())
|
||||||
|
continue;
|
||||||
|
BoundNodesTreeBuilder CaptureBuilder(*Builder);
|
||||||
|
if (InnerMatcher.matches(Capture, Finder, &CaptureBuilder)) {
|
||||||
|
Matched = true;
|
||||||
|
Result.addMatch(CaptureBuilder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*Builder = std::move(Result);
|
||||||
|
return Matched;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Matches a static variable with local scope.
|
/// \brief Matches a static variable with local scope.
|
||||||
///
|
///
|
||||||
/// Example matches y (matcher = varDecl(isStaticLocal()))
|
/// Example matches y (matcher = varDecl(isStaticLocal()))
|
||||||
|
@ -4590,6 +4629,18 @@ AST_POLYMORPHIC_MATCHER_P(hasAnyArgument,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Matches lambda captures.
|
||||||
|
///
|
||||||
|
/// Given
|
||||||
|
/// \code
|
||||||
|
/// int main() {
|
||||||
|
/// int x;
|
||||||
|
/// auto f = [x](){};
|
||||||
|
/// auto g = [x = 1](){};
|
||||||
|
/// }
|
||||||
|
/// \endcode
|
||||||
|
/// In the matcher `lambdaExpr(hasAnyCapture(lambdaCapture()))`,
|
||||||
|
/// `lambdaCapture()` matches `x` and `x=1`.
|
||||||
extern const internal::VariadicAllOfMatcher<LambdaCapture> lambdaCapture;
|
extern const internal::VariadicAllOfMatcher<LambdaCapture> lambdaCapture;
|
||||||
|
|
||||||
/// Matches any capture in a lambda expression.
|
/// Matches any capture in a lambda expression.
|
||||||
|
|
|
@ -246,6 +246,7 @@ RegistryMaps::RegistryMaps() {
|
||||||
REGISTER_MATCHER(forEachArgumentWithParamType);
|
REGISTER_MATCHER(forEachArgumentWithParamType);
|
||||||
REGISTER_MATCHER(forEachConstructorInitializer);
|
REGISTER_MATCHER(forEachConstructorInitializer);
|
||||||
REGISTER_MATCHER(forEachDescendant);
|
REGISTER_MATCHER(forEachDescendant);
|
||||||
|
REGISTER_MATCHER(forEachLambdaCapture);
|
||||||
REGISTER_MATCHER(forEachOverridden);
|
REGISTER_MATCHER(forEachOverridden);
|
||||||
REGISTER_MATCHER(forEachSwitchCase);
|
REGISTER_MATCHER(forEachSwitchCase);
|
||||||
REGISTER_MATCHER(forField);
|
REGISTER_MATCHER(forField);
|
||||||
|
@ -424,6 +425,7 @@ RegistryMaps::RegistryMaps() {
|
||||||
REGISTER_MATCHER(isImplicit);
|
REGISTER_MATCHER(isImplicit);
|
||||||
REGISTER_MATCHER(isInStdNamespace);
|
REGISTER_MATCHER(isInStdNamespace);
|
||||||
REGISTER_MATCHER(isInTemplateInstantiation);
|
REGISTER_MATCHER(isInTemplateInstantiation);
|
||||||
|
REGISTER_MATCHER(isInitCapture);
|
||||||
REGISTER_MATCHER(isInline);
|
REGISTER_MATCHER(isInline);
|
||||||
REGISTER_MATCHER(isInstanceMessage);
|
REGISTER_MATCHER(isInstanceMessage);
|
||||||
REGISTER_MATCHER(isInstanceMethod);
|
REGISTER_MATCHER(isInstanceMethod);
|
||||||
|
|
|
@ -1439,6 +1439,22 @@ TEST_P(ASTMatchersTest, IsStaticLocal) {
|
||||||
EXPECT_TRUE(notMatches("int X;", M));
|
EXPECT_TRUE(notMatches("int X;", M));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(ASTMatchersTest, IsInitCapture) {
|
||||||
|
if (!GetParam().isCXX11OrLater()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto M = varDecl(hasName("vd"), isInitCapture());
|
||||||
|
EXPECT_TRUE(notMatches(
|
||||||
|
"int main() { int vd = 3; auto f = [vd]() { return vd; }; }", M));
|
||||||
|
|
||||||
|
if (!GetParam().isCXX14OrLater()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EXPECT_TRUE(matches("int main() { auto f = [vd=3]() { return vd; }; }", M));
|
||||||
|
EXPECT_TRUE(matches(
|
||||||
|
"int main() { int x = 3; auto f = [vd=x]() { return vd; }; }", M));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(ASTMatchersTest, StorageDuration) {
|
TEST_P(ASTMatchersTest, StorageDuration) {
|
||||||
StringRef T =
|
StringRef T =
|
||||||
"void f() { int x; static int y; } int a;static int b;extern int c;";
|
"void f() { int x; static int y; } int a;static int b;extern int c;";
|
||||||
|
|
|
@ -4769,6 +4769,66 @@ TEST(ForEachConstructorInitializer, MatchesInitializers) {
|
||||||
cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer()))));
|
cxxConstructorDecl(forEachConstructorInitializer(cxxCtorInitializer()))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ForEachLambdaCapture, MatchesCaptures) {
|
||||||
|
EXPECT_TRUE(matches(
|
||||||
|
"int main() { int x, y; auto f = [x, y]() { return x + y; }; }",
|
||||||
|
lambdaExpr(forEachLambdaCapture(lambdaCapture())), langCxx11OrLater()));
|
||||||
|
auto matcher = lambdaExpr(forEachLambdaCapture(
|
||||||
|
lambdaCapture(capturesVar(varDecl(hasType(isInteger())))).bind("LC")));
|
||||||
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
|
"int main() { int x, y; float z; auto f = [=]() { return x + y + z; }; }",
|
||||||
|
matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 2)));
|
||||||
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
|
"int main() { int x, y; float z; auto f = [x, y, z]() { return x + y + "
|
||||||
|
"z; }; }",
|
||||||
|
matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ForEachLambdaCapture, IgnoreUnlessSpelledInSource) {
|
||||||
|
auto matcher =
|
||||||
|
traverse(TK_IgnoreUnlessSpelledInSource,
|
||||||
|
lambdaExpr(forEachLambdaCapture(
|
||||||
|
lambdaCapture(capturesVar(varDecl(hasType(isInteger()))))
|
||||||
|
.bind("LC"))));
|
||||||
|
EXPECT_TRUE(
|
||||||
|
notMatches("int main() { int x, y; auto f = [=]() { return x + y; }; }",
|
||||||
|
matcher, langCxx11OrLater()));
|
||||||
|
EXPECT_TRUE(
|
||||||
|
notMatches("int main() { int x, y; auto f = [&]() { return x + y; }; }",
|
||||||
|
matcher, langCxx11OrLater()));
|
||||||
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
|
R"cc(
|
||||||
|
int main() {
|
||||||
|
int x, y;
|
||||||
|
float z;
|
||||||
|
auto f = [=, &y]() { return x + y + z; };
|
||||||
|
}
|
||||||
|
)cc",
|
||||||
|
matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ForEachLambdaCapture, MatchImplicitCapturesOnly) {
|
||||||
|
auto matcher =
|
||||||
|
lambdaExpr(forEachLambdaCapture(lambdaCapture(isImplicit()).bind("LC")));
|
||||||
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
|
"int main() { int x, y, z; auto f = [=, &z]() { return x + y + z; }; }",
|
||||||
|
matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 2)));
|
||||||
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
|
"int main() { int x, y, z; auto f = [&, z]() { return x + y + z; }; }",
|
||||||
|
matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 2)));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ForEachLambdaCapture, MatchExplicitCapturesOnly) {
|
||||||
|
auto matcher = lambdaExpr(
|
||||||
|
forEachLambdaCapture(lambdaCapture(unless(isImplicit())).bind("LC")));
|
||||||
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
|
"int main() { int x, y, z; auto f = [=, &z]() { return x + y + z; }; }",
|
||||||
|
matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 1)));
|
||||||
|
EXPECT_TRUE(matchAndVerifyResultTrue(
|
||||||
|
"int main() { int x, y, z; auto f = [&, z]() { return x + y + z; }; }",
|
||||||
|
matcher, std::make_unique<VerifyIdIsBoundTo<LambdaCapture>>("LC", 1)));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(HasConditionVariableStatement, DoesNotMatchCondition) {
|
TEST(HasConditionVariableStatement, DoesNotMatchCondition) {
|
||||||
EXPECT_TRUE(notMatches(
|
EXPECT_TRUE(notMatches(
|
||||||
"void x() { if(true) {} }",
|
"void x() { if(true) {} }",
|
||||||
|
|
Loading…
Reference in New Issue