diff options
author | Chris Lattner <sabre@nondot.org> | 2008-04-07 05:30:13 +0000 |
---|---|---|
committer | Chris Lattner <sabre@nondot.org> | 2008-04-07 05:30:13 +0000 |
commit | 2a3569b5d95e1c34379914818a339db36ce7a4d8 (patch) | |
tree | 6ac87ab4b6af6ed65ffef92a4b7e79a0d3170ee0 /clang/lib/Sema/SemaExprObjC.cpp | |
parent | ae947fe3f9a96ee762fb7188be6b9a8efad95aaa (diff) | |
download | bcm5719-llvm-2a3569b5d95e1c34379914818a339db36ce7a4d8.tar.gz bcm5719-llvm-2a3569b5d95e1c34379914818a339db36ce7a4d8.zip |
move ObjCQualifiedIdTypesAreCompatible out of ASTContext into Sema.
While it is similar to the other compatibility predicates in ASTContext,
it is not used by them and is different.
In addition, greatly simplify ObjCQualifiedIdTypesAreCompatible and
fix some canonical type bugs. Also, simplify my Type::getAsObjC* methods.
llvm-svn: 49313
Diffstat (limited to 'clang/lib/Sema/SemaExprObjC.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExprObjC.cpp | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index ec6e41bf39f..63dd0d780fd 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -297,3 +297,170 @@ Sema::ExprResult Sema::ActOnInstanceMessage( return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, 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; + ObjCProtocolDecl** RefPDecl = rProto->getReferencedProtocols(); + for (unsigned i = 0; i < rProto->getNumReferencedProtocols(); i++) + if (ProtocolCompatibleWithProtocol(lProto, RefPDecl[i])) + 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) { + + // 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; +} + +bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, + bool compare) { + // Allow id<P..> and an 'id' or void* type in all cases. + if (const PointerType *PT = lhs->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) + return true; + } else if (const PointerType *PT = rhs->getAsPointerType()) { + QualType PointeeTy = PT->getPointeeType(); + if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) + return true; + } + + const ObjCQualifiedInterfaceType *lhsQI = 0; + const ObjCQualifiedInterfaceType *rhsQI = 0; + ObjCInterfaceDecl *lhsID = 0; + ObjCInterfaceDecl *rhsID = 0; + const ObjCQualifiedIdType *lhsQID = lhs->getAsObjCQualifiedIdType(); + const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); + + if (lhsQID) { + if (!rhsQID && rhs->isPointerType()) { + QualType rtype = rhs->getAsPointerType()->getPointeeType(); + rhsQI = rtype->getAsObjCQualifiedInterfaceType(); + if (!rhsQI) { + if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) + rhsID = IT->getDecl(); + } + } + if (!rhsQI && !rhsQID && !rhsID) + return false; + + ObjCQualifiedIdType::qual_iterator RHSProtoI, RHSProtoE; + if (rhsQI) { + RHSProtoI = rhsQI->qual_begin(); + RHSProtoE = rhsQI->qual_end(); + } else if (rhsQID) { + RHSProtoI = rhsQID->qual_begin(); + RHSProtoE = rhsQID->qual_end(); + } + + for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) { + ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(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. + if (rhsID) { + if (ClassImplementsProtocol(lhsProto, rhsID, true)) + match = true; + } else { + for (; RHSProtoI != RHSProtoE; ++RHSProtoI) { + ObjCProtocolDecl *rhsProto = *RHSProtoI; + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { + match = true; + break; + } + } + } + if (!match) + return false; + } + } else if (rhsQID) { + if (!lhsQID && lhs->isPointerType()) { + QualType ltype = lhs->getAsPointerType()->getPointeeType(); + lhsQI = ltype->getAsObjCQualifiedInterfaceType(); + if (!lhsQI) { + if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) + lhsID = IT->getDecl(); + } + } + if (!lhsQI && !lhsQID && !lhsID) + return false; + + ObjCQualifiedIdType::qual_iterator LHSProtoI, LHSProtoE; + if (lhsQI) { + LHSProtoI = lhsQI->qual_begin(); + LHSProtoE = lhsQI->qual_end(); + } else if (lhsQID) { + LHSProtoI = lhsQID->qual_begin(); + LHSProtoE = lhsQID->qual_end(); + } + + 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 (; LHSProtoI != LHSProtoE; ++LHSProtoI) { + match = false; + ObjCProtocolDecl *lhsProto = *LHSProtoI; + for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { + ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); + if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || + compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { + match = true; + break; + } + } + } + } + if (!match) + return false; + } + return true; +} + |