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