Overhaul the AST representation of Objective-C message send
expressions, to improve source-location information, clarify the
actual receiver of the message, and pave the way for proper C++
support. The ObjCMessageExpr node represents four different kinds of
message sends in a single AST node:

  1) Send to a object instance described by an expression (e.g., [x method:5])
  2) Send to a class described by the class name (e.g., [NSString method:5])
  3) Send to a superclass class (e.g, [super method:5] in class method)
  4) Send to a superclass instance (e.g., [super method:5] in instance method)

Previously these four cases where tangled together. Now, they have
more distinct representations. Specific changes:

  1) Unchanged; the object instance is represented by an Expr*.

  2) Previously stored the ObjCInterfaceDecl* referring to the class
  receiving the message. Now stores a TypeSourceInfo* so that we know
  how the class was spelled. This both maintains typedef information
  and opens the door for more complicated C++ types (e.g., dependent
  types). There was an alternative, unused representation of these
  sends by naming the class via an IdentifierInfo *. In practice, we
  either had an ObjCInterfaceDecl *, from which we would get the
  IdentifierInfo *, or we fell into the case below...

  3) Previously represented by a class message whose IdentifierInfo *
  referred to "super". Sema and CodeGen would use isStr("super") to
  determine if they had a send to super. Now represented as a
  "class super" send, where we have both the location of the "super"
  keyword and the ObjCInterfaceDecl* of the superclass we're
  targetting (statically).

  4) Previously represented by an instance message whose receiver is a
  an ObjCSuperExpr, which Sema and CodeGen would check for via
  isa<ObjCSuperExpr>(). Now represented as an "instance super" send,
  where we have both the location of the "super" keyword and the
  ObjCInterfaceDecl* of the superclass we're targetting
  (statically). Note that ObjCSuperExpr only has one remaining use in
  the AST, which is for "super.prop" references.

The new representation of ObjCMessageExpr is 2 pointers smaller than
the old one, since it combines more storage. It also eliminates a leak
when we loaded message-send expressions from a precompiled header. The
representation also feels much cleaner to me; comments welcome!

This patch attempts to maintain the same semantics we previously had
with Objective-C message sends. In several places, there are massive
changes that boil down to simply replacing a nested-if structure such
as:

  if (message has a receiver expression) {
    // instance message
    if (isa<ObjCSuperExpr>(...)) {
     // send to super
    } else {
     // send to an object
   }
  } else {
    // class message
    if (name->isStr("super")) {
      // class send to super
    } else {
      // send to class
    }
  }

with a switch

  switch (E->getReceiverKind()) {
  case ObjCMessageExpr::SuperInstance: ...
  case ObjCMessageExpr::Instance: ...
  case ObjCMessageExpr::SuperClass: ...
  case ObjCMessageExpr::Class:...
  }

There are quite a few places (particularly in the checkers) where
send-to-super is effectively ignored. I've placed FIXMEs in most of
them, and attempted to address send-to-super in a reasonable way. This
could use some review.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@101972 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Checker/BasicObjCFoundationChecks.cpp b/lib/Checker/BasicObjCFoundationChecks.cpp
index 810d0fb..e7275ca 100644
--- a/lib/Checker/BasicObjCFoundationChecks.cpp
+++ b/lib/Checker/BasicObjCFoundationChecks.cpp
@@ -31,13 +31,22 @@
 using namespace clang;
 
 static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
-  const Expr* Receiver = ME->getReceiver();
+  QualType T;
+  switch (ME->getReceiverKind()) {
+  case ObjCMessageExpr::Instance:
+    T = ME->getInstanceReceiver()->getType();
+    break;
 
-  if (!Receiver)
-    return NULL;
+  case ObjCMessageExpr::SuperInstance:
+    T = ME->getSuperType();
+    break;
 
-  if (const ObjCObjectPointerType *PT =
-      Receiver->getType()->getAs<ObjCObjectPointerType>())
+  case ObjCMessageExpr::Class:
+  case ObjCMessageExpr::SuperClass:
+    return 0;
+  }
+
+  if (const ObjCObjectPointerType *PT = T->getAs<ObjCObjectPointerType>())
     return PT->getInterfaceType();
 
   return NULL;
@@ -509,11 +518,21 @@
 
 void ClassReleaseChecker::PreVisitObjCMessageExpr(CheckerContext &C,
                                                   const ObjCMessageExpr *ME) {
-  
-  const IdentifierInfo *ClsName = ME->getClassName();
-  if (!ClsName)
+  ObjCInterfaceDecl *Class = 0;
+  switch (ME->getReceiverKind()) {
+  case ObjCMessageExpr::Class:
+    Class = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+    break;
+
+  case ObjCMessageExpr::SuperClass:
+    Class = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+    break;
+
+  case ObjCMessageExpr::Instance:
+  case ObjCMessageExpr::SuperInstance:
     return;
-  
+  }
+
   Selector S = ME->getSelector();
   if (!(S == releaseS || S == retainS || S == autoreleaseS || S == drainS))
     return;
@@ -531,7 +550,7 @@
   llvm::raw_svector_ostream os(buf);
 
   os << "The '" << S.getAsString() << "' message should be sent to instances "
-        "of class '" << ClsName->getName()
+        "of class '" << Class->getName()
      << "' and not the class directly";
   
   RangedBugReport *report = new RangedBugReport(*BT, os.str(), N);
diff --git a/lib/Checker/BugReporterVisitors.cpp b/lib/Checker/BugReporterVisitors.cpp
index 544129b..776e12b 100644
--- a/lib/Checker/BugReporterVisitors.cpp
+++ b/lib/Checker/BugReporterVisitors.cpp
@@ -47,14 +47,6 @@
 }
 
 const Stmt*
-clang::bugreporter::GetReceiverExpr(const ExplodedNode *N){
-  const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
-  if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S))
-    return ME->getReceiver();
-  return NULL;
-}
-
-const Stmt*
 clang::bugreporter::GetDenomExpr(const ExplodedNode *N) {
   const Stmt *S = N->getLocationAs<PreStmt>()->getStmt();
   if (const BinaryOperator *BE = dyn_cast<BinaryOperator>(S))
@@ -402,7 +394,7 @@
     const ObjCMessageExpr *ME = P->getStmtAs<ObjCMessageExpr>();
     if (!ME)
       return 0;
-    const Expr *Receiver = ME->getReceiver();
+    const Expr *Receiver = ME->getInstanceReceiver();
     if (!Receiver)
       return 0;
     const GRState *state = N->getState();
diff --git a/lib/Checker/CFRefCount.cpp b/lib/Checker/CFRefCount.cpp
index a0b4666..d26ee1d 100644
--- a/lib/Checker/CFRefCount.cpp
+++ b/lib/Checker/CFRefCount.cpp
@@ -603,12 +603,33 @@
 
     Selector S = ME->getSelector();
 
-    if (Expr* Receiver = ME->getReceiver()) {
-      const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
-      return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+    const ObjCInterfaceDecl* OD = 0;
+    bool IsInstanceMessage = false;
+    switch (ME->getReceiverKind()) {
+    case ObjCMessageExpr::Instance:
+      OD = getReceiverDecl(ME->getInstanceReceiver());
+      IsInstanceMessage = true;
+      break;
+
+    case ObjCMessageExpr::SuperInstance:
+      IsInstanceMessage = true;
+      OD = ME->getSuperType()->getAs<ObjCObjectPointerType>()
+                                                        ->getInterfaceDecl();
+      break;
+
+    case ObjCMessageExpr::Class:
+      OD = ME->getClassReceiver()->getAs<ObjCInterfaceType>()->getDecl();
+      break;
+
+    case ObjCMessageExpr::SuperClass:
+      OD = ME->getSuperType()->getAs<ObjCInterfaceType>()->getDecl();
+      break;
     }
 
-    return M[ObjCSummaryKey(ME->getClassName(), S)];
+    if (IsInstanceMessage)
+      return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
+
+    return M[ObjCSummaryKey(OD->getIdentifier(), S)];
   }
 
   RetainSummary*& operator[](ObjCSummaryKey K) {
@@ -836,7 +857,7 @@
   
   RetainSummary* getInstanceMethodSummary(const ObjCMessageExpr* ME,
                                           const ObjCInterfaceDecl* ID) {
-    return getInstanceMethodSummary(ME->getSelector(), ME->getClassName(),
+    return getInstanceMethodSummary(ME->getSelector(), 0,
                             ID, ME->getMethodDecl(), ME->getType());
   }
 
@@ -851,8 +872,21 @@
                                        QualType RetTy);
 
   RetainSummary *getClassMethodSummary(const ObjCMessageExpr *ME) {
-    return getClassMethodSummary(ME->getSelector(), ME->getClassName(),
-                                 ME->getClassInfo().Decl,
+    ObjCInterfaceDecl *Class = 0;
+    switch (ME->getReceiverKind()) {
+    case ObjCMessageExpr::Class:
+    case ObjCMessageExpr::SuperClass:
+      Class = ME->getReceiverInterface();
+      break;
+
+    case ObjCMessageExpr::Instance:
+    case ObjCMessageExpr::SuperInstance:
+      break;
+    }
+
+    return getClassMethodSummary(ME->getSelector(), 
+                                 Class? Class->getIdentifier() : 0,
+                                 Class,
                                  ME->getMethodDecl(), ME->getType());
   }
 
@@ -1333,37 +1367,44 @@
 
   // We need the type-information of the tracked receiver object
   // Retrieve it from the state.
-  const Expr *Receiver = ME->getReceiver();
+  const Expr *Receiver = ME->getInstanceReceiver();
   const ObjCInterfaceDecl* ID = 0;
 
   // FIXME: Is this really working as expected?  There are cases where
   //  we just use the 'ID' from the message expression.
-  SVal receiverV = state->getSValAsScalarOrLoc(Receiver);
+  SVal receiverV;
+
+  if (const Expr *Receiver = ME->getInstanceReceiver()) {
+    receiverV = state->getSValAsScalarOrLoc(Receiver);
   
-  // FIXME: Eventually replace the use of state->get<RefBindings> with
-  // a generic API for reasoning about the Objective-C types of symbolic
-  // objects.
-  if (SymbolRef Sym = receiverV.getAsLocSymbol())
-    if (const RefVal *T = state->get<RefBindings>(Sym))
-      if (const ObjCObjectPointerType* PT = 
+    // FIXME: Eventually replace the use of state->get<RefBindings> with
+    // a generic API for reasoning about the Objective-C types of symbolic
+    // objects.
+    if (SymbolRef Sym = receiverV.getAsLocSymbol())
+      if (const RefVal *T = state->get<RefBindings>(Sym))
+        if (const ObjCObjectPointerType* PT = 
             T->getType()->getAs<ObjCObjectPointerType>())
+          ID = PT->getInterfaceDecl();
+  
+    // FIXME: this is a hack.  This may or may not be the actual method
+    //  that is called.
+    if (!ID) {
+      if (const ObjCObjectPointerType *PT =
+          Receiver->getType()->getAs<ObjCObjectPointerType>())
         ID = PT->getInterfaceDecl();
-  
-  // FIXME: this is a hack.  This may or may not be the actual method
-  //  that is called.
-  if (!ID) {
-    if (const ObjCObjectPointerType *PT =
-        Receiver->getType()->getAs<ObjCObjectPointerType>())
-      ID = PT->getInterfaceDecl();
+    }
+  } else {
+    // FIXME: Hack for 'super'.
+    ID = ME->getReceiverInterface();
   }
-  
+
   // FIXME: The receiver could be a reference to a class, meaning that
   //  we should use the class method.
   RetainSummary *Summ = getInstanceMethodSummary(ME, ID);
   
   // Special-case: are we sending a mesage to "self"?
   //  This is a hack.  When we have full-IP this should be removed.
-  if (isa<ObjCMethodDecl>(LC->getDecl())) {
+  if (isa<ObjCMethodDecl>(LC->getDecl()) && Receiver) {
     if (const loc::MemRegionVal *L = dyn_cast<loc::MemRegionVal>(&receiverV)) {
       // Get the region associated with 'self'.
       if (const ImplicitParamDecl *SelfDecl = LC->getSelfDecl()) {
@@ -2144,7 +2185,7 @@
       }
     }
     else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
-      if (const Expr *receiver = ME->getReceiver())
+      if (const Expr *receiver = ME->getInstanceReceiver())
         if (CurrSt->getSValAsScalarOrLoc(receiver).getAsLocSymbol() == Sym) {
           // The symbol we are tracking is the receiver.
           AEffects.push_back(Summ->getReceiverEffect());
@@ -2510,7 +2551,7 @@
         // id, id<...>, or Class. If we have an ObjCInterfaceDecl, we know this
         // is a call to a class method whose type we can resolve.  In such
         // cases, promote the return type to XXX* (where XXX is the class).
-        const ObjCInterfaceDecl *D = ME->getClassInfo().Decl;
+        const ObjCInterfaceDecl *D = ME->getReceiverInterface();
         return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
       }
 
@@ -2660,15 +2701,15 @@
   RetEffect RE = Summ.getRetEffect();
 
   if (RE.getKind() == RetEffect::OwnedWhenTrackedReceiver) {
-    assert(Receiver);
-    SVal V = state->getSValAsScalarOrLoc(Receiver);
     bool found = false;
-    if (SymbolRef Sym = V.getAsLocSymbol())
-      if (state->get<RefBindings>(Sym)) {
-        found = true;
-        RE = Summaries.getObjAllocRetEffect();
-      }
-
+    if (Receiver) {
+      SVal V = state->getSValAsScalarOrLoc(Receiver);
+      if (SymbolRef Sym = V.getAsLocSymbol())
+        if (state->get<RefBindings>(Sym)) {
+          found = true;
+          RE = Summaries.getObjAllocRetEffect();
+        }
+    } // FIXME: Otherwise, this is a send-to-super instance message.
     if (!found)
       RE = RetEffect::MakeNoRet();
   }
@@ -2802,12 +2843,12 @@
                                      ExplodedNode* Pred,
                                      const GRState *state) {
   RetainSummary *Summ =
-    ME->getReceiver()
+    ME->isInstanceMessage()
       ? Summaries.getInstanceMethodSummary(ME, state,Pred->getLocationContext())
       : Summaries.getClassMethodSummary(ME);
 
   assert(Summ && "RetainSummary is null");
-  EvalSummary(Dst, Eng, Builder, ME, ME->getReceiver(), *Summ, NULL,
+  EvalSummary(Dst, Eng, Builder, ME, ME->getInstanceReceiver(), *Summ, NULL,
               ME->arg_begin(), ME->arg_end(), Pred, state);
 }
 
diff --git a/lib/Checker/CallAndMessageChecker.cpp b/lib/Checker/CallAndMessageChecker.cpp
index ce9f26e..9d0dc33 100644
--- a/lib/Checker/CallAndMessageChecker.cpp
+++ b/lib/Checker/CallAndMessageChecker.cpp
@@ -218,7 +218,8 @@
 
   const GRState *state = C.getState();
 
-  if (const Expr *receiver = ME->getReceiver())
+  // FIXME: Handle 'super'?
+  if (const Expr *receiver = ME->getInstanceReceiver())
     if (state->getSVal(receiver).isUndef()) {
       if (ExplodedNode *N = C.GenerateSink()) {
         if (!BT_msg_undef)
@@ -265,10 +266,11 @@
      << ME->getType().getAsString() << "' that will be garbage";
 
   EnhancedBugReport *report = new EnhancedBugReport(*BT_msg_ret, os.str(), N);
-  const Expr *receiver = ME->getReceiver();
-  report->addRange(receiver->getSourceRange());
-  report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
-                            receiver);
+  if (const Expr *receiver = ME->getInstanceReceiver()) {
+    report->addRange(receiver->getSourceRange());
+    report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
+                              receiver);
+  }
   C.EmitReport(report);
 }
 
diff --git a/lib/Checker/CheckObjCDealloc.cpp b/lib/Checker/CheckObjCDealloc.cpp
index f510de5..c23be87 100644
--- a/lib/Checker/CheckObjCDealloc.cpp
+++ b/lib/Checker/CheckObjCDealloc.cpp
@@ -27,10 +27,14 @@
 static bool scan_dealloc(Stmt* S, Selector Dealloc) {
 
   if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
-    if (ME->getSelector() == Dealloc)
-      if (ME->getReceiver())
-        if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
-          return isa<ObjCSuperExpr>(Receiver);
+    if (ME->getSelector() == Dealloc) {
+      switch (ME->getReceiverKind()) {
+      case ObjCMessageExpr::Instance: return false;
+      case ObjCMessageExpr::SuperInstance: return true;
+      case ObjCMessageExpr::Class: break;
+      case ObjCMessageExpr::SuperClass: break;
+      }
+    }
 
   // Recurse to children.
 
@@ -50,16 +54,16 @@
   // [mMyIvar release]
   if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
     if (ME->getSelector() == Release)
-      if (ME->getReceiver())
-        if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+      if (ME->getInstanceReceiver())
+        if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
           if (ObjCIvarRefExpr* E = dyn_cast<ObjCIvarRefExpr>(Receiver))
             if (E->getDecl() == ID)
               return true;
 
   // [self setMyIvar:nil];
   if (ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(S))
-    if (ME->getReceiver())
-      if (Expr* Receiver = ME->getReceiver()->IgnoreParenCasts())
+    if (ME->getInstanceReceiver())
+      if (Expr* Receiver = ME->getInstanceReceiver()->IgnoreParenCasts())
         if (DeclRefExpr* E = dyn_cast<DeclRefExpr>(Receiver))
           if (E->getDecl()->getIdentifier() == SelfII)
             if (ME->getMethodDecl() == PD->getSetterMethodDecl() &&
diff --git a/lib/Checker/GRExprEngine.cpp b/lib/Checker/GRExprEngine.cpp
index b5f8fee..a39e7f5 100644
--- a/lib/Checker/GRExprEngine.cpp
+++ b/lib/Checker/GRExprEngine.cpp
@@ -2124,7 +2124,7 @@
 
   // But first evaluate the receiver (if any).
   ObjCMessageExpr::arg_iterator AI = ME->arg_begin(), AE = ME->arg_end();
-  if (Expr *Receiver = ME->getReceiver()) {
+  if (Expr *Receiver = ME->getInstanceReceiver()) {
     ExplodedNodeSet Tmp;
     Visit(Receiver, Pred, Tmp);
 
@@ -2176,7 +2176,7 @@
     SaveAndRestore<bool> OldSink(Builder->BuildSinks);
     SaveOr OldHasGen(Builder->HasGeneratedNode);
 
-    if (const Expr *Receiver = ME->getReceiver()) {
+    if (const Expr *Receiver = ME->getInstanceReceiver()) {
       const GRState *state = GetState(Pred);
 
       // Bifurcate the state into nil and non-nil ones.
@@ -2206,8 +2206,8 @@
       // Dispatch to plug-in transfer function.
       EvalObjCMessageExpr(DstEval, ME, Pred, notNilState);
     }
-    else {
-      IdentifierInfo* ClsName = ME->getClassName();
+    else if (ObjCInterfaceDecl *Iface = ME->getReceiverInterface()) {
+      IdentifierInfo* ClsName = Iface->getIdentifier();
       Selector S = ME->getSelector();
 
       // Check for special instance methods.
diff --git a/lib/Checker/NSAutoreleasePoolChecker.cpp b/lib/Checker/NSAutoreleasePoolChecker.cpp
index 29bac9c..48f03a3 100644
--- a/lib/Checker/NSAutoreleasePoolChecker.cpp
+++ b/lib/Checker/NSAutoreleasePoolChecker.cpp
@@ -56,7 +56,7 @@
 NSAutoreleasePoolChecker::PreVisitObjCMessageExpr(CheckerContext &C,
                                                   const ObjCMessageExpr *ME) {
   
-  const Expr *receiver = ME->getReceiver();
+  const Expr *receiver = ME->getInstanceReceiver();
   if (!receiver)
     return;