SemaExprObjC.cpp revision 4b9846d221146a015478b9bd4745f3a84aed1c56
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->getName()); 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 const char *PrefixStr, 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 Diag(lbrac, diag::warn_method_not_found, std::string(PrefixStr), 121 Sel.getName(), SourceRange(lbrac, rbrac)); 122 ReturnType = Context.getObjCIdType(); 123 return false; 124 } else { 125 ReturnType = Method->getResultType(); 126 } 127 128 unsigned NumNamedArgs = Sel.getNumArgs(); 129 assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!"); 130 131 bool anyIncompatibleArgs = false; 132 for (unsigned i = 0; i < NumNamedArgs; i++) { 133 Expr *argExpr = Args[i]; 134 assert(argExpr && "CheckMessageArgumentTypes(): missing expression"); 135 136 QualType lhsType = Method->getParamDecl(i)->getType(); 137 QualType rhsType = argExpr->getType(); 138 139 // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8]. 140 if (lhsType->isArrayType()) 141 lhsType = Context.getArrayDecayedType(lhsType); 142 else if (lhsType->isFunctionType()) 143 lhsType = Context.getPointerType(lhsType); 144 145 AssignConvertType Result = 146 CheckSingleAssignmentConstraints(lhsType, argExpr); 147 if (Args[i] != argExpr) // The expression was converted. 148 Args[i] = argExpr; // Make sure we store the converted expression. 149 150 anyIncompatibleArgs |= 151 DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType, 152 argExpr, "sending"); 153 } 154 155 // Promote additional arguments to variadic methods. 156 if (Method->isVariadic()) { 157 for (unsigned i = NumNamedArgs; i < NumArgs; ++i) 158 DefaultArgumentPromotion(Args[i]); 159 } else { 160 // Check for extra arguments to non-variadic methods. 161 if (NumArgs != NumNamedArgs) { 162 Diag(Args[NumNamedArgs]->getLocStart(), 163 diag::err_typecheck_call_too_many_args, 164 Method->getSourceRange(), 165 SourceRange(Args[NumNamedArgs]->getLocStart(), 166 Args[NumArgs-1]->getLocEnd())); 167 } 168 } 169 170 return anyIncompatibleArgs; 171} 172 173// ActOnClassMessage - used for both unary and keyword messages. 174// ArgExprs is optional - if it is present, the number of expressions 175// is obtained from Sel.getNumArgs(). 176Sema::ExprResult Sema::ActOnClassMessage( 177 Scope *S, 178 IdentifierInfo *receiverName, Selector Sel, 179 SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs) 180{ 181 assert(receiverName && "missing receiver class name"); 182 183 Expr **ArgExprs = reinterpret_cast<Expr **>(Args); 184 ObjCInterfaceDecl* ClassDecl = 0; 185 bool isSuper = false; 186 187 if (receiverName == SuperID && getCurMethodDecl()) { 188 isSuper = true; 189 ClassDecl = getCurMethodDecl()->getClassInterface()->getSuperClass(); 190 if (!ClassDecl) 191 return Diag(lbrac, diag::error_no_super_class, 192 getCurMethodDecl()->getClassInterface()->getName()); 193 if (getCurMethodDecl()->isInstance()) { 194 QualType superTy = Context.getObjCInterfaceType(ClassDecl); 195 superTy = Context.getPointerType(superTy); 196 ExprResult ReceiverExpr = new PredefinedExpr(SourceLocation(), superTy, 197 PredefinedExpr::ObjCSuper); 198 // We are really in an instance method, redirect. 199 return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, rbrac, 200 Args, NumArgs); 201 } 202 // We are sending a message to 'super' within a class method. Do nothing, 203 // the receiver will pass through as 'super' (how convenient:-). 204 } else 205 ClassDecl = getObjCInterfaceDecl(receiverName); 206 207 // The following code allows for the following GCC-ism: 208 // 209 // typedef XCElementDisplayRect XCElementGraphicsRect; 210 // 211 // @implementation XCRASlice 212 // - whatever { // Note that XCElementGraphicsRect is a typedef name. 213 // _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init]; 214 // } 215 // 216 // If necessary, the following lookup could move to getObjCInterfaceDecl(). 217 if (!ClassDecl) { 218 Decl *IDecl = LookupDecl(receiverName, Decl::IDNS_Ordinary, 0, false); 219 if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) { 220 const ObjCInterfaceType *OCIT; 221 OCIT = OCTD->getUnderlyingType()->getAsObjCInterfaceType(); 222 if (OCIT) 223 ClassDecl = OCIT->getDecl(); 224 } 225 } 226 assert(ClassDecl && "missing interface declaration"); 227 ObjCMethodDecl *Method = 0; 228 QualType returnType; 229 Method = ClassDecl->lookupClassMethod(Sel); 230 231 // If we have an implementation in scope, check "private" methods. 232 if (!Method) { 233 if (ObjCImplementationDecl *ImpDecl = 234 ObjCImplementations[ClassDecl->getIdentifier()]) 235 Method = ImpDecl->getClassMethod(Sel); 236 237 // Look through local category implementations associated with the class. 238 if (!Method) { 239 for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) { 240 if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl) 241 Method = ObjCCategoryImpls[i]->getClassMethod(Sel); 242 } 243 } 244 } 245 // Before we give up, check if the selector is an instance method. 246 if (!Method) 247 Method = ClassDecl->lookupInstanceMethod(Sel); 248 249 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "+", 250 lbrac, rbrac, returnType)) 251 return true; 252 253 // If we have the ObjCInterfaceDecl* for the class that is receiving 254 // the message, use that to construct the ObjCMessageExpr. Otherwise 255 // pass on the IdentifierInfo* for the class. 256 // FIXME: need to do a better job handling 'super' usage within a class 257 // For now, we simply pass the "super" identifier through (which isn't 258 // consistent with instance methods. 259 if (isSuper) 260 return new ObjCMessageExpr(receiverName, Sel, returnType, Method, 261 lbrac, rbrac, ArgExprs, NumArgs); 262 else 263 return new ObjCMessageExpr(ClassDecl, Sel, returnType, Method, 264 lbrac, rbrac, ArgExprs, NumArgs); 265} 266 267// ActOnInstanceMessage - used for both unary and keyword messages. 268// ArgExprs is optional - if it is present, the number of expressions 269// is obtained from Sel.getNumArgs(). 270Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel, 271 SourceLocation lbrac, 272 SourceLocation rbrac, 273 ExprTy **Args, unsigned NumArgs) { 274 assert(receiver && "missing receiver expression"); 275 276 Expr **ArgExprs = reinterpret_cast<Expr **>(Args); 277 Expr *RExpr = static_cast<Expr *>(receiver); 278 QualType returnType; 279 280 QualType ReceiverCType = 281 Context.getCanonicalType(RExpr->getType()).getUnqualifiedType(); 282 283 // Handle messages to id. 284 if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType())) { 285 ObjCMethodDecl *Method = InstanceMethodPool[Sel].Method; 286 if (!Method) 287 Method = FactoryMethodPool[Sel].Method; 288 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-", 289 lbrac, rbrac, returnType)) 290 return true; 291 return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, 292 ArgExprs, NumArgs); 293 } 294 295 // Handle messages to Class. 296 if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) { 297 ObjCMethodDecl *Method = 0; 298 if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { 299 // If we have an implementation in scope, check "private" methods. 300 if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) 301 if (ObjCImplementationDecl *ImpDecl = 302 ObjCImplementations[ClassDecl->getIdentifier()]) 303 Method = ImpDecl->getClassMethod(Sel); 304 } 305 if (!Method) 306 Method = FactoryMethodPool[Sel].Method; 307 if (!Method) 308 Method = InstanceMethodPool[Sel].Method; 309 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-", 310 lbrac, rbrac, returnType)) 311 return true; 312 return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, 313 ArgExprs, NumArgs); 314 } 315 316 ObjCMethodDecl *Method = 0; 317 ObjCInterfaceDecl* ClassDecl = 0; 318 319 // We allow sending a message to a qualified ID ("id<foo>"), which is ok as 320 // long as one of the protocols implements the selector (if not, warn). 321 if (ObjCQualifiedIdType *QIT = dyn_cast<ObjCQualifiedIdType>(ReceiverCType)) { 322 // Search protocols 323 for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { 324 ObjCProtocolDecl *PDecl = QIT->getProtocols(i); 325 if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) 326 break; 327 } 328 if (!Method) 329 Diag(lbrac, diag::warn_method_not_found_in_protocol, 330 std::string("-"), Sel.getName(), 331 RExpr->getSourceRange()); 332 } else if (const ObjCInterfaceType *OCIReceiver = 333 ReceiverCType->getAsPointerToObjCInterfaceType()) { 334 // We allow sending a message to a pointer to an interface (an object). 335 336 ClassDecl = OCIReceiver->getDecl(); 337 // FIXME: consider using InstanceMethodPool, since it will be faster 338 // than the following method (which can do *many* linear searches). The 339 // idea is to add class info to InstanceMethodPool. 340 Method = ClassDecl->lookupInstanceMethod(Sel); 341 342 if (!Method) { 343 // Search protocol qualifiers. 344 for (ObjCQualifiedIdType::qual_iterator QI = OCIReceiver->qual_begin(), 345 E = OCIReceiver->qual_end(); QI != E; ++QI) { 346 if ((Method = (*QI)->lookupInstanceMethod(Sel))) 347 break; 348 } 349 } 350 351 if (!Method && !OCIReceiver->qual_empty()) 352 Diag(lbrac, diag::warn_method_not_found_in_protocol, 353 std::string("-"), Sel.getName(), 354 SourceRange(lbrac, rbrac)); 355 } else { 356 Diag(lbrac, diag::error_bad_receiver_type, 357 RExpr->getType().getAsString(), RExpr->getSourceRange()); 358 return true; 359 } 360 361 if (!Method) { 362 // If we have an implementation in scope, check "private" methods. 363 if (ClassDecl) 364 if (ObjCImplementationDecl *ImpDecl = 365 ObjCImplementations[ClassDecl->getIdentifier()]) 366 Method = ImpDecl->getInstanceMethod(Sel); 367 // If we still haven't found a method, look in the global pool. This 368 // behavior isn't very desirable, however we need it for GCC 369 // compatibility. 370 if (!Method) 371 Method = InstanceMethodPool[Sel].Method; 372 } 373 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-", 374 lbrac, rbrac, returnType)) 375 return true; 376 return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, 377 ArgExprs, NumArgs); 378} 379 380//===----------------------------------------------------------------------===// 381// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. 382//===----------------------------------------------------------------------===// 383 384/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the 385/// inheritance hierarchy of 'rProto'. 386static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, 387 ObjCProtocolDecl *rProto) { 388 if (lProto == rProto) 389 return true; 390 for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), 391 E = rProto->protocol_end(); PI != E; ++PI) 392 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 393 return true; 394 return false; 395} 396 397/// ClassImplementsProtocol - Checks that 'lProto' protocol 398/// has been implemented in IDecl class, its super class or categories (if 399/// lookupCategory is true). 400static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, 401 ObjCInterfaceDecl *IDecl, 402 bool lookupCategory, 403 bool RHSIsQualifiedID = false) { 404 405 // 1st, look up the class. 406 const ObjCList<ObjCProtocolDecl> &Protocols = 407 IDecl->getReferencedProtocols(); 408 409 for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(), 410 E = Protocols.end(); PI != E; ++PI) { 411 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 412 return true; 413 // This is dubious and is added to be compatible with gcc. 414 // In gcc, it is also allowed assigning a protocol-qualified 'id' 415 // type to a LHS object when protocol in qualified LHS is in list 416 // of protocols in the rhs 'id' object. This IMO, should be a bug. 417 // FIXME: Treat this as an extension, and flag this as an error when 418 // GCC extensions are not enabled. 419 if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto)) 420 return true; 421 } 422 423 // 2nd, look up the category. 424 if (lookupCategory) 425 for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; 426 CDecl = CDecl->getNextClassCategory()) { 427 for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), 428 E = CDecl->protocol_end(); PI != E; ++PI) 429 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 430 return true; 431 } 432 433 // 3rd, look up the super class(s) 434 if (IDecl->getSuperClass()) 435 return 436 ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory, 437 RHSIsQualifiedID); 438 439 return false; 440} 441 442/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an 443/// ObjCQualifiedIDType. 444bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, 445 bool compare) { 446 // Allow id<P..> and an 'id' or void* type in all cases. 447 if (const PointerType *PT = lhs->getAsPointerType()) { 448 QualType PointeeTy = PT->getPointeeType(); 449 if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) 450 return true; 451 } else if (const PointerType *PT = rhs->getAsPointerType()) { 452 QualType PointeeTy = PT->getPointeeType(); 453 if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) 454 return true; 455 } 456 457 if (const ObjCQualifiedIdType *lhsQID = lhs->getAsObjCQualifiedIdType()) { 458 const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); 459 const ObjCQualifiedInterfaceType *rhsQI = 0; 460 QualType rtype; 461 462 if (!rhsQID) { 463 // Not comparing two ObjCQualifiedIdType's? 464 if (!rhs->isPointerType()) return false; 465 466 rtype = rhs->getAsPointerType()->getPointeeType(); 467 rhsQI = rtype->getAsObjCQualifiedInterfaceType(); 468 if (rhsQI == 0) { 469 // If the RHS is a unqualified interface pointer "NSString*", 470 // make sure we check the class hierarchy. 471 if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { 472 ObjCInterfaceDecl *rhsID = IT->getDecl(); 473 for (unsigned i = 0; i != lhsQID->getNumProtocols(); ++i) { 474 // when comparing an id<P> on lhs with a static type on rhs, 475 // see if static class implements all of id's protocols, directly or 476 // through its super class and categories. 477 if (!ClassImplementsProtocol(lhsQID->getProtocols(i), rhsID, true)) 478 return false; 479 } 480 return true; 481 } 482 } 483 } 484 485 ObjCQualifiedIdType::qual_iterator RHSProtoI, RHSProtoE; 486 if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *"). 487 RHSProtoI = rhsQI->qual_begin(); 488 RHSProtoE = rhsQI->qual_end(); 489 } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *"). 490 RHSProtoI = rhsQID->qual_begin(); 491 RHSProtoE = rhsQID->qual_end(); 492 } else { 493 return false; 494 } 495 496 for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) { 497 ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(i); 498 bool match = false; 499 500 // when comparing an id<P> on lhs with a static type on rhs, 501 // see if static class implements all of id's protocols, directly or 502 // through its super class and categories. 503 for (; RHSProtoI != RHSProtoE; ++RHSProtoI) { 504 ObjCProtocolDecl *rhsProto = *RHSProtoI; 505 if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || 506 compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { 507 match = true; 508 break; 509 } 510 } 511 if (rhsQI) { 512 // If the RHS is a qualified interface pointer "NSString<P>*", 513 // make sure we check the class hierarchy. 514 if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { 515 ObjCInterfaceDecl *rhsID = IT->getDecl(); 516 for (unsigned i = 0; i != lhsQID->getNumProtocols(); ++i) { 517 // when comparing an id<P> on lhs with a static type on rhs, 518 // see if static class implements all of id's protocols, directly or 519 // through its super class and categories. 520 if (ClassImplementsProtocol(lhsQID->getProtocols(i), rhsID, true)) { 521 match = true; 522 break; 523 } 524 } 525 } 526 } 527 if (!match) 528 return false; 529 } 530 531 return true; 532 } 533 534 const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); 535 assert(rhsQID && "One of the LHS/RHS should be id<x>"); 536 537 if (!lhs->isPointerType()) 538 return false; 539 540 QualType ltype = lhs->getAsPointerType()->getPointeeType(); 541 if (const ObjCQualifiedInterfaceType *lhsQI = 542 ltype->getAsObjCQualifiedInterfaceType()) { 543 ObjCQualifiedIdType::qual_iterator LHSProtoI = lhsQI->qual_begin(); 544 ObjCQualifiedIdType::qual_iterator LHSProtoE = lhsQI->qual_end(); 545 for (; LHSProtoI != LHSProtoE; ++LHSProtoI) { 546 bool match = false; 547 ObjCProtocolDecl *lhsProto = *LHSProtoI; 548 for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { 549 ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); 550 if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || 551 compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { 552 match = true; 553 break; 554 } 555 } 556 if (!match) 557 return false; 558 } 559 return true; 560 } 561 562 if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) { 563 // for static type vs. qualified 'id' type, check that class implements 564 // all of 'id's protocols. 565 ObjCInterfaceDecl *lhsID = IT->getDecl(); 566 for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { 567 ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); 568 if (!ClassImplementsProtocol(rhsProto, lhsID, compare, true)) 569 return false; 570 } 571 return true; 572 } 573 return false; 574} 575 576