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