diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -5658,7 +5658,7 @@
Matches C++ classes that have a direct or indirect base matching BaseSpecMatcher. Example: -matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))) +matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))) class Foo; class Bar : Foo {}; class Baz : Bar {}; @@ -5670,6 +5670,20 @@
Matches C++ classes that have a direct base matching BaseSpecMatcher. + +Example: +matcher hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase")))) + class Foo; + class Bar : Foo {}; + class Baz : Bar {}; + class SpecialBase; + class Proxy : SpecialBase {}; // matches Proxy + class IndirectlyDerived : Proxy {}; // doesn't match +
Matches the first method of a class or struct that satisfies InnerMatcher. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2862,7 +2862,7 @@ /// BaseSpecMatcher. /// /// Example: -/// matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))) +/// matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))) /// \code /// class Foo; /// class Bar : Foo {}; @@ -2878,6 +2878,27 @@ return internal::matchesAnyBase(Node, BaseSpecMatcher, Finder, Builder); } +/// Matches C++ classes that have a direct base matching \p BaseSpecMatcher. +/// +/// Example: +/// matcher hasDirectBase(hasType(cxxRecordDecl(hasName("SpecialBase")))) +/// \code +/// class Foo; +/// class Bar : Foo {}; +/// class Baz : Bar {}; +/// class SpecialBase; +/// class Proxy : SpecialBase {}; // matches Proxy +/// class IndirectlyDerived : Proxy {}; // doesn't match +/// \endcode +AST_MATCHER_P(CXXRecordDecl, hasDirectBase, internal::Matcher, + BaseSpecMatcher) { + + return Node.hasDefinition() && + llvm::any_of(Node.bases(), [&](const CXXBaseSpecifier &Base) { + return BaseSpecMatcher.matches(Base, Finder, Builder); + }); +} + /// Similar to \c isDerivedFrom(), but also matches classes that directly /// match \c Base. AST_POLYMORPHIC_MATCHER_P_OVERLOAD( diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -278,6 +278,7 @@ REGISTER_MATCHER(hasDefinition); REGISTER_MATCHER(hasDescendant); REGISTER_MATCHER(hasDestinationType); + REGISTER_MATCHER(hasDirectBase); REGISTER_MATCHER(hasDynamicExceptionSpec); REGISTER_MATCHER(hasEitherOperand); REGISTER_MATCHER(hasElementType); diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp @@ -3125,5 +3125,44 @@ cxxRecordDecl(hasAnyBase(isVirtual())))); } +TEST(BaseSpecifier, hasDirectBase) { + EXPECT_TRUE(matches( + R"cc( + class Base {}; + class Derived : Base{}; + )cc", + cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasType(cxxRecordDecl(hasName("Base"))))))); + + StringRef MultiDerived = R"cc( + class Base {}; + class Base2 {}; + class Derived : Base, Base2{}; + )cc"; + + EXPECT_TRUE(matches( + MultiDerived, + cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasType(cxxRecordDecl(hasName("Base"))))))); + EXPECT_TRUE(matches( + MultiDerived, + cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasType(cxxRecordDecl(hasName("Base2"))))))); + + StringRef Indirect = R"cc( + class Base {}; + class Intermediate : Base {}; + class Derived : Intermediate{}; + )cc"; + + EXPECT_TRUE( + matches(Indirect, cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasType(cxxRecordDecl( + hasName("Intermediate"))))))); + EXPECT_TRUE(notMatches( + Indirect, + cxxRecordDecl(hasName("Derived"), + hasDirectBase(hasType(cxxRecordDecl(hasName("Base"))))))); +} } // namespace ast_matchers } // namespace clang