r367010 - [clang] Add isDirectlyDerivedFrom AST matcher.
Anton Bikineev via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 25 04:54:13 PDT 2019
Author: antonbikineev
Date: Thu Jul 25 04:54:13 2019
New Revision: 367010
URL: http://llvm.org/viewvc/llvm-project?rev=367010&view=rev
Log:
[clang] Add isDirectlyDerivedFrom AST matcher.
Differential Revision: https://reviews.llvm.org/D65092
Modified:
cfe/trunk/docs/LibASTMatchersReference.html
cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Modified: cfe/trunk/docs/LibASTMatchersReference.html
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/docs/LibASTMatchersReference.html?rev=367010&r1=367009&r2=367010&view=diff
==============================================================================
--- cfe/trunk/docs/LibASTMatchersReference.html (original)
+++ cfe/trunk/docs/LibASTMatchersReference.html Thu Jul 25 04:54:13 2019
@@ -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.
@@ -5252,6 +5257,26 @@ Example matches Y, Z, C (Base == hasName
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('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
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h?rev=367010&r1=367009&r2=367010&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchers.h Thu Jul 25 04:54:13 2019
@@ -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, is
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.
///
Modified: cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h?rev=367010&r1=367009&r2=367010&view=diff
==============================================================================
--- cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h (original)
+++ cfe/trunk/include/clang/ASTMatchers/ASTMatchersInternal.h Thu Jul 25 04:54:13 2019
@@ -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,
Modified: cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp?rev=367010&r1=367009&r2=367010&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/ASTMatchFinder.cpp Thu Jul 25 04:54:13 2019
@@ -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(cons
// 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
*Builder = std::move(Result);
return true;
}
- if (classIsDerivedFrom(ClassDecl, Base, Builder))
+ if (!Directly && classIsDerivedFrom(ClassDecl, Base, Builder, Directly))
return true;
}
return false;
Modified: cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp?rev=367010&r1=367009&r2=367010&view=diff
==============================================================================
--- cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp (original)
+++ cfe/trunk/lib/ASTMatchers/Dynamic/Registry.cpp Thu Jul 25 04:54:13 2019
@@ -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);
Modified: cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp?rev=367010&r1=367009&r2=367010&view=diff
==============================================================================
--- cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp (original)
+++ cfe/trunk/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp Thu Jul 25 04:54:13 2019
@@ -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
More information about the cfe-commits
mailing list