diff options
author | 2022-07-21 13:20:19 -0700 | |
---|---|---|
committer | 2022-07-21 13:35:31 -0700 | |
commit | b17baa1db613a2ce777aa122feb87488750a64d0 (patch) | |
tree | feef68260d507bcd635f380f8f1d5350a205f6ab /clang | |
parent | [libc] Add a convenience class and function for integer to string conversion. (diff) | |
download | llvm-project-b17baa1db613a2ce777aa122feb87488750a64d0.tar.gz llvm-project-b17baa1db613a2ce777aa122feb87488750a64d0.tar.bz2 llvm-project-b17baa1db613a2ce777aa122feb87488750a64d0.zip |
[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
Diffstat (limited to 'clang')
-rw-r--r-- | clang/docs/LibASTMatchersReference.html | 37 | ||||
-rw-r--r-- | clang/include/clang/ASTMatchers/ASTMatchers.h | 33 | ||||
-rw-r--r-- | clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp | 39 | ||||
-rw-r--r-- | clang/unittests/ASTMatchers/Dynamic/RegistryTest.cpp | 19 |
4 files changed, 120 insertions, 8 deletions
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 03ca48cc1a9b..4ac9ab0090cd 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -7255,14 +7255,24 @@ Usable as: Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Bloc </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 @@ match Base. </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 ae5502d7af71..9f4d807c232d 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 195ac67c804d..a83927e6de24 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 318fd3ad1857..7c7d45ac565f 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( |