SemaExprObjC.cpp revision 6c4088e5fc0ce98bf3213d47f6f38bfbfa20c813
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 ReceiverCType->getAsBlockPointerType()) { 286 ObjCMethodDecl *Method = InstanceMethodPool[Sel].Method; 287 if (!Method) 288 Method = FactoryMethodPool[Sel].Method; 289 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-", 290 lbrac, rbrac, returnType)) 291 return true; 292 return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, 293 ArgExprs, NumArgs); 294 } 295 296 // Handle messages to Class. 297 if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) { 298 ObjCMethodDecl *Method = 0; 299 if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) { 300 // If we have an implementation in scope, check "private" methods. 301 if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface()) 302 if (ObjCImplementationDecl *ImpDecl = 303 ObjCImplementations[ClassDecl->getIdentifier()]) 304 Method = ImpDecl->getClassMethod(Sel); 305 } 306 if (!Method) 307 Method = FactoryMethodPool[Sel].Method; 308 if (!Method) 309 Method = InstanceMethodPool[Sel].Method; 310 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-", 311 lbrac, rbrac, returnType)) 312 return true; 313 return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, 314 ArgExprs, NumArgs); 315 } 316 317 ObjCMethodDecl *Method = 0; 318 ObjCInterfaceDecl* ClassDecl = 0; 319 320 // We allow sending a message to a qualified ID ("id<foo>"), which is ok as 321 // long as one of the protocols implements the selector (if not, warn). 322 if (ObjCQualifiedIdType *QIT = dyn_cast<ObjCQualifiedIdType>(ReceiverCType)) { 323 // Search protocols 324 for (unsigned i = 0; i < QIT->getNumProtocols(); i++) { 325 ObjCProtocolDecl *PDecl = QIT->getProtocols(i); 326 if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel))) 327 break; 328 } 329 if (!Method) 330 Diag(lbrac, diag::warn_method_not_found_in_protocol, 331 std::string("-"), Sel.getName(), 332 RExpr->getSourceRange()); 333 } else if (const ObjCInterfaceType *OCIReceiver = 334 ReceiverCType->getAsPointerToObjCInterfaceType()) { 335 // We allow sending a message to a pointer to an interface (an object). 336 337 ClassDecl = OCIReceiver->getDecl(); 338 // FIXME: consider using InstanceMethodPool, since it will be faster 339 // than the following method (which can do *many* linear searches). The 340 // idea is to add class info to InstanceMethodPool. 341 Method = ClassDecl->lookupInstanceMethod(Sel); 342 343 if (!Method) { 344 // Search protocol qualifiers. 345 for (ObjCQualifiedIdType::qual_iterator QI = OCIReceiver->qual_begin(), 346 E = OCIReceiver->qual_end(); QI != E; ++QI) { 347 if ((Method = (*QI)->lookupInstanceMethod(Sel))) 348 break; 349 } 350 } 351 352 if (!Method && !OCIReceiver->qual_empty()) 353 Diag(lbrac, diag::warn_method_not_found_in_protocol, 354 std::string("-"), Sel.getName(), 355 SourceRange(lbrac, rbrac)); 356 } else { 357 Diag(lbrac, diag::error_bad_receiver_type, 358 RExpr->getType().getAsString(), RExpr->getSourceRange()); 359 return true; 360 } 361 362 if (!Method) { 363 // If we have an implementation in scope, check "private" methods. 364 if (ClassDecl) 365 if (ObjCImplementationDecl *ImpDecl = 366 ObjCImplementations[ClassDecl->getIdentifier()]) 367 Method = ImpDecl->getInstanceMethod(Sel); 368 // If we still haven't found a method, look in the global pool. This 369 // behavior isn't very desirable, however we need it for GCC 370 // compatibility. 371 if (!Method) 372 Method = InstanceMethodPool[Sel].Method; 373 } 374 if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-", 375 lbrac, rbrac, returnType)) 376 return true; 377 return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac, 378 ArgExprs, NumArgs); 379} 380 381//===----------------------------------------------------------------------===// 382// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's. 383//===----------------------------------------------------------------------===// 384 385/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the 386/// inheritance hierarchy of 'rProto'. 387static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto, 388 ObjCProtocolDecl *rProto) { 389 if (lProto == rProto) 390 return true; 391 for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(), 392 E = rProto->protocol_end(); PI != E; ++PI) 393 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 394 return true; 395 return false; 396} 397 398/// ClassImplementsProtocol - Checks that 'lProto' protocol 399/// has been implemented in IDecl class, its super class or categories (if 400/// lookupCategory is true). 401static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto, 402 ObjCInterfaceDecl *IDecl, 403 bool lookupCategory, 404 bool RHSIsQualifiedID = false) { 405 406 // 1st, look up the class. 407 const ObjCList<ObjCProtocolDecl> &Protocols = 408 IDecl->getReferencedProtocols(); 409 410 for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(), 411 E = Protocols.end(); PI != E; ++PI) { 412 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 413 return true; 414 // This is dubious and is added to be compatible with gcc. 415 // In gcc, it is also allowed assigning a protocol-qualified 'id' 416 // type to a LHS object when protocol in qualified LHS is in list 417 // of protocols in the rhs 'id' object. This IMO, should be a bug. 418 // FIXME: Treat this as an extension, and flag this as an error when 419 // GCC extensions are not enabled. 420 if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto)) 421 return true; 422 } 423 424 // 2nd, look up the category. 425 if (lookupCategory) 426 for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl; 427 CDecl = CDecl->getNextClassCategory()) { 428 for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(), 429 E = CDecl->protocol_end(); PI != E; ++PI) 430 if (ProtocolCompatibleWithProtocol(lProto, *PI)) 431 return true; 432 } 433 434 // 3rd, look up the super class(s) 435 if (IDecl->getSuperClass()) 436 return 437 ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory, 438 RHSIsQualifiedID); 439 440 return false; 441} 442 443/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an 444/// ObjCQualifiedIDType. 445bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs, 446 bool compare) { 447 // Allow id<P..> and an 'id' or void* type in all cases. 448 if (const PointerType *PT = lhs->getAsPointerType()) { 449 QualType PointeeTy = PT->getPointeeType(); 450 if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) 451 return true; 452 } else if (const PointerType *PT = rhs->getAsPointerType()) { 453 QualType PointeeTy = PT->getPointeeType(); 454 if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType()) 455 return true; 456 } 457 458 if (const ObjCQualifiedIdType *lhsQID = lhs->getAsObjCQualifiedIdType()) { 459 const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); 460 const ObjCQualifiedInterfaceType *rhsQI = 0; 461 QualType rtype; 462 463 if (!rhsQID) { 464 // Not comparing two ObjCQualifiedIdType's? 465 if (!rhs->isPointerType()) return false; 466 467 rtype = rhs->getAsPointerType()->getPointeeType(); 468 rhsQI = rtype->getAsObjCQualifiedInterfaceType(); 469 if (rhsQI == 0) { 470 // If the RHS is a unqualified interface pointer "NSString*", 471 // make sure we check the class hierarchy. 472 if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { 473 ObjCInterfaceDecl *rhsID = IT->getDecl(); 474 for (unsigned i = 0; i != lhsQID->getNumProtocols(); ++i) { 475 // when comparing an id<P> on lhs with a static type on rhs, 476 // see if static class implements all of id's protocols, directly or 477 // through its super class and categories. 478 if (!ClassImplementsProtocol(lhsQID->getProtocols(i), rhsID, true)) 479 return false; 480 } 481 return true; 482 } 483 } 484 } 485 486 ObjCQualifiedIdType::qual_iterator RHSProtoI, RHSProtoE; 487 if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *"). 488 RHSProtoI = rhsQI->qual_begin(); 489 RHSProtoE = rhsQI->qual_end(); 490 } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *"). 491 RHSProtoI = rhsQID->qual_begin(); 492 RHSProtoE = rhsQID->qual_end(); 493 } else { 494 return false; 495 } 496 497 for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) { 498 ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(i); 499 bool match = false; 500 501 // when comparing an id<P> on lhs with a static type on rhs, 502 // see if static class implements all of id's protocols, directly or 503 // through its super class and categories. 504 for (; RHSProtoI != RHSProtoE; ++RHSProtoI) { 505 ObjCProtocolDecl *rhsProto = *RHSProtoI; 506 if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || 507 compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { 508 match = true; 509 break; 510 } 511 } 512 if (rhsQI) { 513 // If the RHS is a qualified interface pointer "NSString<P>*", 514 // make sure we check the class hierarchy. 515 if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) { 516 ObjCInterfaceDecl *rhsID = IT->getDecl(); 517 for (unsigned i = 0; i != lhsQID->getNumProtocols(); ++i) { 518 // when comparing an id<P> on lhs with a static type on rhs, 519 // see if static class implements all of id's protocols, directly or 520 // through its super class and categories. 521 if (ClassImplementsProtocol(lhsQID->getProtocols(i), rhsID, true)) { 522 match = true; 523 break; 524 } 525 } 526 } 527 } 528 if (!match) 529 return false; 530 } 531 532 return true; 533 } 534 535 const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType(); 536 assert(rhsQID && "One of the LHS/RHS should be id<x>"); 537 538 if (!lhs->isPointerType()) 539 return false; 540 541 QualType ltype = lhs->getAsPointerType()->getPointeeType(); 542 if (const ObjCQualifiedInterfaceType *lhsQI = 543 ltype->getAsObjCQualifiedInterfaceType()) { 544 ObjCQualifiedIdType::qual_iterator LHSProtoI = lhsQI->qual_begin(); 545 ObjCQualifiedIdType::qual_iterator LHSProtoE = lhsQI->qual_end(); 546 for (; LHSProtoI != LHSProtoE; ++LHSProtoI) { 547 bool match = false; 548 ObjCProtocolDecl *lhsProto = *LHSProtoI; 549 for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { 550 ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); 551 if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) || 552 compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) { 553 match = true; 554 break; 555 } 556 } 557 if (!match) 558 return false; 559 } 560 return true; 561 } 562 563 if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) { 564 // for static type vs. qualified 'id' type, check that class implements 565 // all of 'id's protocols. 566 ObjCInterfaceDecl *lhsID = IT->getDecl(); 567 for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) { 568 ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j); 569 if (!ClassImplementsProtocol(rhsProto, lhsID, compare, true)) 570 return false; 571 } 572 return true; 573 } 574 return false; 575} 576 577