From: Aaron Ballman Date: Wed, 20 Jan 2016 16:26:48 +0000 (+0000) Subject: Add AST matcher support for FunctionDecls with the hasBody matcher. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=bd6321c036692399ca7de9d48a2e014dab65b17a;p=clang Add AST matcher support for FunctionDecls with the hasBody matcher. Patch by Aleksei Sidorin. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@258322 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 51d30728e2..ed1f3f5f18 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -3436,8 +3436,8 @@ with withInitializer matching (1) Matcher<CXXForRangeStmt>hasBodyMatcher<Stmt> InnerMatcher -
Matches a 'for', 'while', or 'do while' statement that has
-a given body.
+
Matches a 'for', 'while', 'do while' statement or a function
+definition that has a given body.
 
 Given
   for (;;) {}
@@ -3878,8 +3878,8 @@ declaration of class D.
 
 
 Matcher<DoStmt>hasBodyMatcher<Stmt> InnerMatcher
-
Matches a 'for', 'while', or 'do while' statement that has
-a given body.
+
Matches a 'for', 'while', 'do while' statement or a function
+definition that has a given body.
 
 Given
   for (;;) {}
@@ -4059,8 +4059,8 @@ would only match the declaration for a.
 
 
 Matcher<ForStmt>hasBodyMatcher<Stmt> InnerMatcher
-
Matches a 'for', 'while', or 'do while' statement that has
-a given body.
+
Matches a 'for', 'while', 'do while' statement or a function
+definition that has a given body.
 
 Given
   for (;;) {}
@@ -4114,6 +4114,19 @@ with hasAnyParameter(...)
 
+Matcher<FunctionDecl>hasBodyMatcher<Stmt> InnerMatcher +
Matches a 'for', 'while', 'do while' statement or a function
+definition that has a given body.
+
+Given
+  for (;;) {}
+hasBody(compoundStmt())
+  matches 'for (;;) {}'
+with compoundStmt()
+  matching '{}'
+
+ + Matcher<FunctionDecl>hasParameterunsigned N, Matcher<ParmVarDecl> InnerMatcher
Matches the n'th parameter of a function declaration.
 
@@ -4891,8 +4904,8 @@ variableArrayType(hasSizeExpr(ignoringImpCasts(declRefExpr(to(
 
 
 Matcher<WhileStmt>hasBodyMatcher<Stmt> InnerMatcher
-
Matches a 'for', 'while', or 'do while' statement that has
-a given body.
+
Matches a 'for', 'while', 'do while' statement or a function
+definition that has a given body.
 
 Given
   for (;;) {}
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 148a1e5521..6479aaad00 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -3189,8 +3189,8 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
   return false;
 }
 
-/// \brief Matches a 'for', 'while', or 'do while' statement that has
-/// a given body.
+/// \brief Matches a 'for', 'while', 'do while' statement or a function
+/// definition that has a given body.
 ///
 /// Given
 /// \code
@@ -3203,9 +3203,10 @@ AST_MATCHER_P(ArraySubscriptExpr, hasBase,
 AST_POLYMORPHIC_MATCHER_P(hasBody,
                           AST_POLYMORPHIC_SUPPORTED_TYPES(DoStmt, ForStmt,
                                                           WhileStmt,
-                                                          CXXForRangeStmt),
+                                                          CXXForRangeStmt,
+                                                          FunctionDecl),
                           internal::Matcher, InnerMatcher) {
-  const Stmt *const Statement = Node.getBody();
+  const Stmt *const Statement = internal::GetBodyMatcher::get(Node);
   return (Statement != nullptr &&
           InnerMatcher.matches(*Statement, Finder, Builder));
 }
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 1d1d7952c1..b268b6b6e3 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1584,6 +1584,18 @@ struct NotEqualsBoundNodePredicate {
   ast_type_traits::DynTypedNode Node;
 };
 
+template 
+struct GetBodyMatcher {
+  static const Stmt *get(const Ty &Node) {
+    return Node.getBody();
+  }
+};
+
+template <>
+inline const Stmt *GetBodyMatcher::get(const FunctionDecl &Node) {
+  return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
+}
+
 } // end namespace internal
 } // end namespace ast_matchers
 } // end namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.cpp b/unittests/ASTMatchers/ASTMatchersTest.cpp
index d7f5b722df..3cf396a4fd 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -2973,6 +2973,10 @@ TEST(HasBody, FindsBodyOfForWhileDoLoops) {
               doStmt(hasBody(compoundStmt()))));
   EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }",
               cxxForRangeStmt(hasBody(compoundStmt()))));
+  EXPECT_TRUE(matches("void f() {}", functionDecl(hasBody(compoundStmt()))));
+  EXPECT_TRUE(notMatches("void f();", functionDecl(hasBody(compoundStmt()))));
+  EXPECT_TRUE(matches("void f(); void f() {}",
+                         functionDecl(hasBody(compoundStmt()))));
 }
 
 TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 0de6242a67..81373dab96 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -263,7 +263,7 @@ TEST(ParserTest, Errors) {
             "1:1: Matcher does not support binding.",
             ParseWithError("isArrow().bind(\"foo\")"));
   EXPECT_EQ("Input value has unresolved overloaded type: "
-            "Matcher",
+            "Matcher",
             ParseMatcherWithError("hasBody(stmt())"));
 }