stephanemoore created this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.
stephanemoore added a reviewer: aaron.ballman.

This change adds a new AST matcher to detect Objective-C classes that
are subclasses of matching Objective-C interfaces.

Test Notes:
Ran clang unit tests.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D60543

Files:
  clang/docs/LibASTMatchersReference.html
  clang/include/clang/ASTMatchers/ASTMatchers.h
  clang/lib/ASTMatchers/Dynamic/Registry.cpp
  clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp

Index: clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
===================================================================
--- clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
+++ clang/unittests/ASTMatchers/ASTMatchersNarrowingTest.cpp
@@ -1389,6 +1389,23 @@
   EXPECT_TRUE(matchesObjC("void f() { ^{}(); }", blockExpr()));
 }
 
+TEST(IsSubclassOfInterfaceMatcher, SubclassMatching) {
+  std::string ObjCString = "@interface A @end"
+                           "@interface B : A @end"
+                           "@interface C : B @end";
+  EXPECT_TRUE(matchesObjC(
+      ObjCString, objcInterfaceDecl(isSubclassOfInterface(hasName("A")))));
+  EXPECT_TRUE(matchesObjC(ObjCString,
+                          objcInterfaceDecl(isSubclassOfInterface(hasName("A")),
+                                            unless(hasName("B")))));
+  EXPECT_TRUE(matchesObjC(
+      ObjCString, objcInterfaceDecl(isSubclassOfInterface(hasName("B")))));
+  EXPECT_FALSE(matchesObjC(
+      ObjCString, objcInterfaceDecl(isSubclassOfInterface(hasName("C")))));
+  EXPECT_FALSE(matchesObjC(
+      ObjCString, objcInterfaceDecl(isSubclassOfInterface(hasName("X")))));
+}
+
 TEST(StatementCountIs, FindsNoStatementsInAnEmptyCompoundStatement) {
   EXPECT_TRUE(matches("void f() { }",
                       compoundStmt(statementCountIs(0))));
Index: clang/lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -393,6 +393,7 @@
   REGISTER_MATCHER(isStaticLocal);
   REGISTER_MATCHER(isStaticStorageClass);
   REGISTER_MATCHER(isStruct);
+  REGISTER_MATCHER(isSubclassOfInterface);
   REGISTER_MATCHER(isTemplateInstantiation);
   REGISTER_MATCHER(isTypeDependent);
   REGISTER_MATCHER(isUnion);
Index: clang/include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- clang/include/clang/ASTMatchers/ASTMatchers.h
+++ clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -1461,6 +1461,35 @@
 extern const internal::VariadicDynCastAllOfMatcher<Stmt, ObjCAtFinallyStmt>
     objcFinallyStmt;
 
+/// Matches Objective-C classes that directly or indirectly subclass
+/// a matching superclass.
+///
+/// Note that a class is not considered to be a subclass of itself.
+///
+/// Example matches implementation declarations for Y and Z.
+///   (matcher = objcInterfaceDecl(isSubclassOfInterface(hasName("X"))))
+/// \code
+///   @interface X
+///   @end
+///   @interface Y : X  // directly derived
+///   @end
+///   @interface Z : Y  // indirectly derived
+///   @end
+/// \endcode
+AST_MATCHER_P(ObjCInterfaceDecl, isSubclassOfInterface,
+              internal::Matcher<ObjCInterfaceDecl>,
+              InnerMatcher) {
+  // Check if any of the superclasses of the class match.
+  for (const ObjCInterfaceDecl *SuperClass = Node.getSuperClass();
+       SuperClass != nullptr; SuperClass = SuperClass->getSuperClass()) {
+    if (InnerMatcher.matches(*SuperClass, Finder, Builder))
+      return true;
+  }
+
+  // No matches found.
+  return false;
+}
+
 /// Matches expressions that introduce cleanups to be run at the end
 /// of the sub-expression's evaluation.
 ///
Index: clang/docs/LibASTMatchersReference.html
===================================================================
--- clang/docs/LibASTMatchersReference.html
+++ clang/docs/LibASTMatchersReference.html
@@ -6285,6 +6285,23 @@
 </pre></td></tr>
 
 
+<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html";>ObjCInterfaceDecl</a>&gt;</td><td class="name" onclick="toggle('isSubclassOfInterface0')"><a name="isSubclassOfInterface0Anchor">isSubclassOfInterface</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCInterfaceDecl.html";>ObjCInterfaceDecl</a>&gt; InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="isSubclassOfInterface0"><pre>Matches Objective-C classes that directly or indirectly subclass
+a matching superclass.
+
+Note that a class is not considered to be a subclass of itself.
+
+Example matches implementation declarations for Y and Z.
+  (matcher = objcInterfaceDecl(isSubclassOfInterface(hasName("X"))))
+  @interface X
+  @end
+  @interface Y : X  // directly derived
+  @end
+  @interface Z : Y  // indirectly derived
+  @end
+</pre></td></tr>
+
+
 <tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html";>ObjCMessageExpr</a>&gt;</td><td class="name" onclick="toggle('hasAnyArgument3')"><a name="hasAnyArgument3Anchor">hasAnyArgument</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Expr.html";>Expr</a>&gt; InnerMatcher</td></tr>
 <tr><td colspan="4" class="doc" id="hasAnyArgument3"><pre>Matches any argument of a call expression or a constructor call
 expression, or an ObjC-message-send expression.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to