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