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