From: George Karpenkov Date: Thu, 29 Mar 2018 00:51:12 +0000 (+0000) Subject: [ASTMatchers] Introduce a matcher for matching any given Objective-C selector X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8e76adccd4a0615ae685ba81fc796bfb2c3fbfa1;p=clang [ASTMatchers] Introduce a matcher for matching any given Objective-C selector Incudes a tiny related refactoring. Differential Revision: https://reviews.llvm.org/D44858 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@328747 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/docs/LibASTMatchersReference.html b/docs/LibASTMatchersReference.html index 8e63c13888..28f8d900eb 100644 --- a/docs/LibASTMatchersReference.html +++ b/docs/LibASTMatchersReference.html @@ -3958,6 +3958,17 @@ This matcher is only provided as a performance optimization of hasName. +Matcher<internal::Matcher<ObjCMessageExpr>>hasAnySelectorStringRef, ..., StringRef +
Matches when at least one of the supplied string equals to the
+Selector.getAsString()
+
+ matcher = objCMessageExpr(hasSelector("methodA:", "methodB:"));
+ matches both of the expressions below:
+    [myObj methodA:argA];
+    [myObj methodB:argB];
+
+ + Matcher<internal::Matcher<Stmt>>isInTemplateInstantiation
Matches statements inside of a template instantiation.
 
diff --git a/include/clang/ASTMatchers/ASTMatchers.h b/include/clang/ASTMatchers/ASTMatchers.h
index b3366dd487..5008d53e56 100644
--- a/include/clang/ASTMatchers/ASTMatchers.h
+++ b/include/clang/ASTMatchers/ASTMatchers.h
@@ -2313,9 +2313,7 @@ inline internal::Matcher sizeOfExpr(
 ///   namespace a { namespace b { class X; } }
 /// \endcode
 inline internal::Matcher hasName(const std::string &Name) {
-  std::vector Names;
-  Names.push_back(Name);
-  return internal::Matcher(new internal::HasNameMatcher(Names));
+  return internal::Matcher(new internal::HasNameMatcher({Name}));
 }
 
 /// \brief Matches NamedDecl nodes that have any of the specified names.
@@ -2711,7 +2709,7 @@ AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher,
   const QualType TypeDecl = Node.getReceiverType();
   return InnerMatcher.matches(TypeDecl, Finder, Builder);
 }
-  
+
 /// \brief Matches when BaseName == Selector.getAsString()
 ///
 ///  matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
@@ -2725,7 +2723,21 @@ AST_MATCHER_P(ObjCMessageExpr, hasSelector, std::string, BaseName) {
   return BaseName.compare(Sel.getAsString()) == 0;
 }
 
-  
+
+/// \brief Matches when at least one of the supplied string equals to the
+/// Selector.getAsString()
+///
+///  matcher = objCMessageExpr(hasSelector("methodA:", "methodB:"));
+///  matches both of the expressions below:
+/// \code
+///     [myObj methodA:argA];
+///     [myObj methodB:argB];
+/// \endcode
+extern const internal::VariadicFunction,
+                                        StringRef,
+                                        internal::hasAnySelectorFunc>
+                                        hasAnySelector;
+
 /// \brief Matches ObjC selectors whose name contains
 /// a substring matched by the given RegExp.
 ///  matcher = objCMessageExpr(matchesSelector("loadHTMLString\:baseURL?"));
diff --git a/include/clang/ASTMatchers/ASTMatchersInternal.h b/include/clang/ASTMatchers/ASTMatchersInternal.h
index 8bd61a76e1..8c1267be62 100644
--- a/include/clang/ASTMatchers/ASTMatchersInternal.h
+++ b/include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -731,6 +731,11 @@ class HasNameMatcher : public SingleNodeMatcherInterface {
 ///        HasNameMatcher.
 Matcher hasAnyNameFunc(ArrayRef NameRefs);
 
+/// \brief Trampoline function to use VariadicFunction<> to construct a
+///        hasAnySelector matcher.
+Matcher hasAnySelectorFunc(
+    ArrayRef NameRefs);
+
 /// \brief Matches declarations for QualType and CallExpr.
 ///
 /// Type argument DeclMatcherT is required by PolymorphicMatcherWithParam1 but
diff --git a/lib/ASTMatchers/ASTMatchersInternal.cpp b/lib/ASTMatchers/ASTMatchersInternal.cpp
index 0bcdd8e328..5351ffee54 100644
--- a/lib/ASTMatchers/ASTMatchersInternal.cpp
+++ b/lib/ASTMatchers/ASTMatchersInternal.cpp
@@ -315,12 +315,31 @@ bool AnyOfVariadicOperator(const ast_type_traits::DynTypedNode &DynNode,
   return false;
 }
 
-Matcher hasAnyNameFunc(ArrayRef NameRefs) {
+inline static
+std::vector vectorFromRefs(ArrayRef NameRefs) {
   std::vector Names;
   for (auto *Name : NameRefs)
     Names.emplace_back(*Name);
-  return internal::Matcher(
-      new internal::HasNameMatcher(std::move(Names)));
+  return Names;
+}
+
+Matcher hasAnyNameFunc(ArrayRef NameRefs) {
+  std::vector Names = vectorFromRefs(NameRefs);
+  return internal::Matcher(new internal::HasNameMatcher(Names));
+}
+
+AST_MATCHER_P(ObjCMessageExpr, hasAnySelectorMatcher, std::vector,
+              Matches) {
+  std::string SelString = Node.getSelector().getAsString();
+  for (const std::string &S : Matches)
+    if (S == SelString)
+      return true;
+  return false;
+}
+
+Matcher hasAnySelectorFunc(
+    ArrayRef NameRefs) {
+  return hasAnySelectorMatcher(vectorFromRefs(NameRefs));
 }
 
 HasNameMatcher::HasNameMatcher(std::vector N)
@@ -393,7 +412,8 @@ public:
   /// Return true if there are still any patterns left.
   bool consumeNameSuffix(StringRef NodeName, bool CanSkip) {
     for (size_t I = 0; I < Patterns.size();) {
-      if (internal::consumeNameSuffix(Patterns[I].P, NodeName) ||
+      if (::clang::ast_matchers::internal::consumeNameSuffix(Patterns[I].P,
+                                                             NodeName) ||
           CanSkip) {
         ++I;
       } else {
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp
index fd373bca56..afc5f6a9b8 100644
--- a/lib/ASTMatchers/Dynamic/Registry.cpp
+++ b/lib/ASTMatchers/Dynamic/Registry.cpp
@@ -286,6 +286,7 @@ RegistryMaps::RegistryMaps() {
   REGISTER_MATCHER(hasReturnValue);
   REGISTER_MATCHER(hasRHS);
   REGISTER_MATCHER(hasSelector);
+  REGISTER_MATCHER(hasAnySelector);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
diff --git a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
index 59fadadbed..6298e8759d 100644
--- a/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
+++ b/unittests/ASTMatchers/ASTMatchersNodeTest.cpp
@@ -1565,9 +1565,20 @@ TEST(ObjCMessageExprMatcher, SimpleExprs) {
   EXPECT_TRUE(matchesObjC(
     Objc1String,
     objcMessageExpr(anything())));
+  EXPECT_TRUE(matchesObjC(Objc1String,
+                          objcMessageExpr(hasAnySelector({
+                                          "contents", "meth:"}))
+
+                         ));
   EXPECT_TRUE(matchesObjC(
     Objc1String,
     objcMessageExpr(hasSelector("contents"))));
+  EXPECT_TRUE(matchesObjC(
+    Objc1String,
+    objcMessageExpr(hasAnySelector("contents", "contentsA"))));
+  EXPECT_FALSE(matchesObjC(
+    Objc1String,
+    objcMessageExpr(hasAnySelector("contentsB", "contentsC"))));
   EXPECT_TRUE(matchesObjC(
     Objc1String,
     objcMessageExpr(matchesSelector("cont*"))));
diff --git a/unittests/ASTMatchers/Dynamic/ParserTest.cpp b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
index 7224db0942..d670e3129b 100644
--- a/unittests/ASTMatchers/Dynamic/ParserTest.cpp
+++ b/unittests/ASTMatchers/Dynamic/ParserTest.cpp
@@ -236,6 +236,17 @@ TEST(ParserTest, FullParserTest) {
             Error.toStringFull());
 }
 
+TEST(ParserTest, VariadicMatchTest) {
+  Diagnostics Error;
+  llvm::Optional OM(Parser::parseMatcherExpression(
+      "stmt(objcMessageExpr(hasAnySelector(\"methodA\", \"methodB:\")))",
+      &Error));
+  EXPECT_EQ("", Error.toStringFull());
+  auto M = OM->unconditionalConvertTo();
+  EXPECT_TRUE(matchesObjC("@interface I @end "
+                          "void foo(I* i) { [i methodA]; }", M));
+}
+
 std::string ParseWithError(StringRef Code) {
   Diagnostics Error;
   VariantValue Value;