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