Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -2581,6 +2581,11 @@ +
Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)). +
Matches explicit template specializations of function, class, or static member variable template instantiations. @@ -5269,6 +5274,27 @@
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 isDirectlyDerivedFrom(hasName("X")):
+ class Foo;
+ typedef Foo X;
+ class Bar : public Foo {}; // derived from a type that X is a typedef of
+Matches any argument of a call expression or a constructor call
expression, or an ObjC-message-send expression.
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2634,7 +2634,7 @@
/// \endcode
AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
internal::Matcher, Base) {
- return Finder->classIsDerivedFrom(&Node, Base, Builder);
+ return Finder->classIsDerivedFrom(&Node, Base, Builder, false);
}
/// Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
@@ -2659,6 +2659,20 @@
return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
}
+/// Similar to \c isDerivedFrom(), but matches classes that directly derive from
+/// \c Base.
+AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDirectlyDerivedFrom,
+ internal::Matcher, Base, 0) {
+ return Finder->classIsDerivedFrom(&Node, Base, Builder, 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.
///
Index: clang/include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ clang/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -974,10 +974,11 @@
/// 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 &Base,
- BoundNodesTreeBuilder *Builder) = 0;
+ BoundNodesTreeBuilder *Builder,
+ bool Directly) = 0;
template
bool matchesChildOf(const T &Node, const DynTypedMatcher &Matcher,
Index: clang/lib/ASTMatchers/ASTMatchFinder.cpp
===================================================================
--- clang/lib/ASTMatchers/ASTMatchFinder.cpp
+++ clang/lib/ASTMatchers/ASTMatchFinder.cpp
@@ -430,7 +430,8 @@
bool classIsDerivedFrom(const CXXRecordDecl *Declaration,
const Matcher &Base,
- BoundNodesTreeBuilder *Builder) override;
+ BoundNodesTreeBuilder *Builder,
+ bool Directly) override;
// Implements ASTMatchFinder::matchesChildOf.
bool matchesChildOf(const ast_type_traits::DynTypedNode &Node,
@@ -817,7 +818,8 @@
// derived from itself.
bool MatchASTVisitor::classIsDerivedFrom(const CXXRecordDecl *Declaration,
const Matcher &Base,
- BoundNodesTreeBuilder *Builder) {
+ BoundNodesTreeBuilder *Builder,
+ bool Directly) {
if (!Declaration->hasDefinition())
return false;
for (const auto &It : Declaration->bases()) {
@@ -842,7 +844,7 @@
*Builder = std::move(Result);
return true;
}
- if (classIsDerivedFrom(ClassDecl, Base, Builder))
+ if (!Directly && classIsDerivedFrom(ClassDecl, Base, Builder, Directly))
return true;
}
return false;
Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -331,6 +331,16 @@
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,125 +351,240 @@
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 Y : public X {};"
"class Z : public Y {};", ZIsDerivedFromX));
+ EXPECT_TRUE(notMatches("class X {};"
+ "template class Y : public X {};"
+ "class Z : public Y {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(matches("class X {}; template class Z : public X {};",
ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class X {}; template class Z : public X {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class X {}; "
"template class Z : public X {};",
ZIsDerivedFromX));
+ EXPECT_TRUE(matches("template class X {}; "
+ "template class Z : public X {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class X {}; "
"template class Z : public X {};",
ZIsDerivedFromX));
+ EXPECT_TRUE(matches("template class X {}; "
+ "template class Z : public X {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("template class A { class Z : public X {}; };",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template class A { class Z : public X {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class A { public: class Z : public X {}; }; "
"class X{}; void y() { A::Z z; }", ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template class A { public: class Z : public X {}; }; "
+ "class X{}; void y() { A::Z z; }",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class X {}; "
"template class A { class Z : public X {}; };",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template class X {}; "
+ "template class A { class Z : public X {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("template class X> class A { "
" class Z : public X {}; };", ZIsDerivedFromX));
+ EXPECT_TRUE(notMatches("template class X> class A { "
+ " class Z : public X {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class X> class A { "
" public: class Z : public X {}; }; "
"template class X {}; void y() { A::Z z; }",
ZIsDerivedFromX));
+ EXPECT_TRUE(matches("template class X> class A { "
+ " public: class Z : public X {}; }; "
+ "template class X {}; void y() { A::Z z; }",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("template class A { class Z : public X::D {}; };",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template class A { class Z : public X::D {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class A { public: "
" class Z : public X::D {}; }; "
"class Y { public: class X {}; typedef X D; }; "
"void y() { A::Z z; }", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("template class A { public: "
+ " class Z : public X::D {}; }; "
+ "class Y { public: class X {}; typedef X D; }; "
+ "void y() { A::Z z; }",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("class X {}; typedef X Y; class Z : public Y {};",
ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class X {}; typedef X Y; class Z : public Y {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class Y { typedef typename T::U X; "
" class Z : public X {}; };", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("template class Y { typedef typename T::U X; "
+ " class Z : public X {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(matches("class X {}; class Z : public ::X {};",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {}; class Z : public ::X {};", ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("template class X {}; "
"template class A { class Z : public X::D {}; };",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template class X {}; "
+ "template class A { class Z : public X::D {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class X { public: typedef X D; }; "
"template class A { public: "
" class Z : public X::D {}; }; void y() { A::Z z; }",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template class X { public: typedef X D; }; "
+ "template class A { public: "
+ " class Z : public X::D {}; }; void y() { A::Z z; }",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("template class A { class Z : public X::D::E {}; };",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template class A { class Z : public X::D::E {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("class X {}; typedef X V; typedef V W; class Z : public W {};",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {}; typedef X V; typedef V W; class Z : public W {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
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 X {}; "
"template class A { class Z : public X {}; };",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("template class X {}; "
+ "template class A { class Z : public X {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("template class D { typedef X A; typedef A B; "
" typedef B C; class Z : public C {}; };",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ notMatches("template class D { typedef X A; typedef A B; "
+ " typedef B C; class Z : public C {}; };",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("class X {}; typedef X A; typedef A B; "
"class Z : public B {};", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class X {}; typedef X A; typedef A B; "
+ "class Z : public B {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("class X {}; typedef X A; typedef A B; typedef B C; "
"class Z : public C {};", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class X {}; typedef X A; typedef A B; typedef B C; "
+ "class Z : public C {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("class U {}; typedef U X; typedef X V; "
"class Z : public V {};", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class U {}; typedef U X; typedef X V; "
+ "class Z : public V {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("class Base {}; typedef Base X; "
"class Z : public Base {};", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class Base {}; typedef Base X; "
+ "class Z : public Base {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("class Base {}; typedef Base Base2; typedef Base2 X; "
"class Z : public Base {};", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class Base {}; typedef Base Base2; typedef Base2 X; "
+ "class Z : public Base {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("class Base {}; class Base2 {}; typedef Base2 X; "
"class Z : public Base {};", ZIsDerivedFromX));
+ EXPECT_TRUE(notMatches("class Base {}; class Base2 {}; typedef Base2 X; "
+ "class Z : public Base {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("class A {}; typedef A X; typedef A Y; "
"class Z : public Y {};", ZIsDerivedFromX));
+ EXPECT_TRUE(matches("class A {}; typedef A X; typedef A Y; "
+ "class Z : public Y {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("template class Z;"
"template <> class Z {};"
"template class Z : public Z {};",
IsDerivedFromX));
+ EXPECT_TRUE(notMatches("template class Z;"
+ "template <> class Z {};"
+ "template class Z : public Z {};",
+ IsDirectlyDerivedFromX));
EXPECT_TRUE(
matches("template class X;"
"template <> class X {};"
"template class X : public X {};",
IsDerivedFromX));
+ EXPECT_TRUE(matches("template class X;"
+ "template <> class X {};"
+ "template class X : public X {};",
+ IsDirectlyDerivedFromX));
EXPECT_TRUE(matches(
"class X {};"
"template class Z;"
"template <> class Z {};"
"template class Z : public Z, public X {};",
ZIsDerivedFromX));
+ EXPECT_TRUE(
+ matches("class X {};"
+ "template class Z;"
+ "template <> class Z {};"
+ "template class Z : public Z, public X {};",
+ ZIsDirectlyDerivedFromX));
EXPECT_TRUE(
notMatches("template struct X;"
"template struct X : public X {};",
cxxRecordDecl(isDerivedFrom(recordDecl(hasName("Some"))))));
+ EXPECT_TRUE(notMatches(
+ "template struct X;"
+ "template struct X : public X {};",
+ cxxRecordDecl(isDirectlyDerivedFrom(recordDecl(hasName("Some"))))));
EXPECT_TRUE(matches(
"struct A {};"
"template struct X;"
@@ -467,6 +592,14 @@
"template<> struct X<0> : public A {};"
"struct B : public X<42> {};",
cxxRecordDecl(hasName("B"), isDerivedFrom(recordDecl(hasName("A"))))));
+ EXPECT_TRUE(notMatches(
+ "struct A {};"
+ "template struct X;"
+ "template struct X : public X {};"
+ "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
@@ -484,15 +617,28 @@
RecursiveTemplateOneParameter,
varDecl(hasName("z_float"),
hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1")))))));
+ EXPECT_TRUE(notMatches(
+ RecursiveTemplateOneParameter,
+ varDecl(hasName("z_float"), hasInitializer(hasType(cxxRecordDecl(
+ isDirectlyDerivedFrom("Base1")))))));
EXPECT_TRUE(notMatches(
RecursiveTemplateOneParameter,
varDecl(hasName("z_float"),
hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base2")))))));
+ EXPECT_TRUE(notMatches(
+ RecursiveTemplateOneParameter,
+ varDecl(hasName("z_float"), hasInitializer(hasType(cxxRecordDecl(
+ isDirectlyDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
RecursiveTemplateOneParameter,
varDecl(hasName("z_char"),
hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"),
isDerivedFrom("Base2")))))));
+ EXPECT_TRUE(notMatches(
+ RecursiveTemplateOneParameter,
+ varDecl(hasName("z_char"), hasInitializer(hasType(cxxRecordDecl(
+ isDirectlyDerivedFrom("Base1"),
+ isDirectlyDerivedFrom("Base2")))))));
const char *RecursiveTemplateTwoParameters =
"class Base1 {}; class Base2 {};"
@@ -509,31 +655,56 @@
RecursiveTemplateTwoParameters,
varDecl(hasName("z_float"),
hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1")))))));
+ EXPECT_TRUE(notMatches(
+ RecursiveTemplateTwoParameters,
+ varDecl(hasName("z_float"), hasInitializer(hasType(cxxRecordDecl(
+ isDirectlyDerivedFrom("Base1")))))));
EXPECT_TRUE(notMatches(
RecursiveTemplateTwoParameters,
varDecl(hasName("z_float"),
hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base2")))))));
+ EXPECT_TRUE(notMatches(
+ RecursiveTemplateTwoParameters,
+ varDecl(hasName("z_float"), hasInitializer(hasType(cxxRecordDecl(
+ isDirectlyDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
RecursiveTemplateTwoParameters,
varDecl(hasName("z_char"),
hasInitializer(hasType(cxxRecordDecl(isDerivedFrom("Base1"),
isDerivedFrom("Base2")))))));
+ EXPECT_TRUE(notMatches(
+ RecursiveTemplateTwoParameters,
+ varDecl(hasName("z_char"), hasInitializer(hasType(cxxRecordDecl(
+ isDirectlyDerivedFrom("Base1"),
+ isDirectlyDerivedFrom("Base2")))))));
EXPECT_TRUE(matches(
"namespace ns { class X {}; class Y : public X {}; }",
cxxRecordDecl(isDerivedFrom("::ns::X"))));
+ EXPECT_TRUE(matches("namespace ns { class X {}; class Y : public X {}; }",
+ cxxRecordDecl(isDirectlyDerivedFrom("::ns::X"))));
EXPECT_TRUE(notMatches(
"class X {}; class Y : public X {};",
cxxRecordDecl(isDerivedFrom("::ns::X"))));
+ EXPECT_TRUE(notMatches("class X {}; class Y : public X {};",
+ cxxRecordDecl(isDirectlyDerivedFrom("::ns::X"))));
EXPECT_TRUE(matches(
"class X {}; class Y : public X {};",
cxxRecordDecl(isDerivedFrom(recordDecl(hasName("X")).bind("test")))));
+ EXPECT_TRUE(matches("class X {}; class Y : public X {};",
+ cxxRecordDecl(isDirectlyDerivedFrom(
+ recordDecl(hasName("X")).bind("test")))));
EXPECT_TRUE(matches(
"template class X {};"
"template using Z = X;"
"template class Y : Z {};",
cxxRecordDecl(isDerivedFrom(namedDecl(hasName("X"))))));
+ EXPECT_TRUE(
+ matches("template class X {};"
+ "template using Z = X;"
+ "template class Y : Z {};",
+ cxxRecordDecl(isDirectlyDerivedFrom(namedDecl(hasName("X"))))));
}
TEST(DeclarationMatcher, IsLambda) {