SemaExprObjC.cpp revision 0c97e0460148daf132d6623af5b6ff1bc41db649
1//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// This file implements semantic analysis for Objective-C expressions. 11// 12//===----------------------------------------------------------------------===// 13 14#include "Sema.h" 15#include "clang/AST/ASTContext.h" 16#include "clang/AST/DeclObjC.h" 17#include "clang/AST/ExprObjC.h" 18using namespace clang; 19 20Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs, 21 ExprTy **Strings, 22 unsigned NumStrings) { 23 SourceLocation AtLoc = AtLocs[0]; 24 StringLiteral* S = static_cast<StringLiteral *>(Strings[0]); 25 if (NumStrings > 1) { 26 // Concatenate objc strings. 27 StringLiteral* ES = static_cast<StringLiteral *>(Strings[NumStrings-1]); 28 SourceLocation EndLoc = ES->getSourceRange().getEnd(); 29 unsigned Length = 0; 30 for (unsigned i = 0; i < NumStrings; i++) 31 Length += static_cast<StringLiteral *>(Strings[i])->getByteLength(); 32 char *strBuf = new char [Length]; 33 char *p = strBuf; 34 bool isWide = false; 35 for (unsigned i = 0; i < NumStrings; i++) { 36 S = static_cast<StringLiteral *>(Strings[i]); 37 if (S->isWide()) 38 isWide = true; 39 memcpy(p, S->getStrData(), S->getByteLength()); 40 p += S->getByteLength(); 41 S->Destroy(Context); 42 } 43 S = new (Context, 8) StringLiteral(Context, strBuf, Length, isWide, 44 Context.getPointerType(Context.CharTy), 45 AtLoc, EndLoc); 46 } 47 48 if (CheckBuiltinCFStringArgument(S)) 49 return true; 50 51 if (Context.getObjCConstantStringInterface().isNull()) { 52 // Initialize the constant string interface lazily. This assumes 53 // the NSConstantString interface is seen in this translation unit. 54 IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString"); 55 NamedDecl *IFace = LookupName(TUScope, NSIdent, LookupOrdinaryName); 56 ObjCInterfaceDecl *strIFace = dyn_cast_or_null<ObjCInterfaceDecl>(IFace); 57 if (strIFace) 58 Context.setObjCConstantStringInterface(strIFace); 59 } 60 QualType t = Context.getObjCConstantStringInterface(); 61 // If there is no NSConstantString interface defined then treat constant 62 // strings as untyped objects and let the runtime figure it out later. 63 if (t == QualType()) { 64 t = Context.getObjCIdType(); 65 } else { 66 t = Context.getPointerType(t); 67 } 68 return new (Context) ObjCStringLiteral(S, t, AtLoc); 69} 70 71Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc, 72 SourceLocation EncodeLoc, 73 SourceLocation LParenLoc, 74 TypeTy *Ty, 75 SourceLocation RParenLoc) { 76 QualType EncodedType = QualType::getFromOpaquePtr(Ty); 77 78 QualType t = Context.getPointerType(Context.CharTy); 79 return new (Context) ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc); 80} 81 82Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, 83 SourceLocation AtLoc, 84 SourceLocation SelLoc, 85 SourceLocation LParenLoc, 86 SourceLocation RParenLoc) { 87 QualType t = Context.getObjCSelType(); 88 return new (Context) ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc); 89} 90 91Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId, 92 SourceLocation AtLoc, 93 SourceLocation ProtoLoc, 94 SourceLocation LParenLoc, 95 SourceLocation RParenLoc) { 96 ObjCProtocolDecl* PDecl = ObjCProtocols[ProtocolId]; 97 if (!PDecl) { 98 Diag(ProtoLoc, diag::err_undeclared_protocol) << ProtocolId; 99 return true; 100 } 101 102 QualType t = Context.getObjCProtoType(); 103 if (t.isNull()) 104 return true; 105 t = Context.getPointerType(t); 106 return new (Context) ObjCProtocolExpr(t, PDecl, AtLoc, RParenLoc); 107} 108 109bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs, 110 Selector Sel, ObjCMethodDecl *Method, 111 bool isClassMessage, 112 SourceLocation lbrac, SourceLocation rbrac, 113 QualType &ReturnType) { 114 if (!Method) { 115 // Apply default argument promotion as for (C99 6.5.2.2p6). 116 for (unsigned i = 0; i != NumArgs; i++) 117 DefaultArgumentPromotion(Args[i]); 118 119 unsigned DiagID = isClassMessage ? diag::warn_class_method_not_found : 120 diag::warn_inst_method_not_found; 121 Diag(lbrac, DiagID) 122 << Sel << isClassMessage << SourceRange(lbrac, rbrac); 123 ReturnType = Context.getObjCIdType(); 124 return false; 125 } 126 127 ReturnType = Method->getResultType(); 128 129 unsigned NumNamedArgs = Sel.getNumArgs(); 130 assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!"); 131 132 bool anyIncompatibleArgs = false; 133 for (unsigned i = 0; i < NumNamedArgs; i++) { 134 Expr *argExpr = Args[i]; 135 assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); 136 137 QualType lhsType = Method->getParamDecl(i)->getType(); 138 QualType rhsType = argExpr->getType(); 139 140 // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. 141 if (lhsType->isArrayType()) 142 lhsType = Context.getArrayDecayedType(lhsType); 143 else if (lhsType->isFunctionType()) 144 lhsType = Context.getPointerType(lhsType); 145 146 AssignConvertType Result = 147 CheckSingleAssignmentConstraints(lhsType, argExpr); 148 if (Args[i] != argExpr) // The expression was converted. 149 Args[i] = argExpr; // Make sure we store the converted expression. 150 151 anyIncompatibleArgs |= 152 DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, 153 argExpr, "sending"); 154 } 155 156 // Promote additional arguments to variadic methods. 157 if (Method->isVariadic()) { 158 for (unsigned i = NumNamedArgs; i < NumArgs; ++i) 159 DefaultVariadicArgumentPromotion(Args[i], VariadicMethod); 160 } else { 161 // Check for extra arguments to non-variadic methods. 162 if (NumArgs != NumNamedArgs) { 163 Diag(Args[NumNamedArgs]->getLocStart(), 164 diag::err_typecheck_call_too_many_args) 165 << 2 /*method*/ << Method->getSourceRange() 166 << SourceRange(Args[NumNamedArgs]->getLocStart(), 167 Args[NumArgs-1]->getLocEnd()); 168 } 169 } 170 171 return anyIncompatibleArgs; 172} 173 174// ActOnClassMessage - used for both unary and keyword messages. 175// ArgExprs is optional - if it is present, the number of expressions 176// is obtained from Sel.getNumArgs(). 177Sema::ExprResult Sema::ActOnClassMessage( 178 Scope *S, 179 IdentifierInfo *receiverName, Selector Sel, 180 SourceLocation lbrac, SourceLocation receiverLoc, SourceLocation rbrac, 181 ExprTy **Args, unsigned NumArgs) 182{ 183 assert(receiverName && "missing receiver class name"); 184 185 Expr **ArgExprs = reinterpret_cast<Expr **>(Args); 186 ObjCInterfaceDecl* ClassDecl = 0; 187 bool isSuper = false; 188 189 if (receiverName->isStr("super")) { 190 if (getCurMethodDecl()) { 191 isSuper = true; 192 ObjCInterfaceDecl *OID = getCurMethodDecl()->getClassInterface(); 193 if (!OID) 194 return Diag(lbrac, diag::error_no_super_class_message) 195 << getCurMethodDecl()->getDeclName(); 196 ClassDecl = OID->getSuperClass(); 197 if (!ClassDecl) 198 return Diag(lbrac, diag::error_no_super_class) << OID->getDeclName(); 199 if (getCurMethodDecl()->isInstanceMethod()) { 200 QualType superTy = Context.getObjCInterfaceType(ClassDecl); 201 superTy = Context.getPointerType(superTy); 202 ExprResult ReceiverExpr = new (Context) ObjCSuperExpr(SourceLocation(), 203 superTy); 204 // We are really in an instance method, redirect. 205 return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, rbrac, 206 Args, NumArgs); 207 } 208 // We are sending a message to 'super' within a class method. Do nothing, 209 // the receiver will pass through as 'super' (how convenient:-). 210 } else { 211 // 'super' has been used outside a method context. If a variable named 212 // 'super' has been declared, redirect. If not, produce a diagnostic. 213 NamedDecl *SuperDecl = LookupName(S, receiverName, LookupOrdinaryName); 214 ValueDecl *VD = dyn_cast_or_null<ValueDecl>(SuperDecl); 215 if (VD) { 216 ExprResult ReceiverExpr = new (Context) DeclRefExpr(VD, VD->getType(), 217 receiverLoc); 218 // We are really in an instance method, redirect. 219 return ActOnInstanceMessage(ReceiverExpr.get(), Sel, lbrac, rbrac, 220 Args, NumArgs); 221 } 222 return Diag(receiverLoc, diag::err_undeclared_var_use) << receiverName; 223 } 224 } else 225 ClassDecl = getObjCInterfaceDecl(receiverName); 226 227 // The following code allows for the following GCC-ism: 228 // 229 // typedef XCElementDisplayRect XCElementGraphicsRect; 230 // 231 // @implementation XCRASlice 232 // - whatever { // Note that XCElementGraphicsRect is a typedef name. 233 // _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init]; 234 // } 235 // 236 // If necessary, the following lookup could move to getObjCInterfaceDecl(). 237 if (!ClassDecl) { 238 NamedDecl *IDecl = LookupName(TUScope, receiverName, LookupOrdinaryName); 239 if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) { 240 const ObjCInterfaceType *OCIT; 241 OCIT = OCTD->getUnderlyingType()->getAsObjCInterfaceType(); 242 if (!OCIT) 243 return Diag(receiverLoc, diag::err_invalid_receiver_to_message); 244 ClassDecl = OCIT->getDecl(); 245 } 246 } 247 assert(ClassDecl && "missing interface declaration"); 248 ObjCMethodDecl *Method = 0; 249 QualType returnType; 250 Method = ClassDecl->lookupClassMethod(Sel); 251 252 // If we have an implementation in scope, check "private" methods. 253 if (!Method) { 254 if (ObjCImplementationDecl *ImpDecl = 255 ObjCImplementations[ClassDecl->getIdentifier()]) 256 Method = ImpDecl->getClassMethod(Sel); 257 258 // Look through local category implementations associated with the class. 259 if (!Method) { 260 for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) { 261 if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl) 262 Method = ObjCCategoryImpls[i]->getClassMethod(Sel); 263 } 264 } 265 } 266 // Before we give up, check if the selector is an instance method. 267 if (!Method) 268 Method = ClassDecl->lookupInstanceMethod(Sel); 269 270 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, true, 271 lbrac, rbrac, returnType)) 272 return true; 273 274 // If we have the ObjCInterfaceDecl* for the class that is receiving 275 // the message, use that to construct the ObjCMessageExpr. Otherwise 276 // pass on the IdentifierInfo* for the class. 277 // FIXME: need to do a better job handling 'super' usage within a class 278 // For now, we simply pass the "super" identifier through (which isn't 279 // consistent with instance methods. 280 if (isSuper) 281 return new (Context) ObjCMessageExpr(receiverName, Sel, returnType, Method, 282 lbrac, rbrac, ArgExprs, NumArgs); 283 else 284 return new (Context) ObjCMessageExpr(ClassDecl, Sel, returnType, Method, 285 lbrac, rbrac, ArgExprs, NumArgs); 286} 287 288// ActOnInstanceMessage - used for both unary and keyword messages. 289// ArgExprs is optional - if it is present, the number of expressions 290// is obtained from Sel.getNumArgs(). 291Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, 292 SourceLocation lbrac, 293 SourceLocation rbrac, 294 ExprTy **Args, unsigned NumArgs) { 295 assert(receiver && "missing receiver expression"); 296 297 Expr **ArgExprs = reinterpret_cast<Expr **>(Args); 298 Expr *RExpr = static_cast<Expr *>(receiver); 299 QualType returnType; 300 301 QualType ReceiverCType = 302 Context.getCanonicalType(RExpr->getType()).getUnqualifiedType(); 303 304 // Handle messages to 'super'. 305 if (isa<ObjCSuperExpr>(RExpr)) { 306 ObjCMethodDecl *Method = 0; 307 if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { 308 // If we have an interface in scope, check 'super' methods. 309 if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) 310 if (ObjCInterfaceDecl *SuperDecl = ClassDecl->getSuperClass()) 311 Method = SuperDecl->lookupInstanceMethod(Sel); 312 } 313 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, 314 lbrac, rbrac, returnType)) 315 return true; 316 return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, 317 rbrac, ArgExprs, NumArgs); 318 } 319 320 // Handle messages to id. 321 if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) || 322 ReceiverCType->getAsBlockPointerType()) { 323 ObjCMethodDecl *Method = LookupInstanceMethodInGlobalPool( 324 Sel, SourceRange(lbrac,rbrac)); 325 if (!Method) 326 Method = FactoryMethodPool[Sel].Method; 327 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, 328 lbrac, rbrac, returnType)) 329 return true; 330 return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, 331 rbrac, ArgExprs, NumArgs); 332 } 333 334 // Handle messages to Class. 335 if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) { 336 ObjCMethodDecl *Method = 0; 337 if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { 338 // If we have an implementation in scope, check "private" methods. 339 if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) 340 if (ObjCImplementationDecl *ImpDecl = 341 ObjCImplementations[ClassDecl->getIdentifier()]) 342 Method = ImpDecl->getClassMethod(Sel); 343 } 344 if (!Method) 345 Method = FactoryMethodPool[Sel].Method; 346 if (!Method) 347 Method = LookupInstanceMethodInGlobalPool( 348 Sel, SourceRange(lbrac,rbrac)); 349 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, 350 lbrac, rbrac, returnType)) 351 return true; 352 return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, 353 rbrac, ArgExprs, NumArgs); 354 } 355 356 ObjCMethodDecl *Method = 0; 357 ObjCInterfaceDecl* ClassDecl = 0; 358 359 // We allow sending a message to a qualified ID ("id<foo>"), which is ok as 360 // long as one of the protocols implements the selector (if not, warn). 361 if (ObjCQualifiedIdType *QIT = dyn_cast<ObjCQualifiedIdType>(ReceiverCType)) { 362 // Search protocols 363 for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { 364 ObjCProtocolDecl *PDecl = QIT->getProtocols(i); 365 if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) 366 break; 367 } 368 if (!Method) 369 Diag(lbrac, diag::warn_method_not_found_in_protocol) 370 << Sel << RExpr->getSourceRange(); 371 } else if (const ObjCInterfaceType *OCIReceiver = 372 ReceiverCType->getAsPointerToObjCInterfaceType()) { 373 // We allow sending a message to a pointer to an interface (an object). 374 375 ClassDecl = OCIReceiver->getDecl(); 376 // FIXME: consider using LookupInstanceMethodInGlobalPool, since it will be 377 // faster than the following method (which can do *many* linear searches). 378 // The idea is to add class info to InstanceMethodPool. 379 Method = ClassDecl->lookupInstanceMethod(Sel); 380 381 if (!Method) { 382 // Search protocol qualifiers. 383 for (ObjCQualifiedIdType::qual_iterator QI = OCIReceiver->qual_begin(), 384 E = OCIReceiver->qual_end(); QI != E; ++QI) { 385 if ((Method = (*QI)->lookupInstanceMethod(Sel))) 386 break; 387 } 388 } 389 390 if (!Method && !OCIReceiver->qual_empty()) 391 Diag(lbrac, diag::warn_method_not_found_in_protocol) 392 << Sel << SourceRange(lbrac, rbrac); 393 } else { 394 Diag(lbrac, diag::error_bad_receiver_type) 395 << RExpr->getType() << RExpr->getSourceRange(); 396 return true; 397 } 398 399 if (!Method) { 400 // If we have an implementation in scope, check "private" methods. 401 if (ClassDecl) 402 if (ObjCImplementationDecl *ImpDecl = 403 ObjCImplementations[ClassDecl->getIdentifier()]) 404 Method = ImpDecl->getInstanceMethod(Sel); 405 // If we still haven't found a method, look in the global pool. This 406 // behavior isn't very desirable, however we need it for GCC 407 // compatibility. 408 if (!Method) 409 Method = LookupInstanceMethodInGlobalPool( 410 Sel, SourceRange(lbrac,rbrac)); 411 } 412 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, false, 413 lbrac, rbrac, returnType)) 414 return true; 415 return new (Context) ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, 416 rbrac, ArgExprs, NumArgs); 417} 418 419//===----------------------------------------------------------------------===// 420// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. 421//===----------------------------------------------------------------------===// 422 423/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the 424/// inheritance hierarchy of 'rProto'. 425static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, 426 ObjCProtocolDecl *rProto) { 427 if (lProto == rProto) 428 return true; 429 for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), 430 E = rProto->protocol_end(); PI != E; ++PI) 431 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 432 return true; 433 return false; 434} 435 436/// ClassImplementsProtocol - Checks that 'lProto' protocol 437/// has been implemented in IDecl class, its super class or categories (if 438/// lookupCategory is true). 439static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, 440 ObjCInterfaceDecl *IDecl, 441 bool lookupCategory, 442 bool RHSIsQualifiedID = false) { 443 444 // 1st, look up the class. 445 const ObjCList<ObjCProtocolDecl> &Protocols = 446 IDecl->getReferencedProtocols(); 447 448 for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(), 449 E = Protocols.end(); PI != E; ++PI) { 450 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 451 return true; 452 // This is dubious and is added to be compatible with gcc. 453 // In gcc, it is also allowed assigning a protocol-qualified 'id' 454 // type to a LHS object when protocol in qualified LHS is in list 455 // of protocols in the rhs 'id' object. This IMO, should be a bug. 456 // FIXME: Treat this as an extension, and flag this as an error when 457 // GCC extensions are not enabled. 458 if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto)) 459 return true; 460 } 461 462 // 2nd, look up the category. 463 if (lookupCategory) 464 for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; 465 CDecl = CDecl->getNextClassCategory()) { 466 for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), 467 E = CDecl->protocol_end(); PI != E; ++PI) 468 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 469 return true; 470 } 471 472 // 3rd, look up the super class(s) 473 if (IDecl->getSuperClass()) 474 return 475 ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory, 476 RHSIsQualifiedID); 477 478 return false; 479} 480 481/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an 482/// ObjCQualifiedIDType. 483bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, 484 bool compare) { 485 // Allow id<P..> and an 'id' or void* type in all cases. 486 if (const PointerType *PT = lhs->getAsPointerType()) { 487 QualType PointeeTy = PT->getPointeeType(); 488 if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) 489 return true; 490 } else if (const PointerType *PT = rhs->getAsPointerType()) { 491 QualType PointeeTy = PT->getPointeeType(); 492 if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) 493 return true; 494 } 495 496 if (const ObjCQualifiedIdType *lhsQID = lhs->getAsObjCQualifiedIdType()) { 497 const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); 498 const ObjCQualifiedInterfaceType *rhsQI = 0; 499 QualType rtype; 500 501 if (!rhsQID) { 502 // Not comparing two ObjCQualifiedIdType's? 503 if (!rhs->isPointerType()) return false; 504 505 rtype = rhs->getAsPointerType()->getPointeeType(); 506 rhsQI = rtype->getAsObjCQualifiedInterfaceType(); 507 if (rhsQI == 0) { 508 // If the RHS is a unqualified interface pointer "NSString*", 509 // make sure we check the class hierarchy. 510 if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { 511 ObjCInterfaceDecl *rhsID = IT->getDecl(); 512 for (unsigned i = 0; i != lhsQID->getNumProtocols(); ++i) { 513 // when comparing an id<P> on lhs with a static type on rhs, 514 // see if static class implements all of id's protocols, directly or 515 // through its super class and categories. 516 if (!ClassImplementsProtocol(lhsQID->getProtocols(i), rhsID, true)) 517 return false; 518 } 519 return true; 520 } 521 } 522 } 523 524 ObjCQualifiedIdType::qual_iterator RHSProtoI, RHSProtoE; 525 if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *"). 526 RHSProtoI = rhsQI->qual_begin(); 527 RHSProtoE = rhsQI->qual_end(); 528 } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *"). 529 RHSProtoI = rhsQID->qual_begin(); 530 RHSProtoE = rhsQID->qual_end(); 531 } else { 532 return false; 533 } 534 535 for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) { 536 ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(i); 537 bool match = false; 538 539 // when comparing an id<P> on lhs with a static type on rhs, 540 // see if static class implements all of id's protocols, directly or 541 // through its super class and categories. 542 for (; RHSProtoI != RHSProtoE; ++RHSProtoI) { 543 ObjCProtocolDecl *rhsProto = *RHSProtoI; 544 if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || 545 (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { 546 match = true; 547 break; 548 } 549 } 550 if (rhsQI) { 551 // If the RHS is a qualified interface pointer "NSString<P>*", 552 // make sure we check the class hierarchy. 553 if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { 554 ObjCInterfaceDecl *rhsID = IT->getDecl(); 555 for (unsigned i = 0; i != lhsQID->getNumProtocols(); ++i) { 556 // when comparing an id<P> on lhs with a static type on rhs, 557 // see if static class implements all of id's protocols, directly or 558 // through its super class and categories. 559 if (ClassImplementsProtocol(lhsQID->getProtocols(i), rhsID, true)) { 560 match = true; 561 break; 562 } 563 } 564 } 565 } 566 if (!match) 567 return false; 568 } 569 570 return true; 571 } 572 573 const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); 574 assert(rhsQID && "One of the LHS/RHS should be id<x>"); 575 576 if (!lhs->isPointerType()) 577 return false; 578 579 QualType ltype = lhs->getAsPointerType()->getPointeeType(); 580 if (const ObjCQualifiedInterfaceType *lhsQI = 581 ltype->getAsObjCQualifiedInterfaceType()) { 582 ObjCQualifiedIdType::qual_iterator LHSProtoI = lhsQI->qual_begin(); 583 ObjCQualifiedIdType::qual_iterator LHSProtoE = lhsQI->qual_end(); 584 for (; LHSProtoI != LHSProtoE; ++LHSProtoI) { 585 bool match = false; 586 ObjCProtocolDecl *lhsProto = *LHSProtoI; 587 for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { 588 ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); 589 if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || 590 (compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto))) { 591 match = true; 592 break; 593 } 594 } 595 if (!match) 596 return false; 597 } 598 return true; 599 } 600 601 if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) { 602 // for static type vs. qualified 'id' type, check that class implements 603 // all of 'id's protocols. 604 ObjCInterfaceDecl *lhsID = IT->getDecl(); 605 for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { 606 ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); 607 if (!ClassImplementsProtocol(rhsProto, lhsID, compare, true)) 608 return false; 609 } 610 return true; 611 } 612 return false; 613} 614 615