SemaExprObjC.cpp revision 4bfd223a74022ce30ac1b86683bac054ab5fac34
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() << 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