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 struct GetBodyMatcher { + static const Stmt *get(const Ty &Node) { return Node.getBody(); } +}; + template -struct GetBodyMatcher { +struct GetBodyMatcher::value>::type> { static const Stmt *get(const Ty &Node) { - return Node.getBody(); + return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr; } }; -template <> -inline const Stmt *GetBodyMatcher::get(const FunctionDecl &Node) { - return Node.doesThisDeclarationHaveABody() ? Node.getBody() : nullptr; -} - template 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>("func", 1))); +} + +TEST(HasBody, FindsBodyOfFunctionChildren) { + EXPECT_TRUE(matchAndVerifyResultTrue( + "class C { void f(); }; void C::f() {}", + cxxMethodDecl(hasBody(compoundStmt())).bind("met"), + std::make_unique>("met", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + "class C { C(); }; C::C() {}", + cxxConstructorDecl(hasBody(compoundStmt())).bind("ctr"), + std::make_unique>("ctr", 1))); + EXPECT_TRUE(matchAndVerifyResultTrue( + "class C { ~C(); }; C::~C() {}", + cxxDestructorDecl(hasBody(compoundStmt())).bind("dtr"), + std::make_unique>("dtr", 1))); } TEST(HasAnySubstatement, MatchesForTopLevelCompoundStatement) {