njames93 created this revision.
njames93 added reviewers: klimek, aaron.ballman, jkorous.
Herald added subscribers: cfe-commits, dexonsmith.
Herald added a project: clang.
Adds a matcher called `hasDirectBase` for matching the `CXXBaseSpecifier` of a
class that directly derives from another class.
Adds a matcher called `hasClass` that matches on the class that a
`CXXBaseSpecifier` refers to.
Also removed the `CXXBaseSpecifier` overload for the `hasType` Matcher in
favour of this `hasClass` matcher.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D81552
Files:
clang/docs/LibASTMatchersReference.html
clang/include/clang/ASTMatchers/ASTMatchers.h
clang/include/clang/ASTMatchers/ASTMatchersInternal.h
clang/lib/ASTMatchers/Dynamic/Registry.cpp
clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -2997,26 +2997,24 @@
}
TEST(HasAnyBase, DirectBase) {
- EXPECT_TRUE(matches(
- "struct Base {};"
- "struct ExpectedMatch : Base {};",
- cxxRecordDecl(hasName("ExpectedMatch"),
- hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))));
+ EXPECT_TRUE(matches("struct Base {};"
+ "struct ExpectedMatch : Base {};",
+ cxxRecordDecl(hasName("ExpectedMatch"),
+ hasAnyBase(hasClass(hasName("Base"))))));
}
TEST(HasAnyBase, IndirectBase) {
- EXPECT_TRUE(matches(
- "struct Base {};"
- "struct Intermediate : Base {};"
- "struct ExpectedMatch : Intermediate {};",
- cxxRecordDecl(hasName("ExpectedMatch"),
- hasAnyBase(hasType(cxxRecordDecl(hasName("Base")))))));
+ EXPECT_TRUE(matches("struct Base {};"
+ "struct Intermediate : Base {};"
+ "struct ExpectedMatch : Intermediate {};",
+ cxxRecordDecl(hasName("ExpectedMatch"),
+ hasAnyBase(hasClass(hasName("Base"))))));
}
TEST(HasAnyBase, NoBase) {
EXPECT_TRUE(notMatches("struct Foo {};"
"struct Bar {};",
- cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl())))));
+ cxxRecordDecl(hasAnyBase(hasClass(cxxRecordDecl())))));
}
TEST(IsPublicBase, Public) {
@@ -3117,5 +3115,57 @@
cxxRecordDecl(hasAnyBase(isVirtual()))));
}
+TEST(BaseSpecifier, hasDirectBase) {
+ EXPECT_TRUE(matches(
+ R"cc(
+ class Base {};
+ class Derived : Base{};
+ )cc",
+ cxxRecordDecl(hasName("Derived"),
+ hasDirectBase(hasClass(hasName("Base"))))));
+
+ StringRef MultiDerived = R"cc(
+ class Base {};
+ class Base2 {};
+ class Derived : Base, Base2{};
+ )cc";
+
+ EXPECT_TRUE(matches(MultiDerived,
+ cxxRecordDecl(hasName("Derived"),
+ hasDirectBase(hasClass(hasName("Base"))))));
+ EXPECT_TRUE(matches(
+ MultiDerived, cxxRecordDecl(hasName("Derived"),
+ hasDirectBase(hasClass(hasName("Base2"))))));
+
+ StringRef Indirect = R"cc(
+ class Base {};
+ class Intermediate : Base {};
+ class Derived : Intermediate{};
+ )cc";
+
+ EXPECT_TRUE(
+ matches(Indirect,
+ cxxRecordDecl(hasName("Derived"),
+ hasDirectBase(hasClass(hasName("Intermediate"))))));
+ EXPECT_TRUE(notMatches(
+ Indirect, cxxRecordDecl(hasName("Derived"),
+ hasDirectBase(hasClass(hasName("Base"))))));
+
+ // Only really here to make sure the asserts don't fire
+ EXPECT_FALSE(
+ matches(R"cc(
+ class Base {};
+ class Derived : BAse {};
+ )cc",
+ cxxRecordDecl(hasDirectBase(hasClass(hasName("Base"))))));
+
+ EXPECT_FALSE(
+ matches(R"cc(
+ using Base = int;
+ class Derived : Base {};
+ )cc",
+ cxxRecordDecl(hasDirectBase(hasClass(hasName("Base"))))));
+}
+
} // namespace ast_matchers
} // namespace clang
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -261,6 +261,7 @@
REGISTER_MATCHER(hasCanonicalType);
REGISTER_MATCHER(hasCaseConstant);
REGISTER_MATCHER(hasCastKind);
+ REGISTER_MATCHER(hasClass);
REGISTER_MATCHER(hasCondition);
REGISTER_MATCHER(hasConditionVariableStatement);
REGISTER_MATCHER(hasDecayedType);
@@ -271,6 +272,7 @@
REGISTER_MATCHER(hasDefinition);
REGISTER_MATCHER(hasDescendant);
REGISTER_MATCHER(hasDestinationType);
+ REGISTER_MATCHER(hasDirectBase);
REGISTER_MATCHER(hasDynamicExceptionSpec);
REGISTER_MATCHER(hasEitherOperand);
REGISTER_MATCHER(hasElementType);
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -130,9 +130,6 @@
return TSI->getType();
return QualType();
}
-inline QualType getUnderlyingType(const CXXBaseSpecifier &Node) {
- return Node.getType();
-}
/// Unifies obtaining the FunctionProtoType pointer from both
/// FunctionProtoType and FunctionDecl nodes..
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2864,7 +2864,7 @@
/// BaseSpecMatcher.
///
/// Example:
-/// matcher hasAnyBase(hasType(cxxRecordDecl(hasName("SpecialBase")))))
+/// matcher hasAnyBase(hasClass(hasName("SpecialBase")))
/// \code
/// class Foo;
/// class Bar : Foo {};
@@ -2880,6 +2880,27 @@
return internal::matchesAnyBase(Node, BaseSpecMatcher, Finder, Builder);
}
+/// Matches C++ classes that have a direct base matching \p BaseSpecMatcher.
+///
+/// Example:
+/// matcher hasDirectBase(hasClass(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(
@@ -3510,19 +3531,10 @@
/// class Y { friend class X; };
/// \endcode
///
-/// Example matches class Derived
-/// (matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
-/// \code
-/// class Base {};
-/// class Derived : Base {};
-/// \endcode
///
-/// Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>,
-/// Matcher<CXXBaseSpecifier>
+/// Usable as: Matcher<Expr>, Matcher<FriendDecl>, Matcher<ValueDecl>
AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
- hasType,
- AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl,
- CXXBaseSpecifier),
+ hasType, AST_POLYMORPHIC_SUPPORTED_TYPES(Expr, FriendDecl, ValueDecl),
internal::Matcher<Decl>, InnerMatcher, 1) {
QualType QT = internal::getUnderlyingType(Node);
if (!QT.isNull())
@@ -3530,6 +3542,23 @@
return false;
}
+/// Matches if the Base specifier refers to the given class matcher.
+///
+/// Example matches class Derived
+/// (matcher = cxxRecordDecl(hasAnyBase(hasClass(hasName("Base")))))
+/// \code
+/// class Base {};
+/// class Derived : Base {};
+/// \endcode
+AST_MATCHER_P(CXXBaseSpecifier, hasClass, internal::Matcher<CXXRecordDecl>,
+ InnerMatcher) {
+ QualType QT = Node.getType();
+ assert(!QT.isNull() && "CXXBaseSpecifier shouldn't have a null type");
+ const CXXRecordDecl *RD = QT->getAsCXXRecordDecl();
+ assert(RD && "CXXBaseSpecifier should refer to a CXXRecordDecl");
+ return InnerMatcher.matches(*RD, Finder, Builder);
+}
+
/// Matches if the type location of the declarator decl's type matches
/// the inner matcher.
///
Index: clang/docs/LibASTMatchersReference.html
===================================================================
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -1226,6 +1226,11 @@
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('fixedPointLiteral0')"><a name="fixedPointLiteral0Anchor">fixedPointLiteral</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FixedPointLiteral.html">FixedPointLiteral</a>>...</td></tr>
+<tr><td colspan="4" class="doc" id="fixedPointLiteral0"><pre>Matches fixed point literals
+</pre></td></tr>
+
+
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Stmt.html">Stmt</a>></td><td class="name" onclick="toggle('floatLiteral0')"><a name="floatLiteral0Anchor">floatLiteral</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FloatingLiteral.html">FloatingLiteral</a>>...</td></tr>
<tr><td colspan="4" class="doc" id="floatLiteral0"><pre>Matches float literals of all sizes / encodings, e.g.
1.0, 1.0f, 1.0L and 1e10.
@@ -5219,30 +5224,13 @@
</pre></td></tr>
-<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasType7')"><a name="hasType7Anchor">hasType</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="hasType7"><pre>Overloaded to match the declaration of the expression's or value
-declaration's type.
-
-In case of a value declaration (for example a variable declaration),
-this resolves one layer of indirection. For example, in the value
-declaration "X x;", cxxRecordDecl(hasName("X")) matches the declaration of
-X, while varDecl(hasType(cxxRecordDecl(hasName("X")))) matches the
-declaration of x.
-
-Example matches x (matcher = expr(hasType(cxxRecordDecl(hasName("X")))))
- and z (matcher = varDecl(hasType(cxxRecordDecl(hasName("X")))))
- and friend class X (matcher = friendDecl(hasType("X"))
- class X {};
- void y(X &x) { x; X z; }
- class Y { friend class X; };
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>></td><td class="name" onclick="toggle('hasClass0')"><a name="hasClass0Anchor">hasClass</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="hasClass0"><pre>Matches if the Base specifier refers to the given class matcher.
Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
+(matcher = cxxRecordDecl(hasAnyBase(hasClass(hasName("Base")))))
class Base {};
class Derived : Base {};
-
-Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>,
-Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
</pre></td></tr>
@@ -5632,18 +5620,33 @@
<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasAnyBase0')"><a name="hasAnyBase0Anchor">hasAnyBase</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>> BaseSpecMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasAnyBase0"><pre>Matches C++ classes that have a direct or indirect base matching BaseSpecMatcher.
-Example matches DirectlyDerived, IndirectlyDerived (BaseSpecMatcher ==
-hasType(cxxRecordDecl(hasName("SpecialBase")))) class Foo;
+Example:
+matcher hasAnyBase(hasClass(hasName("SpecialBase")))
+ class Foo;
class Bar : Foo {};
class Baz : Bar {};
class SpecialBase;
- class DirectlyDerived : SpecialBase {}; // directly derived
- class IndirectlyDerived : DirectlyDerived {}; // indirectly derived
+ class Proxy : SpecialBase {}; // matches Proxy
+ class IndirectlyDerived : Proxy {}; //matches IndirectlyDerived
FIXME: Refactor this and isDerivedFrom to reuse implementation.
</pre></td></tr>
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasDirectBase0')"><a name="hasDirectBase0Anchor">hasDirectBase</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>> 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(hasClass(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<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('hasMethod0')"><a name="hasMethod0Anchor">hasMethod</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXMethodDecl.html">CXXMethodDecl</a>> InnerMatcher</td></tr>
<tr><td colspan="4" class="doc" id="hasMethod0"><pre>Matches the first method of a class or struct that satisfies InnerMatcher.
@@ -6201,13 +6204,8 @@
void y(X &x) { x; X z; }
class Y { friend class X; };
-Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
-class Base {};
-class Derived : Base {};
-Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>,
-Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
+Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>
</pre></td></tr>
@@ -6421,13 +6419,8 @@
void y(X &x) { x; X z; }
class Y { friend class X; };
-Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
-class Base {};
-class Derived : Base {};
-Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>,
-Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
+Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>
</pre></td></tr>
@@ -7815,13 +7808,8 @@
void y(X &x) { x; X z; }
class Y { friend class X; };
-Example matches class Derived
-(matcher = cxxRecordDecl(hasAnyBase(hasType(cxxRecordDecl(hasName("Base"))))))
-class Base {};
-class Derived : Base {};
-Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>,
-Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXBaseSpecifier.html">CXXBaseSpecifier</a>>
+Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>, Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ValueDecl.html">ValueDecl</a>>
</pre></td></tr>
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits