//===--- 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::OCLImage1d: | |
case BuiltinType::OCLImage1dArray: | |
case BuiltinType::OCLImage1dBuffer: | |
case BuiltinType::OCLImage2d: | |
case BuiltinType::OCLImage2dArray: | |
case BuiltinType::OCLImage3d: | |
case BuiltinType::BoundMember: | |
case BuiltinType::Dependent: | |
case BuiltinType::Overload: | |
case BuiltinType::UnknownAny: | |
case BuiltinType::ARCUnbridgedCast: | |
case BuiltinType::Half: | |
case BuiltinType::PseudoObject: | |
case BuiltinType::BuiltinFn: | |
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; | |
} |