[PATCH] D87527: [ASTMatchers] Fix `hasBody` for the descendants of `FunctionDecl`

Balogh, Ádám via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 11 10:02:29 PDT 2020


baloghadamsoftware created this revision.
baloghadamsoftware added reviewers: klimek, sbenza.
baloghadamsoftware added a project: clang.
Herald added subscribers: martong, gamesh411, Szelethus, dkrupp, rnkovacs.
baloghadamsoftware requested review of this revision.

//AST Matcher// `hasBody` is a polymorphic matcher that behaves differently for loop statements and function declarations. The main difference is the for functions declarations it does not only call `FunctionDecl::getBody()` but first checks whether the declaration in question is that specific declaration which has the body by calling `FunctionDecl::doesThisDeclarationHaveABody()`. This is achieved by specialization of the template `GetBodyMatcher`. Unfortunately template specializations do not catch the descendants of the class for which the template is specialized. Therefore it does not work correcly for the descendants of `FunctionDecl`, such as `CXXMethodDecl`, `CXXConstructorDecl`, `CXXDestructorDecl` etc. This patch fixes this issue by using a template metaprogram.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D87527

Files:
  clang/include/clang/ASTMatchers/ASTMatchersInternal.h
  clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp


Index: clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -1454,10 +1454,30 @@
                       doStmt(hasBody(compoundStmt()))));
   EXPECT_TRUE(matches("void f() { int p[2]; for (auto x : p) {} }",
                       cxxForRangeStmt(hasBody(compoundStmt()))));
+}
+
+TEST(HasBody, FindsBodyOfFunctions) {
   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()))));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "void f(); void f() {}",
+      functionDecl(hasBody(compoundStmt())).bind("func"),
+      std::make_unique<VerifyIdIsBoundTo<FunctionDecl>>("func", 1)));
+}
+
+TEST(HasBody, FindsBodyOfFunctionChildren) {
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "class C { void f(); }; void C::f() {}",
+      cxxMethodDecl(hasBody(compoundStmt())).bind("met"),
+      std::make_unique<VerifyIdIsBoundTo<CXXMethodDecl>>("met", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "class C { C(); }; C::C() {}",
+      cxxConstructorDecl(hasBody(compoundStmt())).bind("ctr"),
+      std::make_unique<VerifyIdIsBoundTo<CXXConstructorDecl>>("ctr", 1)));
+  EXPECT_TRUE(matchAndVerifyResultTrue(
+      "class C { ~C(); }; C::~C() {}",
+      cxxDestructorDecl(hasBody(compoundStmt())).bind("dtr"),
+      std::make_unique<VerifyIdIsBoundTo<CXXDestructorDecl>>("dtr", 1)));
 }
 
 TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -1835,18 +1835,18 @@
   DynTypedNode Node;
 };
 
+template <typename Ty, typename Enable = void> struct GetBodyMatcher {
+  static const Stmt *get(const Ty &Node) { return Node.getBody(); }
+};
+
 template <typename Ty>
-struct GetBodyMatcher {
+struct GetBodyMatcher<Ty, typename std::enable_if<
+                              std::is_base_of<FunctionDecl, Ty>::value>::type> {
   static const Stmt *get(const Ty &Node) {
-    return Node.getBody();
+    return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
   }
 };
 
-template <>
-inline const Stmt *GetBodyMatcher<FunctionDecl>::get(const FunctionDecl &Node) {
-  return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr;
-}
-
 template <typename Ty>
 struct HasSizeMatcher {
   static bool hasSize(const Ty &Node, unsigned int N) {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D87527.291260.patch
Type: text/x-patch
Size: 2834 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20200911/70f5bcf7/attachment-0001.bin>


More information about the cfe-commits mailing list