[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