Now includes documentation for each of the matches. Also added the new matchers 
to the registry for dynamic use.


http://reviews.llvm.org/D7710

Files:
  include/clang/ASTMatchers/ASTMatchers.h
  include/clang/ASTMatchers/ASTMatchersInternal.h
  lib/ASTMatchers/Dynamic/Registry.cpp
  lib/Sema/SemaExprObjC.cpp
  test/SemaObjC/objc-literal-nsnumber.m
  unittests/ASTMatchers/ASTMatchersTest.cpp
  unittests/ASTMatchers/ASTMatchersTest.h

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: include/clang/ASTMatchers/ASTMatchers.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchers.h
+++ include/clang/ASTMatchers/ASTMatchers.h
@@ -47,6 +47,7 @@
 
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/DeclFriend.h"
+#include "clang/AST/DeclObjC.h"
 #include "clang/AST/DeclTemplate.h"
 #include "clang/ASTMatchers/ASTMatchersInternal.h"
 #include "clang/ASTMatchers/ASTMatchersMacros.h"
@@ -872,6 +873,20 @@
   Stmt,
   CXXMemberCallExpr> memberCallExpr;
 
+/// \brief Matches ObjectiveC Message invocation expressions.
+///
+/// The innermost message send invokes the "alloc" class method on the
+/// NSString class, while the outermost message send invokes the
+/// "initWithString" instance method on the object returned from
+/// NSString's "alloc". This matcher should match both message sends.
+/// \code
+///   [[NSString alloc] initWithString:@"Hello"]
+/// \endcode
+const internal::VariadicDynCastAllOfMatcher<
+  Stmt,
+  ObjCMessageExpr> objcMessageExpr;
+
+
 /// \brief Matches expressions that introduce cleanups to be run at the end
 /// of the sub-expression's evaluation.
 ///
@@ -2011,6 +2026,104 @@
           InnerMatcher.matches(*ExprNode, Finder, Builder));
 }
 
+
+/// \brief Matches on the receiver of an ObjectiveC Message expression.
+///
+/// Example
+/// matcher = objCMessageExpr(hasRecieverType(asString("UIWebView *")));
+/// matches the [webView ...] message invocation.
+/// \code
+/// NSString *webViewJavaScript = ...
+/// UIWebView *webView = ...
+/// [webView stringByEvaluatingJavaScriptFromString:webViewJavascript];
+/// \endcode
+AST_MATCHER_P(ObjCMessageExpr, hasReceiverType, internal::Matcher<QualType>,
+              InnerMatcher) {
+  const QualType TypeDecl = Node.getReceiverType();
+  return InnerMatcher.matches(TypeDecl, Finder, Builder);
+}
+  
+/// \brief Matches when BaseName == Selector.getAsString()
+///
+///  matcher = objCMessageExpr(hasSelector("loadHTMLString:baseURL:"));
+///  matches the outer message expr in the code below, but NOT the message
+///  invocation for self.bodyView.
+/// \code
+///     [self.bodyView loadHTMLString:html baseURL:NULL];
+/// \endcode
+  AST_MATCHER_P(ObjCMessageExpr, hasSelector, std::string, BaseName) {
+  Selector Sel = Node.getSelector();
+  return BaseName.compare(Sel.getAsString()) == 0;
+}
+
+  
+/// \brief Matches ObjC selectors whose name contains
+/// a substring matched by the given RegExp.
+///  matcher = objCMessageExpr(matchesSelector("loadHTMLString\:baseURL?"));
+///  matches the outer message expr in the code below, but NOT the message
+///  invocation for self.bodyView.
+/// \code
+///     [self.bodyView loadHTMLString:html baseURL:NULL];
+/// \endcode
+AST_MATCHER_P(ObjCMessageExpr, matchesSelector, std::string, RegExp) {
+  assert(!RegExp.empty());
+  std::string SelectorString = Node.getSelector().getAsString();
+  llvm::Regex RE(RegExp);
+  return RE.match(SelectorString);
+}
+
+/// \brief Matches when the selector is the empty selector
+///
+/// Matches only when the selector of the objCMessageExpr is NULL. This may
+/// represent an error condition in the tree!
+AST_MATCHER(ObjCMessageExpr, hasNullSelector) {
+  return Node.getSelector().isNull();
+}
+
+/// \brief Matches when the selector is a Unary Selector
+///
+///  matcher = objCMessageExpr(matchesSelector(hasUnarySelector());
+///  matches self.bodyView in the code below, but NOT the outer message
+///  invocation of "loadHTMLString:baseURL:".
+/// \code
+///     [self.bodyView loadHTMLString:html baseURL:NULL];
+/// \endcode
+AST_MATCHER(ObjCMessageExpr, hasUnarySelector) {
+  return Node.getSelector().isUnarySelector();
+}
+
+/// \brief Matches when the selector is a keyword selector
+///
+/// objCMessageExpr(hasKeywordSelector()) matches the generated setFrame
+/// message expression in
+///
+/// \code
+///   UIWebView *webView = ...;
+///   CGRect bodyFrame = webView.frame;
+///   bodyFrame.size.height = self.bodyContentHeight;
+///   webView.frame = bodyFrame;
+/// //       ^---- matches here
+/// \endcode
+
+AST_MATCHER(ObjCMessageExpr, hasKeywordSelector) {
+  return Node.getSelector().isKeywordSelector();
+}
+
+/// \brief Matches when the selector has the specified number of arguments
+///
+///  matcher = objCMessageExpr(numSelectorArgs(1));
+///  matches self.bodyView in the code below
+///
+///  matcher = objCMessageExpr(numSelectorArgs(2));
+///  matches the invocation of "loadHTMLString:baseURL:" but not that
+///  of self.bodyView
+/// \code
+///     [self.bodyView loadHTMLString:html baseURL:NULL];
+/// \endcode
+AST_MATCHER_P(ObjCMessageExpr, numSelectorArgs, unsigned, N) {
+  return Node.getSelector().getNumArgs() == N;
+}
+   
 /// \brief Matches if the call expression's callee expression matches.
 ///
 /// Given
@@ -2317,8 +2430,10 @@
 ///   void f(int x, int y);
 ///   f(0, 0);
 /// \endcode
-AST_POLYMORPHIC_MATCHER_P(argumentCountIs, AST_POLYMORPHIC_SUPPORTED_TYPES_2(
-                                               CallExpr, CXXConstructExpr),
+AST_POLYMORPHIC_MATCHER_P(
+    argumentCountIs,
+    AST_POLYMORPHIC_SUPPORTED_TYPES_3(CallExpr, CXXConstructExpr,
+				      ObjCMessageExpr),
                           unsigned, N) {
   return Node.getNumArgs() == N;
 }
@@ -2333,7 +2448,8 @@
 /// \endcode
 AST_POLYMORPHIC_MATCHER_P2(
     hasArgument,
-    AST_POLYMORPHIC_SUPPORTED_TYPES_2(CallExpr, CXXConstructExpr),
+    AST_POLYMORPHIC_SUPPORTED_TYPES_3(CallExpr, CXXConstructExpr,
+				      ObjCMessageExpr),
     unsigned, N, internal::Matcher<Expr>, InnerMatcher) {
   return (N < Node.getNumArgs() &&
           InnerMatcher.matches(
Index: include/clang/ASTMatchers/ASTMatchersInternal.h
===================================================================
--- include/clang/ASTMatchers/ASTMatchersInternal.h
+++ include/clang/ASTMatchers/ASTMatchersInternal.h
@@ -38,9 +38,12 @@
 #include "clang/AST/ASTTypeTraits.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclObjC.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/ExprObjC.h"
 #include "clang/AST/Stmt.h"
 #include "clang/AST/StmtCXX.h"
+#include "clang/AST/StmtObjC.h"
 #include "clang/AST/Type.h"
 #include "llvm/ADT/Optional.h"
 #include "llvm/ADT/VariadicFunction.h"
Index: lib/ASTMatchers/Dynamic/Registry.cpp
===================================================================
--- lib/ASTMatchers/Dynamic/Registry.cpp
+++ lib/ASTMatchers/Dynamic/Registry.cpp
@@ -198,21 +198,25 @@
   REGISTER_MATCHER(hasIncrement);
   REGISTER_MATCHER(hasIndex);
   REGISTER_MATCHER(hasInitializer);
+  REGISTER_MATCHER(hasKeywordSelector);
   REGISTER_MATCHER(hasLHS);
   REGISTER_MATCHER(hasLocalQualifiers);
   REGISTER_MATCHER(hasLocalStorage);
   REGISTER_MATCHER(hasLoopInit);
   REGISTER_MATCHER(hasLoopVariable);
   REGISTER_MATCHER(hasMethod);
   REGISTER_MATCHER(hasName);
+  REGISTER_MATCHER(hasNullSelector);
   REGISTER_MATCHER(hasObjectExpression);
   REGISTER_MATCHER(hasOperatorName);
   REGISTER_MATCHER(hasOverloadedOperatorName);
   REGISTER_MATCHER(hasParameter);
   REGISTER_MATCHER(hasParent);
   REGISTER_MATCHER(hasQualifier);
   REGISTER_MATCHER(hasRangeInit);
+  REGISTER_MATCHER(hasReceiverType);
   REGISTER_MATCHER(hasRHS);
+  REGISTER_MATCHER(hasSelector);
   REGISTER_MATCHER(hasSingleDecl);
   REGISTER_MATCHER(hasSize);
   REGISTER_MATCHER(hasSizeExpr);
@@ -223,6 +227,7 @@
   REGISTER_MATCHER(hasTrueExpression);
   REGISTER_MATCHER(hasTypeLoc);
   REGISTER_MATCHER(hasUnaryOperand);
+  REGISTER_MATCHER(hasUnarySelector);
   REGISTER_MATCHER(hasValueType);
   REGISTER_MATCHER(ifStmt);
   REGISTER_MATCHER(ignoringImpCasts);
@@ -262,6 +267,7 @@
   REGISTER_MATCHER(lambdaExpr);
   REGISTER_MATCHER(lValueReferenceType);
   REGISTER_MATCHER(matchesName);
+  REGISTER_MATCHER(matchesSelector);
   REGISTER_MATCHER(materializeTemporaryExpr);
   REGISTER_MATCHER(member);
   REGISTER_MATCHER(memberCallExpr);
@@ -276,7 +282,9 @@
   REGISTER_MATCHER(newExpr);
   REGISTER_MATCHER(nullPtrLiteralExpr);
   REGISTER_MATCHER(nullStmt);
+  REGISTER_MATCHER(numSelectorArgs);
   REGISTER_MATCHER(ofClass);
+  REGISTER_MATCHER(objcMessageExpr);
   REGISTER_MATCHER(on);
   REGISTER_MATCHER(onImplicitObjectArgument);
   REGISTER_MATCHER(operatorCallExpr);
Index: lib/Sema/SemaExprObjC.cpp
===================================================================
--- lib/Sema/SemaExprObjC.cpp
+++ lib/Sema/SemaExprObjC.cpp
@@ -218,9 +218,7 @@
       S.Diag(Loc, diag::err_undeclared_nsnumber);
       return nullptr;
     }
-  }
-
-  if (S.NSNumberPointer.isNull()) {
+    
     // generate the pointer to NSNumber type.
     QualType NSNumberObject = CX.getObjCInterfaceType(S.NSNumberDecl);
     S.NSNumberPointer = CX.getObjCObjectPointerType(NSNumberObject);
Index: test/SemaObjC/objc-literal-nsnumber.m
===================================================================
--- test/SemaObjC/objc-literal-nsnumber.m
+++ test/SemaObjC/objc-literal-nsnumber.m
@@ -9,24 +9,6 @@
 typedef int NSInteger;
 #endif
 
-void checkNSNumberUnavailableDiagnostic() {
-  id num = @1000; // expected-error {{NSNumber must be available to use Objective-C literals}}
-
-  int x = 1000;
-  id num1 = @(x); // expected-error {{NSNumber must be available to use Objective-C literals}}\
-                  // expected-error {{illegal type 'int' used in a boxed expression}}
-}
-
-@class NSNumber;
-
-void checkNSNumberFDDiagnostic() {
-  id num = @1000; // expected-error {{NSNumber must be available to use Objective-C literals}}
-
-  int x = 1000;
-  id num1 = @(x); // expected-error {{declaration of 'numberWithInt:' is missing in NSNumber class}}\
-                  // expected-error {{illegal type 'int' used in a boxed expression}}
-}
-
 @interface NSObject
 + (NSObject*)nsobject;
 @end
Index: unittests/ASTMatchers/ASTMatchersTest.cpp
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.cpp
+++ unittests/ASTMatchers/ASTMatchersTest.cpp
@@ -4712,5 +4712,50 @@
 
 #endif // LLVM_ON_WIN32
 
+  
+TEST(ObjCMessageExprMatcher, SimpleExprs) {
+  // don't find ObjCMessageExpr where none are present
+  EXPECT_TRUE(notMatchesObjC("", objcMessageExpr(anything())));
+ 
+  std::string Objc1String =
+  "@interface Str "
+  " - (Str *)uppercaseString:(Str *)str;"
+  "@end "
+  "@interface foo "
+  "- (void)meth:(Str *)text;"
+  "@end "
+  " "
+  "@implementation foo "
+  "- (void) meth:(Str *)text { "
+  "  [self contents];"
+  "  Str *up = [text uppercaseString];"
+  "} "
+  "@end ";
+  EXPECT_TRUE(matchesObjC(
+      Objc1String,
+      objcMessageExpr(anything())));
+  EXPECT_TRUE(matchesObjC(
+      Objc1String,
+      objcMessageExpr(hasSelector("contents"))));
+  EXPECT_TRUE(matchesObjC(
+      Objc1String,
+      objcMessageExpr(matchesSelector("cont*"))));
+  EXPECT_FALSE(matchesObjC(
+      Objc1String,
+      objcMessageExpr(matchesSelector("?cont*"))));
+  EXPECT_TRUE(notMatchesObjC(
+      Objc1String,
+      objcMessageExpr(hasSelector("contents"), hasNullSelector())));
+  EXPECT_TRUE(matchesObjC(
+      Objc1String,
+      objcMessageExpr(hasSelector("contents"), hasUnarySelector())));
+  EXPECT_TRUE(matchesObjC(
+      Objc1String,
+      objcMessageExpr(matchesSelector("uppercase*"),
+                      argumentCountIs(0)
+                      )));
+  
+}
+
 } // end namespace ast_matchers
 } // end namespace clang
Index: unittests/ASTMatchers/ASTMatchersTest.h
===================================================================
--- unittests/ASTMatchers/ASTMatchersTest.h
+++ unittests/ASTMatchers/ASTMatchersTest.h
@@ -62,7 +62,8 @@
 testing::AssertionResult matchesConditionally(
     const std::string &Code, const T &AMatcher, bool ExpectMatch,
     llvm::StringRef CompileArg,
-    const FileContentMappings &VirtualMappedFiles = FileContentMappings()) {
+    const FileContentMappings &VirtualMappedFiles = FileContentMappings(),
+    const std::string &Filename = "input.cc") {
   bool Found = false, DynamicFound = false;
   MatchFinder Finder;
   VerifyMatch VerifyFound(nullptr, &Found);
@@ -74,7 +75,7 @@
       newFrontendActionFactory(&Finder));
   // Some tests use typeof, which is a gnu extension.
   std::vector<std::string> Args(1, CompileArg);
-  if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, "input.cc",
+  if (!runToolOnCodeWithArgs(Factory->create(), Code, Args, Filename,
                              VirtualMappedFiles)) {
     return testing::AssertionFailure() << "Parsing error in \"" << Code << "\"";
   }
@@ -105,6 +106,23 @@
   return matchesConditionally(Code, AMatcher, false, "-std=c++11");
 }
 
+template <typename T>
+testing::AssertionResult matchesObjC(const std::string &Code,
+                                     const T &AMatcher) {
+  return matchesConditionally(
+    Code, AMatcher, true,
+    "", FileContentMappings(), "input.m");
+}
+
+template <typename T>
+testing::AssertionResult notMatchesObjC(const std::string &Code,
+                                     const T &AMatcher) {
+  return matchesConditionally(
+    Code, AMatcher, false,
+    "", FileContentMappings(), "input.m");
+}
+
+
 // Function based on matchesConditionally with "-x cuda" argument added and
 // small CUDA header prepended to the code string.
 template <typename T>
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to