This patch includes a conceptually simple, but very intrusive/pervasive change. 

The idea is to segregate Objective-C "object" pointers from general C pointers (utilizing the recently added ObjCObjectPointerType). The fun starts in Sema::GetTypeForDeclarator(), where "SomeInterface *" is now represented by a single AST node (rather than a PointerType whose Pointee is an ObjCInterfaceType). Since a significant amount of code assumed ObjC object pointers where based on C pointers/structs, this patch is very tedious. It should also explain why it is hard to accomplish this in smaller, self-contained patches.

This patch does most of the "heavy lifting" related to moving from PointerType->ObjCObjectPointerType. It doesn't include all potential "cleanups". The good news is additional cleanups can be done later (some are noted in the code). This patch is so large that I didn't want to include any changes that are purely aesthetic.

By making the ObjC types truly built-in, they are much easier to work with (and require fewer "hacks"). For example, there is no need for ASTContext::isObjCIdStructType() or ASTContext::isObjCClassStructType()! We believe this change (and the follow-up cleanups) will pay dividends over time. 

Given the amount of code change, I do expect some fallout from this change (though it does pass all of the clang tests). If you notice any problems, please let us know asap! Thanks.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@75314 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp
index aa85769..b454a36 100644
--- a/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -31,26 +31,21 @@
 
 using namespace clang;
 
-static ObjCInterfaceType* GetReceiverType(ObjCMessageExpr* ME) {
-  Expr* Receiver = ME->getReceiver();
+static const ObjCInterfaceType* GetReceiverType(const ObjCMessageExpr* ME) {
+  const Expr* Receiver = ME->getReceiver();
   
   if (!Receiver)
     return NULL;
   
-  QualType X = Receiver->getType();
-  
-  if (X->isPointerType()) {
-    Type* TP = X.getTypePtr();
-    const PointerType* T = TP->getAsPointerType();    
-    return dyn_cast<ObjCInterfaceType>(T->getPointeeType().getTypePtr());
-  }
+  if (const ObjCObjectPointerType *PT =
+      Receiver->getType()->getAsObjCObjectPointerType())
+    return PT->getInterfaceType();
 
-  // FIXME: Support ObjCQualifiedIdType?
   return NULL;
 }
 
-static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
-  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+static const char* GetReceiverNameType(const ObjCMessageExpr* ME) {
+  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
   return ReceiverType ? ReceiverType->getDecl()->getIdentifier()->getName()
                       : NULL;
 }
@@ -67,7 +62,7 @@
   BugReporter& BR;
   ASTContext &Ctx;
       
-  bool isNSString(ObjCInterfaceType* T, const char* suffix);
+  bool isNSString(const ObjCInterfaceType *T, const char* suffix);
   bool AuditNSString(NodeTy* N, ObjCMessageExpr* ME);
       
   void Warn(NodeTy* N, Expr* E, const std::string& s);  
@@ -114,7 +109,7 @@
   ObjCMessageExpr* ME =
     cast<ObjCMessageExpr>(cast<PostStmt>(N->getLocation()).getStmt());
 
-  ObjCInterfaceType* ReceiverType = GetReceiverType(ME);
+  const ObjCInterfaceType *ReceiverType = GetReceiverType(ME);
   
   if (!ReceiverType)
     return false;
@@ -129,8 +124,7 @@
       
   name += 2;
   
-  // FIXME: Make all of this faster.
-  
+  // FIXME: Make all of this faster.  
   if (isNSString(ReceiverType, name))
     return AuditNSString(N, ME);
 
@@ -163,9 +157,8 @@
 // NSString checking.
 //===----------------------------------------------------------------------===//
 
-bool BasicObjCFoundationChecks::isNSString(ObjCInterfaceType* T,
-                                           const char* suffix) {
-  
+bool BasicObjCFoundationChecks::isNSString(const ObjCInterfaceType *T,
+                                           const char* suffix) {  
   return !strcmp("String", suffix) || !strcmp("MutableString", suffix);
 }
 
diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp
index c74668c..1cfd783 100644
--- a/lib/Analysis/CFRefCount.cpp
+++ b/lib/Analysis/CFRefCount.cpp
@@ -547,14 +547,12 @@
     return I == M.end() ? M.find(ObjCSummaryKey(S)) : I;
   }
   
-  ObjCInterfaceDecl* getReceiverDecl(Expr* E) {
-    
-    const PointerType* PT = E->getType()->getAsPointerType();
-    if (!PT) return 0;
-    
-    ObjCInterfaceType* OI = dyn_cast<ObjCInterfaceType>(PT->getPointeeType());
-    
-    return OI ? OI->getDecl() : 0;
+  const ObjCInterfaceDecl* getReceiverDecl(Expr* E) {    
+    if (const ObjCObjectPointerType* PT =
+        E->getType()->getAsObjCObjectPointerType())
+      return PT->getInterfaceDecl();
+
+    return NULL;
   }
   
   iterator end() { return M.end(); }
@@ -564,7 +562,7 @@
     Selector S = ME->getSelector();
     
     if (Expr* Receiver = ME->getReceiver()) {
-      ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
+      const ObjCInterfaceDecl* OD = getReceiverDecl(Receiver);
       return OD ? M[ObjCSummaryKey(OD->getIdentifier(), S)] : M[S];
     }
     
@@ -886,20 +884,20 @@
   if (!Ctx.isObjCObjectPointerType(Ty))
     return false;
 
-  // We assume that id<..>, id, and "Class" all represent tracked objects.
-  const PointerType *PT = Ty->getAsPointerType();
-  if (PT == 0)
+  const ObjCObjectPointerType *PT = Ty->getAsObjCObjectPointerType();
+  
+  // Can be true for objects with the 'NSObject' attribute.
+  if (!PT)
     return true;
-    
-  const ObjCInterfaceType *OT = PT->getPointeeType()->getAsObjCInterfaceType();
+  
+  // We assume that id<..>, id, and "Class" all represent tracked objects.
+  if (PT->isObjCIdType() || PT->isObjCQualifiedIdType() ||
+      PT->isObjCClassType())
+    return true;
 
-  // We assume that id<..>, id, and "Class" all represent tracked objects.
-  if (!OT)
-    return true;
-    
   // Does the interface subclass NSObject?    
   // FIXME: We can memoize here if this gets too expensive.    
-  ObjCInterfaceDecl* ID = OT->getDecl();  
+  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();  
 
   // Assume that anything declared with a forward declaration and no
   // @interface subclasses NSObject.
@@ -908,7 +906,6 @@
   
   IdentifierInfo* NSObjectII = &Ctx.Idents.get("NSObject");
 
-
   for ( ; ID ; ID = ID->getSuperClass())
     if (ID->getIdentifier() == NSObjectII)
       return true;
@@ -977,7 +974,7 @@
       case 17:
         // Handle: id NSMakeCollectable(CFTypeRef)
         if (!memcmp(FName, "NSMakeCollectable", 17)) {
-          S = (RetTy == Ctx.getObjCIdType())
+          S = (RetTy->isObjCIdType())
               ? getUnarySummary(FT, cfmakecollectable)
               : getPersistentStopSummary();
         }
@@ -2726,34 +2723,26 @@
 ///  While the the return type can be queried directly from RetEx, when
 ///  invoking class methods we augment to the return type to be that of
 ///  a pointer to the class (as opposed it just being id).
-static QualType GetReturnType(Expr* RetE, ASTContext& Ctx) {
-
+static QualType GetReturnType(const Expr* RetE, ASTContext& Ctx) {
   QualType RetTy = RetE->getType();
-
-  // FIXME: We aren't handling id<...>.
-  const PointerType* PT = RetTy->getAsPointerType();
-  if (!PT)
-    return RetTy;
-    
-  // If RetEx is not a message expression just return its type.
-  // If RetEx is a message expression, return its types if it is something
+  // If RetE is not a message expression just return its type.
+  // If RetE is a message expression, return its types if it is something
   /// more specific than id.
+  if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(RetE))
+    if (const ObjCObjectPointerType *PT = RetTy->getAsObjCObjectPointerType())
+      if (PT->isObjCQualifiedIdType() || PT->isObjCIdType() || 
+          PT->isObjCClassType()) {
+        // At this point we know the return type of the message expression is
+        // 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().first;  
+        return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+      }
   
-  ObjCMessageExpr* ME = dyn_cast<ObjCMessageExpr>(RetE);
-  
-  if (!ME || !Ctx.isObjCIdStructType(PT->getPointeeType()))
-    return RetTy;
-  
-  ObjCInterfaceDecl* D = ME->getClassInfo().first;  
-
-  // At this point we know the return type of the message expression is id.
-  // If we have an ObjCInterceDecl, we know this is a call to a class method
-  // whose type we can resolve.  In such cases, promote the return type to
-  // Class*.  
-  return !D ? RetTy : Ctx.getPointerType(Ctx.getObjCInterfaceType(D));
+  return RetTy;
 }
 
-
 void CFRefCount::EvalSummary(ExplodedNodeSet<GRState>& Dst,
                              GRExprEngine& Eng,
                              GRStmtNodeBuilder<GRState>& Builder,
@@ -3009,26 +2998,21 @@
     SVal V = St->getSValAsScalarOrLoc(Receiver);
 
     SymbolRef Sym = V.getAsLocSymbol();
+    
     if (Sym) {
       if (const RefVal* T  = St->get<RefBindings>(Sym)) {
-        QualType Ty = T->getType();
-        
-        if (const PointerType* PT = Ty->getAsPointerType()) {
-          QualType PointeeTy = PT->getPointeeType();
-          
-          if (ObjCInterfaceType* IT = dyn_cast<ObjCInterfaceType>(PointeeTy))
-            ID = IT->getDecl();
-        }
+        if (const ObjCObjectPointerType* PT =
+            T->getType()->getAsObjCObjectPointerType())
+          ID = PT->getInterfaceDecl();
       }
     }
 
     // FIXME: this is a hack.  This may or may not be the actual method
     //  that is called.
     if (!ID) {
-      if (const PointerType *PT = Receiver->getType()->getAsPointerType())
-        if (const ObjCInterfaceType *p =
-            PT->getPointeeType()->getAsObjCInterfaceType())
-          ID = p->getDecl();
+      if (const ObjCObjectPointerType *PT =
+          Receiver->getType()->getAsObjCObjectPointerType())
+        ID = PT->getInterfaceDecl();
     }
 
     // FIXME: The receiver could be a reference to a class, meaning that
diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp
index c91442b..c1382d0 100644
--- a/lib/Analysis/CheckNSError.cpp
+++ b/lib/Analysis/CheckNSError.cpp
@@ -162,16 +162,22 @@
 bool NSErrorCheck::CheckNSErrorArgument(QualType ArgTy) {
   
   const PointerType* PPT = ArgTy->getAsPointerType();
-  if (!PPT) return false;
+  if (!PPT)
+    return false;
   
-  const PointerType* PT = PPT->getPointeeType()->getAsPointerType();
-  if (!PT) return false;
+  const ObjCObjectPointerType* PT =
+    PPT->getPointeeType()->getAsObjCObjectPointerType();
+
+  if (!PT)
+    return false;
   
-  const ObjCInterfaceType *IT =
-  PT->getPointeeType()->getAsObjCInterfaceType();
+  const ObjCInterfaceDecl *ID = PT->getInterfaceDecl();
   
-  if (!IT) return false;
-  return IT->getDecl()->getIdentifier() == II;
+  // FIXME: Can ID ever be NULL?
+  if (ID)
+    return II == ID->getIdentifier();
+  
+  return false;
 }
 
 bool NSErrorCheck::CheckCFErrorArgument(QualType ArgTy) {
diff --git a/lib/Analysis/CheckObjCInstMethSignature.cpp b/lib/Analysis/CheckObjCInstMethSignature.cpp
index 2881486..c4e586d 100644
--- a/lib/Analysis/CheckObjCInstMethSignature.cpp
+++ b/lib/Analysis/CheckObjCInstMethSignature.cpp
@@ -30,8 +30,8 @@
 
   // Right now don't compare the compatibility of pointers.  That involves
   // looking at subtyping relationships.  FIXME: Future patch.
-  if ((Derived->isPointerType() || Derived->isObjCQualifiedIdType())  && 
-      (Ancestor->isPointerType() || Ancestor->isObjCQualifiedIdType()))
+  if ((Derived->isPointerType() || Derived->isObjCObjectPointerType())  && 
+      (Ancestor->isPointerType() || Ancestor->isObjCObjectPointerType()))
     return true;
 
   return C.typesAreCompatible(Derived, Ancestor);