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