[cfe-commits] r45294 - in /cfe/trunk: AST/ASTContext.cpp test/Sema/objc-comptypes-5.m

Fariborz Jahanian fjahanian at apple.com
Fri Dec 21 14:22:33 PST 2007


Author: fjahanian
Date: Fri Dec 21 16:22:33 2007
New Revision: 45294

URL: http://llvm.org/viewvc/llvm-project?rev=45294&view=rev
Log:
This patch implements some of the more obscure type-checking involving
'id' quallified with protocols and static types which have categories and
inheritance which implement these protocols.

Added:
    cfe/trunk/test/Sema/objc-comptypes-5.m
Modified:
    cfe/trunk/AST/ASTContext.cpp

Modified: cfe/trunk/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/AST/ASTContext.cpp?rev=45294&r1=45293&r2=45294&view=diff

==============================================================================
--- cfe/trunk/AST/ASTContext.cpp (original)
+++ cfe/trunk/AST/ASTContext.cpp Fri Dec 21 16:22:33 2007
@@ -1306,6 +1306,39 @@
   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) {
+  
+  // 1st, look up the class.
+  ObjcProtocolDecl **protoList = IDecl->getReferencedProtocols();
+  for (unsigned i = 0; i < IDecl->getNumIntfRefProtocols(); i++) {
+    if (ProtocolCompatibleWithProtocol(lProto, protoList[i]))
+      return true;
+  }
+  
+  // 2nd, look up the category.
+  if (lookupCategory)
+    for (ObjcCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
+         CDecl = CDecl->getNextClassCategory()) {
+      protoList = CDecl->getReferencedProtocols();
+      for (unsigned i = 0; i < CDecl->getNumReferencedProtocols(); i++) {
+        if (ProtocolCompatibleWithProtocol(lProto, protoList[i]))
+          return true;
+      }
+    }
+  
+  // 3rd, look up the super class(s)
+  if (IDecl->getSuperClass())
+    return 
+      ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory);
+  
+  return false;
+}
+                                           
 /// ObjcQualifiedIdTypesAreCompatible - Compares two types, at least
 /// one of which is a protocol qualified 'id' type. When 'compare'
 /// is true it is for comparison; when false, for assignment/initialization.
@@ -1350,24 +1383,29 @@
     if (!rhsQI && !rhsQID && !rhsID)
       return false;
     
+    unsigned numRhsProtocols;
+    ObjcProtocolDecl **rhsProtoList;
+    if (rhsQI) {
+      numRhsProtocols = rhsQI->getNumProtocols();
+      rhsProtoList = rhsQI->getReferencedProtocols();
+    }
+    else if (rhsQID) {
+      numRhsProtocols = rhsQID->getNumProtocols();
+      rhsProtoList = rhsQID->getReferencedProtocols();
+    }
+    
     for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) {
-      bool match = false;
       ObjcProtocolDecl *lhsProto = lhsQID->getProtocols(i);
-      unsigned numRhsProtocols;
-      ObjcProtocolDecl **rhsProtoList;
-      if (rhsQI) {
-        numRhsProtocols = rhsQI->getNumProtocols();
-        rhsProtoList = rhsQI->getReferencedProtocols();
-      }
-      else if (rhsQID) {
-        numRhsProtocols = rhsQID->getNumProtocols();
-        rhsProtoList = rhsQID->getReferencedProtocols();
-      }
-      else {
-        numRhsProtocols = rhsID->getNumIntfRefProtocols();
-        rhsProtoList = rhsID->getReferencedProtocols();
+      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.
+      if (rhsID) {
+        if (ClassImplementsProtocol(lhsProto, rhsID, true))
+          match = true;
       }
-      for (unsigned j = 0; j < numRhsProtocols; j++) {
+      else for (unsigned j = 0; j < numRhsProtocols; j++) {
         ObjcProtocolDecl *rhsProto = rhsProtoList[j];
         if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
             compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) {
@@ -1405,14 +1443,21 @@
     else if (lhsQID) {
       numLhsProtocols = lhsQID->getNumProtocols();
       lhsProtoList = lhsQID->getReferencedProtocols();
-    }
-    else {
-      numLhsProtocols = lhsID->getNumIntfRefProtocols();
-      lhsProtoList = lhsID->getReferencedProtocols();
-    }
-    
-    for (unsigned i =0; i < numLhsProtocols; i++) {
-      bool match = false;
+    }    
+    bool match = false;
+    // for static type vs. qualified 'id' type, check that class implements
+    // one of 'id's protocols.
+    if (lhsID) {
+      for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) {
+        ObjcProtocolDecl *rhsProto = rhsQID->getProtocols(j);
+        if (ClassImplementsProtocol(rhsProto, lhsID, compare)) {
+          match = true;
+          break;
+        }
+      }
+    }    
+    else for (unsigned i =0; i < numLhsProtocols; i++) {
+      match = false;
       ObjcProtocolDecl *lhsProto = lhsProtoList[i];
       for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) {
         ObjcProtocolDecl *rhsProto = rhsQID->getProtocols(j);
@@ -1422,9 +1467,9 @@
           break;
         }
       }
-      if (!match)
-        return false;
-    }    
+    }
+    if (!match)
+      return false;
   }
   return true;
 }

Added: cfe/trunk/test/Sema/objc-comptypes-5.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/objc-comptypes-5.m?rev=45294&view=auto

==============================================================================
--- cfe/trunk/test/Sema/objc-comptypes-5.m (added)
+++ cfe/trunk/test/Sema/objc-comptypes-5.m Fri Dec 21 16:22:33 2007
@@ -0,0 +1,37 @@
+// RUN: clang -fsyntax-only -verify %s
+
+extern void foo();
+#include <objc/objc.h>
+
+ at protocol MyProtocol
+- (void) method;
+ at end
+
+ at interface MyClass
+ at end
+
+ at interface MyClass (Addition) <MyProtocol>
+- (void) method;
+ at end
+
+ at interface MyOtherClass : MyClass
+ at end
+
+int main()
+{
+  id <MyProtocol> obj_id_p = nil;
+  MyClass *obj_c_cat_p = nil;
+  MyOtherClass *obj_c_super_p = nil;
+
+  obj_c_cat_p = obj_id_p;   // expected-error {{incompatible types assigning 'id<MyProtocol>' to 'MyClass *'}}
+  obj_c_super_p = obj_id_p;  // expected-error {{incompatible types assigning 'id<MyProtocol>' to 'MyOtherClass *'}}
+  obj_id_p = obj_c_cat_p;  /* Ok */
+  obj_id_p = obj_c_super_p; /* Ok */
+
+  if (obj_c_cat_p == obj_id_p) foo(); /* Ok */
+  if (obj_c_super_p == obj_id_p) foo() ; /* Ok */
+  if (obj_id_p == obj_c_cat_p)  foo(); /* Ok */
+  if (obj_id_p == obj_c_super_p)  foo(); /* Ok */
+
+  return 0;
+}





More information about the cfe-commits mailing list