2012-12-18 22:30:41 +08:00
|
|
|
//===--- 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)
|
2014-05-12 13:36:57 +08:00
|
|
|
: Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr),
|
|
|
|
NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr),
|
|
|
|
NSUTF8StringEncodingId(nullptr) {}
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<NSAPI::NSStringMethodKind>
|
2012-12-18 22:30:41 +08:00
|
|
|
NSAPI::getNSStringMethodKind(Selector Sel) const {
|
|
|
|
for (unsigned i = 0; i != NumNSStringMethods; ++i) {
|
|
|
|
NSStringMethodKind MK = NSStringMethodKind(i);
|
|
|
|
if (Sel == getNSStringSelector(MK))
|
|
|
|
return MK;
|
|
|
|
}
|
|
|
|
|
2013-02-21 09:47:18 +08:00
|
|
|
return None;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
|
2012-12-18 22:30:41 +08:00
|
|
|
for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
|
|
|
|
NSArrayMethodKind MK = NSArrayMethodKind(i);
|
|
|
|
if (Sel == getNSArraySelector(MK))
|
|
|
|
return MK;
|
|
|
|
}
|
|
|
|
|
2013-02-21 09:47:18 +08:00
|
|
|
return None;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2013-01-17 07:54:48 +08:00
|
|
|
case NSDict_initWithObjectsForKeys: {
|
|
|
|
IdentifierInfo *KeyIdents[] = {
|
|
|
|
&Ctx.Idents.get("initWithObjects"),
|
|
|
|
&Ctx.Idents.get("forKeys")
|
|
|
|
};
|
|
|
|
Sel = Ctx.Selectors.getSelector(2, KeyIdents);
|
|
|
|
break;
|
|
|
|
}
|
2012-12-18 22:30:41 +08:00
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<NSAPI::NSDictionaryMethodKind>
|
2012-12-18 22:30:41 +08:00
|
|
|
NSAPI::getNSDictionaryMethodKind(Selector Sel) {
|
|
|
|
for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
|
|
|
|
NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
|
|
|
|
if (Sel == getNSDictionarySelector(MK))
|
|
|
|
return MK;
|
|
|
|
}
|
|
|
|
|
2013-02-21 09:47:18 +08:00
|
|
|
return None;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<NSAPI::NSNumberLiteralMethodKind>
|
2012-12-18 22:30:41 +08:00
|
|
|
NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
|
|
|
|
for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
|
|
|
|
NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
|
|
|
|
if (isNSNumberLiteralSelector(MK, Sel))
|
|
|
|
return MK;
|
|
|
|
}
|
|
|
|
|
2013-02-21 09:47:18 +08:00
|
|
|
return None;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
2013-02-21 06:23:23 +08:00
|
|
|
Optional<NSAPI::NSNumberLiteralMethodKind>
|
2012-12-18 22:30:41 +08:00
|
|
|
NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
|
|
|
|
const BuiltinType *BT = T->getAs<BuiltinType>();
|
|
|
|
if (!BT)
|
2013-02-21 09:47:18 +08:00
|
|
|
return None;
|
2012-12-18 22:30:41 +08:00
|
|
|
|
|
|
|
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:
|
2012-12-18 22:38:23 +08:00
|
|
|
case BuiltinType::OCLImage1d:
|
|
|
|
case BuiltinType::OCLImage1dArray:
|
|
|
|
case BuiltinType::OCLImage1dBuffer:
|
|
|
|
case BuiltinType::OCLImage2d:
|
|
|
|
case BuiltinType::OCLImage2dArray:
|
|
|
|
case BuiltinType::OCLImage3d:
|
2013-02-07 18:55:47 +08:00
|
|
|
case BuiltinType::OCLSampler:
|
2013-01-20 20:31:11 +08:00
|
|
|
case BuiltinType::OCLEvent:
|
2012-12-18 22:30:41 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-02-21 09:47:18 +08:00
|
|
|
return None;
|
2012-12-18 22:30:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// \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;
|
|
|
|
}
|