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