600 lines · cpp
1//===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/AST/NSAPI.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/DeclObjC.h"12#include "clang/AST/Expr.h"13#include "llvm/ADT/StringSwitch.h"14#include <optional>15 16using namespace clang;17 18NSAPI::NSAPI(ASTContext &ctx)19 : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr),20 NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr),21 NSUTF8StringEncodingId(nullptr) {}22 23IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {24 static const char *ClassName[NumClassIds] = {25 "NSObject",26 "NSString",27 "NSArray",28 "NSMutableArray",29 "NSDictionary",30 "NSMutableDictionary",31 "NSNumber",32 "NSMutableSet",33 "NSMutableOrderedSet",34 "NSValue"35 };36 37 if (!ClassIds[K])38 return (ClassIds[K] = &Ctx.Idents.get(ClassName[K]));39 40 return ClassIds[K];41}42 43Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {44 if (NSStringSelectors[MK].isNull()) {45 Selector Sel;46 switch (MK) {47 case NSStr_stringWithString:48 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString"));49 break;50 case NSStr_stringWithUTF8String:51 Sel = Ctx.Selectors.getUnarySelector(52 &Ctx.Idents.get("stringWithUTF8String"));53 break;54 case NSStr_initWithUTF8String:55 Sel = Ctx.Selectors.getUnarySelector(56 &Ctx.Idents.get("initWithUTF8String"));57 break;58 case NSStr_stringWithCStringEncoding: {59 const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("stringWithCString"),60 &Ctx.Idents.get("encoding")};61 Sel = Ctx.Selectors.getSelector(2, KeyIdents);62 break;63 }64 case NSStr_stringWithCString:65 Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString"));66 break;67 case NSStr_initWithString:68 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString"));69 break;70 }71 return (NSStringSelectors[MK] = Sel);72 }73 74 return NSStringSelectors[MK];75}76 77Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {78 if (NSArraySelectors[MK].isNull()) {79 Selector Sel;80 switch (MK) {81 case NSArr_array:82 Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array"));83 break;84 case NSArr_arrayWithArray:85 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray"));86 break;87 case NSArr_arrayWithObject:88 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject"));89 break;90 case NSArr_arrayWithObjects:91 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));92 break;93 case NSArr_arrayWithObjectsCount: {94 const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("arrayWithObjects"),95 &Ctx.Idents.get("count")};96 Sel = Ctx.Selectors.getSelector(2, KeyIdents);97 break;98 }99 case NSArr_initWithArray:100 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray"));101 break;102 case NSArr_initWithObjects:103 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects"));104 break;105 case NSArr_objectAtIndex:106 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));107 break;108 case NSMutableArr_replaceObjectAtIndex: {109 const IdentifierInfo *KeyIdents[] = {110 &Ctx.Idents.get("replaceObjectAtIndex"),111 &Ctx.Idents.get("withObject")};112 Sel = Ctx.Selectors.getSelector(2, KeyIdents);113 break;114 }115 case NSMutableArr_addObject:116 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));117 break;118 case NSMutableArr_insertObjectAtIndex: {119 const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"),120 &Ctx.Idents.get("atIndex")};121 Sel = Ctx.Selectors.getSelector(2, KeyIdents);122 break;123 }124 case NSMutableArr_setObjectAtIndexedSubscript: {125 const IdentifierInfo *KeyIdents[] = {126 &Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")};127 Sel = Ctx.Selectors.getSelector(2, KeyIdents);128 break;129 }130 }131 return (NSArraySelectors[MK] = Sel);132 }133 134 return NSArraySelectors[MK];135}136 137std::optional<NSAPI::NSArrayMethodKind>138NSAPI::getNSArrayMethodKind(Selector Sel) {139 for (unsigned i = 0; i != NumNSArrayMethods; ++i) {140 NSArrayMethodKind MK = NSArrayMethodKind(i);141 if (Sel == getNSArraySelector(MK))142 return MK;143 }144 145 return std::nullopt;146}147 148Selector NSAPI::getNSDictionarySelector(149 NSDictionaryMethodKind MK) const {150 if (NSDictionarySelectors[MK].isNull()) {151 Selector Sel;152 switch (MK) {153 case NSDict_dictionary:154 Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));155 break;156 case NSDict_dictionaryWithDictionary:157 Sel = Ctx.Selectors.getUnarySelector(158 &Ctx.Idents.get("dictionaryWithDictionary"));159 break;160 case NSDict_dictionaryWithObjectForKey: {161 const IdentifierInfo *KeyIdents[] = {162 &Ctx.Idents.get("dictionaryWithObject"), &Ctx.Idents.get("forKey")};163 Sel = Ctx.Selectors.getSelector(2, KeyIdents);164 break;165 }166 case NSDict_dictionaryWithObjectsForKeys: {167 const IdentifierInfo *KeyIdents[] = {168 &Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys")};169 Sel = Ctx.Selectors.getSelector(2, KeyIdents);170 break;171 }172 case NSDict_dictionaryWithObjectsForKeysCount: {173 const IdentifierInfo *KeyIdents[] = {174 &Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys"),175 &Ctx.Idents.get("count")};176 Sel = Ctx.Selectors.getSelector(3, KeyIdents);177 break;178 }179 case NSDict_dictionaryWithObjectsAndKeys:180 Sel = Ctx.Selectors.getUnarySelector(181 &Ctx.Idents.get("dictionaryWithObjectsAndKeys"));182 break;183 case NSDict_initWithDictionary:184 Sel = Ctx.Selectors.getUnarySelector(185 &Ctx.Idents.get("initWithDictionary"));186 break;187 case NSDict_initWithObjectsAndKeys:188 Sel = Ctx.Selectors.getUnarySelector(189 &Ctx.Idents.get("initWithObjectsAndKeys"));190 break;191 case NSDict_initWithObjectsForKeys: {192 const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("initWithObjects"),193 &Ctx.Idents.get("forKeys")};194 Sel = Ctx.Selectors.getSelector(2, KeyIdents);195 break;196 }197 case NSDict_objectForKey:198 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));199 break;200 case NSMutableDict_setObjectForKey: {201 const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"),202 &Ctx.Idents.get("forKey")};203 Sel = Ctx.Selectors.getSelector(2, KeyIdents);204 break;205 }206 case NSMutableDict_setObjectForKeyedSubscript: {207 const IdentifierInfo *KeyIdents[] = {208 &Ctx.Idents.get("setObject"), &Ctx.Idents.get("forKeyedSubscript")};209 Sel = Ctx.Selectors.getSelector(2, KeyIdents);210 break;211 }212 case NSMutableDict_setValueForKey: {213 const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setValue"),214 &Ctx.Idents.get("forKey")};215 Sel = Ctx.Selectors.getSelector(2, KeyIdents);216 break;217 }218 }219 return (NSDictionarySelectors[MK] = Sel);220 }221 222 return NSDictionarySelectors[MK];223}224 225std::optional<NSAPI::NSDictionaryMethodKind>226NSAPI::getNSDictionaryMethodKind(Selector Sel) {227 for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {228 NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);229 if (Sel == getNSDictionarySelector(MK))230 return MK;231 }232 233 return std::nullopt;234}235 236Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {237 if (NSSetSelectors[MK].isNull()) {238 Selector Sel;239 switch (MK) {240 case NSMutableSet_addObject:241 Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));242 break;243 case NSOrderedSet_insertObjectAtIndex: {244 const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"),245 &Ctx.Idents.get("atIndex")};246 Sel = Ctx.Selectors.getSelector(2, KeyIdents);247 break;248 }249 case NSOrderedSet_setObjectAtIndex: {250 const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"),251 &Ctx.Idents.get("atIndex")};252 Sel = Ctx.Selectors.getSelector(2, KeyIdents);253 break;254 }255 case NSOrderedSet_setObjectAtIndexedSubscript: {256 const IdentifierInfo *KeyIdents[] = {257 &Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")};258 Sel = Ctx.Selectors.getSelector(2, KeyIdents);259 break;260 }261 case NSOrderedSet_replaceObjectAtIndexWithObject: {262 const IdentifierInfo *KeyIdents[] = {263 &Ctx.Idents.get("replaceObjectAtIndex"),264 &Ctx.Idents.get("withObject")};265 Sel = Ctx.Selectors.getSelector(2, KeyIdents);266 break;267 }268 }269 return (NSSetSelectors[MK] = Sel);270 }271 272 return NSSetSelectors[MK];273}274 275std::optional<NSAPI::NSSetMethodKind> NSAPI::getNSSetMethodKind(Selector Sel) {276 for (unsigned i = 0; i != NumNSSetMethods; ++i) {277 NSSetMethodKind MK = NSSetMethodKind(i);278 if (Sel == getNSSetSelector(MK))279 return MK;280 }281 282 return std::nullopt;283}284 285Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,286 bool Instance) const {287 static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {288 "numberWithChar",289 "numberWithUnsignedChar",290 "numberWithShort",291 "numberWithUnsignedShort",292 "numberWithInt",293 "numberWithUnsignedInt",294 "numberWithLong",295 "numberWithUnsignedLong",296 "numberWithLongLong",297 "numberWithUnsignedLongLong",298 "numberWithFloat",299 "numberWithDouble",300 "numberWithBool",301 "numberWithInteger",302 "numberWithUnsignedInteger"303 };304 static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {305 "initWithChar",306 "initWithUnsignedChar",307 "initWithShort",308 "initWithUnsignedShort",309 "initWithInt",310 "initWithUnsignedInt",311 "initWithLong",312 "initWithUnsignedLong",313 "initWithLongLong",314 "initWithUnsignedLongLong",315 "initWithFloat",316 "initWithDouble",317 "initWithBool",318 "initWithInteger",319 "initWithUnsignedInteger"320 };321 322 Selector *Sels;323 const char **Names;324 if (Instance) {325 Sels = NSNumberInstanceSelectors;326 Names = InstanceSelectorName;327 } else {328 Sels = NSNumberClassSelectors;329 Names = ClassSelectorName;330 }331 332 if (Sels[MK].isNull())333 Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));334 return Sels[MK];335}336 337std::optional<NSAPI::NSNumberLiteralMethodKind>338NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {339 for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {340 NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);341 if (isNSNumberLiteralSelector(MK, Sel))342 return MK;343 }344 345 return std::nullopt;346}347 348std::optional<NSAPI::NSNumberLiteralMethodKind>349NSAPI::getNSNumberFactoryMethodKind(QualType T) const {350 const BuiltinType *BT = T->getAs<BuiltinType>();351 if (!BT)352 return std::nullopt;353 354 const TypedefType *TDT = T->getAs<TypedefType>();355 if (TDT) {356 QualType TDTTy = QualType(TDT, 0);357 if (isObjCBOOLType(TDTTy))358 return NSAPI::NSNumberWithBool;359 if (isObjCNSIntegerType(TDTTy))360 return NSAPI::NSNumberWithInteger;361 if (isObjCNSUIntegerType(TDTTy))362 return NSAPI::NSNumberWithUnsignedInteger;363 }364 365 switch (BT->getKind()) {366 case BuiltinType::Char_S:367 case BuiltinType::SChar:368 return NSAPI::NSNumberWithChar;369 case BuiltinType::Char_U:370 case BuiltinType::UChar:371 return NSAPI::NSNumberWithUnsignedChar;372 case BuiltinType::Short:373 return NSAPI::NSNumberWithShort;374 case BuiltinType::UShort:375 return NSAPI::NSNumberWithUnsignedShort;376 case BuiltinType::Int:377 return NSAPI::NSNumberWithInt;378 case BuiltinType::UInt:379 return NSAPI::NSNumberWithUnsignedInt;380 case BuiltinType::Long:381 return NSAPI::NSNumberWithLong;382 case BuiltinType::ULong:383 return NSAPI::NSNumberWithUnsignedLong;384 case BuiltinType::LongLong:385 return NSAPI::NSNumberWithLongLong;386 case BuiltinType::ULongLong:387 return NSAPI::NSNumberWithUnsignedLongLong;388 case BuiltinType::Float:389 return NSAPI::NSNumberWithFloat;390 case BuiltinType::Double:391 return NSAPI::NSNumberWithDouble;392 case BuiltinType::Bool:393 return NSAPI::NSNumberWithBool;394 395 case BuiltinType::Void:396 case BuiltinType::WChar_U:397 case BuiltinType::WChar_S:398 case BuiltinType::Char8:399 case BuiltinType::Char16:400 case BuiltinType::Char32:401 case BuiltinType::Int128:402 case BuiltinType::LongDouble:403 case BuiltinType::ShortAccum:404 case BuiltinType::Accum:405 case BuiltinType::LongAccum:406 case BuiltinType::UShortAccum:407 case BuiltinType::UAccum:408 case BuiltinType::ULongAccum:409 case BuiltinType::ShortFract:410 case BuiltinType::Fract:411 case BuiltinType::LongFract:412 case BuiltinType::UShortFract:413 case BuiltinType::UFract:414 case BuiltinType::ULongFract:415 case BuiltinType::SatShortAccum:416 case BuiltinType::SatAccum:417 case BuiltinType::SatLongAccum:418 case BuiltinType::SatUShortAccum:419 case BuiltinType::SatUAccum:420 case BuiltinType::SatULongAccum:421 case BuiltinType::SatShortFract:422 case BuiltinType::SatFract:423 case BuiltinType::SatLongFract:424 case BuiltinType::SatUShortFract:425 case BuiltinType::SatUFract:426 case BuiltinType::SatULongFract:427 case BuiltinType::UInt128:428 case BuiltinType::Float16:429 case BuiltinType::Float128:430 case BuiltinType::Ibm128:431 case BuiltinType::NullPtr:432 case BuiltinType::ObjCClass:433 case BuiltinType::ObjCId:434 case BuiltinType::ObjCSel:435#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \436 case BuiltinType::Id:437#include "clang/Basic/OpenCLImageTypes.def"438#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \439 case BuiltinType::Id:440#include "clang/Basic/OpenCLExtensionTypes.def"441 case BuiltinType::OCLSampler:442 case BuiltinType::OCLEvent:443 case BuiltinType::OCLClkEvent:444 case BuiltinType::OCLQueue:445 case BuiltinType::OCLReserveID:446#define SVE_TYPE(Name, Id, SingletonId) \447 case BuiltinType::Id:448#include "clang/Basic/AArch64ACLETypes.def"449#define PPC_VECTOR_TYPE(Name, Id, Size) \450 case BuiltinType::Id:451#include "clang/Basic/PPCTypes.def"452#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:453#include "clang/Basic/RISCVVTypes.def"454#define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:455#include "clang/Basic/WebAssemblyReferenceTypes.def"456#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:457#include "clang/Basic/AMDGPUTypes.def"458#define HLSL_INTANGIBLE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:459#include "clang/Basic/HLSLIntangibleTypes.def"460 case BuiltinType::BoundMember:461 case BuiltinType::UnresolvedTemplate:462 case BuiltinType::Dependent:463 case BuiltinType::Overload:464 case BuiltinType::UnknownAny:465 case BuiltinType::ARCUnbridgedCast:466 case BuiltinType::Half:467 case BuiltinType::PseudoObject:468 case BuiltinType::BuiltinFn:469 case BuiltinType::IncompleteMatrixIdx:470 case BuiltinType::ArraySection:471 case BuiltinType::OMPArrayShaping:472 case BuiltinType::OMPIterator:473 case BuiltinType::BFloat16:474 break;475 }476 477 return std::nullopt;478}479 480/// Returns true if \param T is a typedef of "BOOL" in objective-c.481bool NSAPI::isObjCBOOLType(QualType T) const {482 return isObjCTypedef(T, "BOOL", BOOLId);483}484/// Returns true if \param T is a typedef of "NSInteger" in objective-c.485bool NSAPI::isObjCNSIntegerType(QualType T) const {486 return isObjCTypedef(T, "NSInteger", NSIntegerId);487}488/// Returns true if \param T is a typedef of "NSUInteger" in objective-c.489bool NSAPI::isObjCNSUIntegerType(QualType T) const {490 return isObjCTypedef(T, "NSUInteger", NSUIntegerId);491}492 493StringRef NSAPI::GetNSIntegralKind(QualType T) const {494 if (!Ctx.getLangOpts().ObjC || T.isNull())495 return StringRef();496 497 while (const TypedefType *TDT = T->getAs<TypedefType>()) {498 StringRef NSIntegralResust =499 llvm::StringSwitch<StringRef>(500 TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName())501 .Case("int8_t", "int8_t")502 .Case("int16_t", "int16_t")503 .Case("int32_t", "int32_t")504 .Case("NSInteger", "NSInteger")505 .Case("int64_t", "int64_t")506 .Case("uint8_t", "uint8_t")507 .Case("uint16_t", "uint16_t")508 .Case("uint32_t", "uint32_t")509 .Case("NSUInteger", "NSUInteger")510 .Case("uint64_t", "uint64_t")511 .Default(StringRef());512 if (!NSIntegralResust.empty())513 return NSIntegralResust;514 T = TDT->desugar();515 }516 return StringRef();517}518 519bool NSAPI::isMacroDefined(StringRef Id) const {520 // FIXME: Check whether the relevant module macros are visible.521 return Ctx.Idents.get(Id).hasMacroDefinition();522}523 524bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl,525 NSClassIdKindKind NSClassKind) const {526 if (!InterfaceDecl) {527 return false;528 }529 530 IdentifierInfo *NSClassID = getNSClassId(NSClassKind);531 532 bool IsSubclass = false;533 do {534 IsSubclass = NSClassID == InterfaceDecl->getIdentifier();535 536 if (IsSubclass) {537 break;538 }539 } while ((InterfaceDecl = InterfaceDecl->getSuperClass()));540 541 return IsSubclass;542}543 544bool NSAPI::isObjCTypedef(QualType T,545 StringRef name, IdentifierInfo *&II) const {546 if (!Ctx.getLangOpts().ObjC)547 return false;548 if (T.isNull())549 return false;550 551 if (!II)552 II = &Ctx.Idents.get(name);553 554 while (const TypedefType *TDT = T->getAs<TypedefType>()) {555 if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)556 return true;557 T = TDT->desugar();558 }559 560 return false;561}562 563bool NSAPI::isObjCEnumerator(const Expr *E,564 StringRef name, IdentifierInfo *&II) const {565 if (!Ctx.getLangOpts().ObjC)566 return false;567 if (!E)568 return false;569 570 if (!II)571 II = &Ctx.Idents.get(name);572 573 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))574 if (const EnumConstantDecl *575 EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))576 return EnumD->getIdentifier() == II;577 578 return false;579}580 581Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,582 Selector &Sel) const {583 if (Sel.isNull()) {584 SmallVector<const IdentifierInfo *, 4> Idents;585 for (ArrayRef<StringRef>::const_iterator586 I = Ids.begin(), E = Ids.end(); I != E; ++I)587 Idents.push_back(&Ctx.Idents.get(*I));588 Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());589 }590 return Sel;591}592 593Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const {594 if (Sel.isNull()) {595 const IdentifierInfo *Ident = &Ctx.Idents.get(Id);596 Sel = Ctx.Selectors.getSelector(0, &Ident);597 }598 return Sel;599}600