Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -8814,7 +8814,7 @@
Matches declaration of the function the statement belongs to ++ Matches declaration of the function the statement belongs to. Given: F& operator=(const F& o) { @@ -8827,6 +8827,23 @@+ Matcher<Stmt> forCallable Matcher<Decl> InnerMatcher + + +Matches declaration of the function, method, or block the statement belongs to. +Similar to 'forFunction' but additionally covers Objective-C methods and blocks. + +Given: +-(void) foo { + int x = 1; + dispatch_sync(queue, ^{ int y = 2; }); +} + +declStmt(forCallable(objcMethodDecl())) + matches 'int x = 1' + but does not match 'int y = 2'. +Matcher<Stmt> sizeOfExpr Matcher<UnaryExprOrTypeTraitExpr> InnerMatcher Same as unaryExprOrTypeTraitExpr, but only matching sizeof. Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -7543,7 +7543,7 @@ }); } -/// Matches declaration of the function the statement belongs to +/// Matches declaration of the function the statement belongs to. /// /// Given: /// \code @@ -7559,21 +7559,67 @@ InnerMatcher) { const auto &Parents = Finder->getASTContext().getParents(Node); + llvm::SmallVectorStack(Parents.begin(), Parents.end()); + while (!Stack.empty()) { + const auto &CurNode = Stack.back(); + Stack.pop_back(); + if (const auto *FuncDeclNode = CurNode.get ()) { + if (InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) { + return true; + } + } else if (const auto *LambdaExprNode = CurNode.get ()) { + if (InnerMatcher.matches(*LambdaExprNode->getCallOperator(), Finder, + Builder)) { + return true; + } + } else { + for (const auto &Parent : Finder->getASTContext().getParents(CurNode)) + Stack.push_back(Parent); + } + } + return false; +} + +/// Matches declaration of the function, method, or block +/// the statement belongs to. Similar to 'forFunction' but additionally covers +/// Objective-C methods and blocks. +/// +/// Given: +/// \code +/// -(void) foo { +/// int x = 1; +/// dispatch_sync(queue, ^{ int y = 2; }); +/// } +/// \endcode +/// declStmt(forCallable(objcMethodDecl())) +/// matches 'int x = 1' +/// but does not match 'int y = 2'. +AST_MATCHER_P(Stmt, forCallable, internal::Matcher , InnerMatcher) { + const auto &Parents = Finder->getASTContext().getParents(Node); + llvm::SmallVector Stack(Parents.begin(), Parents.end()); while(!Stack.empty()) { const auto &CurNode = Stack.back(); Stack.pop_back(); - if(const auto *FuncDeclNode = CurNode.get ()) { - if(InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) { + if (const auto *FuncDeclNode = CurNode.get ()) { + if (InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) { + return true; + } + } else if (const auto *LambdaExprNode = CurNode.get ()) { + if (InnerMatcher.matches(*LambdaExprNode->getCallOperator(), Finder, + Builder)) { + return true; + } + } else if (const auto *ObjCMethodDeclNode = CurNode.get ()) { + if (InnerMatcher.matches(*ObjCMethodDeclNode, Finder, Builder)) { return true; } - } else if(const auto *LambdaExprNode = CurNode.get ()) { - if(InnerMatcher.matches(*LambdaExprNode->getCallOperator(), - Finder, Builder)) { + } else if (const auto *BlockDeclNode = CurNode.get ()) { + if (InnerMatcher.matches(*BlockDeclNode, Finder, Builder)) { return true; } } else { - for(const auto &Parent: Finder->getASTContext().getParents(CurNode)) + for (const auto &Parent : Finder->getASTContext().getParents(CurNode)) Stack.push_back(Parent); } } Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp +++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp @@ -5524,6 +5524,47 @@ EXPECT_TRUE(notMatches(CppString2, returnStmt(forFunction(hasName("F"))))); } +TEST(StatementMatcher, ForCallable) { + StringRef ObjCString1 = "@interface I" + "-(void) foo;" + "@end" + "@implementation I" + "-(void) foo {" + " void (^block)() = ^{ 0x2b | ~0x2b; };" + "}" + "@end"; + + EXPECT_TRUE( + matchesObjC( + ObjCString1, + binaryOperator(forCallable(blockDecl())))); + + EXPECT_TRUE( + notMatchesObjC( + ObjCString1, + binaryOperator(forCallable(objcMethodDecl())))); + + StringRef ObjCString2 = "@interface I" + "-(void) foo;" + "@end" + "@implementation I" + "-(void) foo {" + " 0x2b | ~0x2b;" + " void (^block)() = ^{};" + "}" + "@end"; + + EXPECT_TRUE( + matchesObjC( + ObjCString2, + binaryOperator(forCallable(objcMethodDecl())))); + + EXPECT_TRUE( + notMatchesObjC( + ObjCString2, + binaryOperator(forCallable(blockDecl())))); +} + TEST(Matcher, ForEachOverriden) { const auto ForEachOverriddenInClass = [](const char *ClassName) { return cxxMethodDecl(ofClass(hasName(ClassName)), isVirtual(),