Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -2581,6 +2581,11 @@ +Matcher<CXXRecordDecl>isDirectlyDerivedFromstd::string BaseName +
Overloaded method as shortcut for isDirectlyDerivedFrom(hasName(...)).
+
+ + Matcher<CXXRecordDecl>isExplicitTemplateSpecialization
Matches explicit template specializations of function, class, or
 static member variable template instantiations.
@@ -5269,6 +5274,27 @@
 
+Matcher<CXXRecordDecl>isDirectlyDerivedFromMatcher<NamedDecl> Base +
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
+
+ + Matcher<CXXUnresolvedConstructExpr>hasAnyArgumentMatcher<Expr> InnerMatcher
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) {