• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
NSAPI(ASTContext & ctx)16 NSAPI::NSAPI(ASTContext &ctx)
17   : Ctx(ctx), ClassIds(), BOOLId(0), NSIntegerId(0), NSUIntegerId(0),
18     NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) {
19 }
20 
getNSClassId(NSClassIdKindKind K) const21 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 
getNSStringSelector(NSStringMethodKind MK) const38 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>
getNSStringMethodKind(Selector Sel) const71 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 
getNSArraySelector(NSArrayMethodKind MK) const81 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>
getNSArrayMethodKind(Selector Sel)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 
getNSDictionarySelector(NSDictionaryMethodKind MK) const140 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>
getNSDictionaryMethodKind(Selector Sel)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 
getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,bool Instance) const218 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>
getNSNumberLiteralMethodKind(Selector Sel) const271 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>
getNSNumberFactoryMethodKind(QualType T) const282 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   case BuiltinType::BuiltinFn:
348     break;
349   }
350 
351   return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
352 }
353 
354 /// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
isObjCBOOLType(QualType T) const355 bool NSAPI::isObjCBOOLType(QualType T) const {
356   return isObjCTypedef(T, "BOOL", BOOLId);
357 }
358 /// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
isObjCNSIntegerType(QualType T) const359 bool NSAPI::isObjCNSIntegerType(QualType T) const {
360   return isObjCTypedef(T, "NSInteger", NSIntegerId);
361 }
362 /// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
isObjCNSUIntegerType(QualType T) const363 bool NSAPI::isObjCNSUIntegerType(QualType T) const {
364   return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
365 }
366 
isObjCTypedef(QualType T,StringRef name,IdentifierInfo * & II) const367 bool NSAPI::isObjCTypedef(QualType T,
368                           StringRef name, IdentifierInfo *&II) const {
369   if (!Ctx.getLangOpts().ObjC1)
370     return false;
371   if (T.isNull())
372     return false;
373 
374   if (!II)
375     II = &Ctx.Idents.get(name);
376 
377   while (const TypedefType *TDT = T->getAs<TypedefType>()) {
378     if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
379       return true;
380     T = TDT->desugar();
381   }
382 
383   return false;
384 }
385 
isObjCEnumerator(const Expr * E,StringRef name,IdentifierInfo * & II) const386 bool NSAPI::isObjCEnumerator(const Expr *E,
387                              StringRef name, IdentifierInfo *&II) const {
388   if (!Ctx.getLangOpts().ObjC1)
389     return false;
390   if (!E)
391     return false;
392 
393   if (!II)
394     II = &Ctx.Idents.get(name);
395 
396   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
397     if (const EnumConstantDecl *
398           EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
399       return EnumD->getIdentifier() == II;
400 
401   return false;
402 }
403 
getOrInitSelector(ArrayRef<StringRef> Ids,Selector & Sel) const404 Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
405                                   Selector &Sel) const {
406   if (Sel.isNull()) {
407     SmallVector<IdentifierInfo *, 4> Idents;
408     for (ArrayRef<StringRef>::const_iterator
409            I = Ids.begin(), E = Ids.end(); I != E; ++I)
410       Idents.push_back(&Ctx.Idents.get(*I));
411     Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
412   }
413   return Sel;
414 }
415