|  | //===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/AST/NSAPI.h" | 
|  | #include "clang/AST/ASTContext.h" | 
|  | #include "clang/AST/DeclObjC.h" | 
|  | #include "clang/AST/Expr.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  |  | 
|  | using namespace clang; | 
|  |  | 
|  | NSAPI::NSAPI(ASTContext &ctx) | 
|  | : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr), | 
|  | NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr), | 
|  | NSUTF8StringEncodingId(nullptr) {} | 
|  |  | 
|  | IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const { | 
|  | static const char *ClassName[NumClassIds] = { | 
|  | "NSObject", | 
|  | "NSString", | 
|  | "NSArray", | 
|  | "NSMutableArray", | 
|  | "NSDictionary", | 
|  | "NSMutableDictionary", | 
|  | "NSNumber", | 
|  | "NSMutableSet", | 
|  | "NSMutableOrderedSet", | 
|  | "NSValue" | 
|  | }; | 
|  |  | 
|  | if (!ClassIds[K]) | 
|  | return (ClassIds[K] = &Ctx.Idents.get(ClassName[K])); | 
|  |  | 
|  | return ClassIds[K]; | 
|  | } | 
|  |  | 
|  | Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const { | 
|  | if (NSStringSelectors[MK].isNull()) { | 
|  | Selector Sel; | 
|  | switch (MK) { | 
|  | case NSStr_stringWithString: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString")); | 
|  | break; | 
|  | case NSStr_stringWithUTF8String: | 
|  | Sel = Ctx.Selectors.getUnarySelector( | 
|  | &Ctx.Idents.get("stringWithUTF8String")); | 
|  | break; | 
|  | case NSStr_initWithUTF8String: | 
|  | Sel = Ctx.Selectors.getUnarySelector( | 
|  | &Ctx.Idents.get("initWithUTF8String")); | 
|  | break; | 
|  | case NSStr_stringWithCStringEncoding: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("stringWithCString"), | 
|  | &Ctx.Idents.get("encoding") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSStr_stringWithCString: | 
|  | Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString")); | 
|  | break; | 
|  | case NSStr_initWithString: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString")); | 
|  | break; | 
|  | } | 
|  | return (NSStringSelectors[MK] = Sel); | 
|  | } | 
|  |  | 
|  | return NSStringSelectors[MK]; | 
|  | } | 
|  |  | 
|  | Optional<NSAPI::NSStringMethodKind> | 
|  | NSAPI::getNSStringMethodKind(Selector Sel) const { | 
|  | for (unsigned i = 0; i != NumNSStringMethods; ++i) { | 
|  | NSStringMethodKind MK = NSStringMethodKind(i); | 
|  | if (Sel == getNSStringSelector(MK)) | 
|  | return MK; | 
|  | } | 
|  |  | 
|  | return None; | 
|  | } | 
|  |  | 
|  | Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const { | 
|  | if (NSArraySelectors[MK].isNull()) { | 
|  | Selector Sel; | 
|  | switch (MK) { | 
|  | case NSArr_array: | 
|  | Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array")); | 
|  | break; | 
|  | case NSArr_arrayWithArray: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray")); | 
|  | break; | 
|  | case NSArr_arrayWithObject: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject")); | 
|  | break; | 
|  | case NSArr_arrayWithObjects: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects")); | 
|  | break; | 
|  | case NSArr_arrayWithObjectsCount: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("arrayWithObjects"), | 
|  | &Ctx.Idents.get("count") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSArr_initWithArray: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray")); | 
|  | break; | 
|  | case NSArr_initWithObjects: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects")); | 
|  | break; | 
|  | case NSArr_objectAtIndex: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex")); | 
|  | break; | 
|  | case NSMutableArr_replaceObjectAtIndex: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("replaceObjectAtIndex"), | 
|  | &Ctx.Idents.get("withObject") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSMutableArr_addObject: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); | 
|  | break; | 
|  | case NSMutableArr_insertObjectAtIndex: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("insertObject"), | 
|  | &Ctx.Idents.get("atIndex") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSMutableArr_setObjectAtIndexedSubscript: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("setObject"), | 
|  | &Ctx.Idents.get("atIndexedSubscript") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | } | 
|  | return (NSArraySelectors[MK] = Sel); | 
|  | } | 
|  |  | 
|  | return NSArraySelectors[MK]; | 
|  | } | 
|  |  | 
|  | Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) { | 
|  | for (unsigned i = 0; i != NumNSArrayMethods; ++i) { | 
|  | NSArrayMethodKind MK = NSArrayMethodKind(i); | 
|  | if (Sel == getNSArraySelector(MK)) | 
|  | return MK; | 
|  | } | 
|  |  | 
|  | return None; | 
|  | } | 
|  |  | 
|  | Selector NSAPI::getNSDictionarySelector( | 
|  | NSDictionaryMethodKind MK) const { | 
|  | if (NSDictionarySelectors[MK].isNull()) { | 
|  | Selector Sel; | 
|  | switch (MK) { | 
|  | case NSDict_dictionary: | 
|  | Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary")); | 
|  | break; | 
|  | case NSDict_dictionaryWithDictionary: | 
|  | Sel = Ctx.Selectors.getUnarySelector( | 
|  | &Ctx.Idents.get("dictionaryWithDictionary")); | 
|  | break; | 
|  | case NSDict_dictionaryWithObjectForKey: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("dictionaryWithObject"), | 
|  | &Ctx.Idents.get("forKey") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSDict_dictionaryWithObjectsForKeys: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("dictionaryWithObjects"), | 
|  | &Ctx.Idents.get("forKeys") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSDict_dictionaryWithObjectsForKeysCount: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("dictionaryWithObjects"), | 
|  | &Ctx.Idents.get("forKeys"), | 
|  | &Ctx.Idents.get("count") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(3, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSDict_dictionaryWithObjectsAndKeys: | 
|  | Sel = Ctx.Selectors.getUnarySelector( | 
|  | &Ctx.Idents.get("dictionaryWithObjectsAndKeys")); | 
|  | break; | 
|  | case NSDict_initWithDictionary: | 
|  | Sel = Ctx.Selectors.getUnarySelector( | 
|  | &Ctx.Idents.get("initWithDictionary")); | 
|  | break; | 
|  | case NSDict_initWithObjectsAndKeys: | 
|  | Sel = Ctx.Selectors.getUnarySelector( | 
|  | &Ctx.Idents.get("initWithObjectsAndKeys")); | 
|  | break; | 
|  | case NSDict_initWithObjectsForKeys: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("initWithObjects"), | 
|  | &Ctx.Idents.get("forKeys") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSDict_objectForKey: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey")); | 
|  | break; | 
|  | case NSMutableDict_setObjectForKey: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("setObject"), | 
|  | &Ctx.Idents.get("forKey") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSMutableDict_setObjectForKeyedSubscript: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("setObject"), | 
|  | &Ctx.Idents.get("forKeyedSubscript") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSMutableDict_setValueForKey: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("setValue"), | 
|  | &Ctx.Idents.get("forKey") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | } | 
|  | return (NSDictionarySelectors[MK] = Sel); | 
|  | } | 
|  |  | 
|  | return NSDictionarySelectors[MK]; | 
|  | } | 
|  |  | 
|  | Optional<NSAPI::NSDictionaryMethodKind> | 
|  | NSAPI::getNSDictionaryMethodKind(Selector Sel) { | 
|  | for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) { | 
|  | NSDictionaryMethodKind MK = NSDictionaryMethodKind(i); | 
|  | if (Sel == getNSDictionarySelector(MK)) | 
|  | return MK; | 
|  | } | 
|  |  | 
|  | return None; | 
|  | } | 
|  |  | 
|  | Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const { | 
|  | if (NSSetSelectors[MK].isNull()) { | 
|  | Selector Sel; | 
|  | switch (MK) { | 
|  | case NSMutableSet_addObject: | 
|  | Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject")); | 
|  | break; | 
|  | case NSOrderedSet_insertObjectAtIndex: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("insertObject"), | 
|  | &Ctx.Idents.get("atIndex") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSOrderedSet_setObjectAtIndex: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("setObject"), | 
|  | &Ctx.Idents.get("atIndex") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSOrderedSet_setObjectAtIndexedSubscript: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("setObject"), | 
|  | &Ctx.Idents.get("atIndexedSubscript") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | case NSOrderedSet_replaceObjectAtIndexWithObject: { | 
|  | IdentifierInfo *KeyIdents[] = { | 
|  | &Ctx.Idents.get("replaceObjectAtIndex"), | 
|  | &Ctx.Idents.get("withObject") | 
|  | }; | 
|  | Sel = Ctx.Selectors.getSelector(2, KeyIdents); | 
|  | break; | 
|  | } | 
|  | } | 
|  | return (NSSetSelectors[MK] = Sel); | 
|  | } | 
|  |  | 
|  | return NSSetSelectors[MK]; | 
|  | } | 
|  |  | 
|  | Optional<NSAPI::NSSetMethodKind> | 
|  | NSAPI::getNSSetMethodKind(Selector Sel) { | 
|  | for (unsigned i = 0; i != NumNSSetMethods; ++i) { | 
|  | NSSetMethodKind MK = NSSetMethodKind(i); | 
|  | if (Sel == getNSSetSelector(MK)) | 
|  | return MK; | 
|  | } | 
|  |  | 
|  | return None; | 
|  | } | 
|  |  | 
|  | Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK, | 
|  | bool Instance) const { | 
|  | static const char *ClassSelectorName[NumNSNumberLiteralMethods] = { | 
|  | "numberWithChar", | 
|  | "numberWithUnsignedChar", | 
|  | "numberWithShort", | 
|  | "numberWithUnsignedShort", | 
|  | "numberWithInt", | 
|  | "numberWithUnsignedInt", | 
|  | "numberWithLong", | 
|  | "numberWithUnsignedLong", | 
|  | "numberWithLongLong", | 
|  | "numberWithUnsignedLongLong", | 
|  | "numberWithFloat", | 
|  | "numberWithDouble", | 
|  | "numberWithBool", | 
|  | "numberWithInteger", | 
|  | "numberWithUnsignedInteger" | 
|  | }; | 
|  | static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = { | 
|  | "initWithChar", | 
|  | "initWithUnsignedChar", | 
|  | "initWithShort", | 
|  | "initWithUnsignedShort", | 
|  | "initWithInt", | 
|  | "initWithUnsignedInt", | 
|  | "initWithLong", | 
|  | "initWithUnsignedLong", | 
|  | "initWithLongLong", | 
|  | "initWithUnsignedLongLong", | 
|  | "initWithFloat", | 
|  | "initWithDouble", | 
|  | "initWithBool", | 
|  | "initWithInteger", | 
|  | "initWithUnsignedInteger" | 
|  | }; | 
|  |  | 
|  | Selector *Sels; | 
|  | const char **Names; | 
|  | if (Instance) { | 
|  | Sels = NSNumberInstanceSelectors; | 
|  | Names = InstanceSelectorName; | 
|  | } else { | 
|  | Sels = NSNumberClassSelectors; | 
|  | Names = ClassSelectorName; | 
|  | } | 
|  |  | 
|  | if (Sels[MK].isNull()) | 
|  | Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK])); | 
|  | return Sels[MK]; | 
|  | } | 
|  |  | 
|  | Optional<NSAPI::NSNumberLiteralMethodKind> | 
|  | NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const { | 
|  | for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) { | 
|  | NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i); | 
|  | if (isNSNumberLiteralSelector(MK, Sel)) | 
|  | return MK; | 
|  | } | 
|  |  | 
|  | return None; | 
|  | } | 
|  |  | 
|  | Optional<NSAPI::NSNumberLiteralMethodKind> | 
|  | NSAPI::getNSNumberFactoryMethodKind(QualType T) const { | 
|  | const BuiltinType *BT = T->getAs<BuiltinType>(); | 
|  | if (!BT) | 
|  | return None; | 
|  |  | 
|  | const TypedefType *TDT = T->getAs<TypedefType>(); | 
|  | if (TDT) { | 
|  | QualType TDTTy = QualType(TDT, 0); | 
|  | if (isObjCBOOLType(TDTTy)) | 
|  | return NSAPI::NSNumberWithBool; | 
|  | if (isObjCNSIntegerType(TDTTy)) | 
|  | return NSAPI::NSNumberWithInteger; | 
|  | if (isObjCNSUIntegerType(TDTTy)) | 
|  | return NSAPI::NSNumberWithUnsignedInteger; | 
|  | } | 
|  |  | 
|  | switch (BT->getKind()) { | 
|  | case BuiltinType::Char_S: | 
|  | case BuiltinType::SChar: | 
|  | return NSAPI::NSNumberWithChar; | 
|  | case BuiltinType::Char_U: | 
|  | case BuiltinType::UChar: | 
|  | return NSAPI::NSNumberWithUnsignedChar; | 
|  | case BuiltinType::Short: | 
|  | return NSAPI::NSNumberWithShort; | 
|  | case BuiltinType::UShort: | 
|  | return NSAPI::NSNumberWithUnsignedShort; | 
|  | case BuiltinType::Int: | 
|  | return NSAPI::NSNumberWithInt; | 
|  | case BuiltinType::UInt: | 
|  | return NSAPI::NSNumberWithUnsignedInt; | 
|  | case BuiltinType::Long: | 
|  | return NSAPI::NSNumberWithLong; | 
|  | case BuiltinType::ULong: | 
|  | return NSAPI::NSNumberWithUnsignedLong; | 
|  | case BuiltinType::LongLong: | 
|  | return NSAPI::NSNumberWithLongLong; | 
|  | case BuiltinType::ULongLong: | 
|  | return NSAPI::NSNumberWithUnsignedLongLong; | 
|  | case BuiltinType::Float: | 
|  | return NSAPI::NSNumberWithFloat; | 
|  | case BuiltinType::Double: | 
|  | return NSAPI::NSNumberWithDouble; | 
|  | case BuiltinType::Bool: | 
|  | return NSAPI::NSNumberWithBool; | 
|  |  | 
|  | case BuiltinType::Void: | 
|  | case BuiltinType::WChar_U: | 
|  | case BuiltinType::WChar_S: | 
|  | case BuiltinType::Char16: | 
|  | case BuiltinType::Char32: | 
|  | case BuiltinType::Int128: | 
|  | case BuiltinType::LongDouble: | 
|  | case BuiltinType::UInt128: | 
|  | case BuiltinType::Float128: | 
|  | case BuiltinType::NullPtr: | 
|  | case BuiltinType::ObjCClass: | 
|  | case BuiltinType::ObjCId: | 
|  | case BuiltinType::ObjCSel: | 
|  | #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ | 
|  | case BuiltinType::Id: | 
|  | #include "clang/Basic/OpenCLImageTypes.def" | 
|  | case BuiltinType::OCLSampler: | 
|  | case BuiltinType::OCLEvent: | 
|  | case BuiltinType::OCLClkEvent: | 
|  | case BuiltinType::OCLQueue: | 
|  | case BuiltinType::OCLReserveID: | 
|  | case BuiltinType::BoundMember: | 
|  | case BuiltinType::Dependent: | 
|  | case BuiltinType::Overload: | 
|  | case BuiltinType::UnknownAny: | 
|  | case BuiltinType::ARCUnbridgedCast: | 
|  | case BuiltinType::Half: | 
|  | case BuiltinType::PseudoObject: | 
|  | case BuiltinType::BuiltinFn: | 
|  | case BuiltinType::OMPArraySection: | 
|  | break; | 
|  | } | 
|  |  | 
|  | return None; | 
|  | } | 
|  |  | 
|  | /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c. | 
|  | bool NSAPI::isObjCBOOLType(QualType T) const { | 
|  | return isObjCTypedef(T, "BOOL", BOOLId); | 
|  | } | 
|  | /// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c. | 
|  | bool NSAPI::isObjCNSIntegerType(QualType T) const { | 
|  | return isObjCTypedef(T, "NSInteger", NSIntegerId); | 
|  | } | 
|  | /// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c. | 
|  | bool NSAPI::isObjCNSUIntegerType(QualType T) const { | 
|  | return isObjCTypedef(T, "NSUInteger", NSUIntegerId); | 
|  | } | 
|  |  | 
|  | StringRef NSAPI::GetNSIntegralKind(QualType T) const { | 
|  | if (!Ctx.getLangOpts().ObjC1 || T.isNull()) | 
|  | return StringRef(); | 
|  |  | 
|  | while (const TypedefType *TDT = T->getAs<TypedefType>()) { | 
|  | StringRef NSIntegralResust = | 
|  | llvm::StringSwitch<StringRef>( | 
|  | TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName()) | 
|  | .Case("int8_t", "int8_t") | 
|  | .Case("int16_t", "int16_t") | 
|  | .Case("int32_t", "int32_t") | 
|  | .Case("NSInteger", "NSInteger") | 
|  | .Case("int64_t", "int64_t") | 
|  | .Case("uint8_t", "uint8_t") | 
|  | .Case("uint16_t", "uint16_t") | 
|  | .Case("uint32_t", "uint32_t") | 
|  | .Case("NSUInteger", "NSUInteger") | 
|  | .Case("uint64_t", "uint64_t") | 
|  | .Default(StringRef()); | 
|  | if (!NSIntegralResust.empty()) | 
|  | return NSIntegralResust; | 
|  | T = TDT->desugar(); | 
|  | } | 
|  | return StringRef(); | 
|  | } | 
|  |  | 
|  | bool NSAPI::isMacroDefined(StringRef Id) const { | 
|  | // FIXME: Check whether the relevant module macros are visible. | 
|  | return Ctx.Idents.get(Id).hasMacroDefinition(); | 
|  | } | 
|  |  | 
|  | bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl, | 
|  | NSClassIdKindKind NSClassKind) const { | 
|  | if (!InterfaceDecl) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | IdentifierInfo *NSClassID = getNSClassId(NSClassKind); | 
|  |  | 
|  | bool IsSubclass = false; | 
|  | do { | 
|  | IsSubclass = NSClassID == InterfaceDecl->getIdentifier(); | 
|  |  | 
|  | if (IsSubclass) { | 
|  | break; | 
|  | } | 
|  | } while ((InterfaceDecl = InterfaceDecl->getSuperClass())); | 
|  |  | 
|  | return IsSubclass; | 
|  | } | 
|  |  | 
|  | bool NSAPI::isObjCTypedef(QualType T, | 
|  | StringRef name, IdentifierInfo *&II) const { | 
|  | if (!Ctx.getLangOpts().ObjC1) | 
|  | return false; | 
|  | if (T.isNull()) | 
|  | return false; | 
|  |  | 
|  | if (!II) | 
|  | II = &Ctx.Idents.get(name); | 
|  |  | 
|  | while (const TypedefType *TDT = T->getAs<TypedefType>()) { | 
|  | if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II) | 
|  | return true; | 
|  | T = TDT->desugar(); | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool NSAPI::isObjCEnumerator(const Expr *E, | 
|  | StringRef name, IdentifierInfo *&II) const { | 
|  | if (!Ctx.getLangOpts().ObjC1) | 
|  | return false; | 
|  | if (!E) | 
|  | return false; | 
|  |  | 
|  | if (!II) | 
|  | II = &Ctx.Idents.get(name); | 
|  |  | 
|  | if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) | 
|  | if (const EnumConstantDecl * | 
|  | EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl())) | 
|  | return EnumD->getIdentifier() == II; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids, | 
|  | Selector &Sel) const { | 
|  | if (Sel.isNull()) { | 
|  | SmallVector<IdentifierInfo *, 4> Idents; | 
|  | for (ArrayRef<StringRef>::const_iterator | 
|  | I = Ids.begin(), E = Ids.end(); I != E; ++I) | 
|  | Idents.push_back(&Ctx.Idents.get(*I)); | 
|  | Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data()); | 
|  | } | 
|  | return Sel; | 
|  | } |