xref: /llvm-project-15.0.7/clang/lib/AST/NSAPI.cpp (revision 433c8a1f)
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_objectForKey:
190       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
191       break;
192     case NSMutableDict_setObjectForKey: {
193       IdentifierInfo *KeyIdents[] = {
194         &Ctx.Idents.get("setObject"),
195         &Ctx.Idents.get("forKey")
196       };
197       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
198       break;
199     }
200     }
201     return (NSDictionarySelectors[MK] = Sel);
202   }
203 
204   return NSDictionarySelectors[MK];
205 }
206 
207 llvm::Optional<NSAPI::NSDictionaryMethodKind>
208 NSAPI::getNSDictionaryMethodKind(Selector Sel) {
209   for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
210     NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
211     if (Sel == getNSDictionarySelector(MK))
212       return MK;
213   }
214 
215   return llvm::Optional<NSDictionaryMethodKind>();
216 }
217 
218 Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
219                                            bool Instance) const {
220   static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
221     "numberWithChar",
222     "numberWithUnsignedChar",
223     "numberWithShort",
224     "numberWithUnsignedShort",
225     "numberWithInt",
226     "numberWithUnsignedInt",
227     "numberWithLong",
228     "numberWithUnsignedLong",
229     "numberWithLongLong",
230     "numberWithUnsignedLongLong",
231     "numberWithFloat",
232     "numberWithDouble",
233     "numberWithBool",
234     "numberWithInteger",
235     "numberWithUnsignedInteger"
236   };
237   static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
238     "initWithChar",
239     "initWithUnsignedChar",
240     "initWithShort",
241     "initWithUnsignedShort",
242     "initWithInt",
243     "initWithUnsignedInt",
244     "initWithLong",
245     "initWithUnsignedLong",
246     "initWithLongLong",
247     "initWithUnsignedLongLong",
248     "initWithFloat",
249     "initWithDouble",
250     "initWithBool",
251     "initWithInteger",
252     "initWithUnsignedInteger"
253   };
254 
255   Selector *Sels;
256   const char **Names;
257   if (Instance) {
258     Sels = NSNumberInstanceSelectors;
259     Names = InstanceSelectorName;
260   } else {
261     Sels = NSNumberClassSelectors;
262     Names = ClassSelectorName;
263   }
264 
265   if (Sels[MK].isNull())
266     Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
267   return Sels[MK];
268 }
269 
270 llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
271 NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
272   for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
273     NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
274     if (isNSNumberLiteralSelector(MK, Sel))
275       return MK;
276   }
277 
278   return llvm::Optional<NSNumberLiteralMethodKind>();
279 }
280 
281 llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
282 NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
283   const BuiltinType *BT = T->getAs<BuiltinType>();
284   if (!BT)
285     return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
286 
287   const TypedefType *TDT = T->getAs<TypedefType>();
288   if (TDT) {
289     QualType TDTTy = QualType(TDT, 0);
290     if (isObjCBOOLType(TDTTy))
291       return NSAPI::NSNumberWithBool;
292     if (isObjCNSIntegerType(TDTTy))
293       return NSAPI::NSNumberWithInteger;
294     if (isObjCNSUIntegerType(TDTTy))
295       return NSAPI::NSNumberWithUnsignedInteger;
296   }
297 
298   switch (BT->getKind()) {
299   case BuiltinType::Char_S:
300   case BuiltinType::SChar:
301     return NSAPI::NSNumberWithChar;
302   case BuiltinType::Char_U:
303   case BuiltinType::UChar:
304     return NSAPI::NSNumberWithUnsignedChar;
305   case BuiltinType::Short:
306     return NSAPI::NSNumberWithShort;
307   case BuiltinType::UShort:
308     return NSAPI::NSNumberWithUnsignedShort;
309   case BuiltinType::Int:
310     return NSAPI::NSNumberWithInt;
311   case BuiltinType::UInt:
312     return NSAPI::NSNumberWithUnsignedInt;
313   case BuiltinType::Long:
314     return NSAPI::NSNumberWithLong;
315   case BuiltinType::ULong:
316     return NSAPI::NSNumberWithUnsignedLong;
317   case BuiltinType::LongLong:
318     return NSAPI::NSNumberWithLongLong;
319   case BuiltinType::ULongLong:
320     return NSAPI::NSNumberWithUnsignedLongLong;
321   case BuiltinType::Float:
322     return NSAPI::NSNumberWithFloat;
323   case BuiltinType::Double:
324     return NSAPI::NSNumberWithDouble;
325   case BuiltinType::Bool:
326     return NSAPI::NSNumberWithBool;
327 
328   case BuiltinType::Void:
329   case BuiltinType::WChar_U:
330   case BuiltinType::WChar_S:
331   case BuiltinType::Char16:
332   case BuiltinType::Char32:
333   case BuiltinType::Int128:
334   case BuiltinType::LongDouble:
335   case BuiltinType::UInt128:
336   case BuiltinType::NullPtr:
337   case BuiltinType::ObjCClass:
338   case BuiltinType::ObjCId:
339   case BuiltinType::ObjCSel:
340   case BuiltinType::BoundMember:
341   case BuiltinType::Dependent:
342   case BuiltinType::Overload:
343   case BuiltinType::UnknownAny:
344   case BuiltinType::ARCUnbridgedCast:
345   case BuiltinType::Half:
346   case BuiltinType::PseudoObject:
347     break;
348   }
349 
350   return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
351 }
352 
353 /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
354 bool NSAPI::isObjCBOOLType(QualType T) const {
355   return isObjCTypedef(T, "BOOL", BOOLId);
356 }
357 /// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
358 bool NSAPI::isObjCNSIntegerType(QualType T) const {
359   return isObjCTypedef(T, "NSInteger", NSIntegerId);
360 }
361 /// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
362 bool NSAPI::isObjCNSUIntegerType(QualType T) const {
363   return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
364 }
365 
366 bool NSAPI::isObjCTypedef(QualType T,
367                           StringRef name, IdentifierInfo *&II) const {
368   if (!Ctx.getLangOpts().ObjC1)
369     return false;
370   if (T.isNull())
371     return false;
372 
373   if (!II)
374     II = &Ctx.Idents.get(name);
375 
376   while (const TypedefType *TDT = T->getAs<TypedefType>()) {
377     if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
378       return true;
379     T = TDT->desugar();
380   }
381 
382   return false;
383 }
384 
385 bool NSAPI::isObjCEnumerator(const Expr *E,
386                              StringRef name, IdentifierInfo *&II) const {
387   if (!Ctx.getLangOpts().ObjC1)
388     return false;
389   if (!E)
390     return false;
391 
392   if (!II)
393     II = &Ctx.Idents.get(name);
394 
395   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
396     if (const EnumConstantDecl *
397           EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
398       return EnumD->getIdentifier() == II;
399 
400   return false;
401 }
402 
403 Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
404                                   Selector &Sel) const {
405   if (Sel.isNull()) {
406     SmallVector<IdentifierInfo *, 4> Idents;
407     for (ArrayRef<StringRef>::const_iterator
408            I = Ids.begin(), E = Ids.end(); I != E; ++I)
409       Idents.push_back(&Ctx.Idents.get(*I));
410     Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
411   }
412   return Sel;
413 }
414