stephanemoore updated this revision to Diff 198956. stephanemoore added a comment.
Present one potential option for making isDerivedFrom support Objective-C classes. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D60543/new/ https://reviews.llvm.org/D60543 Files: clang/docs/LibASTMatchersReference.html clang/include/clang/ASTMatchers/ASTMatchers.h clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp =================================================================== --- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp +++ 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)); Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ 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<NamedDecl>, Base) { - return Finder->classIsDerivedFrom(&Node, Base, Builder); + // Check if the node is a C++ struct/union/class. + if (const auto *RecordDecl = dyn_cast<CXXRecordDecl>(&Node)) + return Finder->classIsDerivedFrom(RecordDecl, Base, Builder); + + // Check if the node is an Objective-C class. + if (const auto *InterfaceDecl = dyn_cast<ObjCInterfaceDecl>(&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<NamedDecl>, Base, 0) { - return Matcher<CXXRecordDecl>(anyOf(Base, isDerivedFrom(Base))) + return Matcher<NamedDecl>(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); Index: clang/docs/LibASTMatchersReference.html =================================================================== --- clang/docs/LibASTMatchersReference.html +++ clang/docs/LibASTMatchersReference.html @@ -2526,11 +2526,6 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom1')"><a name="isDerivedFrom1Anchor">isDerivedFrom</a></td><td>std::string BaseName</td></tr> -<tr><td colspan="4" class="doc" id="isDerivedFrom1"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)). -</pre></td></tr> - - <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isExplicitTemplateSpecialization2')"><a name="isExplicitTemplateSpecialization2Anchor">isExplicitTemplateSpecialization</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isExplicitTemplateSpecialization2"><pre>Matches explicit template specializations of function, class, or static member variable template instantiations. @@ -2573,12 +2568,6 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom1')"><a name="isSameOrDerivedFrom1Anchor">isSameOrDerivedFrom</a></td><td>std::string BaseName</td></tr> -<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom1"><pre>Overloaded method as shortcut for -isSameOrDerivedFrom(hasName(...)). -</pre></td></tr> - - <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isTemplateInstantiation2')"><a name="isTemplateInstantiation2Anchor">isTemplateInstantiation</a></td><td></td></tr> <tr><td colspan="4" class="doc" id="isTemplateInstantiation2"><pre>Matches template instantiations of function, class, or static member variable template instantiations. @@ -3436,6 +3425,17 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom1')"><a name="isDerivedFrom1Anchor">isDerivedFrom</a></td><td>std::string BaseName</td></tr> +<tr><td colspan="4" class="doc" id="isDerivedFrom1"><pre>Overloaded method as shortcut for isDerivedFrom(hasName(...)). +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom1')"><a name="isSameOrDerivedFrom1Anchor">isSameOrDerivedFrom</a></td><td>std::string BaseName</td></tr> +<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom1"><pre>Overloaded method as shortcut for +isSameOrDerivedFrom(hasName(...)). +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('matchesName0')"><a name="matchesName0Anchor">matchesName</a></td><td>std::string RegExp</td></tr> <tr><td colspan="4" class="doc" id="matchesName0"><pre>Matches NamedDecl nodes whose fully qualified names contain a substring matched by the given RegExp. @@ -5192,33 +5192,6 @@ </pre></td></tr> -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom0')"><a name="isDerivedFrom0Anchor">isDerivedFrom</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr> -<tr><td colspan="4" class="doc" id="isDerivedFrom0"><pre>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 -</pre></td></tr> - - -<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXRecordDecl.html">CXXRecordDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom0')"><a name="isSameOrDerivedFrom0Anchor">isSameOrDerivedFrom</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr> -<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom0"><pre>Similar to isDerivedFrom(), but also matches classes that directly -match Base. -</pre></td></tr> - - <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CXXUnresolvedConstructExpr.html">CXXUnresolvedConstructExpr</a>></td><td class="name" onclick="toggle('hasAnyArgument2')"><a name="hasAnyArgument2Anchor">hasAnyArgument</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html">Expr</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasAnyArgument2"><pre>Matches any argument of a call expression or a constructor call expression, or an ObjC-message-send expression. @@ -6254,6 +6227,38 @@ </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('isDerivedFrom0')"><a name="isDerivedFrom0Anchor">isDerivedFrom</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr> +<tr><td colspan="4" class="doc" id="isDerivedFrom0"><pre>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 +</pre></td></tr> + + +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>></td><td class="name" onclick="toggle('isSameOrDerivedFrom0')"><a name="isSameOrDerivedFrom0Anchor">isSameOrDerivedFrom</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NamedDecl.html">NamedDecl</a>> Base</td></tr> +<tr><td colspan="4" class="doc" id="isSameOrDerivedFrom0"><pre>Similar to isDerivedFrom(), but also matches classes that directly +match Base. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>></td><td class="name" onclick="toggle('hasPrefix1')"><a name="hasPrefix1Anchor">hasPrefix</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1NestedNameSpecifierLoc.html">NestedNameSpecifierLoc</a>> InnerMatcher</td></tr> <tr><td colspan="4" class="doc" id="hasPrefix1"><pre>Matches on the prefix of a NestedNameSpecifierLoc.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits