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 @@ -
Overloaded method as shortcut for isDerivedFrom(hasName(...)). -
Matches explicit template specializations of function, class, or static member variable template instantiations. @@ -2573,12 +2568,6 @@
Overloaded method as shortcut for -isSameOrDerivedFrom(hasName(...)). -
Matches template instantiations of function, class, or static member variable template instantiations. @@ -3436,6 +3425,17 @@
Overloaded method as shortcut for isDerivedFrom(hasName(...)). +
Overloaded method as shortcut for +isSameOrDerivedFrom(hasName(...)). +
Matches NamedDecl nodes whose fully qualified names contain a substring matched by the given RegExp. @@ -5192,33 +5192,6 @@
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
-Similar to isDerivedFrom(), but also matches classes that directly -match Base. -
Matches any argument of a call expression or a constructor call expression, or an ObjC-message-send expression. @@ -6254,6 +6227,38 @@
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
+Similar to isDerivedFrom(), but also matches classes that directly +match Base. +
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));