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