Skip to content

Commit

Permalink
[ASTMatchers] Introduce Objective-C matchers isClassMessage, `isCla…
Browse files Browse the repository at this point in the history
…ssMethod`, and `isInstanceMethod`

Summary:
isClassMessage is an equivalent to isInstanceMessage for ObjCMessageExpr, but matches message expressions to classes.

isClassMethod and isInstanceMethod check whether a method declaration (or definition) is for a class method or instance method (respectively).

Contributed by @mywman!

Reviewers: benhamilton, klimek, mwyman

Reviewed By: benhamilton, mwyman

Subscribers: cfe-commits

Tags: #clang

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

llvm-svn: 358904
  • Loading branch information
bhamiltoncx committed Apr 22, 2019
1 parent e90d5c8 commit a282bde
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 2 deletions.
39 changes: 38 additions & 1 deletion clang/docs/LibASTMatchersReference.html
Expand Up @@ -3567,11 +3567,24 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
</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('isClassMessage0')"><a name="isClassMessage0Anchor">isClassMessage</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isClassMessage0"><pre>Returns true when the Objective-C message is sent to a class.

Example
matcher = objcMessageExpr(isClassMessage())
matches
[NSString stringWithFormat:@"format"];
but not
NSString *x = @"hello";
[x containsString:@"h"];
</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('isInstanceMessage0')"><a name="isInstanceMessage0Anchor">isInstanceMessage</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isInstanceMessage0"><pre>Returns true when the Objective-C message is sent to an instance.

Example
matcher = objcMessagaeExpr(isInstanceMessage())
matcher = objcMessageExpr(isInstanceMessage())
matches
NSString *x = @"hello";
[x containsString:@"h"];
Expand All @@ -3580,6 +3593,30 @@ <h2 id="narrowing-matchers">Narrowing Matchers</h2>
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>&gt;</td><td class="name" onclick="toggle('isClassMethod0')"><a name="isClassMethod0Anchor">isClassMethod</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isClassMethod0"><pre>Returns true when the Objective-C method declaration is a class method.

Example
matcher = objcMethodDecl(isClassMethod())
matches
@interface I + (void)foo; @end
but not
@interface I - (void)bar; @end
</pre></td></tr>


<tr><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1ObjCMethodDecl.html">ObjCMethodDecl</a>&gt;</td><td class="name" onclick="toggle('isInstanceMessage0')"><a name="isInstanceMessage0Anchor">isInstanceMethod</a></td><td></td></tr>
<tr><td colspan="4" class="doc" id="isInstanceMethod0"><pre>Returns true when the Objective-C method declaration is an instance method.

Example
matcher = objcMethodDecl(isInstanceMethod())
matches
@interface I - (void)bar; @end
but not
@interface I + (void)foo; @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('matchesSelector0')"><a name="matchesSelector0Anchor">matchesSelector</a></td><td>std::string RegExp</td></tr>
<tr><td colspan="4" class="doc" id="matchesSelector0"><pre>Matches ObjC selectors whose name contains
a substring matched by the given RegExp.
Expand Down
51 changes: 50 additions & 1 deletion clang/include/clang/ASTMatchers/ASTMatchers.h
Expand Up @@ -2938,10 +2938,59 @@ AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher<QualType>,
return InnerMatcher.matches(TypeDecl, Finder, Builder);
}

/// Returns true when the Objective-C method declaration is a class method.
///
/// Example
/// matcher = objcMethodDecl(isClassMethod())
/// matches
/// \code
/// @interface I + (void)foo; @end
/// \endcode
/// but not
/// \code
/// @interface I - (void)bar; @end
/// \endcode
AST_MATCHER(ObjCMethodDecl, isClassMethod) {
return Node.isClassMethod();
}

/// Returns true when the Objective-C method declaration is an instance method.
///
/// Example
/// matcher = objcMethodDecl(isInstanceMethod())
/// matches
/// \code
/// @interface I - (void)bar; @end
/// \endcode
/// but not
/// \code
/// @interface I + (void)foo; @end
/// \endcode
AST_MATCHER(ObjCMethodDecl, isInstanceMethod) {
return Node.isInstanceMethod();
}

/// Returns true when the Objective-C message is sent to a class.
///
/// Example
/// matcher = objcMessageExpr(isClassMessage())
/// matches
/// \code
/// [NSString stringWithFormat:@"format"];
/// \endcode
/// but not
/// \code
/// NSString *x = @"hello";
/// [x containsString:@"h"];
/// \endcode
AST_MATCHER(ObjCMessageExpr, isClassMessage) {
return Node.isClassMessage();
}

/// Returns true when the Objective-C message is sent to an instance.
///
/// Example
/// matcher = objcMessagaeExpr(isInstanceMessage())
/// matcher = objcMessageExpr(isInstanceMessage())
/// matches
/// \code
/// NSString *x = @"hello";
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/ASTMatchers/Dynamic/Registry.cpp
Expand Up @@ -344,6 +344,8 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isBitField);
REGISTER_MATCHER(isCatchAll);
REGISTER_MATCHER(isClass);
REGISTER_MATCHER(isClassMessage);
REGISTER_MATCHER(isClassMethod);
REGISTER_MATCHER(isConst);
REGISTER_MATCHER(isConstQualified);
REGISTER_MATCHER(isConstexpr);
Expand All @@ -367,6 +369,7 @@ RegistryMaps::RegistryMaps() {
REGISTER_MATCHER(isInTemplateInstantiation);
REGISTER_MATCHER(isInline);
REGISTER_MATCHER(isInstanceMessage);
REGISTER_MATCHER(isInstanceMethod);
REGISTER_MATCHER(isInstantiated);
REGISTER_MATCHER(isInstantiationDependent);
REGISTER_MATCHER(isInteger);
Expand Down
54 changes: 54 additions & 0 deletions clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
Expand Up @@ -454,6 +454,20 @@ TEST(Matcher, HasReceiver) {
objcMessageExpr(hasReceiver(declRefExpr(to(varDecl(hasName("x"))))))));
}

TEST(Matcher, isClassMessage) {
EXPECT_TRUE(matchesObjC(
"@interface NSString +(NSString *) stringWithFormat; @end "
"void f() { [NSString stringWithFormat]; }",
objcMessageExpr(isClassMessage())));

EXPECT_FALSE(matchesObjC(
"@interface NSString @end "
"void f(NSString *x) {"
"[x containsString];"
"}",
objcMessageExpr(isClassMessage())));
}

TEST(Matcher, isInstanceMessage) {
EXPECT_TRUE(matchesObjC(
"@interface NSString @end "
Expand All @@ -469,6 +483,46 @@ TEST(Matcher, isInstanceMessage) {

}

TEST(Matcher, isClassMethod) {
EXPECT_TRUE(matchesObjC(
"@interface Bar + (void)bar; @end",
objcMethodDecl(isClassMethod())));

EXPECT_TRUE(matchesObjC(
"@interface Bar @end"
"@implementation Bar + (void)bar {} @end",
objcMethodDecl(isClassMethod())));

EXPECT_FALSE(matchesObjC(
"@interface Foo - (void)foo; @end",
objcMethodDecl(isClassMethod())));

EXPECT_FALSE(matchesObjC(
"@interface Foo @end "
"@implementation Foo - (void)foo {} @end",
objcMethodDecl(isClassMethod())));
}

TEST(Matcher, isInstanceMethod) {
EXPECT_TRUE(matchesObjC(
"@interface Foo - (void)foo; @end",
objcMethodDecl(isInstanceMethod())));

EXPECT_TRUE(matchesObjC(
"@interface Foo @end "
"@implementation Foo - (void)foo {} @end",
objcMethodDecl(isInstanceMethod())));

EXPECT_FALSE(matchesObjC(
"@interface Bar + (void)bar; @end",
objcMethodDecl(isInstanceMethod())));

EXPECT_FALSE(matchesObjC(
"@interface Bar @end"
"@implementation Bar + (void)bar {} @end",
objcMethodDecl(isInstanceMethod())));
}

TEST(MatcherCXXMemberCallExpr, On) {
auto Snippet1 = R"cc(
struct Y {
Expand Down

0 comments on commit a282bde

Please sign in to comment.