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) {
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) {
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits