| //===--- 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/Expr.h" |
| |
| using namespace clang; |
| |
| NSAPI::NSAPI(ASTContext &ctx) |
| : Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0), |
| NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) { |
| } |
| |
| IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const { |
| static const char *ClassName[NumClassIds] = { |
| "NSObject", |
| "NSString", |
| "NSArray", |
| "NSMutableArray", |
| "NSDictionary", |
| "NSMutableDictionary", |
| "NSNumber" |
| }; |
| |
| 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_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]; |
| } |
| |
| llvm::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 llvm::Optional<NSStringMethodKind>(); |
| } |
| |
| 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; |
| } |
| } |
| return (NSArraySelectors[MK] = Sel); |
| } |
| |
| return NSArraySelectors[MK]; |
| } |
| |
| llvm::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 llvm::Optional<NSArrayMethodKind>(); |
| } |
| |
| 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_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; |
| } |
| } |
| return (NSDictionarySelectors[MK] = Sel); |
| } |
| |
| return NSDictionarySelectors[MK]; |
| } |
| |
| llvm::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 llvm::Optional<NSDictionaryMethodKind>(); |
| } |
| |
| 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]; |
| } |
| |
| llvm::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 llvm::Optional<NSNumberLiteralMethodKind>(); |
| } |
| |
| llvm::Optional<NSAPI::NSNumberLiteralMethodKind> |
| NSAPI::getNSNumberFactoryMethodKind(QualType T) const { |
| const BuiltinType *BT = T->getAs<BuiltinType>(); |
| if (!BT) |
| return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>(); |
| |
| 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::NullPtr: |
| case BuiltinType::ObjCClass: |
| case BuiltinType::ObjCId: |
| case BuiltinType::ObjCSel: |
| case BuiltinType::BoundMember: |
| case BuiltinType::Dependent: |
| case BuiltinType::Overload: |
| case BuiltinType::UnknownAny: |
| case BuiltinType::ARCUnbridgedCast: |
| case BuiltinType::Half: |
| case BuiltinType::PseudoObject: |
| break; |
| } |
| |
| return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>(); |
| } |
| |
| /// \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); |
| } |
| |
| 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; |
| } |