//===--- 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::OCLNDRange:
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;
}