summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGabor Horvath <xazax.hun@gmail.com>2016-05-04 11:59:39 +0000
committerGabor Horvath <xazax.hun@gmail.com>2016-05-04 11:59:39 +0000
commit1b3f8db8b6effddf363affce4f66da241d2234ff (patch)
tree57e0867526ea9c13606283e065ebe38b7b48fa32
parentb7a29675fcd1802e06e3f03231fd53650f784822 (diff)
downloadbcm5719-llvm-1b3f8db8b6effddf363affce4f66da241d2234ff.tar.gz
bcm5719-llvm-1b3f8db8b6effddf363affce4f66da241d2234ff.zip
[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 llvm-svn: 268490
-rw-r--r--clang/docs/LibASTMatchersReference.html14
-rw-r--r--clang/include/clang/ASTMatchers/ASTMatchers.h39
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp1
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersTest.cpp35
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&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('forFunction0')"><a name="forFunction0Anchor">forFunction</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1FunctionDecl.html">FunctionDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="forFunction0"><pre>Matches declaration of the function the statemenet belongs to
+
+Given:
+F&amp; operator=(const F&amp; o) {
+ std::copy_if(o.begin(), o.end(), begin(), [](V v) { return v &gt; 0; });
+ return *this;
+}
+returnStmt(forFunction(hasName("operator=")))
+ matches 'return *this'
+ but does match 'return &gt; 0'
+</pre></td></tr>
+
+
<tr><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>&gt;</td><td class="name" onclick="toggle('sizeOfExpr0')"><a name="sizeOfExpr0Anchor">sizeOfExpr</a></td><td>Matcher&lt;<a href="http://clang.llvm.org/doxygen/classclang_1_1UnaryExprOrTypeTraitExpr.html">UnaryExprOrTypeTraitExpr</a>&gt; 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
OpenPOWER on IntegriCloud