summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Hamilton <benhamilton@google.com>2019-04-22 17:54:11 +0000
committerBen Hamilton <benhamilton@google.com>2019-04-22 17:54:11 +0000
commita282bde69e375985edd4c371b79864f617380ad5 (patch)
treeb60df64a7a97de295a9b104a5dd91c7da0bdb941
parente90d5c8db069f4a456963b45c90407500eacf77f (diff)
downloadbcm5719-llvm-a282bde69e375985edd4c371b79864f617380ad5.tar.gz
bcm5719-llvm-a282bde69e375985edd4c371b79864f617380ad5.zip
[ASTMatchers] Introduce Objective-C matchers `isClassMessage`, `isClassMethod`, 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
-rw-r--r--clang/docs/LibASTMatchersReference.html39
-rw-r--r--clang/include/clang/ASTMatchers/ASTMatchers.h51
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp3
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp54
4 files changed, 145 insertions, 2 deletions
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html
index 3f8e4178d6b..f0e965568da 100644
--- a/clang/docs/LibASTMatchersReference.html
+++ b/clang/docs/LibASTMatchersReference.html
@@ -3567,11 +3567,24 @@ represent an error condition in the tree!
</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"];
@@ -3580,6 +3593,30 @@ but not
</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.
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index c5ec9f48a05..661dcbc7670 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -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";
diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
index b7e0a25757e..37f1a0077a0 100644
--- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -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);
@@ -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);
diff --git a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
index bdd476091af..dafc8c52e9a 100644
--- a/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
+++ b/clang/unittests/ASTMatchers/ASTMatchersTraversalTest.cpp
@@ -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 "
@@ -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 {
OpenPOWER on IntegriCloud