summaryrefslogtreecommitdiffstats
path: root/clang/lib/Sema/SemaExprObjC.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Sema/SemaExprObjC.cpp')
-rw-r--r--clang/lib/Sema/SemaExprObjC.cpp167
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;
+}
+
OpenPOWER on IntegriCloud