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