diff options
| -rw-r--r-- | clang/docs/LibASTMatchersReference.html | 14 | ||||
| -rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchers.h | 39 | ||||
| -rw-r--r-- | clang/lib/ASTMatchers/Dynamic/Registry.cpp | 1 | ||||
| -rw-r--r-- | clang/unittests/ASTMatchers/ASTMatchersTest.cpp | 35 |
4 files changed, 89 insertions, 0 deletions
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 0f474136ee2..d17a32d7a48 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -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. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 5ae71a93960..300dca9ff54 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -5108,6 +5108,45 @@ AST_MATCHER_FUNCTION(internal::Matcher<Expr>, nullPointerConstant) { 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 diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 9fd43332b7f..e43960241d7 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -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); diff --git a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp index 332438ede1b..adf3b27cb13 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersTest.cpp @@ -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 |

