SemaExprObjC.cpp revision 6c4088e5fc0ce98bf3213d47f6f38bfbfa20c813
1//===--- SemaExprObjC.cpp - Semantic Analysis for ObjC Expressions --------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10//  This file implements semantic analysis for Objective-C expressions.
11//
12//===----------------------------------------------------------------------===//
13
14#include "Sema.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/DeclObjC.h"
17#include "clang/AST/ExprObjC.h"
18#include "clang/Basic/Diagnostic.h"
19using namespace clang;
20
21Sema::ExprResult Sema::ParseObjCStringLiteral(SourceLocation *AtLocs,
22                                              ExprTy **Strings,
23                                              unsigned NumStrings) {
24  SourceLocation AtLoc = AtLocs[0];
25  StringLiteral* S = static_cast<StringLiteral *>(Strings[0]);
26  if (NumStrings > 1) {
27    // Concatenate objc strings.
28    StringLiteral* ES = static_cast<StringLiteral *>(Strings[NumStrings-1]);
29    SourceLocation EndLoc = ES->getSourceRange().getEnd();
30    unsigned Length = 0;
31    for (unsigned i = 0; i < NumStrings; i++)
32      Length += static_cast<StringLiteral *>(Strings[i])->getByteLength();
33    char *strBuf = new char [Length];
34    char *p = strBuf;
35    bool isWide = false;
36    for (unsigned i = 0; i < NumStrings; i++) {
37      S = static_cast<StringLiteral *>(Strings[i]);
38      if (S->isWide())
39        isWide = true;
40      memcpy(p, S->getStrData(), S->getByteLength());
41      p += S->getByteLength();
42      delete S;
43    }
44    S = new StringLiteral(strBuf, Length,
45                          isWide, Context.getPointerType(Context.CharTy),
46                          AtLoc, EndLoc);
47  }
48
49  if (CheckBuiltinCFStringArgument(S))
50    return true;
51
52  if (Context.getObjCConstantStringInterface().isNull()) {
53    // Initialize the constant string interface lazily. This assumes
54    // the NSConstantString interface is seen in this translation unit.
55    IdentifierInfo *NSIdent = &Context.Idents.get("NSConstantString");
56    Decl *IFace = LookupDecl(NSIdent, Decl::IDNS_Ordinary, TUScope);
57    ObjCInterfaceDecl *strIFace = dyn_cast_or_null<ObjCInterfaceDecl>(IFace);
58    if (strIFace)
59      Context.setObjCConstantStringInterface(strIFace);
60  }
61  QualType t = Context.getObjCConstantStringInterface();
62  // If there is no NSConstantString interface defined then treat constant
63  // strings as untyped objects and let the runtime figure it out later.
64  if (t == QualType()) {
65    t = Context.getObjCIdType();
66  } else {
67    t = Context.getPointerType(t);
68  }
69  return new ObjCStringLiteral(S, t, AtLoc);
70}
71
72Sema::ExprResult Sema::ParseObjCEncodeExpression(SourceLocation AtLoc,
73                                                 SourceLocation EncodeLoc,
74                                                 SourceLocation LParenLoc,
75                                                 TypeTy *Ty,
76                                                 SourceLocation RParenLoc) {
77  QualType EncodedType = QualType::getFromOpaquePtr(Ty);
78
79  QualType t = Context.getPointerType(Context.CharTy);
80  return new ObjCEncodeExpr(t, EncodedType, AtLoc, RParenLoc);
81}
82
83Sema::ExprResult Sema::ParseObjCSelectorExpression(Selector Sel,
84                                                   SourceLocation AtLoc,
85                                                   SourceLocation SelLoc,
86                                                   SourceLocation LParenLoc,
87                                                   SourceLocation RParenLoc) {
88  QualType t = Context.getObjCSelType();
89  return new ObjCSelectorExpr(t, Sel, AtLoc, RParenLoc);
90}
91
92Sema::ExprResult Sema::ParseObjCProtocolExpression(IdentifierInfo *ProtocolId,
93                                                   SourceLocation AtLoc,
94                                                   SourceLocation ProtoLoc,
95                                                   SourceLocation LParenLoc,
96                                                   SourceLocation RParenLoc) {
97  ObjCProtocolDecl* PDecl = ObjCProtocols[ProtocolId];
98  if (!PDecl) {
99    Diag(ProtoLoc, diag::err_undeclared_protocol, ProtocolId->getName());
100    return true;
101  }
102
103  QualType t = Context.getObjCProtoType();
104  if (t.isNull())
105    return true;
106  t = Context.getPointerType(t);
107  return new ObjCProtocolExpr(t, PDecl, AtLoc, RParenLoc);
108}
109
110bool Sema::CheckMessageArgumentTypes(Expr **Args, unsigned NumArgs,
111                                     Selector Sel, ObjCMethodDecl *Method,
112                                     const char *PrefixStr,
113                                     SourceLocation lbrac, SourceLocation rbrac,
114                                     QualType &ReturnType) {
115  if (!Method) {
116    // Apply default argument promotion as for (C99 6.5.2.2p6).
117    for (unsigned i = 0; i != NumArgs; i++)
118      DefaultArgumentPromotion(Args[i]);
119
120    Diag(lbrac, diag::warn_method_not_found, std::string(PrefixStr),
121         Sel.getName(), SourceRange(lbrac, rbrac));
122    ReturnType = Context.getObjCIdType();
123    return false;
124  } else {
125    ReturnType = Method->getResultType();
126  }
127
128  unsigned NumNamedArgs = Sel.getNumArgs();
129  assert(NumArgs >= NumNamedArgs && "Too few arguments for selector!");
130
131  bool anyIncompatibleArgs = false;
132  for (unsigned i = 0; i < NumNamedArgs; i++) {
133    Expr *argExpr = Args[i];
134    assert(argExpr && "CheckMessageArgumentTypes(): missing expression");
135
136    QualType lhsType = Method->getParamDecl(i)->getType();
137    QualType rhsType = argExpr->getType();
138
139    // If necessary, apply function/array conversion. C99 6.7.5.3p[7,8].
140    if (lhsType->isArrayType())
141      lhsType = Context.getArrayDecayedType(lhsType);
142    else if (lhsType->isFunctionType())
143      lhsType = Context.getPointerType(lhsType);
144
145    AssignConvertType Result =
146      CheckSingleAssignmentConstraints(lhsType, argExpr);
147    if (Args[i] != argExpr) // The expression was converted.
148      Args[i] = argExpr; // Make sure we store the converted expression.
149
150    anyIncompatibleArgs |=
151      DiagnoseAssignmentResult(Result, argExpr->getLocStart(), lhsType, rhsType,
152                               argExpr, "sending");
153  }
154
155  // Promote additional arguments to variadic methods.
156  if (Method->isVariadic()) {
157    for (unsigned i = NumNamedArgs; i < NumArgs; ++i)
158      DefaultArgumentPromotion(Args[i]);
159  } else {
160    // Check for extra arguments to non-variadic methods.
161    if (NumArgs != NumNamedArgs) {
162      Diag(Args[NumNamedArgs]->getLocStart(),
163           diag::err_typecheck_call_too_many_args,
164           Method->getSourceRange(),
165           SourceRange(Args[NumNamedArgs]->getLocStart(),
166                       Args[NumArgs-1]->getLocEnd()));
167    }
168  }
169
170  return anyIncompatibleArgs;
171}
172
173// ActOnClassMessage - used for both unary and keyword messages.
174// ArgExprs is optional - if it is present, the number of expressions
175// is obtained from Sel.getNumArgs().
176Sema::ExprResult Sema::ActOnClassMessage(
177  Scope *S,
178  IdentifierInfo *receiverName, Selector Sel,
179  SourceLocation lbrac, SourceLocation rbrac, ExprTy **Args, unsigned NumArgs)
180{
181  assert(receiverName && "missing receiver class name");
182
183  Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
184  ObjCInterfaceDecl* ClassDecl = 0;
185  bool isSuper = false;
186
187  if (receiverName == SuperID && getCurMethodDecl()) {
188    isSuper = true;
189    ClassDecl = getCurMethodDecl()->getClassInterface()->getSuperClass();
190    if (!ClassDecl)
191      return Diag(lbrac, diag::error_no_super_class,
192                  getCurMethodDecl()->getClassInterface()->getName());
193    if (getCurMethodDecl()->isInstance()) {
194      QualType superTy = Context.getObjCInterfaceType(ClassDecl);
195      superTy = Context.getPointerType(superTy);
196      ExprResult ReceiverExpr = new PredefinedExpr(SourceLocation(), superTy,
197          PredefinedExpr::ObjCSuper);
198      // We are really in an instance method, redirect.
199      return ActOnInstanceMessage(ReceiverExpr.Val, Sel, lbrac, rbrac,
200                                  Args, NumArgs);
201    }
202    // We are sending a message to 'super' within a class method. Do nothing,
203    // the receiver will pass through as 'super' (how convenient:-).
204  } else
205    ClassDecl = getObjCInterfaceDecl(receiverName);
206
207  // The following code allows for the following GCC-ism:
208  //
209  //  typedef XCElementDisplayRect XCElementGraphicsRect;
210  //
211  //  @implementation XCRASlice
212  //  - whatever { // Note that XCElementGraphicsRect is a typedef name.
213  //    _sGraphicsDelegate =[[XCElementGraphicsRect alloc] init];
214  //  }
215  //
216  // If necessary, the following lookup could move to getObjCInterfaceDecl().
217  if (!ClassDecl) {
218    Decl *IDecl = LookupDecl(receiverName, Decl::IDNS_Ordinary, 0, false);
219    if (TypedefDecl *OCTD = dyn_cast_or_null<TypedefDecl>(IDecl)) {
220      const ObjCInterfaceType *OCIT;
221      OCIT = OCTD->getUnderlyingType()->getAsObjCInterfaceType();
222      if (OCIT)
223        ClassDecl = OCIT->getDecl();
224    }
225  }
226  assert(ClassDecl && "missing interface declaration");
227  ObjCMethodDecl *Method = 0;
228  QualType returnType;
229  Method = ClassDecl->lookupClassMethod(Sel);
230
231  // If we have an implementation in scope, check "private" methods.
232  if (!Method) {
233    if (ObjCImplementationDecl *ImpDecl =
234        ObjCImplementations[ClassDecl->getIdentifier()])
235      Method = ImpDecl->getClassMethod(Sel);
236
237    // Look through local category implementations associated with the class.
238    if (!Method) {
239      for (unsigned i = 0; i < ObjCCategoryImpls.size() && !Method; i++) {
240        if (ObjCCategoryImpls[i]->getClassInterface() == ClassDecl)
241          Method = ObjCCategoryImpls[i]->getClassMethod(Sel);
242      }
243    }
244  }
245  // Before we give up, check if the selector is an instance method.
246  if (!Method)
247    Method = ClassDecl->lookupInstanceMethod(Sel);
248
249  if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "+",
250                                lbrac, rbrac, returnType))
251    return true;
252
253  // If we have the ObjCInterfaceDecl* for the class that is receiving
254  // the message, use that to construct the ObjCMessageExpr.  Otherwise
255  // pass on the IdentifierInfo* for the class.
256  // FIXME: need to do a better job handling 'super' usage within a class
257  // For now, we simply pass the "super" identifier through (which isn't
258  // consistent with instance methods.
259  if (isSuper)
260    return new ObjCMessageExpr(receiverName, Sel, returnType, Method,
261                               lbrac, rbrac, ArgExprs, NumArgs);
262  else
263    return new ObjCMessageExpr(ClassDecl, Sel, returnType, Method,
264                               lbrac, rbrac, ArgExprs, NumArgs);
265}
266
267// ActOnInstanceMessage - used for both unary and keyword messages.
268// ArgExprs is optional - if it is present, the number of expressions
269// is obtained from Sel.getNumArgs().
270Sema::ExprResult Sema::ActOnInstanceMessage(ExprTy *receiver, Selector Sel,
271                                            SourceLocation lbrac,
272                                            SourceLocation rbrac,
273                                            ExprTy **Args, unsigned NumArgs) {
274  assert(receiver && "missing receiver expression");
275
276  Expr **ArgExprs = reinterpret_cast<Expr **>(Args);
277  Expr *RExpr = static_cast<Expr *>(receiver);
278  QualType returnType;
279
280  QualType ReceiverCType =
281    Context.getCanonicalType(RExpr->getType()).getUnqualifiedType();
282
283  // Handle messages to id.
284  if (ReceiverCType == Context.getCanonicalType(Context.getObjCIdType()) ||
285      ReceiverCType->getAsBlockPointerType()) {
286    ObjCMethodDecl *Method = InstanceMethodPool[Sel].Method;
287    if (!Method)
288      Method = FactoryMethodPool[Sel].Method;
289    if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-",
290                                  lbrac, rbrac, returnType))
291      return true;
292    return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac,
293                               ArgExprs, NumArgs);
294  }
295
296  // Handle messages to Class.
297  if (ReceiverCType == Context.getCanonicalType(Context.getObjCClassType())) {
298    ObjCMethodDecl *Method = 0;
299    if (ObjCMethodDecl *CurMeth = getCurMethodDecl()) {
300      // If we have an implementation in scope, check "private" methods.
301      if (ObjCInterfaceDecl *ClassDecl = CurMeth->getClassInterface())
302        if (ObjCImplementationDecl *ImpDecl =
303              ObjCImplementations[ClassDecl->getIdentifier()])
304          Method = ImpDecl->getClassMethod(Sel);
305    }
306    if (!Method)
307      Method = FactoryMethodPool[Sel].Method;
308    if (!Method)
309      Method = InstanceMethodPool[Sel].Method;
310    if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-",
311                                  lbrac, rbrac, returnType))
312      return true;
313    return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac,
314                               ArgExprs, NumArgs);
315  }
316
317  ObjCMethodDecl *Method = 0;
318  ObjCInterfaceDecl* ClassDecl = 0;
319
320  // We allow sending a message to a qualified ID ("id<foo>"), which is ok as
321  // long as one of the protocols implements the selector (if not, warn).
322  if (ObjCQualifiedIdType *QIT = dyn_cast<ObjCQualifiedIdType>(ReceiverCType)) {
323    // Search protocols
324    for (unsigned i = 0; i < QIT->getNumProtocols(); i++) {
325      ObjCProtocolDecl *PDecl = QIT->getProtocols(i);
326      if (PDecl && (Method = PDecl->lookupInstanceMethod(Sel)))
327        break;
328    }
329    if (!Method)
330      Diag(lbrac, diag::warn_method_not_found_in_protocol,
331           std::string("-"), Sel.getName(),
332           RExpr->getSourceRange());
333  } else if (const ObjCInterfaceType *OCIReceiver =
334                ReceiverCType->getAsPointerToObjCInterfaceType()) {
335    // We allow sending a message to a pointer to an interface (an object).
336
337    ClassDecl = OCIReceiver->getDecl();
338    // FIXME: consider using InstanceMethodPool, since it will be faster
339    // than the following method (which can do *many* linear searches). The
340    // idea is to add class info to InstanceMethodPool.
341    Method = ClassDecl->lookupInstanceMethod(Sel);
342
343    if (!Method) {
344      // Search protocol qualifiers.
345      for (ObjCQualifiedIdType::qual_iterator QI = OCIReceiver->qual_begin(),
346           E = OCIReceiver->qual_end(); QI != E; ++QI) {
347        if ((Method = (*QI)->lookupInstanceMethod(Sel)))
348          break;
349      }
350    }
351
352    if (!Method && !OCIReceiver->qual_empty())
353      Diag(lbrac, diag::warn_method_not_found_in_protocol,
354           std::string("-"), Sel.getName(),
355           SourceRange(lbrac, rbrac));
356  } else {
357    Diag(lbrac, diag::error_bad_receiver_type,
358         RExpr->getType().getAsString(), RExpr->getSourceRange());
359    return true;
360  }
361
362  if (!Method) {
363    // If we have an implementation in scope, check "private" methods.
364    if (ClassDecl)
365      if (ObjCImplementationDecl *ImpDecl =
366            ObjCImplementations[ClassDecl->getIdentifier()])
367        Method = ImpDecl->getInstanceMethod(Sel);
368        // If we still haven't found a method, look in the global pool. This
369        // behavior isn't very desirable, however we need it for GCC
370        // compatibility.
371        if (!Method)
372          Method = InstanceMethodPool[Sel].Method;
373  }
374  if (CheckMessageArgumentTypes(ArgExprs, NumArgs, Sel, Method, "-",
375                                lbrac, rbrac, returnType))
376    return true;
377  return new ObjCMessageExpr(RExpr, Sel, returnType, Method, lbrac, rbrac,
378                             ArgExprs, NumArgs);
379}
380
381//===----------------------------------------------------------------------===//
382// ObjCQualifiedIdTypesAreCompatible - Compatibility testing for qualified id's.
383//===----------------------------------------------------------------------===//
384
385/// ProtocolCompatibleWithProtocol - return 'true' if 'lProto' is in the
386/// inheritance hierarchy of 'rProto'.
387static bool ProtocolCompatibleWithProtocol(ObjCProtocolDecl *lProto,
388                                           ObjCProtocolDecl *rProto) {
389  if (lProto == rProto)
390    return true;
391  for (ObjCProtocolDecl::protocol_iterator PI = rProto->protocol_begin(),
392       E = rProto->protocol_end(); PI != E; ++PI)
393    if (ProtocolCompatibleWithProtocol(lProto, *PI))
394      return true;
395  return false;
396}
397
398/// ClassImplementsProtocol - Checks that 'lProto' protocol
399/// has been implemented in IDecl class, its super class or categories (if
400/// lookupCategory is true).
401static bool ClassImplementsProtocol(ObjCProtocolDecl *lProto,
402                                    ObjCInterfaceDecl *IDecl,
403                                    bool lookupCategory,
404                                    bool RHSIsQualifiedID = false) {
405
406  // 1st, look up the class.
407  const ObjCList<ObjCProtocolDecl> &Protocols =
408    IDecl->getReferencedProtocols();
409
410  for (ObjCList<ObjCProtocolDecl>::iterator PI = Protocols.begin(),
411       E = Protocols.end(); PI != E; ++PI) {
412    if (ProtocolCompatibleWithProtocol(lProto, *PI))
413      return true;
414    // This is dubious and is added to be compatible with gcc.
415    // In gcc, it is also allowed assigning a protocol-qualified 'id'
416    // type to a LHS object when protocol in qualified LHS is in list
417    // of protocols in the rhs 'id' object. This IMO, should be a bug.
418    // FIXME: Treat this as an extension, and flag this as an error when
419    //  GCC extensions are not enabled.
420    if (RHSIsQualifiedID && ProtocolCompatibleWithProtocol(*PI, lProto))
421      return true;
422  }
423
424  // 2nd, look up the category.
425  if (lookupCategory)
426    for (ObjCCategoryDecl *CDecl = IDecl->getCategoryList(); CDecl;
427         CDecl = CDecl->getNextClassCategory()) {
428      for (ObjCCategoryDecl::protocol_iterator PI = CDecl->protocol_begin(),
429           E = CDecl->protocol_end(); PI != E; ++PI)
430        if (ProtocolCompatibleWithProtocol(lProto, *PI))
431          return true;
432    }
433
434  // 3rd, look up the super class(s)
435  if (IDecl->getSuperClass())
436    return
437      ClassImplementsProtocol(lProto, IDecl->getSuperClass(), lookupCategory,
438                              RHSIsQualifiedID);
439
440  return false;
441}
442
443/// ObjCQualifiedIdTypesAreCompatible - We know that one of lhs/rhs is an
444/// ObjCQualifiedIDType.
445bool Sema::ObjCQualifiedIdTypesAreCompatible(QualType lhs, QualType rhs,
446                                             bool compare) {
447  // Allow id<P..> and an 'id' or void* type in all cases.
448  if (const PointerType *PT = lhs->getAsPointerType()) {
449    QualType PointeeTy = PT->getPointeeType();
450    if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType())
451      return true;
452  } else if (const PointerType *PT = rhs->getAsPointerType()) {
453    QualType PointeeTy = PT->getPointeeType();
454    if (Context.isObjCIdType(PointeeTy) || PointeeTy->isVoidType())
455      return true;
456  }
457
458  if (const ObjCQualifiedIdType *lhsQID = lhs->getAsObjCQualifiedIdType()) {
459    const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType();
460    const ObjCQualifiedInterfaceType *rhsQI = 0;
461    QualType rtype;
462
463    if (!rhsQID) {
464      // Not comparing two ObjCQualifiedIdType's?
465      if (!rhs->isPointerType()) return false;
466
467      rtype = rhs->getAsPointerType()->getPointeeType();
468      rhsQI = rtype->getAsObjCQualifiedInterfaceType();
469      if (rhsQI == 0) {
470        // If the RHS is a unqualified interface pointer "NSString*",
471        // make sure we check the class hierarchy.
472        if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
473          ObjCInterfaceDecl *rhsID = IT->getDecl();
474          for (unsigned i = 0; i != lhsQID->getNumProtocols(); ++i) {
475            // when comparing an id<P> on lhs with a static type on rhs,
476            // see if static class implements all of id's protocols, directly or
477            // through its super class and categories.
478            if (!ClassImplementsProtocol(lhsQID->getProtocols(i), rhsID, true))
479              return false;
480          }
481          return true;
482        }
483      }
484    }
485
486    ObjCQualifiedIdType::qual_iterator RHSProtoI, RHSProtoE;
487    if (rhsQI) { // We have a qualified interface (e.g. "NSObject<Proto> *").
488      RHSProtoI = rhsQI->qual_begin();
489      RHSProtoE = rhsQI->qual_end();
490    } else if (rhsQID) { // We have a qualified id (e.g. "id<Proto> *").
491      RHSProtoI = rhsQID->qual_begin();
492      RHSProtoE = rhsQID->qual_end();
493    } else {
494      return false;
495    }
496
497    for (unsigned i =0; i < lhsQID->getNumProtocols(); i++) {
498      ObjCProtocolDecl *lhsProto = lhsQID->getProtocols(i);
499      bool match = false;
500
501      // when comparing an id<P> on lhs with a static type on rhs,
502      // see if static class implements all of id's protocols, directly or
503      // through its super class and categories.
504      for (; RHSProtoI != RHSProtoE; ++RHSProtoI) {
505        ObjCProtocolDecl *rhsProto = *RHSProtoI;
506        if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
507            compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) {
508          match = true;
509          break;
510        }
511      }
512      if (rhsQI) {
513        // If the RHS is a qualified interface pointer "NSString<P>*",
514        // make sure we check the class hierarchy.
515        if (const ObjCInterfaceType *IT = rtype->getAsObjCInterfaceType()) {
516          ObjCInterfaceDecl *rhsID = IT->getDecl();
517          for (unsigned i = 0; i != lhsQID->getNumProtocols(); ++i) {
518            // when comparing an id<P> on lhs with a static type on rhs,
519            // see if static class implements all of id's protocols, directly or
520            // through its super class and categories.
521            if (ClassImplementsProtocol(lhsQID->getProtocols(i), rhsID, true)) {
522              match = true;
523              break;
524            }
525          }
526        }
527      }
528      if (!match)
529        return false;
530    }
531
532    return true;
533  }
534
535  const ObjCQualifiedIdType *rhsQID = rhs->getAsObjCQualifiedIdType();
536  assert(rhsQID && "One of the LHS/RHS should be id<x>");
537
538  if (!lhs->isPointerType())
539    return false;
540
541  QualType ltype = lhs->getAsPointerType()->getPointeeType();
542  if (const ObjCQualifiedInterfaceType *lhsQI =
543         ltype->getAsObjCQualifiedInterfaceType()) {
544    ObjCQualifiedIdType::qual_iterator LHSProtoI = lhsQI->qual_begin();
545    ObjCQualifiedIdType::qual_iterator LHSProtoE = lhsQI->qual_end();
546    for (; LHSProtoI != LHSProtoE; ++LHSProtoI) {
547      bool match = false;
548      ObjCProtocolDecl *lhsProto = *LHSProtoI;
549      for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) {
550        ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j);
551        if (ProtocolCompatibleWithProtocol(lhsProto, rhsProto) ||
552            compare && ProtocolCompatibleWithProtocol(rhsProto, lhsProto)) {
553          match = true;
554          break;
555        }
556      }
557      if (!match)
558        return false;
559    }
560    return true;
561  }
562
563  if (const ObjCInterfaceType *IT = ltype->getAsObjCInterfaceType()) {
564    // for static type vs. qualified 'id' type, check that class implements
565    // all of 'id's protocols.
566    ObjCInterfaceDecl *lhsID = IT->getDecl();
567    for (unsigned j = 0; j < rhsQID->getNumProtocols(); j++) {
568      ObjCProtocolDecl *rhsProto = rhsQID->getProtocols(j);
569      if (!ClassImplementsProtocol(rhsProto, lhsID, compare, true))
570        return false;
571    }
572    return true;
573  }
574  return false;
575}
576
577