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