rhiro created this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Add new AST matchers `hasAnyCapture` and `capturesThis` as LambdaExpr matchers. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D72414 Files: clang/include/clang/ASTMatchers/ASTMatchers.h clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -454,6 +454,26 @@ 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(capturesThis()); + 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, isClassMessage) { EXPECT_TRUE(matchesObjC( "@interface NSString +(NSString *) stringWithFormat; @end " Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -55,6 +55,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/OperationKinds.h" @@ -4014,6 +4015,53 @@ return false; } +/// Matches any capture of a lambda expression. +/// +/// Given +/// \code +/// void foo() { +/// int x; +/// auto f = [x](){}; +/// } +/// \endcode +/// lambdaExpr(hasAnyCapture(anything())) +/// matches [x](){}; +AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher<VarDecl>, + InnerMatcher) { + for (const LambdaCapture &Capture : Node.captures()) { + if (Capture.capturesThis()) { + continue; + } + BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(*Capture.getCapturedVar(), Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +/// Matches any capture of 'this' in a lambda expression. +/// +/// Given +/// \code +/// struct foo { +/// void bar() { +/// auto f = [this](){}; +/// } +/// } +/// \endcode +/// lambdaExpr(capturesThis()) +/// matches [this](){}; +AST_MATCHER(LambdaExpr, capturesThis) { + for (const LambdaCapture &Capture : Node.captures()) { + if (Capture.capturesThis()) { + return true; + } + } + return false; +} + /// Matches a constructor call expression which uses list initialization. AST_MATCHER(CXXConstructExpr, isListInitialization) { return Node.isListInitialization();
Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -454,6 +454,26 @@ 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(capturesThis()); + 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, isClassMessage) { EXPECT_TRUE(matchesObjC( "@interface NSString +(NSString *) stringWithFormat; @end " Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -55,6 +55,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/LambdaCapture.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/OpenMPClause.h" #include "clang/AST/OperationKinds.h" @@ -4014,6 +4015,53 @@ return false; } +/// Matches any capture of a lambda expression. +/// +/// Given +/// \code +/// void foo() { +/// int x; +/// auto f = [x](){}; +/// } +/// \endcode +/// lambdaExpr(hasAnyCapture(anything())) +/// matches [x](){}; +AST_MATCHER_P(LambdaExpr, hasAnyCapture, internal::Matcher<VarDecl>, + InnerMatcher) { + for (const LambdaCapture &Capture : Node.captures()) { + if (Capture.capturesThis()) { + continue; + } + BoundNodesTreeBuilder Result(*Builder); + if (InnerMatcher.matches(*Capture.getCapturedVar(), Finder, &Result)) { + *Builder = std::move(Result); + return true; + } + } + return false; +} + +/// Matches any capture of 'this' in a lambda expression. +/// +/// Given +/// \code +/// struct foo { +/// void bar() { +/// auto f = [this](){}; +/// } +/// } +/// \endcode +/// lambdaExpr(capturesThis()) +/// matches [this](){}; +AST_MATCHER(LambdaExpr, capturesThis) { + for (const LambdaCapture &Capture : Node.captures()) { + if (Capture.capturesThis()) { + return true; + } + } + return false; +} + /// Matches a constructor call expression which uses list initialization. AST_MATCHER(CXXConstructExpr, isListInitialization) { return Node.isListInitialization();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits