jcking1034 updated this revision to Diff 386577. jcking1034 added a comment.
Add additional unit tests. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D113575/new/ https://reviews.llvm.org/D113575 Files: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/lib/ASTMatchers/Dynamic/Registry.cpp clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -4769,6 +4769,66 @@ 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) { EXPECT_TRUE(notMatches( "void x() { if(true) {} }", Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -1439,6 +1439,22 @@ 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) { StringRef T = "void f() { int x; static int y; } int a;static int b;extern int c;"; Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -246,6 +246,7 @@ REGISTER_MATCHER(forEachArgumentWithParamType); REGISTER_MATCHER(forEachConstructorInitializer); REGISTER_MATCHER(forEachDescendant); + REGISTER_MATCHER(forEachLambdaCapture); REGISTER_MATCHER(forEachOverridden); REGISTER_MATCHER(forEachSwitchCase); REGISTER_MATCHER(forField); @@ -424,6 +425,7 @@ REGISTER_MATCHER(isImplicit); REGISTER_MATCHER(isInStdNamespace); REGISTER_MATCHER(isInTemplateInstantiation); + REGISTER_MATCHER(isInitCapture); REGISTER_MATCHER(isInline); REGISTER_MATCHER(isInstanceMessage); REGISTER_MATCHER(isInstanceMethod); Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -4205,6 +4205,45 @@ 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. /// /// Example matches y (matcher = varDecl(isStaticLocal())) @@ -4590,6 +4629,18 @@ 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; /// Matches any capture in a lambda expression. Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -1191,7 +1191,17 @@ <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> @@ -4540,6 +4550,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('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 colspan="4" class="doc" id="hasAnyCapture0"><pre>Matches any capture in a lambda expression. @@ -5666,6 +5691,15 @@ </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 colspan="4" class="doc" id="isStaticLocal0"><pre>Matches a static variable with local scope.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits