diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -8867,6 +8867,20 @@ +
matches if ObjCMessageExpr's callee declaration matches + +Given + @interface I: NSObject + +(void)foo; + @end + ... + [I foo] +The example above matches [I foo] with +objcMessageExpr(objcMessageCallee(objcMethodDecl(hasName("foo")))) +
Matches any parameter of a function or an ObjC method declaration or a block. 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 @@ -3838,6 +3838,25 @@ InnerMatcher.matches(*ExprNode, Finder, Builder)); } +/// matches if ObjCMessageExpr's callee declaration matches +/// +/// Given +/// \code +/// @interface I: NSObject +/// +(void)foo; +/// @end +/// ... +/// [I foo] +/// \endcode +/// The example above matches \code [I foo] \endcode with +/// objcMessageExpr(objcMessageCallee(objcMethodDecl(hasName("foo")))) +AST_MATCHER_P(ObjCMessageExpr, objcMessageCallee, + internal::Matcher, InnerMatcher) { + const ObjCMethodDecl *msgDecl = Node.getMethodDecl(); + return (msgDecl != nullptr && + InnerMatcher.matches(*msgDecl, Finder, Builder)); +} + /// Matches if the call expression's callee's declaration matches the /// given matcher. /// diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -501,6 +501,7 @@ REGISTER_MATCHER(objcIvarDecl); REGISTER_MATCHER(objcIvarRefExpr); REGISTER_MATCHER(objcMessageExpr); + REGISTER_MATCHER(objcMessageCallee); REGISTER_MATCHER(objcMethodDecl); REGISTER_MATCHER(objcObjectPointerType); REGISTER_MATCHER(objcPropertyDecl); diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -2352,6 +2352,37 @@ argumentCountIs(0)))); } +TEST(ASTMatchersTestObjC, ObjCMessageCallee) { + // Will NOT match function callee: + EXPECT_TRUE(notMatchesObjC("void f() {" + " f(); " + "}", + objcMessageExpr(objcMessageCallee(hasName("f"))))); + + StringRef Objc1String = "@interface I " + " - (void)instanceMethod;" + " + (void)classMethod;" + " + (void)uncalledMethod;" + "@end\n" + "int main(void) {\n" + " [I classMethod];" + " I *i = [[I alloc] init];" + " [i instanceMethod];" + "}"; + // Should find the two method declarations through the message expressions: + EXPECT_TRUE( + matchesObjC(Objc1String, objcMessageExpr(objcMessageCallee( + objcMethodDecl(hasName("classMethod")))))); + EXPECT_TRUE(matchesObjC(Objc1String, + objcMessageExpr(objcMessageCallee( + objcMethodDecl(hasName("instanceMethod")))))); + // Will NOT match a method declaration through `objcMessageCallee` if there is + // no such message expression: + EXPECT_FALSE(matchesObjC(Objc1String, + objcMessageExpr(objcMessageCallee( + objcMethodDecl(hasName("uncalledMethod")))))); +} + TEST(ASTMatchersTestObjC, ObjCStringLiteral) { StringRef Objc1String = "@interface NSObject "