[analyzer] Introduce ObjCMessage which represents both explicit ObjC message expressions and implicit
messages that are sent for handling properties in dot syntax.

Replace all direct uses of ObjCMessageExpr in the checkers and checker interface with ObjCMessage.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@124159 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
index 3910196..8fa7e24 100644
--- a/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
+++ b/lib/StaticAnalyzer/Checkers/BasicObjCFoundationChecks.cpp
@@ -42,14 +42,14 @@
 // Utility functions.
 //===----------------------------------------------------------------------===//
 
-static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
-  if (ObjCInterfaceDecl *ID = ME->getReceiverInterface())
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessage &msg) {
+  if (const ObjCInterfaceDecl *ID = msg.getReceiverInterface())
     return ID->getTypeForDecl()->getAs<ObjCInterfaceType>();
   return NULL;
 }
 
-static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
-  if (const ObjCInterfaceType *ReceiverType = GetReceiverType(ME))
+static const char* GetReceiverNameType(const ObjCMessage &msg) {
+  if (const ObjCInterfaceType *ReceiverType = GetReceiverType(msg))
     return ReceiverType->getDecl()->getIdentifier()->getNameStart();
   return NULL;
 }
@@ -69,16 +69,16 @@
 namespace {
   class NilArgChecker : public CheckerVisitor<NilArgChecker> {
     APIMisuse *BT;
-    void WarnNilArg(CheckerContext &C, const ObjCMessageExpr* ME, unsigned Arg);
+    void WarnNilArg(CheckerContext &C, const ObjCMessage &msg, unsigned Arg);
   public:
     NilArgChecker() : BT(0) {}
     static void *getTag() { static int x = 0; return &x; }
-    void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
+    void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
   };
 }
 
 void NilArgChecker::WarnNilArg(CheckerContext &C,
-                               const clang::ObjCMessageExpr *ME,
+                               const ObjCMessage &msg,
                                unsigned int Arg)
 {
   if (!BT)
@@ -87,24 +87,24 @@
   if (ExplodedNode *N = C.generateSink()) {
     llvm::SmallString<128> sbuf;
     llvm::raw_svector_ostream os(sbuf);
-    os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
-       << ME->getSelector().getAsString() << "' cannot be nil";
+    os << "Argument to '" << GetReceiverNameType(msg) << "' method '"
+       << msg.getSelector().getAsString() << "' cannot be nil";
 
     RangedBugReport *R = new RangedBugReport(*BT, os.str(), N);
-    R->addRange(ME->getArg(Arg)->getSourceRange());
+    R->addRange(msg.getArgSourceRange(Arg));
     C.EmitReport(R);
   }
 }
 
-void NilArgChecker::PreVisitObjCMessageExpr(CheckerContext &C,
-                                            const ObjCMessageExpr *ME)
+void NilArgChecker::preVisitObjCMessage(CheckerContext &C,
+                                        ObjCMessage msg)
 {
-  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
+  const ObjCInterfaceType *ReceiverType = GetReceiverType(msg);
   if (!ReceiverType)
     return;
   
   if (isNSString(ReceiverType->getDecl()->getIdentifier()->getName())) {
-    Selector S = ME->getSelector();
+    Selector S = msg.getSelector();
     
     if (S.isUnarySelector())
       return;
@@ -127,8 +127,8 @@
         Name == "compare:options:range:locale:" ||
         Name == "componentsSeparatedByCharactersInSet:" ||
         Name == "initWithFormat:") {
-      if (isNil(C.getState()->getSVal(ME->getArg(0))))
-        WarnNilArg(C, ME, 0);
+      if (isNil(msg.getArgSVal(0, C.getState())))
+        WarnNilArg(C, msg, 0);
     }
   }
 }
@@ -441,12 +441,12 @@
 
   static void *getTag() { static int x = 0; return &x; }
       
-  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);    
+  void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
 };
 }
 
-void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
-                                                  const ObjCMessageExpr *ME) {
+void ClassReleaseChecker::preVisitObjCMessage(CheckerContext &C,
+                                              ObjCMessage msg) {
   
   if (!BT) {
     BT = new APIMisuse("message incorrectly sent to class instead of class "
@@ -459,21 +459,12 @@
     drainS = GetNullarySelector("drain", Ctx);
   }
   
-  ObjCInterfaceDecl *Class = 0;
-
-  switch (ME->getReceiverKind()) {
-  case ObjCMessageExpr::Class:
-    Class = ME->getClassReceiver()->getAs<ObjCObjectType>()->getInterface();
-    break;
-  case ObjCMessageExpr::SuperClass:
-    Class = ME->getSuperType()->getAs<ObjCObjectType>()->getInterface();
-    break;
-  case ObjCMessageExpr::Instance:
-  case ObjCMessageExpr::SuperInstance:
+  if (msg.isInstanceMessage())
     return;
-  }
+  const ObjCInterfaceDecl *Class = msg.getReceiverInterface();
+  assert(Class);
 
-  Selector S = ME->getSelector();
+  Selector S = msg.getSelector();
   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
     return;
   
@@ -486,7 +477,7 @@
        << "' and not the class directly";
   
     RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
-    report->addRange(ME->getSourceRange());
+    report->addRange(msg.getSourceRange());
     C.EmitReport(report);
   }
 }
diff --git a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
index 2998406..e6a40bb 100644
--- a/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/CallAndMessageChecker.cpp
@@ -41,19 +41,21 @@
   }
 
   void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
-  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);
-  bool evalNilReceiver(CheckerContext &C, const ObjCMessageExpr *ME);
+  void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
+  bool evalNilReceiver(CheckerContext &C, ObjCMessage msg);
 
 private:
-  bool PreVisitProcessArg(CheckerContext &C, const Expr *Ex,
-                          const char *BT_desc, BugType *&BT);
+  void PreVisitProcessArgs(CheckerContext &C, CallOrObjCMessage callOrMsg,
+                           const char *BT_desc, BugType *&BT);
+  bool PreVisitProcessArg(CheckerContext &C, SVal V, SourceRange argRange,
+                          const Expr *argEx, const char *BT_desc, BugType *&BT);
 
   void EmitBadCall(BugType *BT, CheckerContext &C, const CallExpr *CE);
-  void emitNilReceiverBug(CheckerContext &C, const ObjCMessageExpr *ME,
+  void emitNilReceiverBug(CheckerContext &C, const ObjCMessage &msg,
                           ExplodedNode *N);
 
   void HandleNilReceiver(CheckerContext &C, const GRState *state,
-                         const ObjCMessageExpr *ME);
+                         ObjCMessage msg);
 
   void LazyInit_BT(const char *desc, BugType *&BT) {
     if (!BT)
@@ -78,21 +80,32 @@
   C.EmitReport(R);
 }
 
+void CallAndMessageChecker::PreVisitProcessArgs(CheckerContext &C,
+                                                CallOrObjCMessage callOrMsg,
+                                                const char *BT_desc,
+                                                BugType *&BT) {
+  for (unsigned i = 0, e = callOrMsg.getNumArgs(); i != e; ++i)
+    if (PreVisitProcessArg(C, callOrMsg.getArgSVal(i),
+                           callOrMsg.getArgSourceRange(i), callOrMsg.getArg(i),
+                           BT_desc, BT))
+      return;
+}
+
 bool CallAndMessageChecker::PreVisitProcessArg(CheckerContext &C,
-                                               const Expr *Ex,
+                                               SVal V, SourceRange argRange,
+                                               const Expr *argEx,
                                                const char *BT_desc,
                                                BugType *&BT) {
 
-  const SVal &V = C.getState()->getSVal(Ex);
-
   if (V.isUndef()) {
     if (ExplodedNode *N = C.generateSink()) {
       LazyInit_BT(BT_desc, BT);
 
       // Generate a report for this bug.
       EnhancedBugReport *R = new EnhancedBugReport(*BT, BT->getName(), N);
-      R->addRange(Ex->getSourceRange());
-      R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, Ex);
+      R->addRange(argRange);
+      if (argEx)
+        R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, argEx);
       C.EmitReport(R);
     }
     return true;
@@ -172,7 +185,7 @@
 
         // Generate a report for this bug.
         EnhancedBugReport *R = new EnhancedBugReport(*BT, os.str(), N);
-        R->addRange(Ex->getSourceRange());
+        R->addRange(argRange);
 
         // FIXME: enhance track back for uninitialized value for arbitrary
         // memregions
@@ -206,21 +219,18 @@
     EmitBadCall(BT_call_null, C, CE);
   }
 
-  for (CallExpr::const_arg_iterator I = CE->arg_begin(), E = CE->arg_end();
-       I != E; ++I)
-    if (PreVisitProcessArg(C, *I,
-                           "Function call argument is an uninitialized value",
-                           BT_call_arg))
-      return;
+  PreVisitProcessArgs(C, CallOrObjCMessage(CE, C.getState()),
+                      "Function call argument is an uninitialized value",
+                      BT_call_arg);
 }
 
-void CallAndMessageChecker::PreVisitObjCMessageExpr(CheckerContext &C,
-                                                    const ObjCMessageExpr *ME) {
+void CallAndMessageChecker::preVisitObjCMessage(CheckerContext &C,
+                                                ObjCMessage msg) {
 
   const GRState *state = C.getState();
 
   // FIXME: Handle 'super'?
-  if (const Expr *receiver = ME->getInstanceReceiver())
+  if (const Expr *receiver = msg.getInstanceReceiver())
     if (state->getSVal(receiver).isUndef()) {
       if (ExplodedNode *N = C.generateSink()) {
         if (!BT_msg_undef)
@@ -237,22 +247,19 @@
     }
 
   // Check for any arguments that are uninitialized/undefined.
-  for (ObjCMessageExpr::const_arg_iterator I = ME->arg_begin(),
-         E = ME->arg_end(); I != E; ++I)
-    if (PreVisitProcessArg(C, *I,
-                           "Argument in message expression "
-                           "is an uninitialized value", BT_msg_arg))
-        return;
+  PreVisitProcessArgs(C, CallOrObjCMessage(msg, state),
+                      "Argument in message expression "
+                      "is an uninitialized value", BT_msg_arg);
 }
 
 bool CallAndMessageChecker::evalNilReceiver(CheckerContext &C,
-                                            const ObjCMessageExpr *ME) {
-  HandleNilReceiver(C, C.getState(), ME);
+                                            ObjCMessage msg) {
+  HandleNilReceiver(C, C.getState(), msg);
   return true; // Nil receiver is not handled elsewhere.
 }
 
 void CallAndMessageChecker::emitNilReceiverBug(CheckerContext &C,
-                                               const ObjCMessageExpr *ME,
+                                               const ObjCMessage &msg,
                                                ExplodedNode *N) {
 
   if (!BT_msg_ret)
@@ -262,12 +269,12 @@
 
   llvm::SmallString<200> buf;
   llvm::raw_svector_ostream os(buf);
-  os << "The receiver of message '" << ME->getSelector().getAsString()
+  os << "The receiver of message '" << msg.getSelector().getAsString()
      << "' is nil and returns a value of type '"
-     << ME->getType().getAsString() << "' that will be garbage";
+     << msg.getType(C.getASTContext()).getAsString() << "' that will be garbage";
 
   EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
-  if (const Expr *receiver = ME->getInstanceReceiver()) {
+  if (const Expr *receiver = msg.getInstanceReceiver()) {
     report->addRange(receiver->getSourceRange());
     report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
                               receiver);
@@ -284,22 +291,22 @@
 
 void CallAndMessageChecker::HandleNilReceiver(CheckerContext &C,
                                               const GRState *state,
-                                              const ObjCMessageExpr *ME) {
+                                              ObjCMessage msg) {
+  ASTContext &Ctx = C.getASTContext();
 
   // Check the return type of the message expression.  A message to nil will
   // return different values depending on the return type and the architecture.
-  QualType RetTy = ME->getType();
+  QualType RetTy = msg.getType(Ctx);
 
-  ASTContext &Ctx = C.getASTContext();
   CanQualType CanRetTy = Ctx.getCanonicalType(RetTy);
 
   if (CanRetTy->isStructureOrClassType()) {
     // FIXME: At some point we shouldn't rely on isConsumedExpr(), but instead
     // have the "use of undefined value" be smarter about where the
     // undefined value came from.
-    if (C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+    if (C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())){
       if (ExplodedNode* N = C.generateSink(state))
-        emitNilReceiverBug(C, ME, N);
+        emitNilReceiverBug(C, msg, N);
       return;
     }
 
@@ -311,7 +318,7 @@
 
   // Other cases: check if the return type is smaller than void*.
   if (CanRetTy != Ctx.VoidTy &&
-      C.getPredecessor()->getParentMap().isConsumedExpr(ME)) {
+      C.getPredecessor()->getParentMap().isConsumedExpr(msg.getOriginExpr())) {
     // Compute: sizeof(void *) and sizeof(return type)
     const uint64_t voidPtrSize = Ctx.getTypeSize(Ctx.VoidPtrTy);
     const uint64_t returnTypeSize = Ctx.getTypeSize(CanRetTy);
@@ -324,7 +331,7 @@
            Ctx.LongLongTy == CanRetTy ||
            Ctx.UnsignedLongLongTy == CanRetTy))) {
       if (ExplodedNode* N = C.generateSink(state))
-        emitNilReceiverBug(C, ME, N);
+        emitNilReceiverBug(C, msg, N);
       return;
     }
 
@@ -341,8 +348,8 @@
     // it most likely isn't nil.  We should assume the semantics
     // of this case unless we have *a lot* more knowledge.
     //
-    SVal V = C.getSValBuilder().makeZeroVal(ME->getType());
-    C.generateNode(state->BindExpr(ME, V));
+    SVal V = C.getSValBuilder().makeZeroVal(msg.getType(Ctx));
+    C.generateNode(state->BindExpr(msg.getOriginExpr(), V));
     return;
   }
 
diff --git a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
index a022562..6932f4a 100644
--- a/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Checkers/ExprEngine.cpp
@@ -145,10 +145,49 @@
   // automatically.
 }
 
-void ExprEngine::CheckerEvalNilReceiver(const ObjCMessageExpr *ME,
-                                          ExplodedNodeSet &Dst,
-                                          const GRState *state,
-                                          ExplodedNode *Pred) {
+void ExprEngine::CheckerVisitObjCMessage(const ObjCMessage &msg,
+                                         ExplodedNodeSet &Dst,
+                                         ExplodedNodeSet &Src,
+                                         bool isPrevisit) {
+
+  if (Checkers.empty()) {
+    Dst.insert(Src);
+    return;
+  }
+
+  ExplodedNodeSet Tmp;
+  ExplodedNodeSet *PrevSet = &Src;
+
+  for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
+  {
+    ExplodedNodeSet *CurrSet = 0;
+    if (I+1 == E)
+      CurrSet = &Dst;
+    else {
+      CurrSet = (PrevSet == &Tmp) ? &Src : &Tmp;
+      CurrSet->clear();
+    }
+
+    void *tag = I->first;
+    Checker *checker = I->second;
+
+    for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
+         NI != NE; ++NI)
+      checker->GR_visitObjCMessage(*CurrSet, *Builder, *this, msg,
+                                   *NI, tag, isPrevisit);
+
+    // Update which NodeSet is the current one.
+    PrevSet = CurrSet;
+  }
+
+  // Don't autotransition.  The CheckerContext objects should do this
+  // automatically.
+}
+
+void ExprEngine::CheckerEvalNilReceiver(const ObjCMessage &msg,
+                                        ExplodedNodeSet &Dst,
+                                        const GRState *state,
+                                        ExplodedNode *Pred) {
   bool evaluated = false;
   ExplodedNodeSet DstTmp;
 
@@ -156,7 +195,7 @@
     void *tag = I->first;
     Checker *checker = I->second;
 
-    if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, ME, Pred, state,
+    if (checker->GR_evalNilReceiver(DstTmp, *Builder, *this, msg, Pred, state,
                                     tag)) {
       evaluated = true;
       break;
@@ -2263,7 +2302,7 @@
 
   // Now that the arguments are processed, handle the previsits checks.
   ExplodedNodeSet DstPrevisit;
-  CheckerVisit(ME, DstPrevisit, ArgsEvaluated, PreVisitStmtCallback);
+  CheckerVisitObjCMessage(ME, DstPrevisit, ArgsEvaluated, /*isPreVisit=*/true);
 
   // Proceed with evaluate the message expression.
   ExplodedNodeSet dstEval;
@@ -2305,7 +2344,7 @@
         Builder->BuildSinks = true;
 
       // Dispatch to plug-in transfer function.
-      evalObjCMessageExpr(dstEval, ME, Pred, notNilState);
+      evalObjCMessage(dstEval, ME, Pred, notNilState);
     }
     else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
       IdentifierInfo* ClsName = Iface->getIdentifier();
@@ -2353,7 +2392,7 @@
         Builder->BuildSinks = true;
 
       // Dispatch to plug-in transfer function.
-      evalObjCMessageExpr(dstEval, ME, Pred, Builder->GetState(Pred));
+      evalObjCMessage(dstEval, ME, Pred, Builder->GetState(Pred));
     }
 
     // Handle the case where no nodes where generated.  Auto-generate that
@@ -2365,7 +2404,7 @@
 
   // Finally, perform the post-condition check of the ObjCMessageExpr and store
   // the created nodes in 'Dst'.
-  CheckerVisit(ME, Dst, dstEval, PostVisitStmtCallback);
+  CheckerVisitObjCMessage(ME, Dst, dstEval, /*isPreVisit=*/false);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
index 6ef242b..b1b4773 100644
--- a/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/NSAutoreleasePoolChecker.cpp
@@ -39,7 +39,7 @@
     return &x;
   }
 
-  void PreVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *ME);    
+  void preVisitObjCMessage(CheckerContext &C, ObjCMessage msg);    
 };
 
 } // end anonymous namespace
@@ -54,10 +54,10 @@
 }
 
 void
-NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
-                                                  const ObjCMessageExpr *ME) {
+NSAutoreleasePoolChecker::preVisitObjCMessage(CheckerContext &C,
+                                              ObjCMessage msg) {
   
-  const Expr *receiver = ME->getInstanceReceiver();
+  const Expr *receiver = msg.getInstanceReceiver();
   if (!receiver)
     return;
   
@@ -75,13 +75,13 @@
     return;
   
   // Sending 'release' message?
-  if (ME->getSelector() != releaseS)
+  if (msg.getSelector() != releaseS)
     return;
                      
-  SourceRange R = ME->getSourceRange();
+  SourceRange R = msg.getSourceRange();
 
   C.getBugReporter().EmitBasicReport("Use -drain instead of -release",
     "API Upgrade (Apple)",
     "Use -drain instead of -release when using NSAutoreleasePool "
-    "and garbage collection", ME->getLocStart(), &R, 1);
+    "and garbage collection", R.getBegin(), &R, 1);
 }
diff --git a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
index 9eb6b19..c887ac8 100644
--- a/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/ObjCSelfInitChecker.cpp
@@ -58,7 +58,7 @@
 
 static bool shouldRunOnFunctionOrMethod(const NamedDecl *ND);
 static bool isInitializationMethod(const ObjCMethodDecl *MD);
-static bool isInitMessage(const ObjCMessageExpr *E);
+static bool isInitMessage(const ObjCMessage &msg);
 static bool isSelfVar(SVal location, CheckerContext &C);
 
 namespace {
@@ -82,7 +82,7 @@
 
 public:
   static void *getTag() { static int tag = 0; return &tag; }
-  void PostVisitObjCMessageExpr(CheckerContext &C, const ObjCMessageExpr *E);
+  void postVisitObjCMessage(CheckerContext &C, ObjCMessage msg);
   void PostVisitObjCIvarRefExpr(CheckerContext &C, const ObjCIvarRefExpr *E);
   void PreVisitReturnStmt(CheckerContext &C, const ReturnStmt *S);
   void PreVisitGenericCall(CheckerContext &C, const CallExpr *CE);
@@ -176,8 +176,8 @@
   C.EmitReport(report);
 }
 
-void ObjCSelfInitChecker::PostVisitObjCMessageExpr(CheckerContext &C,
-                                                   const ObjCMessageExpr *E) {
+void ObjCSelfInitChecker::postVisitObjCMessage(CheckerContext &C,
+                                               ObjCMessage msg) {
   // When encountering a message that does initialization (init rule),
   // tag the return value so that we know later on that if self has this value
   // then it is properly initialized.
@@ -187,10 +187,10 @@
                                      C.getCurrentAnalysisContext()->getDecl())))
     return;
 
-  if (isInitMessage(E)) {
+  if (isInitMessage(msg)) {
     // Tag the return value as the result of an initializer.
     const GRState *state = C.getState();
-    SVal V = state->getSVal(E);
+    SVal V = state->getSVal(msg.getOriginExpr());
     addSelfFlag(V, SelfFlag_InitRes, C);
     return;
   }
@@ -301,6 +301,6 @@
                                     /*ignorePrefix=*/false) == cocoa::InitRule;
 }
 
-static bool isInitMessage(const ObjCMessageExpr *E) {
-  return cocoa::deriveNamingConvention(E->getSelector()) == cocoa::InitRule;
+static bool isInitMessage(const ObjCMessage &msg) {
+  return cocoa::deriveNamingConvention(msg.getSelector()) == cocoa::InitRule;
 }