From: Aaron Ballman Date: Wed, 15 Mar 2017 20:14:25 +0000 (+0000) Subject: Add AST matchers for ObjCProtocolDecl, ObjCCategoryDecl, ObjCMethodDecl, ObjCIvarDecl... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=219029ad97df7d75a12bdc390877379e72b463b5;p=clang Add AST matchers for ObjCProtocolDecl, ObjCCategoryDecl, ObjCMethodDecl, ObjCIvarDecl, and ObjCPropertyDecl. Patch by Dave Lee. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@297882 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 0fd7a744b3..dd29149e63 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -337,6 +337,15 @@ nonTypeTemplateParmDecl() +Matcher<Decl>objcCategoryDeclMatcher<ObjCCategoryDecl>... +
Matches Objective-C category declarations.
+
+Example matches Foo (Additions)
+  @interface Foo (Additions)
+  @end
+
+ + Matcher<Decl>objcInterfaceDeclMatcher<ObjCInterfaceDecl>...
Matches Objective-C interface declarations.
 
@@ -346,6 +355,50 @@ Example matches Foo
 
+Matcher<Decl>objcIvarDeclMatcher<ObjCIvarDecl>... +
Matches Objective-C instance variable declarations.
+
+Example matches _enabled
+  @implementation Foo {
+    BOOL _enabled;
+  }
+  @end
+
+ + +Matcher<Decl>objcMethodDeclMatcher<ObjCMethodDecl>... +
Matches Objective-C method declarations.
+
+Example matches both declaration and definition of -[Foo method]
+  @interface Foo
+  - (void)method;
+  @end
+
+  @implementation Foo
+  - (void)method {}
+  @end
+
+ + +Matcher<Decl>objcPropertyDeclMatcher<ObjCPropertyDecl>... +
Matches Objective-C property declarations.
+
+Example matches enabled
+  @interface Foo
+  @property BOOL enabled;
+  @end
+
+ + +Matcher<Decl>objcProtocolDeclMatcher<ObjCProtocolDecl>... +
Matches Objective-C protocol declarations.
+
+Example matches FooDelegate
+  @protocol FooDelegate
+  @end
+
+ + Matcher<Decl>parmVarDeclMatcher<ParmVarDecl>...
Matches parameter variable declarations.
 
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index 6c1c8e4428..1f11c71cf8 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -1118,6 +1118,69 @@ const internal::VariadicDynCastAllOfMatcher<
   Decl,
   ObjCInterfaceDecl> objcInterfaceDecl;
 
+/// \brief Matches Objective-C protocol declarations.
+///
+/// Example matches FooDelegate
+/// \code
+///   @protocol FooDelegate
+///   @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+  Decl,
+  ObjCProtocolDecl> objcProtocolDecl;
+
+/// \brief Matches Objective-C category declarations.
+///
+/// Example matches Foo (Additions)
+/// \code
+///   @interface Foo (Additions)
+///   @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+  Decl,
+  ObjCCategoryDecl> objcCategoryDecl;
+
+/// \brief Matches Objective-C method declarations.
+///
+/// Example matches both declaration and definition of -[Foo method]
+/// \code
+///   @interface Foo
+///   - (void)method;
+///   @end
+///
+///   @implementation Foo
+///   - (void)method {}
+///   @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+  Decl,
+  ObjCMethodDecl> objcMethodDecl;
+
+/// \brief Matches Objective-C instance variable declarations.
+///
+/// Example matches _enabled
+/// \code
+///   @implementation Foo {
+///     BOOL _enabled;
+///   }
+///   @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+  Decl,
+  ObjCIvarDecl> objcIvarDecl;
+
+/// \brief Matches Objective-C property declarations.
+///
+/// Example matches enabled
+/// \code
+///   @interface Foo
+///   @property BOOL enabled;
+///   @end
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+  Decl,
+  ObjCPropertyDecl> objcPropertyDecl;
+
 /// \brief Matches expressions that introduce cleanups to be run at the end
 /// of the sub-expression's evaluation.
 ///
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index d1cab80c1a..a73f522efc 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -359,9 +359,14 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(nullStmt);
   REGISTER_MATCHER(numSelectorArgs);
   REGISTER_MATCHER(ofClass);
+  REGISTER_MATCHER(objcCategoryDecl);
   REGISTER_MATCHER(objcInterfaceDecl);
+  REGISTER_MATCHER(objcIvarDecl);
   REGISTER_MATCHER(objcMessageExpr);
+  REGISTER_MATCHER(objcMethodDecl);
   REGISTER_MATCHER(objcObjectPointerType);
+  REGISTER_MATCHER(objcPropertyDecl);
+  REGISTER_MATCHER(objcProtocolDecl);
   REGISTER_MATCHER(on);
   REGISTER_MATCHER(onImplicitObjectArgument);
   REGISTER_MATCHER(opaqueValueExpr);
diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index dd45ca3ced..4c13acfaf0 100644
--- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1500,9 +1500,10 @@ TEST(ObjCMessageExprMatcher, SimpleExprs) {
 
   std::string Objc1String =
     "@interface Str "
-      " - (Str *)uppercaseString:(Str *)str;"
+      " - (Str *)uppercaseString;"
       "@end "
       "@interface foo "
+      "- (void)contents;"
       "- (void)meth:(Str *)text;"
       "@end "
       " "
@@ -1540,5 +1541,45 @@ TEST(ObjCMessageExprMatcher, SimpleExprs) {
     )));
 }
 
+TEST(ObjCDeclMacher, CoreDecls) {
+  std::string ObjCString =
+    "@protocol Proto "
+    "- (void)protoDidThing; "
+    "@end "
+    "@interface Thing "
+    "@property int enabled; "
+    "@end "
+    "@interface Thing (ABC) "
+    "- (void)abc_doThing; "
+    "@end "
+    "@implementation Thing "
+    "{ id _ivar; } "
+    "- (void)anything {} "
+    "@end "
+    ;
+
+  EXPECT_TRUE(matchesObjC(
+    ObjCString,
+    objcProtocolDecl(hasName("Proto"))));
+  EXPECT_TRUE(matchesObjC(
+    ObjCString,
+    objcCategoryDecl(hasName("ABC"))));
+  EXPECT_TRUE(matchesObjC(
+    ObjCString,
+    objcMethodDecl(hasName("protoDidThing"))));
+  EXPECT_TRUE(matchesObjC(
+    ObjCString,
+    objcMethodDecl(hasName("abc_doThing"))));
+  EXPECT_TRUE(matchesObjC(
+    ObjCString,
+    objcMethodDecl(hasName("anything"))));
+  EXPECT_TRUE(matchesObjC(
+    ObjCString,
+    objcIvarDecl(hasName("_ivar"))));
+  EXPECT_TRUE(matchesObjC(
+    ObjCString,
+    objcPropertyDecl(hasName("enabled"))));
+}
+
 } // namespace ast_matchers
 } // namespace clang
diff --git a/unittests/ASTMatchers/ASTMatchersTest.h b/unittests/ASTMatchers/ASTMatchersTest.h
index fdb273c672..4f5579ce0d 100644
--- a/unittests/ASTMatchers/ASTMatchersTest.h
+++ b/unittests/ASTMatchers/ASTMatchersTest.h
@@ -61,7 +61,7 @@ private:
 template 
 testing::AssertionResult matchesConditionally(
     const std::string &Code, const T &AMatcher, bool ExpectMatch,
-    llvm::StringRef CompileArg,
+    llvm::ArrayRef CompileArgs,
     const FileContentMappings &VirtualMappedFiles = FileContentMappings(),
     const std::string &Filename = "input.cc") {
   bool Found = false, DynamicFound = false;
@@ -81,8 +81,9 @@ testing::AssertionResult matchesConditionally(
   // FIXME: This is a hack to work around the fact that there's no way to do the
   // equivalent of runToolOnCodeWithArgs without instantiating a full Driver.
   // We should consider having a function, at least for tests, that invokes cc1.
-  std::vector Args = {CompileArg, "-frtti", "-fexceptions",
-                                   "-target", "i386-unknown-unknown"};
+  std::vector Args(CompileArgs.begin(), CompileArgs.end());
+  Args.insert(Args.end(), {"-frtti", "-fexceptions",
+                           "-target", "i386-unknown-unknown"});
   if (!runToolOnCodeWithArgs(
           Factory->create(), Code, Args, Filename, "clang-tool",
           std::make_shared(), VirtualMappedFiles)) {
@@ -104,6 +105,17 @@ testing::AssertionResult matchesConditionally(
   return testing::AssertionSuccess();
 }
 
+template 
+testing::AssertionResult matchesConditionally(
+    const std::string &Code, const T &AMatcher, bool ExpectMatch,
+    llvm::StringRef CompileArg,
+    const FileContentMappings &VirtualMappedFiles = FileContentMappings(),
+    const std::string &Filename = "input.cc") {
+  return matchesConditionally(Code, AMatcher, ExpectMatch,
+                              llvm::makeArrayRef(CompileArg),
+                              VirtualMappedFiles, Filename);
+}
+
 template 
 testing::AssertionResult matches(const std::string &Code, const T &AMatcher) {
   return matchesConditionally(Code, AMatcher, true, "-std=c++11");
@@ -116,11 +128,12 @@ testing::AssertionResult notMatches(const std::string &Code,
 }
 
 template 
-testing::AssertionResult matchesObjC(const std::string &Code,
-                                     const T &AMatcher) {
-  return matchesConditionally(
-    Code, AMatcher, true,
-    "", FileContentMappings(), "input.m");
+testing::AssertionResult matchesObjC(const std::string &Code, const T &AMatcher,
+                                     bool ExpectMatch = true) {
+  return matchesConditionally(Code, AMatcher, ExpectMatch,
+                              {"-fobjc-nonfragile-abi", "-Wno-objc-root-class",
+                               "-Wno-incomplete-implementation"},
+                              FileContentMappings(), "input.m");
 }
 
 template 
@@ -145,10 +158,8 @@ testing::AssertionResult notMatchesC(const std::string &Code,
 
 template 
 testing::AssertionResult notMatchesObjC(const std::string &Code,
-                                     const T &AMatcher) {
-  return matchesConditionally(
-    Code, AMatcher, false,
-    "", FileContentMappings(), "input.m");
+                                        const T &AMatcher) {
+  return matchesObjC(Code, AMatcher, false);
 }