This patch adds the SVE built-in types defined by the Procedure Call Standard for the Arm Architecture: https://developer.arm.com/docs/100986/0000 It handles the types in all relevant places that deal with built-in types. At the moment, some of these places bail out with an error, including: (1) trying to generate LLVM IR for the types (2) trying to generate debug info for the types (3) trying to mangle the types using the Microsoft C++ ABI (4) trying to @encode the types in Objective C (1) and (2) are fixed by follow-on patches but (unlike this patch) they deal mostly with target-specific LLVM details, so seemed like a logically separate change. There is currently no spec for (3) and (4), so reporting an error seems like the correct behaviour for now. The intention is that the types will become sizeless types: http://lists.llvm.org/pipermail/cfe-dev/2019-June/062523.html The main purpose of the sizeless type extension is to diagnose impossible or dangerous uses of the types, such as any that would require sizeof to have a meaningful defined value. Until then, the patch sets the alignments of the types to the values specified in the link above. It also sets the sizes of the types to zero, which is chosen to be consistently wrong and shouldn't affect correctly-written code (i.e. code that would compile even with the sizeless type extension). The patch adds the common subset of functionality needed to test the sizeless type extension on the one hand and to provide SVE intrinsic functions on the other. After this patch, the two pieces of work are essentially independent. The patch is based on one by Graham Hunter: https://reviews.llvm.org/D59245 Differential Revision: https://reviews.llvm.org/D62960 llvm-svn: 368413
623 lines
18 KiB
C++
623 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];
|
|
}
|
|
|
|
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::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"
|
|
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;
|
|
}
|
|
|
|
/// 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;
|
|
}
|