Author: xazax Date: Wed May 4 06:59:39 2016 New Revision: 268490 URL: http://llvm.org/viewvc/llvm-project?rev=268490&view=rev Log: [ASTMatchers] New matcher forFunction
Summary: Matcher proposed in the review of checker misc-assign-operator (name pending). Its goal is to find the direct enclosing function declaration of a statement and run the inner matcher on it. Two version is attached in this patch (thus it will not compile), to be decided which approach to take. The second one always chooses one single parent while the first one does a depth-first search upwards (thus a height-first search) and returns the first positive match of the inner matcher (thus it always returns zero or one matches, not more). Further questions: is it enough to implement it in-place, or ASTMatchersInternals or maybe ASTMatchFinder should be involved? Reviewers: sbenza Subscribers: aaron.ballman, klimek, o.gyorgy, xazax.hun, cfe-commits Differential Revision: http://reviews.llvm.org/D19357 Modified: cfe/trunk/docs/LibASTMatchersReference.html cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Modified: cfe/trunk/docs/LibASTMatchersReference.html URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=268490&r1=268489&r2=268490&view=diff ============================================================================== --- cfe/trunk/docs/LibASTMatchersReference.html (original) +++ cfe/trunk/docs/LibASTMatchersReference.html Wed May 4 06:59:39 2016 @@ -4923,6 +4923,20 @@ alignof. </pre></td></tr> +<tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('forFunction0')"><a name="forFunction0Anchor">forFunction</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>> InnerMatcher</td></tr> +<tr><td colspan="4" class="doc" id="forFunction0"><pre>Matches declaration of the function the statemenet belongs to + +Given: +F& operator=(const F& o) { + std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v > 0; }); + return *this; +} +returnStmt(forFunction(hasName("operator="))) + matches 'return *this' + but does match 'return > 0' +</pre></td></tr> + + <tr><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('sizeOfExpr0')"><a name="sizeOfExpr0Anchor">sizeOfExpr</a></td><td>Matcher<<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="sizeOfExpr0"><pre>Same as unaryExprOrTypeTraitExpr, but only matching sizeof. Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=268490&r1=268489&r2=268490&view=diff ============================================================================== --- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original) +++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Wed May 4 06:59:39 2016 @@ -5108,6 +5108,45 @@ AST_MATCHER_FUNCTION(internal::Matcher<E 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<FunctionDecl>, + InnerMatcher) { + const auto &Parents = Finder->getASTContext().getParents(Node); + + llvm::SmallVector<ast_type_traits::DynTypedNode, 8> Stack(Parents.begin(), + Parents.end()); + while(!Stack.empty()) { + const auto &CurNode = Stack.back(); + Stack.pop_back(); + if(const auto *FuncDeclNode = CurNode.get<FunctionDecl>()) { + if(InnerMatcher.matches(*FuncDeclNode, Finder, Builder)) { + return true; + } + } else if(const auto *LambdaExprNode = CurNode.get<LambdaExpr>()) { + if(InnerMatcher.matches(*LambdaExprNode->getCallOperator(), + Finder, Builder)) { + return true; + } + } else { + for(const auto &Parent: Finder->getASTContext().getParents(CurNode)) + Stack.push_back(Parent); + } + } + return false; +} + } // end namespace ast_matchers } // end namespace clang Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=268490&r1=268489&r2=268490&view=diff ============================================================================== --- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original) +++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Wed May 4 06:59:39 2016 @@ -184,6 +184,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(forEachDescendant); REGISTER_MATCHER(forEachSwitchCase); REGISTER_MATCHER(forField); + REGISTER_MATCHER(forFunction); REGISTER_MATCHER(forStmt); REGISTER_MATCHER(friendDecl); REGISTER_MATCHER(functionDecl); Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp?rev=268490&r1=268489&r2=268490&view=diff ============================================================================== --- cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp (original) +++ cfe/trunk/unittests/ASTMatchers/ASTMatchersTest.cpp Wed May 4 06:59:39 2016 @@ -5572,5 +5572,40 @@ TEST(StatementMatcher, HasReturnValue) { EXPECT_FALSE(matches("void F() { return; }", RetVal)); } +TEST(StatementMatcher, ForFunction) { + const auto CppString1 = + "struct PosVec {" + " PosVec& operator=(const PosVec&) {" + " auto x = [] { return 1; };" + " return *this;" + " }" + "};"; + const auto CppString2 = + "void F() {" + " struct S {" + " void F2() {" + " return;" + " }" + " };" + "}"; + EXPECT_TRUE( + matches( + CppString1, + returnStmt(forFunction(hasName("operator=")), + has(unaryOperator(hasOperatorName("*")))))); + EXPECT_TRUE( + notMatches( + CppString1, + returnStmt(forFunction(hasName("operator=")), + has(integerLiteral())))); + EXPECT_TRUE( + matches( + CppString1, + returnStmt(forFunction(hasName("operator()")), + has(integerLiteral())))); + EXPECT_TRUE(matches(CppString2, returnStmt(forFunction(hasName("F2"))))); + EXPECT_TRUE(notMatches(CppString2, returnStmt(forFunction(hasName("F"))))); +} + } // end namespace ast_matchers } // end namespace clang _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits