Remove a bunch of FIXME's related to ObjC type checking.

- Move Sema::ObjCQualifiedIdTypesAreCompatible(), Sema::QualifiedIdConformsQualifiedId(), and a couple helper functions to ASTContext.
- Change ASTContext::canAssignObjCInterfaces() to use ASTContext:: ObjCQualifiedIdTypesAreCompatible(). 
- Tweak several test cases to accommodate the new/improved type checking.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@76830 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3bb763a..9f3eff9 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1201,7 +1201,6 @@
                            bool &IncompleteImpl);
   void WarnConflictingTypedMethods(ObjCMethodDecl *ImpMethod,
                                    ObjCMethodDecl *IntfMethod);
-  bool QualifiedIdConformsQualifiedId(QualType LHS, QualType RHS);
 
   NamespaceDecl *GetStdNamespace();
   
@@ -3197,9 +3196,6 @@
                                           unsigned NewWidth, bool NewSign,
                                           SourceLocation Loc, unsigned DiagID);
   
-  bool ObjCQualifiedIdTypesAreCompatible(QualType LHS, QualType RHS,
-                                         bool ForCompare);
-
   /// Checks that the Objective-C declaration is declared in the global scope.
   /// Emits an error and marks the declaration as invalid if it's not declared
   /// in the global scope.
diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp
index 19cbf09..8bd2f53 100644
--- a/lib/Sema/SemaDeclObjC.cpp
+++ b/lib/Sema/SemaDeclObjC.cpp
@@ -369,7 +369,7 @@
   if (!Context.typesAreCompatible(LHSType, RHSType)) {
     // FIXME: Incorporate this test with typesAreCompatible.
     if (LHSType->isObjCQualifiedIdType() && RHSType->isObjCQualifiedIdType())
-      if (ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
+      if (Context.ObjCQualifiedIdTypesAreCompatible(LHSType, RHSType, false))
         return;
     Diag(Property->getLocation(), diag::warn_property_types_are_incompatible)
       << Property->getType() << SuperProperty->getType() << inheritedName;
@@ -804,8 +804,8 @@
                                        ObjCMethodDecl *IntfMethodDecl) {
   if (!Context.typesAreCompatible(IntfMethodDecl->getResultType(),
                                   ImpMethodDecl->getResultType()) &&
-      !QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(),
-                                      ImpMethodDecl->getResultType())) {
+      !Context.QualifiedIdConformsQualifiedId(IntfMethodDecl->getResultType(),
+                                              ImpMethodDecl->getResultType())) {
     Diag(ImpMethodDecl->getLocation(), diag::warn_conflicting_ret_types) 
       << ImpMethodDecl->getDeclName() << IntfMethodDecl->getResultType()
       << ImpMethodDecl->getResultType();
@@ -816,7 +816,8 @@
        IF = IntfMethodDecl->param_begin(), EM = ImpMethodDecl->param_end();
        IM != EM; ++IM, ++IF) {
     if (Context.typesAreCompatible((*IF)->getType(), (*IM)->getType()) ||
-        QualifiedIdConformsQualifiedId((*IF)->getType(), (*IM)->getType()))
+        Context.QualifiedIdConformsQualifiedId((*IF)->getType(), 
+                                               (*IM)->getType()))
       continue;
     
     Diag((*IM)->getLocation(), diag::warn_conflicting_param_types) 
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index 5d4fbd8..bfde991 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -3171,7 +3171,7 @@
       compositeType = RHSTy;
     } else if ((LHSTy->isObjCQualifiedIdType() || 
                 RHSTy->isObjCQualifiedIdType()) &&
-                ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
+                Context.ObjCQualifiedIdTypesAreCompatible(LHSTy, RHSTy, true)) {
       // Need to handle "id<xx>" explicitly. 
       // GCC allows qualified id and any Objective-C type to devolve to
       // id. Currently localizing to here until clear this should be
@@ -3436,17 +3436,6 @@
       return Compatible;
     return Incompatible;
   }
-  // FIXME: Look into removing. With ObjCObjectPointerType, I don't see a need.
-  if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType()) {
-    if (ObjCQualifiedIdTypesAreCompatible(lhsType, rhsType, false))
-      return Compatible;
-    // Relax integer conversions like we do for pointers below.
-    if (rhsType->isIntegerType())
-      return IntToPointer;
-    if (lhsType->isIntegerType())
-      return PointerToInt;
-    return IncompatibleObjCQualifiedId;
-  }
   // Allow scalar to ExtVector assignments, and assignments of an ExtVector type
   // to the same ExtVector type.
   if (lhsType->isExtVectorType()) {
@@ -3528,6 +3517,8 @@
         return Compatible;
       if (Context.typesAreCompatible(lhsType, rhsType))
         return Compatible;
+      if (lhsType->isObjCQualifiedIdType() || rhsType->isObjCQualifiedIdType())
+        return IncompatibleObjCQualifiedId;
       return IncompatiblePointer;
     }
     if (const PointerType *RHSPT = rhsType->getAsPointerType()) {
diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp
index 2d14410..47ce949 100644
--- a/lib/Sema/SemaExprObjC.cpp
+++ b/lib/Sema/SemaExprObjC.cpp
@@ -651,196 +651,3 @@
                                        rbrac, ArgExprs, NumArgs);
 }
 
-//===----------------------------------------------------------------------===//
-// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
-//===----------------------------------------------------------------------===//
-
-/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
-/// inheritance hierarchy of 'rProto'.
-static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
-                                           ObjCProtocolDecl *rProto) {
-  if (lProto == rProto)
-    return true;
-  for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
-       E = rProto->protocol_end(); PI != E; ++PI)
-    if (ProtocolCompatibleWithProtocol(lProto, *PI))
-      return true;
-  return false;
-}
-
-/// ClassImplementsProtocol - Checks that 'lProto' protocol
-/// has been implemented in IDecl class, its super class or categories (if
-/// lookupCategory is true). 
-static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto,
-                                    ObjCInterfaceDecl *IDecl, 
-                                    bool lookupCategory,
-                                    bool RHSIsQualifiedID = false) {
-  
-  // 1st, look up the class.
-  const ObjCList<ObjCProtocolDecl> &Protocols =
-    IDecl->getReferencedProtocols();
-
-  for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(),
-       E = Protocols.end(); PI != E; ++PI) {
-    if (ProtocolCompatibleWithProtocol(lProto, *PI))
-      return true;
-    // This is dubious and is added to be compatible with gcc.  In gcc, it is
-    // also allowed assigning a protocol-qualified 'id' type to a LHS object
-    // when protocol in qualified LHS is in list of protocols in the rhs 'id'
-    // object. This IMO, should be a bug.
-    // FIXME: Treat this as an extension, and flag this as an error when GCC
-    // extensions are not enabled.
-    if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto))
-      return true;
-  }
-  
-  // 2nd, look up the category.
-  if (lookupCategory)
-    for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
-         CDecl = CDecl->getNextClassCategory()) {
-      for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(),
-           E = CDecl->protocol_end(); PI != E; ++PI)
-        if (ProtocolCompatibleWithProtocol(lProto, *PI))
-          return true;
-    }
-  
-  // 3rd, look up the super class(s)
-  if (IDecl->getSuperClass())
-    return 
-      ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory,
-                              RHSIsQualifiedID);
-  
-  return false;
-}
-
-/// QualifiedIdConformsQualifiedId - compare id<p,...> with id<p1,...>
-/// return true if lhs's protocols conform to rhs's protocol; false
-/// otherwise.
-bool Sema::QualifiedIdConformsQualifiedId(QualType lhs, QualType rhs) {
-  if (lhs->isObjCQualifiedIdType() && rhs->isObjCQualifiedIdType())
-    return ObjCQualifiedIdTypesAreCompatible(lhs, rhs, false);
-  return false;
-}
-
-/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an
-/// ObjCQualifiedIDType.
-/// FIXME: Move to ASTContext::typesAreCompatible() and friends.
-bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
-                                             bool compare) {
-  // Allow id<P..> and an 'id' or void* type in all cases.
-  if (lhs->isVoidPointerType() || 
-      lhs->isObjCIdType() || lhs->isObjCClassType())
-    return true;
-  else if (rhs->isVoidPointerType() || 
-           rhs->isObjCIdType() || rhs->isObjCClassType())
-    return true;
-
-  if (const ObjCObjectPointerType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
-    const ObjCObjectPointerType *rhsOPT = rhs->getAsObjCObjectPointerType();
-    
-    if (!rhsOPT) return false;
-    
-    if (rhsOPT->qual_empty()) {
-      // If the RHS is a unqualified interface pointer "NSString*", 
-      // make sure we check the class hierarchy.
-      if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
-        for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
-             E = lhsQID->qual_end(); I != E; ++I) {
-          // when comparing an id<P> on lhs with a static type on rhs,
-          // see if static class implements all of id's protocols, directly or
-          // through its super class and categories.
-          if (!ClassImplementsProtocol(*I, rhsID, true))
-            return false;
-        }
-      }
-      // If there are no qualifiers and no interface, we have an 'id'.
-      return true;
-    }
-    // Both the right and left sides have qualifiers.    
-    for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
-         E = lhsQID->qual_end(); I != E; ++I) {
-      ObjCProtocolDecl *lhsProto = *I;
-      bool match = false;
-
-      // when comparing an id<P> on lhs with a static type on rhs,
-      // see if static class implements all of id's protocols, directly or
-      // through its super class and categories.
-      for (ObjCObjectPointerType::qual_iterator J = rhsOPT->qual_begin(),
-           E = rhsOPT->qual_end(); J != E; ++J) {
-        ObjCProtocolDecl *rhsProto = *J;
-        if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
-            (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
-          match = true;
-          break;
-        }
-      }
-      // If the RHS is a qualified interface pointer "NSString<P>*", 
-      // make sure we check the class hierarchy.
-      if (ObjCInterfaceDecl *rhsID = rhsOPT->getInterfaceDecl()) {
-        for (ObjCObjectPointerType::qual_iterator I = lhsQID->qual_begin(),
-             E = lhsQID->qual_end(); I != E; ++I) {
-          // when comparing an id<P> on lhs with a static type on rhs,
-          // see if static class implements all of id's protocols, directly or
-          // through its super class and categories.
-          if (ClassImplementsProtocol(*I, rhsID, true)) {
-            match = true;
-            break;
-          }
-        }
-      }
-      if (!match)
-        return false;
-    }
-    
-    return true;
-  }
-  
-  const ObjCObjectPointerType *rhsQID = rhs->getAsObjCQualifiedIdType();
-  assert(rhsQID && "One of the LHS/RHS should be id<x>");
-
-  if (const ObjCObjectPointerType *lhsOPT = 
-        lhs->getAsObjCInterfacePointerType()) {
-    if (lhsOPT->qual_empty()) {
-      bool match = false;
-      if (ObjCInterfaceDecl *lhsID = lhsOPT->getInterfaceDecl()) {
-        for (ObjCObjectPointerType::qual_iterator I = rhsQID->qual_begin(),
-             E = rhsQID->qual_end(); I != E; ++I) {
-          // when comparing an id<P> on lhs with a static type on rhs,
-          // see if static class implements all of id's protocols, directly or
-          // through its super class and categories.
-          if (ClassImplementsProtocol(*I, lhsID, true)) {
-            match = true;
-            break;
-          }
-        }
-        if (!match)
-          return false;
-      }
-      return true;
-    }
-    // Both the right and left sides have qualifiers.    
-    for (ObjCObjectPointerType::qual_iterator I = lhsOPT->qual_begin(),
-         E = lhsOPT->qual_end(); I != E; ++I) {
-      ObjCProtocolDecl *lhsProto = *I;
-      bool match = false;
-
-      // when comparing an id<P> on lhs with a static type on rhs,
-      // see if static class implements all of id's protocols, directly or
-      // through its super class and categories.
-      for (ObjCObjectPointerType::qual_iterator J = rhsQID->qual_begin(),
-           E = rhsQID->qual_end(); J != E; ++J) {
-        ObjCProtocolDecl *rhsProto = *J;
-        if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
-            (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) {
-          match = true;
-          break;
-        }
-      }
-      if (!match)
-        return false;
-    }
-    return true;
-  }
-  return false;
-}
-
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index 503f226..dc5f3e8 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1020,7 +1020,8 @@
     // Conversions with Objective-C's id<...>.
     if ((FromObjCPtr->isObjCQualifiedIdType() || 
          ToObjCPtr->isObjCQualifiedIdType()) &&
-        ObjCQualifiedIdTypesAreCompatible(ToType, FromType, /*compare=*/false)) {
+        Context.ObjCQualifiedIdTypesAreCompatible(ToType, FromType, 
+                                                  /*compare=*/false)) {
       ConvertedType = ToType;
       return true;
     }