Index: include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- include/clang/ASTMatchers/ASTMatchers.h +++ include/clang/ASTMatchers/ASTMatchers.h @@ -5108,6 +5108,66 @@ gnuNullExpr(), cxxNullPtrLiteralExpr(), integerLiteral(equals(0), hasParent(expr(hasType(pointerType()))))); } + +/// \brief Matches declaration of the function the statemenet belongs to +/// +/// Given: +/// \code +/// F& operator=(const F& o) { +/// std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; }); +/// return *this; +/// } +/// \endcode +/// returnStmt(forFunction(hasName("operator="))) +/// matches 'return *this' +/// but does match 'return > 0' +AST_MATCHER_P(Stmt, forFunction, internal::Matcher, + InnerMatcher) { + const auto &Parents = Finder->getASTContext().getParents(Node); + assert(!Parents.empty() && "Found node that is not in the parent map."); + + std::deque Stack(Parents.begin(), + Parents.end()); + while(!Stack.empty()) { + const auto &CurNode = Stack.back(); + Stack.pop_back(); + if(const auto *DeclNode = CurNode.get()) { + if(const auto *FuncDeclNode = dyn_cast(DeclNode)) { + if(InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) { + return true; + } + } + } + const auto *StmtNode = CurNode.get(); + if(StmtNode&&!isa(StmtNode)) { + for(const auto &Parent: Finder->getASTContext().getParents(*StmtNode)) + Stack.push_back(Parent); + } + } + return false; +} + +AST_MATCHER_P(Stmt, forFunction, internal::Matcher, + InnerMatcher) { + const auto *CurNode = &Node; + while(CurNode) { + const auto &Parents = Finder->getASTContext().getParents(*CurNode); + assert(!Parents.empty() && "Found node that is not in the parent map."); + const auto &Parent = Parents[0]; + if(const auto *DeclNode = Parent.get()) { + if(const auto *FuncDeclNode = dyn_cast(DeclNode)) { + return InnerMatcher.matches(*FuncDeclNode, Finder, Builder); + } + return false; + } + CurNode = Parent.get(); + if(CurNode&&isa(CurNode)) { + return false; + } + } + return false; +} + } // end namespace ast_matchers } // end namespace clang Index: lib/ASTMatchers/Dynamic/Registry.cpp =================================================================== --- lib/ASTMatchers/Dynamic/Registry.cpp +++ lib/ASTMatchers/Dynamic/Registry.cpp @@ -184,6 +184,7 @@ REGISTER_MATCHER(forEachDescendant); REGISTER_MATCHER(forEachSwitchCase); REGISTER_MATCHER(forField); + REGISTER_MATCHER(forFunction); REGISTER_MATCHER(forStmt); REGISTER_MATCHER(friendDecl); REGISTER_MATCHER(functionDecl); Index: unittests/ASTMatchers/ASTMatchersTest.cpp =================================================================== --- unittests/ASTMatchers/ASTMatchersTest.cpp +++ unittests/ASTMatchers/ASTMatchersTest.cpp @@ -5568,5 +5568,38 @@ EXPECT_FALSE(matches("void F() { return; }", RetVal)); } +TEST(StatementMatcher, ForFunction) { + const auto CppString = + "namespace std {" + "template" + "OIter copy_if(IIter sb, IIter se, OIter db, Pred pr);" + "}" + "class PosVec {" + " int n;" + "public:" + " typedef PosVec *iterator;" + " typedef const PosVec *const_iterator;" + " iterator begin();" + " iterator end();" + " const_iterator begin() const;" + " const_iterator end() const;" + " PosVec& operator= (const PosVec& o) {" + " std::copy_if(o.begin(), o.end(), begin(), [](PosVec& v) { return v.n > 0; });" + " return *this;" + " }" + "};"; + EXPECT_TRUE( + matches( + CppString, + returnStmt(forFunction(hasName("operator=")), + has(unaryOperator(hasOperatorName("*")))))); + EXPECT_FALSE( + matches( + CppString, + returnStmt(forFunction(hasName("operator=")), + has(binaryOperator(hasOperatorName(">")))))); + llvm::errs()<<"d"; +} + } // end namespace ast_matchers } // end namespace clang