diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -2526,8 +2526,8 @@ -Matcher<CXXRecordDecl>isDerivedFromstd::string BaseName -
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+Matcher<CXXRecordDecl>isDerivedFromstd::string BaseName
+
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
 
@@ -2573,8 +2573,8 @@
-Matcher<CXXRecordDecl>isSameOrDerivedFromstd::string BaseName -
Overloaded method as shortcut for
+Matcher<CXXRecordDecl>isSameOrDerivedFromstd::string BaseName
+
Overloaded method as shortcut for
 isSameOrDerivedFrom(hasName(...)).
 
@@ -3538,6 +3538,17 @@
+Matcher<ObjCInterfaceDecl>isDerivedFromstd::string BaseName +
Overloaded method as shortcut for isDerivedFrom(hasName(...)).
+
+ + +Matcher<ObjCInterfaceDecl>isSameOrDerivedFromstd::string BaseName +
Overloaded method as shortcut for
+isSameOrDerivedFrom(hasName(...)).
+
+ + Matcher<ObjCMessageExpr>argumentCountIsunsigned N
Checks that a call expression or a constructor call expression has
 a specific number of arguments (including absent default arguments).
@@ -5193,8 +5204,9 @@
 
 
 Matcher<CXXRecordDecl>isDerivedFromMatcher<NamedDecl> Base
-
Matches C++ classes that are directly or indirectly derived from
-a class matching 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.
 
@@ -5210,6 +5222,12 @@
   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
+
+Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
 
@@ -6345,6 +6363,40 @@
+Matcher<ObjCInterfaceDecl>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
+
+Usable as: Matcher<CXXRecordDecl>, Matcher<ObjCInterfaceDecl>
+
+ + +Matcher<ObjCInterfaceDecl>isSameOrDerivedFromMatcher<NamedDecl> Base +
Similar to isDerivedFrom(), but also matches classes that directly
+match Base.
+
+ + Matcher<ObjCMessageExpr>hasAnyArgumentMatcher<Expr> InnerMatcher
Matches any argument of a call expression or a constructor call
 expression, or an ObjC-message-send expression.
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,31 +2622,91 @@
 ///   typedef Foo X;
 ///   class Bar : public Foo {};  // derived from a type that X is a typedef of
 /// \endcode
-AST_MATCHER_P(CXXRecordDecl, isDerivedFrom,
-              internal::Matcher, Base) {
-  return Finder->classIsDerivedFrom(&Node, Base, Builder);
+///
+/// In the following example, Bar matches isDerivedFrom(hasName("NSObject"))
+/// \code
+///   @interface NSObject @end
+///   @interface Bar : NSObject @end
+/// \endcode
+///
+/// Usable as: Matcher, Matcher
+AST_POLYMORPHIC_MATCHER_P(
+    isDerivedFrom,
+    AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+    internal::Matcher, Base) {
+  // 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_POLYMORPHIC_MATCHER_P_OVERLOAD(
+    isDerivedFrom,
+    AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+    std::string, BaseName, 1) {
   assert(!BaseName.empty());
-  return isDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
+
+  const auto M = isDerivedFrom(hasName(BaseName));
+
+  if (const auto *RecordDecl = dyn_cast(&Node))
+    return Matcher(M).matches(*RecordDecl, Finder, Builder);
+
+  if (const auto *InterfaceDecl = dyn_cast(&Node))
+    return Matcher(M).matches(*InterfaceDecl, Finder,
+                                                 Builder);
+
+  llvm_unreachable("Not a valid polymorphic type");
 }
 
 /// Similar to \c isDerivedFrom(), but also matches classes that directly
 /// match \c Base.
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom,
-                       internal::Matcher, Base, 0) {
-  return Matcher(anyOf(Base, isDerivedFrom(Base)))
-      .matches(Node, Finder, Builder);
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+    isSameOrDerivedFrom,
+    AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+    internal::Matcher, Base, 0) {
+  const auto M = anyOf(Base, isDerivedFrom(Base));
+
+  if (const auto *RecordDecl = dyn_cast(&Node))
+    return Matcher(M).matches(*RecordDecl, Finder, Builder);
+
+  if (const auto *InterfaceDecl = dyn_cast(&Node))
+    return Matcher(M).matches(*InterfaceDecl, Finder,
+                                                 Builder);
+
+  llvm_unreachable("Not a valid polymorphic type");
 }
 
 /// Overloaded method as shortcut for
 /// \c isSameOrDerivedFrom(hasName(...)).
-AST_MATCHER_P_OVERLOAD(CXXRecordDecl, isSameOrDerivedFrom, std::string,
-                       BaseName, 1) {
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+    isSameOrDerivedFrom,
+    AST_POLYMORPHIC_SUPPORTED_TYPES(CXXRecordDecl, ObjCInterfaceDecl),
+    std::string, BaseName, 1) {
   assert(!BaseName.empty());
-  return isSameOrDerivedFrom(hasName(BaseName)).matches(Node, Finder, Builder);
+
+  const auto M = isSameOrDerivedFrom(hasName(BaseName));
+
+  if (const auto *RecordDecl = dyn_cast(&Node))
+    return Matcher(M).matches(*RecordDecl, Finder, Builder);
+
+  if (const auto *InterfaceDecl = dyn_cast(&Node))
+    return Matcher(M).matches(*InterfaceDecl, Finder,
+                                                 Builder);
+
+  llvm_unreachable("Not a valid polymorphic type");
 }
 
 /// Matches the first method of a class or struct that satisfies \c
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,38 @@
     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));
+}
+
 TEST(DeclarationMatcher, IsLambda) {
   const auto IsLambda = cxxMethodDecl(ofClass(cxxRecordDecl(isLambda())));
   EXPECT_TRUE(matches("auto x = []{};", IsLambda));