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