Skip to content

Commit

Permalink
[ASTMatchers] Added hasDirectBase Matcher
Browse files Browse the repository at this point in the history
Adds a matcher called `hasDirectBase` for matching the `CXXBaseSpecifier` of a class that directly derives from another class.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D81552
  • Loading branch information
njames93 committed Jul 7, 2020
1 parent 52495b9 commit b0d3ea1
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 2 deletions.
16 changes: 15 additions & 1 deletion clang/docs/LibASTMatchersReference.html
Original file line number Diff line number Diff line change
Expand Up @@ -5658,7 +5658,7 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
<tr><td colspan="4" class="doc" id="hasAnyBase0"><pre>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 {};
Expand All @@ -5670,6 +5670,20 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('hasDirectBase0')"><a name="hasDirectBase0Anchor">hasDirectBase</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>&gt; BaseSpecMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasDirectBase0"><pre>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
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>&gt;</td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>&gt; InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.

Expand Down
22 changes: 21 additions & 1 deletion clang/include/clang/ASTMatchers/ASTMatchers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2862,7 +2862,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
/// BaseSpecMatcher.
///
/// Example:
/// matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
/// matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase"))))
/// \code
/// class Foo;
/// class Bar : Foo {};
Expand All @@ -2878,6 +2878,26 @@ AST_MATCHER_P(CXXRecordDecl, hasAnyBase, internal::Matcher<CXXBaseSpecifier>,
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<CXXBaseSpecifier>,
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(
Expand Down
1 change: 1 addition & 0 deletions clang/lib/ASTMatchers/Dynamic/Registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(hasDefinition);
REGISTER_MATCHER(hasDescendant);
REGISTER_MATCHER(hasDestinationType);
REGISTER_MATCHER(hasDirectBase);
REGISTER_MATCHER(hasDynamicExceptionSpec);
REGISTER_MATCHER(hasEitherOperand);
REGISTER_MATCHER(hasElementType);
Expand Down
39 changes: 39 additions & 0 deletions clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3125,5 +3125,44 @@ TEST(IsVirtual, NoVirtualBase) {
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

0 comments on commit b0d3ea1

Please sign in to comment.