[clang] b17baa1 - [ASTMatchers] Adding a new matcher for callee declarations of Obj-C

Ziqing Luo via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 21 13:35:59 PDT 2022


Author: Ziqing Luo
Date: 2022-07-21T13:35:31-07:00
New Revision: b17baa1db613a2ce777aa122feb87488750a64d0

URL: https://github.com/llvm/llvm-project/commit/b17baa1db613a2ce777aa122feb87488750a64d0
DIFF: https://github.com/llvm/llvm-project/commit/b17baa1db613a2ce777aa122feb87488750a64d0.diff

LOG: [ASTMatchers] Adding a new matcher for callee declarations of Obj-C
message expressions

For an Obj-C message expression `[o m]`, the adding matcher will match
the declaration of the method `m`.  This commit overloads the existing
`callee` ASTMatcher, which originally was only for C/C++ nodes but
also applies to Obj-C messages now.

Reviewed By: aaron.ballman

Differential Revision: https://reviews.llvm.org/D129398

Added: 
    

Modified: 
    clang/docs/LibASTMatchersReference.html
    clang/include/clang/ASTMatchers/ASTMatchers.h
    clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
    clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 03ca48cc1a9b3..4ac9ab0090cd4 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -7255,14 +7255,24 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
 </pre></td></tr>
 
 
-<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
-<tr><td colspan="4" class="doc" id="callee1"><pre>Matches if the call expression's callee's declaration matches the
-given matcher.
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1CallExpr.html">CallExpr</a>></td><td class="name" onclick="toggle('callee2')"><a name="callee2Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="callee2"><pre>Matches 1) if the call expression's callee's declaration matches the
+given matcher; or 2) if the Obj-C message expression's callee's method
+declaration matches the given matcher.
 
 Example matches y.x() (matcher = callExpr(callee(
                                    cxxMethodDecl(hasName("x")))))
   class Y { public: void x(); };
   void z() { Y y; y.x(); }
+
+Example 2. Matches [I foo] with
+objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
+
+  @interface I: NSObject
+  +(void)foo;
+  @end
+  ...
+  [I foo]
 </pre></td></tr>
 
 
@@ -8814,6 +8824,27 @@ <h2 id="traversal-matchers">AST Traversal Matchers</h2>
 </pre></td></tr>
 
 
+<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('callee1')"><a name="callee1Anchor">callee</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>> InnerMatcher</td></tr>
+<tr><td colspan="4" class="doc" id="callee1"><pre>Matches 1) if the call expression's callee's declaration matches the
+given matcher; or 2) if the Obj-C message expression's callee's method
+declaration matches the given matcher.
+
+Example matches y.x() (matcher = callExpr(callee(
+                                   cxxMethodDecl(hasName("x")))))
+  class Y { public: void x(); };
+  void z() { Y y; y.x(); }
+
+Example 2. Matches [I foo] with
+objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
+
+  @interface I: NSObject
+  +(void)foo;
+  @end
+  ...
+  [I foo]
+</pre></td></tr>
+
+
 <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMessageExpr.html">ObjCMessageExpr</a>></td><td class="name" onclick="toggle('hasAnyArgument3')"><a name="hasAnyArgument3Anchor">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="hasAnyArgument3"><pre>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
index ae5502d7af71b..9f4d807c232dc 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -3838,8 +3838,9 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
           InnerMatcher.matches(*ExprNode, Finder, Builder));
 }
 
-/// Matches if the call expression's callee's declaration matches the
-/// given matcher.
+/// Matches 1) if the call expression's callee's declaration matches the
+/// given matcher; or 2) if the Obj-C message expression's callee's method
+/// declaration matches the given matcher.
 ///
 /// Example matches y.x() (matcher = callExpr(callee(
 ///                                    cxxMethodDecl(hasName("x")))))
@@ -3847,9 +3848,31 @@ AST_MATCHER_P(CallExpr, callee, internal::Matcher<Stmt>,
 ///   class Y { public: void x(); };
 ///   void z() { Y y; y.x(); }
 /// \endcode
-AST_MATCHER_P_OVERLOAD(CallExpr, callee, internal::Matcher<Decl>, InnerMatcher,
-                       1) {
-  return callExpr(hasDeclaration(InnerMatcher)).matches(Node, Finder, Builder);
+///
+/// Example 2. Matches [I foo] with
+/// objcMessageExpr(callee(objcMethodDecl(hasName("foo"))))
+///
+/// \code
+///   @interface I: NSObject
+///   +(void)foo;
+///   @end
+///   ...
+///   [I foo]
+/// \endcode
+AST_POLYMORPHIC_MATCHER_P_OVERLOAD(
+    callee, AST_POLYMORPHIC_SUPPORTED_TYPES(ObjCMessageExpr, CallExpr),
+    internal::Matcher<Decl>, InnerMatcher, 1) {
+  if (const auto *CallNode = dyn_cast<CallExpr>(&Node))
+    return callExpr(hasDeclaration(InnerMatcher))
+        .matches(Node, Finder, Builder);
+  else {
+    // The dynamic cast below is guaranteed to succeed as there are only 2
+    // supported return types.
+    const auto *MsgNode = cast<ObjCMessageExpr>(&Node);
+    const Decl *DeclNode = MsgNode->getMethodDecl();
+    return (DeclNode != nullptr &&
+            InnerMatcher.matches(*DeclNode, Finder, Builder));
+  }
 }
 
 /// Matches if the expression's or declaration's type matches a type

diff  --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 195ac67c804dd..a83927e6de249 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -2307,6 +2307,45 @@ TEST_P(ASTMatchersTest,
           hasName("cc"), hasInitializer(integerLiteral(equals(1))))))))));
 }
 
+TEST(ASTMatchersTestObjC, ObjCMessageCalees) {
+  StatementMatcher MessagingFoo =
+      objcMessageExpr(callee(objcMethodDecl(hasName("foo"))));
+
+  EXPECT_TRUE(matchesObjC("@interface I"
+                          "+ (void)foo;"
+                          "@end\n"
+                          "int main() {"
+                          "  [I foo];"
+                          "}",
+                          MessagingFoo));
+  EXPECT_TRUE(notMatchesObjC("@interface I"
+                             "+ (void)foo;"
+                             "+ (void)bar;"
+                             "@end\n"
+                             "int main() {"
+                             "  [I bar];"
+                             "}",
+                             MessagingFoo));
+  EXPECT_TRUE(matchesObjC("@interface I"
+                          "- (void)foo;"
+                          "- (void)bar;"
+                          "@end\n"
+                          "int main() {"
+                          "  I *i;"
+                          "  [i foo];"
+                          "}",
+                          MessagingFoo));
+  EXPECT_TRUE(notMatchesObjC("@interface I"
+                             "- (void)foo;"
+                             "- (void)bar;"
+                             "@end\n"
+                             "int main() {"
+                             "  I *i;"
+                             "  [i bar];"
+                             "}",
+                             MessagingFoo));
+}
+
 TEST(ASTMatchersTestObjC, ObjCMessageExpr) {
   // Don't find ObjCMessageExpr where none are present.
   EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything())));

diff  --git a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
index 318fd3ad1857e..7c7d45ac565f8 100644
--- a/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
+++ b/clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp
@@ -198,13 +198,32 @@ TEST_F(RegistryTest, OverloadedMatchers) {
                            constructMatcher("hasName", StringRef("x")))))
       .getTypedMatcher<Stmt>();
 
+  Matcher<Stmt> ObjCMsgExpr =
+      constructMatcher(
+          "objcMessageExpr",
+          constructMatcher(
+              "callee",
+              constructMatcher("objcMethodDecl",
+                               constructMatcher("hasName", StringRef("x")))))
+          .getTypedMatcher<Stmt>();
+
   std::string Code = "class Y { public: void x(); }; void z() { Y y; y.x(); }";
   EXPECT_FALSE(matches(Code, CallExpr0));
   EXPECT_TRUE(matches(Code, CallExpr1));
+  EXPECT_FALSE(matches(Code, ObjCMsgExpr));
 
   Code = "class Z { public: void z() { this->z(); } };";
   EXPECT_TRUE(matches(Code, CallExpr0));
   EXPECT_FALSE(matches(Code, CallExpr1));
+  EXPECT_FALSE(matches(Code, ObjCMsgExpr));
+
+  Code = "@interface I "
+         "+ (void)x; "
+         "@end\n"
+         "int main() { [I x]; }";
+  EXPECT_FALSE(matchesObjC(Code, CallExpr0));
+  EXPECT_FALSE(matchesObjC(Code, CallExpr1));
+  EXPECT_TRUE(matchesObjC(Code, ObjCMsgExpr));
 
   Matcher<Decl> DeclDecl = declaratorDecl(hasTypeLoc(
       constructMatcher(


        


More information about the cfe-commits mailing list