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