forked from OSchip/llvm-project
[clang] Add isDirectlyDerivedFrom AST matcher.
Differential Revision: https://reviews.llvm.org/D65092 llvm-svn: 367010
This commit is contained in:
parent
ec67e73430
commit
4e1d188be2
|
@ -2581,6 +2581,11 @@ class y;
|
|||
</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('isDirectlyDerivedFrom1')"><a name="isDirectlyDerivedFrom1Anchor">isDirectlyDerivedFrom</a></td><td>std::string BaseName</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isDirectlyDerivedFrom1"><pre>Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)).
|
||||
</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('isExplicitTemplateSpecialization2')"><a name="isExplicitTemplateSpecialization2Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization2"><pre>Matches explicit template specializations of function, class, or
|
||||
static member variable template instantiations.
|
||||
|
@ -5263,6 +5268,26 @@ In the following example, Bar matches isDerivedFrom(hasName("X")):
|
|||
</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('isDirectlyDerivedFrom0')"><a name="isDirectlyDerivedFrom0Anchor">isDirectlyDerivedFrom</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isDirectlyDerivedFrom0"><pre>Matches C++ classes that are directly derived from a class matching Base.
|
||||
|
||||
Note that a class is not considered to be derived from itself.
|
||||
|
||||
Example matches Y, C (Base == hasName("X"))
|
||||
class X;
|
||||
class Y : public X {}; // directly derived
|
||||
class Z : public Y {}; // indirectly derived
|
||||
typedef X A;
|
||||
typedef A B;
|
||||
class C : public B {}; // derived from a typedef of X
|
||||
|
||||
In the following example, Bar matches isDerivedFrom(hasName("X")):
|
||||
class Foo;
|
||||
typedef Foo X;
|
||||
class Bar : public Foo {}; // derived from a type that X is a typedef of
|
||||
</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('isSameOrDerivedFrom0')"><a name="isSameOrDerivedFrom0Anchor">isSameOrDerivedFrom</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr>
|
||||
<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom0"><pre>Similar to isDerivedFrom(), but also matches classes that directly
|
||||
match Base.
|
||||
|
|
|
@ -2634,7 +2634,7 @@ hasOverloadedOperatorName(StringRef Name) {
|
|||
/// \endcode
|
||||
AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
|
||||
internal::Matcher<NamedDecl>, Base) {
|
||||
return Finder->classIsDerivedFrom(&Node, Base, Builder);
|
||||
return Finder->classIsDerivedFrom(&Node, Base, Builder, /*Directly=*/false);
|
||||
}
|
||||
|
||||
/// Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
|
||||
|
@ -2659,6 +2659,38 @@ AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string,
|
|||
return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
|
||||
}
|
||||
|
||||
/// Matches C++ classes that are directly derived from a class matching \c Base.
|
||||
///
|
||||
/// Note that a class is not considered to be derived from itself.
|
||||
///
|
||||
/// Example matches Y, C (Base == hasName("X"))
|
||||
/// \code
|
||||
/// class X;
|
||||
/// class Y : public X {}; // directly derived
|
||||
/// class Z : public Y {}; // indirectly derived
|
||||
/// typedef X A;
|
||||
/// typedef A B;
|
||||
/// class C : public B {}; // derived from a typedef of X
|
||||
/// \endcode
|
||||
///
|
||||
/// In the following example, Bar matches isDerivedFrom(hasName("X")):
|
||||
/// \code
|
||||
/// class Foo;
|
||||
/// typedef Foo X;
|
||||
/// class Bar : public Foo {}; // derived from a type that X is a typedef of
|
||||
/// \endcode
|
||||
AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDirectlyDerivedFrom,
|
||||
internal::Matcher<NamedDecl>, Base, 0) {
|
||||
return Finder->classIsDerivedFrom(&Node, Base, Builder, /*Directly=*/true);
|
||||
}
|
||||
|
||||
/// Overloaded method as shortcut for \c isDirectlyDerivedFrom(hasName(...)).
|
||||
AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDirectlyDerivedFrom, std::string,
|
||||
BaseName, 1) {
|
||||
assert(!BaseName.empty());
|
||||
return isDirectlyDerivedFrom(hasName(BaseName))
|
||||
.matches(Node, Finder, Builder);
|
||||
}
|
||||
/// Matches the first method of a class or struct that satisfies \c
|
||||
/// InnerMatcher.
|
||||
///
|
||||
|
|
|
@ -974,10 +974,11 @@ public:
|
|||
/// Returns true if the given class is directly or indirectly derived
|
||||
/// from a base type matching \c base.
|
||||
///
|
||||
/// A class is considered to be also derived from itself.
|
||||
/// A class is not considered to be derived from itself.
|
||||
virtual bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
|
||||
const Matcher<NamedDecl> &Base,
|
||||
BoundNodesTreeBuilder *Builder) = 0;
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
bool Directly) = 0;
|
||||
|
||||
template <typename T>
|
||||
bool matchesChildOf(const T &Node, const DynTypedMatcher &Matcher,
|
||||
|
|
|
@ -430,7 +430,8 @@ public:
|
|||
|
||||
bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
|
||||
const Matcher<NamedDecl> &Base,
|
||||
BoundNodesTreeBuilder *Builder) override;
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
bool Directly) override;
|
||||
|
||||
// Implements ASTMatchFinder::matchesChildOf.
|
||||
bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
|
||||
|
@ -817,7 +818,8 @@ getAsCXXRecordDeclOrPrimaryTemplate(const Type *TypeNode) {
|
|||
// derived from itself.
|
||||
bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
|
||||
const Matcher<NamedDecl> &Base,
|
||||
BoundNodesTreeBuilder *Builder) {
|
||||
BoundNodesTreeBuilder *Builder,
|
||||
bool Directly) {
|
||||
if (!Declaration->hasDefinition())
|
||||
return false;
|
||||
for (const auto &It : Declaration->bases()) {
|
||||
|
@ -842,7 +844,7 @@ bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
|
|||
*Builder = std::move(Result);
|
||||
return true;
|
||||
}
|
||||
if (classIsDerivedFrom(ClassDecl, Base, Builder))
|
||||
if (!Directly && classIsDerivedFrom(ClassDecl, Base, Builder, Directly))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -108,6 +108,7 @@ RegistryMaps::RegistryMaps() {
|
|||
REGISTER_OVERLOADED_2(hasType);
|
||||
REGISTER_OVERLOADED_2(ignoringParens);
|
||||
REGISTER_OVERLOADED_2(isDerivedFrom);
|
||||
REGISTER_OVERLOADED_2(isDirectlyDerivedFrom);
|
||||
REGISTER_OVERLOADED_2(isSameOrDerivedFrom);
|
||||
REGISTER_OVERLOADED_2(loc);
|
||||
REGISTER_OVERLOADED_2(pointsTo);
|
||||
|
|
|
@ -331,6 +331,16 @@ TEST(DeclarationMatcher, ClassIsDerived) {
|
|||
EXPECT_TRUE(notMatches("class Y;", IsDerivedFromX));
|
||||
EXPECT_TRUE(notMatches("", IsDerivedFromX));
|
||||
|
||||
DeclarationMatcher IsDirectlyDerivedFromX =
|
||||
cxxRecordDecl(isDirectlyDerivedFrom("X"));
|
||||
|
||||
EXPECT_TRUE(
|
||||
matches("class X {}; class Y : public X {};", IsDirectlyDerivedFromX));
|
||||
EXPECT_TRUE(notMatches("class X {};", IsDirectlyDerivedFromX));
|
||||
EXPECT_TRUE(notMatches("class X;", IsDirectlyDerivedFromX));
|
||||
EXPECT_TRUE(notMatches("class Y;", IsDirectlyDerivedFromX));
|
||||
EXPECT_TRUE(notMatches("", IsDirectlyDerivedFromX));
|
||||
|
||||
DeclarationMatcher IsAX = cxxRecordDecl(isSameOrDerivedFrom("X"));
|
||||
|
||||
EXPECT_TRUE(matches("class X {}; class Y : public X {};", IsAX));
|
||||
|
@ -341,13 +351,22 @@ TEST(DeclarationMatcher, ClassIsDerived) {
|
|||
|
||||
DeclarationMatcher ZIsDerivedFromX =
|
||||
cxxRecordDecl(hasName("Z"), isDerivedFrom("X"));
|
||||
DeclarationMatcher ZIsDirectlyDerivedFromX =
|
||||
cxxRecordDecl(hasName("Z"), isDirectlyDerivedFrom("X"));
|
||||
EXPECT_TRUE(
|
||||
matches("class X {}; class Y : public X {}; class Z : public Y {};",
|
||||
ZIsDerivedFromX));
|
||||
EXPECT_TRUE(
|
||||
notMatches("class X {}; class Y : public X {}; class Z : public Y {};",
|
||||
ZIsDirectlyDerivedFromX));
|
||||
EXPECT_TRUE(
|
||||
matches("class X {};"
|
||||
"template<class T> class Y : public X {};"
|
||||
"class Z : public Y<int> {};", ZIsDerivedFromX));
|
||||
EXPECT_TRUE(notMatches("class X {};"
|
||||
"template<class T> class Y : public X {};"
|
||||
"class Z : public Y<int> {};",
|
||||
ZIsDirectlyDerivedFromX));
|
||||
EXPECT_TRUE(matches("class X {}; template<class T> class Z : public X {};",
|
||||
ZIsDerivedFromX));
|
||||
EXPECT_TRUE(
|
||||
|
@ -411,6 +430,9 @@ TEST(DeclarationMatcher, ClassIsDerived) {
|
|||
matches("class X {}; class Y : public X {}; "
|
||||
"typedef Y V; typedef V W; class Z : public W {};",
|
||||
ZIsDerivedFromX));
|
||||
EXPECT_TRUE(notMatches("class X {}; class Y : public X {}; "
|
||||
"typedef Y V; typedef V W; class Z : public W {};",
|
||||
ZIsDirectlyDerivedFromX));
|
||||
EXPECT_TRUE(
|
||||
matches("template<class T, class U> class X {}; "
|
||||
"template<class T> class A { class Z : public X<T, int> {}; };",
|
||||
|
@ -467,6 +489,14 @@ TEST(DeclarationMatcher, ClassIsDerived) {
|
|||
"template<> struct X<0> : public A {};"
|
||||
"struct B : public X<42> {};",
|
||||
cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl(hasName("A"))))));
|
||||
EXPECT_TRUE(notMatches(
|
||||
"struct A {};"
|
||||
"template<int> struct X;"
|
||||
"template<int i> struct X : public X<i-1> {};"
|
||||
"template<> struct X<0> : public A {};"
|
||||
"struct B : public X<42> {};",
|
||||
cxxRecordDecl(hasName("B"),
|
||||
isDirectlyDerivedFrom(recordDecl(hasName("A"))))));
|
||||
|
||||
// FIXME: Once we have better matchers for template type matching,
|
||||
// get rid of the Variable(...) matching and match the right template
|
||||
|
|
Loading…
Reference in New Issue