xref: /llvm-project-15.0.7/clang/lib/AST/NSAPI.cpp (revision ecafcb86)
1 //===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/AST/NSAPI.h"
11 #include "clang/AST/ASTContext.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   };
32 
33   if (!ClassIds[K])
34     return (ClassIds[K] = &Ctx.Idents.get(ClassName[K]));
35 
36   return ClassIds[K];
37 }
38 
39 Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
40   if (NSStringSelectors[MK].isNull()) {
41     Selector Sel;
42     switch (MK) {
43     case NSStr_stringWithString:
44       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString"));
45       break;
46     case NSStr_stringWithUTF8String:
47       Sel = Ctx.Selectors.getUnarySelector(
48                                        &Ctx.Idents.get("stringWithUTF8String"));
49       break;
50     case NSStr_initWithUTF8String:
51       Sel = Ctx.Selectors.getUnarySelector(
52                                        &Ctx.Idents.get("initWithUTF8String"));
53       break;
54     case NSStr_stringWithCStringEncoding: {
55       IdentifierInfo *KeyIdents[] = {
56         &Ctx.Idents.get("stringWithCString"),
57         &Ctx.Idents.get("encoding")
58       };
59       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
60       break;
61     }
62     case NSStr_stringWithCString:
63       Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString"));
64       break;
65     case NSStr_initWithString:
66       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString"));
67       break;
68     }
69     return (NSStringSelectors[MK] = Sel);
70   }
71 
72   return NSStringSelectors[MK];
73 }
74 
75 Optional<NSAPI::NSStringMethodKind>
76 NSAPI::getNSStringMethodKind(Selector Sel) const {
77   for (unsigned i = 0; i != NumNSStringMethods; ++i) {
78     NSStringMethodKind MK = NSStringMethodKind(i);
79     if (Sel == getNSStringSelector(MK))
80       return MK;
81   }
82 
83   return None;
84 }
85 
86 Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
87   if (NSArraySelectors[MK].isNull()) {
88     Selector Sel;
89     switch (MK) {
90     case NSArr_array:
91       Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array"));
92       break;
93     case NSArr_arrayWithArray:
94       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray"));
95       break;
96     case NSArr_arrayWithObject:
97       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject"));
98       break;
99     case NSArr_arrayWithObjects:
100       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));
101       break;
102     case NSArr_arrayWithObjectsCount: {
103       IdentifierInfo *KeyIdents[] = {
104         &Ctx.Idents.get("arrayWithObjects"),
105         &Ctx.Idents.get("count")
106       };
107       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
108       break;
109     }
110     case NSArr_initWithArray:
111       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray"));
112       break;
113     case NSArr_initWithObjects:
114       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects"));
115       break;
116     case NSArr_objectAtIndex:
117       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));
118       break;
119     case NSMutableArr_replaceObjectAtIndex: {
120       IdentifierInfo *KeyIdents[] = {
121         &Ctx.Idents.get("replaceObjectAtIndex"),
122         &Ctx.Idents.get("withObject")
123       };
124       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
125       break;
126     }
127     case NSArr_initWithObjectsCount: {
128       IdentifierInfo *KeyIdents[] = {
129         &Ctx.Idents.get("initWithObjects"),
130         &Ctx.Idents.get("count")
131       };
132       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
133       break;
134     }
135     }
136     return (NSArraySelectors[MK] = Sel);
137   }
138 
139   return NSArraySelectors[MK];
140 }
141 
142 Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
143   for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
144     NSArrayMethodKind MK = NSArrayMethodKind(i);
145     if (Sel == getNSArraySelector(MK))
146       return MK;
147   }
148 
149   return None;
150 }
151 
152 Selector NSAPI::getNSDictionarySelector(
153                                        NSDictionaryMethodKind MK) const {
154   if (NSDictionarySelectors[MK].isNull()) {
155     Selector Sel;
156     switch (MK) {
157     case NSDict_dictionary:
158       Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));
159       break;
160     case NSDict_dictionaryWithDictionary:
161       Sel = Ctx.Selectors.getUnarySelector(
162                                    &Ctx.Idents.get("dictionaryWithDictionary"));
163       break;
164     case NSDict_dictionaryWithObjectForKey: {
165       IdentifierInfo *KeyIdents[] = {
166         &Ctx.Idents.get("dictionaryWithObject"),
167         &Ctx.Idents.get("forKey")
168       };
169       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
170       break;
171     }
172     case NSDict_dictionaryWithObjectsForKeys: {
173       IdentifierInfo *KeyIdents[] = {
174         &Ctx.Idents.get("dictionaryWithObjects"),
175         &Ctx.Idents.get("forKeys")
176       };
177       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
178       break;
179     }
180     case NSDict_dictionaryWithObjectsForKeysCount: {
181       IdentifierInfo *KeyIdents[] = {
182         &Ctx.Idents.get("dictionaryWithObjects"),
183         &Ctx.Idents.get("forKeys"),
184         &Ctx.Idents.get("count")
185       };
186       Sel = Ctx.Selectors.getSelector(3, KeyIdents);
187       break;
188     }
189     case NSDict_dictionaryWithObjectsAndKeys:
190       Sel = Ctx.Selectors.getUnarySelector(
191                                &Ctx.Idents.get("dictionaryWithObjectsAndKeys"));
192       break;
193     case NSDict_initWithDictionary:
194       Sel = Ctx.Selectors.getUnarySelector(
195                                          &Ctx.Idents.get("initWithDictionary"));
196       break;
197     case NSDict_initWithObjectsAndKeys:
198       Sel = Ctx.Selectors.getUnarySelector(
199                                      &Ctx.Idents.get("initWithObjectsAndKeys"));
200       break;
201     case NSDict_initWithObjectsForKeys: {
202       IdentifierInfo *KeyIdents[] = {
203         &Ctx.Idents.get("initWithObjects"),
204         &Ctx.Idents.get("forKeys")
205       };
206       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
207       break;
208     }
209     case NSDict_objectForKey:
210       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
211       break;
212     case NSMutableDict_setObjectForKey: {
213       IdentifierInfo *KeyIdents[] = {
214         &Ctx.Idents.get("setObject"),
215         &Ctx.Idents.get("forKey")
216       };
217       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
218       break;
219     }
220     case NSDict_initWithObjectsForKeysCount: {
221       IdentifierInfo *KeyIdents[] = {
222         &Ctx.Idents.get("initWithObjects"),
223         &Ctx.Idents.get("forKeys"),
224         &Ctx.Idents.get("count")
225       };
226       Sel = Ctx.Selectors.getSelector(3, KeyIdents);
227       break;
228     }
229     }
230     return (NSDictionarySelectors[MK] = Sel);
231   }
232 
233   return NSDictionarySelectors[MK];
234 }
235 
236 Optional<NSAPI::NSDictionaryMethodKind>
237 NSAPI::getNSDictionaryMethodKind(Selector Sel) {
238   for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
239     NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
240     if (Sel == getNSDictionarySelector(MK))
241       return MK;
242   }
243 
244   return None;
245 }
246 
247 Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
248                                            bool Instance) const {
249   static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
250     "numberWithChar",
251     "numberWithUnsignedChar",
252     "numberWithShort",
253     "numberWithUnsignedShort",
254     "numberWithInt",
255     "numberWithUnsignedInt",
256     "numberWithLong",
257     "numberWithUnsignedLong",
258     "numberWithLongLong",
259     "numberWithUnsignedLongLong",
260     "numberWithFloat",
261     "numberWithDouble",
262     "numberWithBool",
263     "numberWithInteger",
264     "numberWithUnsignedInteger"
265   };
266   static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
267     "initWithChar",
268     "initWithUnsignedChar",
269     "initWithShort",
270     "initWithUnsignedShort",
271     "initWithInt",
272     "initWithUnsignedInt",
273     "initWithLong",
274     "initWithUnsignedLong",
275     "initWithLongLong",
276     "initWithUnsignedLongLong",
277     "initWithFloat",
278     "initWithDouble",
279     "initWithBool",
280     "initWithInteger",
281     "initWithUnsignedInteger"
282   };
283 
284   Selector *Sels;
285   const char **Names;
286   if (Instance) {
287     Sels = NSNumberInstanceSelectors;
288     Names = InstanceSelectorName;
289   } else {
290     Sels = NSNumberClassSelectors;
291     Names = ClassSelectorName;
292   }
293 
294   if (Sels[MK].isNull())
295     Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
296   return Sels[MK];
297 }
298 
299 Optional<NSAPI::NSNumberLiteralMethodKind>
300 NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
301   for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
302     NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
303     if (isNSNumberLiteralSelector(MK, Sel))
304       return MK;
305   }
306 
307   return None;
308 }
309 
310 Optional<NSAPI::NSNumberLiteralMethodKind>
311 NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
312   const BuiltinType *BT = T->getAs<BuiltinType>();
313   if (!BT)
314     return None;
315 
316   const TypedefType *TDT = T->getAs<TypedefType>();
317   if (TDT) {
318     QualType TDTTy = QualType(TDT, 0);
319     if (isObjCBOOLType(TDTTy))
320       return NSAPI::NSNumberWithBool;
321     if (isObjCNSIntegerType(TDTTy))
322       return NSAPI::NSNumberWithInteger;
323     if (isObjCNSUIntegerType(TDTTy))
324       return NSAPI::NSNumberWithUnsignedInteger;
325   }
326 
327   switch (BT->getKind()) {
328   case BuiltinType::Char_S:
329   case BuiltinType::SChar:
330     return NSAPI::NSNumberWithChar;
331   case BuiltinType::Char_U:
332   case BuiltinType::UChar:
333     return NSAPI::NSNumberWithUnsignedChar;
334   case BuiltinType::Short:
335     return NSAPI::NSNumberWithShort;
336   case BuiltinType::UShort:
337     return NSAPI::NSNumberWithUnsignedShort;
338   case BuiltinType::Int:
339     return NSAPI::NSNumberWithInt;
340   case BuiltinType::UInt:
341     return NSAPI::NSNumberWithUnsignedInt;
342   case BuiltinType::Long:
343     return NSAPI::NSNumberWithLong;
344   case BuiltinType::ULong:
345     return NSAPI::NSNumberWithUnsignedLong;
346   case BuiltinType::LongLong:
347     return NSAPI::NSNumberWithLongLong;
348   case BuiltinType::ULongLong:
349     return NSAPI::NSNumberWithUnsignedLongLong;
350   case BuiltinType::Float:
351     return NSAPI::NSNumberWithFloat;
352   case BuiltinType::Double:
353     return NSAPI::NSNumberWithDouble;
354   case BuiltinType::Bool:
355     return NSAPI::NSNumberWithBool;
356 
357   case BuiltinType::Void:
358   case BuiltinType::WChar_U:
359   case BuiltinType::WChar_S:
360   case BuiltinType::Char16:
361   case BuiltinType::Char32:
362   case BuiltinType::Int128:
363   case BuiltinType::LongDouble:
364   case BuiltinType::UInt128:
365   case BuiltinType::NullPtr:
366   case BuiltinType::ObjCClass:
367   case BuiltinType::ObjCId:
368   case BuiltinType::ObjCSel:
369   case BuiltinType::OCLImage1d:
370   case BuiltinType::OCLImage1dArray:
371   case BuiltinType::OCLImage1dBuffer:
372   case BuiltinType::OCLImage2d:
373   case BuiltinType::OCLImage2dArray:
374   case BuiltinType::OCLImage3d:
375   case BuiltinType::OCLSampler:
376   case BuiltinType::OCLEvent:
377   case BuiltinType::BoundMember:
378   case BuiltinType::Dependent:
379   case BuiltinType::Overload:
380   case BuiltinType::UnknownAny:
381   case BuiltinType::ARCUnbridgedCast:
382   case BuiltinType::Half:
383   case BuiltinType::PseudoObject:
384   case BuiltinType::BuiltinFn:
385     break;
386   }
387 
388   return None;
389 }
390 
391 /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
392 bool NSAPI::isObjCBOOLType(QualType T) const {
393   return isObjCTypedef(T, "BOOL", BOOLId);
394 }
395 /// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
396 bool NSAPI::isObjCNSIntegerType(QualType T) const {
397   return isObjCTypedef(T, "NSInteger", NSIntegerId);
398 }
399 /// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
400 bool NSAPI::isObjCNSUIntegerType(QualType T) const {
401   return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
402 }
403 
404 StringRef NSAPI::GetNSIntegralKind(QualType T) const {
405   if (!Ctx.getLangOpts().ObjC1 || T.isNull())
406     return StringRef();
407 
408   while (const TypedefType *TDT = T->getAs<TypedefType>()) {
409     StringRef NSIntegralResust =
410       llvm::StringSwitch<StringRef>(
411         TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName())
412     .Case("int8_t", "int8_t")
413     .Case("int16_t", "int16_t")
414     .Case("int32_t", "int32_t")
415     .Case("NSInteger", "NSInteger")
416     .Case("int64_t", "int64_t")
417     .Case("uint8_t", "uint8_t")
418     .Case("uint16_t", "uint16_t")
419     .Case("uint32_t", "uint32_t")
420     .Case("NSUInteger", "NSUInteger")
421     .Case("uint64_t", "uint64_t")
422     .Default(StringRef());
423     if (!NSIntegralResust.empty())
424       return NSIntegralResust;
425     T = TDT->desugar();
426   }
427   return StringRef();
428 }
429 
430 bool NSAPI::isObjCTypedef(QualType T,
431                           StringRef name, IdentifierInfo *&II) const {
432   if (!Ctx.getLangOpts().ObjC1)
433     return false;
434   if (T.isNull())
435     return false;
436 
437   if (!II)
438     II = &Ctx.Idents.get(name);
439 
440   while (const TypedefType *TDT = T->getAs<TypedefType>()) {
441     if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
442       return true;
443     T = TDT->desugar();
444   }
445 
446   return false;
447 }
448 
449 bool NSAPI::isObjCEnumerator(const Expr *E,
450                              StringRef name, IdentifierInfo *&II) const {
451   if (!Ctx.getLangOpts().ObjC1)
452     return false;
453   if (!E)
454     return false;
455 
456   if (!II)
457     II = &Ctx.Idents.get(name);
458 
459   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
460     if (const EnumConstantDecl *
461           EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
462       return EnumD->getIdentifier() == II;
463 
464   return false;
465 }
466 
467 Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
468                                   Selector &Sel) const {
469   if (Sel.isNull()) {
470     SmallVector<IdentifierInfo *, 4> Idents;
471     for (ArrayRef<StringRef>::const_iterator
472            I = Ids.begin(), E = Ids.end(); I != E; ++I)
473       Idents.push_back(&Ctx.Idents.get(*I));
474     Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
475   }
476   return Sel;
477 }
478