diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -2526,11 +2526,6 @@ -Matcher<CXXRecordDecl>isDerivedFromstd::string BaseName -
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
-
- - Matcher<CXXRecordDecl>isExplicitTemplateSpecialization
Matches explicit template specializations of function, class, or
 static member variable template instantiations.
@@ -2573,12 +2568,6 @@
 
-Matcher<CXXRecordDecl>isSameOrDerivedFromstd::string BaseName -
Overloaded method as shortcut for
-isSameOrDerivedFrom(hasName(...)).
-
- - Matcher<CXXRecordDecl>isTemplateInstantiation
Matches template instantiations of function, class, or static
 member variable template instantiations.
@@ -3436,6 +3425,17 @@
 
+Matcher<NamedDecl>isDerivedFromstd::string BaseName +
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+
+ + +Matcher<NamedDecl>isSameOrDerivedFromstd::string BaseName +
Overloaded method as shortcut for
+isSameOrDerivedFrom(hasName(...)).
+
+ + Matcher<NamedDecl>matchesNamestd::string RegExp
Matches NamedDecl nodes whose fully qualified names contain
 a substring matched by the given RegExp.
@@ -5192,33 +5192,6 @@
 
-Matcher<CXXRecordDecl>isDerivedFromMatcher<NamedDecl> Base -
Matches C++ classes that are directly or indirectly derived from
-a class matching Base.
-
-Note that a class is not considered to be derived from itself.
-
-Example matches Y, Z, 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
-
- - -Matcher<CXXRecordDecl>isSameOrDerivedFromMatcher<NamedDecl> Base -
Similar to isDerivedFrom(), but also matches classes that directly
-match Base.
-
- - Matcher<CXXUnresolvedConstructExpr>hasAnyArgumentMatcher<Expr> InnerMatcher
Matches any argument of a call expression or a constructor call
 expression, or an ObjC-message-send expression.
@@ -6254,6 +6227,38 @@
 
+Matcher<NamedDecl>isDerivedFromMatcher<NamedDecl> Base +
Matches C++ classes that are directly or indirectly derived from a class
+matching Base, or Objective-C classes that directly or indirectly
+subclass a class matching Base.
+
+Note that a class is not considered to be derived from itself.
+
+Example matches Y, Z, 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
+
+In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+  @interface NSObject @end
+  @interface Bar : NSObject @end
+
+ + +Matcher<NamedDecl>isSameOrDerivedFromMatcher<NamedDecl> Base +
Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+
+ + Matcher<NestedNameSpecifierLoc>hasPrefixMatcher<NestedNameSpecifierLoc> InnerMatcher
Matches on the prefix of a NestedNameSpecifierLoc.
 
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -2600,8 +2600,9 @@
       AST_POLYMORPHIC_SUPPORTED_TYPES(CXXOperatorCallExpr, FunctionDecl)>(Name);
 }
 
-/// Matches C++ classes that are directly or indirectly derived from
-/// a class matching \c Base.
+/// Matches C++ classes that are directly or indirectly derived from a class
+/// matching \c Base, or Objective-C classes that directly or indirectly
+/// subclass a class matching \c Base.
 ///
 /// Note that a class is not considered to be derived from itself.
 ///
@@ -2621,28 +2622,49 @@
 ///   typedef Foo X;
 ///   class Bar : public Foo {};  // derived from a type that X is a typedef of
 /// \endcode
-AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
+///
+/// In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+/// \code
+///   @interface NSObject @end
+///   @interface Bar : NSObject @end
+/// \endcode
+AST_MATCHER_P(NamedDecl, isDerivedFrom,
               internal::Matcher, Base) {
-  return Finder->classIsDerivedFrom(&Node, Base, Builder);
+  // Check if the node is a C++ struct/union/class.
+  if (const auto *RecordDecl = dyn_cast(&Node))
+    return Finder->classIsDerivedFrom(RecordDecl, Base, Builder);
+
+  // Check if the node is an Objective-C class.
+  if (const auto *InterfaceDecl = dyn_cast(&Node)) {
+    // Check if any of the superclasses of the class match.
+    for (const ObjCInterfaceDecl *SuperClass = InterfaceDecl->getSuperClass();
+         SuperClass != nullptr; SuperClass = SuperClass->getSuperClass()) {
+      if (Base.matches(*SuperClass, Finder, Builder))
+        return true;
+    }
+  }
+
+  // No matches found.
+  return false;
 }
 
 /// Overloaded method as shortcut for \c isDerivedFrom(hasName(...)).
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isDerivedFrom, std::string, BaseName, 1) {
+AST_MATCHER_P_OVERLOAD(NamedDecl, isDerivedFrom, std::string, BaseName, 1) {
   assert(!BaseName.empty());
   return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
 }
 
 /// Similar to \c isDerivedFrom(), but also matches classes that directly
 /// match \c Base.
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom,
+AST_MATCHER_P_OVERLOAD(NamedDecl, isSameOrDerivedFrom,
                        internal::Matcher, Base, 0) {
-  return Matcher(anyOf(Base, isDerivedFrom(Base)))
+  return Matcher(anyOf(Base, isDerivedFrom(Base)))
       .matches(Node, Finder, Builder);
 }
 
 /// Overloaded method as shortcut for
 /// \c isSameOrDerivedFrom(hasName(...)).
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string,
+AST_MATCHER_P_OVERLOAD(NamedDecl, isSameOrDerivedFrom, std::string,
                        BaseName, 1) {
   assert(!BaseName.empty());
   return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
--- a/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -536,6 +536,39 @@
     cxxRecordDecl(isDerivedFrom(namedDecl(hasName("X"))))));
 }
 
+TEST(DeclarationMatcher, ObjCClassIsDerived) {
+  DeclarationMatcher IsDerivedFromX = objcInterfaceDecl(isDerivedFrom("X"));
+  EXPECT_TRUE(matchesObjC("@interface X @end @interface Y : X @end", IsDerivedFromX));
+  EXPECT_TRUE(matchesObjC("@interface X @end @interface Y<__covariant ObjectType> : X @end", IsDerivedFromX));
+  EXPECT_TRUE(notMatchesObjC("@interface X @end", IsDerivedFromX));
+  EXPECT_TRUE(notMatchesObjC("@class X;", IsDerivedFromX));
+  EXPECT_TRUE(notMatchesObjC("@class Y;", IsDerivedFromX));
+
+  DeclarationMatcher IsAX = objcInterfaceDecl(isSameOrDerivedFrom("X"));
+  EXPECT_TRUE(matchesObjC("@interface X @end @interface Y : X @end", IsAX));
+  EXPECT_TRUE(matchesObjC("@interface X @end", IsAX));
+  EXPECT_TRUE(matchesObjC("@class X;", IsAX));
+  EXPECT_TRUE(notMatchesObjC("@interface Y @end", IsAX));
+  EXPECT_TRUE(notMatchesObjC("@class Y;", IsAX));
+
+  DeclarationMatcher ZIsDerivedFromX = objcInterfaceDecl(hasName("Z"), isDerivedFrom("X"));
+  EXPECT_TRUE(
+      matchesObjC("@interface X @end @interface Y : X @end @interface Z : Y @end",
+                  ZIsDerivedFromX));
+  EXPECT_TRUE(
+      matchesObjC("@interface X @end typedef X Y; @interface Z : Y @end",
+                  ZIsDerivedFromX));
+  EXPECT_TRUE(
+      matchesObjC("@interface X @end @interface Y : X @end typedef Y V; typedef V W; @interface Z : W @end",
+                  ZIsDerivedFromX));
+  EXPECT_TRUE(
+      notMatchesObjC("@interface Y @end typedef Y X; @interface Z : X @end",
+                  ZIsDerivedFromX));
+  EXPECT_TRUE(
+      notMatchesObjC("@interface Y @end @interface Y2 @end typedef Y2 X; @interface Z : Y @end",
+                     ZIsDerivedFromX));
+}
+
 TEST(DeclarationMatcher, IsLambda) {
   const auto IsLambda = cxxMethodDecl(ofClass(cxxRecordDecl(isLambda())));
   EXPECT_TRUE(matches("auto x = []{};", IsLambda));