619 lines
18 KiB
C++
619 lines
18 KiB
C++
//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#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];
|
|
}
|
|
|
|
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::Char8:
|
|
case BuiltinType::Char16:
|
|
case BuiltinType::Char32:
|
|
case BuiltinType::Int128:
|
|
case BuiltinType::LongDouble:
|
|
case BuiltinType::ShortAccum:
|
|
case BuiltinType::Accum:
|
|
case BuiltinType::LongAccum:
|
|
case BuiltinType::UShortAccum:
|
|
case BuiltinType::UAccum:
|
|
case BuiltinType::ULongAccum:
|
|
case BuiltinType::ShortFract:
|
|
case BuiltinType::Fract:
|
|
case BuiltinType::LongFract:
|
|
case BuiltinType::UShortFract:
|
|
case BuiltinType::UFract:
|
|
case BuiltinType::ULongFract:
|
|
case BuiltinType::SatShortAccum:
|
|
case BuiltinType::SatAccum:
|
|
case BuiltinType::SatLongAccum:
|
|
case BuiltinType::SatUShortAccum:
|
|
case BuiltinType::SatUAccum:
|
|
case BuiltinType::SatULongAccum:
|
|
case BuiltinType::SatShortFract:
|
|
case BuiltinType::SatFract:
|
|
case BuiltinType::SatLongFract:
|
|
case BuiltinType::SatUShortFract:
|
|
case BuiltinType::SatUFract:
|
|
case BuiltinType::SatULongFract:
|
|
case BuiltinType::UInt128:
|
|
case BuiltinType::Float16:
|
|
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"
|
|
#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
|
|
case BuiltinType::Id:
|
|
#include "clang/Basic/OpenCLExtensionTypes.def"
|
|
case BuiltinType::OCLSampler:
|
|
case BuiltinType::OCLEvent:
|
|
case BuiltinType::OCLClkEvent:
|
|
case BuiltinType::OCLQueue:
|
|
case BuiltinType::OCLReserveID:
|
|
#define SVE_TYPE(Name, Id, SingletonId) \
|
|
case BuiltinType::Id:
|
|
#include "clang/Basic/AArch64SVEACLETypes.def"
|
|
#define PPC_VECTOR_TYPE(Name, Id, Size) \
|
|
case BuiltinType::Id:
|
|
#include "clang/Basic/PPCTypes.def"
|
|
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::IncompleteMatrixIdx:
|
|
case BuiltinType::OMPArraySection:
|
|
case BuiltinType::OMPArrayShaping:
|
|
case BuiltinType::OMPIterator:
|
|
case BuiltinType::BFloat16:
|
|
break;
|
|
}
|
|
|
|
return None;
|
|
}
|
|
|
|
/// Returns true if \param T is a typedef of "BOOL" in objective-c.
|
|
bool NSAPI::isObjCBOOLType(QualType T) const {
|
|
return isObjCTypedef(T, "BOOL", BOOLId);
|
|
}
|
|
/// Returns true if \param T is a typedef of "NSInteger" in objective-c.
|
|
bool NSAPI::isObjCNSIntegerType(QualType T) const {
|
|
return isObjCTypedef(T, "NSInteger", NSIntegerId);
|
|
}
|
|
/// 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().ObjC || 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().ObjC)
|
|
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().ObjC)
|
|
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;
|
|
}
|
|
|
|
Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const {
|
|
if (Sel.isNull()) {
|
|
IdentifierInfo *Ident = &Ctx.Idents.get(Id);
|
|
Sel = Ctx.Selectors.getSelector(0, &Ident);
|
|
}
|
|
return Sel;
|
|
}
|