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
14using namespace clang;
15
16NSAPI::NSAPI(ASTContext &ctx)
17  : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr),
18    NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr),
19    NSUTF8StringEncodingId(nullptr) {}
20
21IdentifierInfo *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
38Selector 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
70Optional<NSAPI::NSStringMethodKind>
71NSAPI::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 None;
79}
80
81Selector 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
129Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
130  for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
131    NSArrayMethodKind MK = NSArrayMethodKind(i);
132    if (Sel == getNSArraySelector(MK))
133      return MK;
134  }
135
136  return None;
137}
138
139Selector NSAPI::getNSDictionarySelector(
140                                       NSDictionaryMethodKind MK) const {
141  if (NSDictionarySelectors[MK].isNull()) {
142    Selector Sel;
143    switch (MK) {
144    case NSDict_dictionary:
145      Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));
146      break;
147    case NSDict_dictionaryWithDictionary:
148      Sel = Ctx.Selectors.getUnarySelector(
149                                   &Ctx.Idents.get("dictionaryWithDictionary"));
150      break;
151    case NSDict_dictionaryWithObjectForKey: {
152      IdentifierInfo *KeyIdents[] = {
153        &Ctx.Idents.get("dictionaryWithObject"),
154        &Ctx.Idents.get("forKey")
155      };
156      Sel = Ctx.Selectors.getSelector(2, KeyIdents);
157      break;
158    }
159    case NSDict_dictionaryWithObjectsForKeys: {
160      IdentifierInfo *KeyIdents[] = {
161        &Ctx.Idents.get("dictionaryWithObjects"),
162        &Ctx.Idents.get("forKeys")
163      };
164      Sel = Ctx.Selectors.getSelector(2, KeyIdents);
165      break;
166    }
167    case NSDict_dictionaryWithObjectsForKeysCount: {
168      IdentifierInfo *KeyIdents[] = {
169        &Ctx.Idents.get("dictionaryWithObjects"),
170        &Ctx.Idents.get("forKeys"),
171        &Ctx.Idents.get("count")
172      };
173      Sel = Ctx.Selectors.getSelector(3, KeyIdents);
174      break;
175    }
176    case NSDict_dictionaryWithObjectsAndKeys:
177      Sel = Ctx.Selectors.getUnarySelector(
178                               &Ctx.Idents.get("dictionaryWithObjectsAndKeys"));
179      break;
180    case NSDict_initWithDictionary:
181      Sel = Ctx.Selectors.getUnarySelector(
182                                         &Ctx.Idents.get("initWithDictionary"));
183      break;
184    case NSDict_initWithObjectsAndKeys:
185      Sel = Ctx.Selectors.getUnarySelector(
186                                     &Ctx.Idents.get("initWithObjectsAndKeys"));
187      break;
188    case NSDict_initWithObjectsForKeys: {
189      IdentifierInfo *KeyIdents[] = {
190        &Ctx.Idents.get("initWithObjects"),
191        &Ctx.Idents.get("forKeys")
192      };
193      Sel = Ctx.Selectors.getSelector(2, KeyIdents);
194      break;
195    }
196    case NSDict_objectForKey:
197      Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
198      break;
199    case NSMutableDict_setObjectForKey: {
200      IdentifierInfo *KeyIdents[] = {
201        &Ctx.Idents.get("setObject"),
202        &Ctx.Idents.get("forKey")
203      };
204      Sel = Ctx.Selectors.getSelector(2, KeyIdents);
205      break;
206    }
207    }
208    return (NSDictionarySelectors[MK] = Sel);
209  }
210
211  return NSDictionarySelectors[MK];
212}
213
214Optional<NSAPI::NSDictionaryMethodKind>
215NSAPI::getNSDictionaryMethodKind(Selector Sel) {
216  for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
217    NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
218    if (Sel == getNSDictionarySelector(MK))
219      return MK;
220  }
221
222  return None;
223}
224
225Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
226                                           bool Instance) const {
227  static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
228    "numberWithChar",
229    "numberWithUnsignedChar",
230    "numberWithShort",
231    "numberWithUnsignedShort",
232    "numberWithInt",
233    "numberWithUnsignedInt",
234    "numberWithLong",
235    "numberWithUnsignedLong",
236    "numberWithLongLong",
237    "numberWithUnsignedLongLong",
238    "numberWithFloat",
239    "numberWithDouble",
240    "numberWithBool",
241    "numberWithInteger",
242    "numberWithUnsignedInteger"
243  };
244  static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
245    "initWithChar",
246    "initWithUnsignedChar",
247    "initWithShort",
248    "initWithUnsignedShort",
249    "initWithInt",
250    "initWithUnsignedInt",
251    "initWithLong",
252    "initWithUnsignedLong",
253    "initWithLongLong",
254    "initWithUnsignedLongLong",
255    "initWithFloat",
256    "initWithDouble",
257    "initWithBool",
258    "initWithInteger",
259    "initWithUnsignedInteger"
260  };
261
262  Selector *Sels;
263  const char **Names;
264  if (Instance) {
265    Sels = NSNumberInstanceSelectors;
266    Names = InstanceSelectorName;
267  } else {
268    Sels = NSNumberClassSelectors;
269    Names = ClassSelectorName;
270  }
271
272  if (Sels[MK].isNull())
273    Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
274  return Sels[MK];
275}
276
277Optional<NSAPI::NSNumberLiteralMethodKind>
278NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
279  for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
280    NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
281    if (isNSNumberLiteralSelector(MK, Sel))
282      return MK;
283  }
284
285  return None;
286}
287
288Optional<NSAPI::NSNumberLiteralMethodKind>
289NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
290  const BuiltinType *BT = T->getAs<BuiltinType>();
291  if (!BT)
292    return None;
293
294  const TypedefType *TDT = T->getAs<TypedefType>();
295  if (TDT) {
296    QualType TDTTy = QualType(TDT, 0);
297    if (isObjCBOOLType(TDTTy))
298      return NSAPI::NSNumberWithBool;
299    if (isObjCNSIntegerType(TDTTy))
300      return NSAPI::NSNumberWithInteger;
301    if (isObjCNSUIntegerType(TDTTy))
302      return NSAPI::NSNumberWithUnsignedInteger;
303  }
304
305  switch (BT->getKind()) {
306  case BuiltinType::Char_S:
307  case BuiltinType::SChar:
308    return NSAPI::NSNumberWithChar;
309  case BuiltinType::Char_U:
310  case BuiltinType::UChar:
311    return NSAPI::NSNumberWithUnsignedChar;
312  case BuiltinType::Short:
313    return NSAPI::NSNumberWithShort;
314  case BuiltinType::UShort:
315    return NSAPI::NSNumberWithUnsignedShort;
316  case BuiltinType::Int:
317    return NSAPI::NSNumberWithInt;
318  case BuiltinType::UInt:
319    return NSAPI::NSNumberWithUnsignedInt;
320  case BuiltinType::Long:
321    return NSAPI::NSNumberWithLong;
322  case BuiltinType::ULong:
323    return NSAPI::NSNumberWithUnsignedLong;
324  case BuiltinType::LongLong:
325    return NSAPI::NSNumberWithLongLong;
326  case BuiltinType::ULongLong:
327    return NSAPI::NSNumberWithUnsignedLongLong;
328  case BuiltinType::Float:
329    return NSAPI::NSNumberWithFloat;
330  case BuiltinType::Double:
331    return NSAPI::NSNumberWithDouble;
332  case BuiltinType::Bool:
333    return NSAPI::NSNumberWithBool;
334
335  case BuiltinType::Void:
336  case BuiltinType::WChar_U:
337  case BuiltinType::WChar_S:
338  case BuiltinType::Char16:
339  case BuiltinType::Char32:
340  case BuiltinType::Int128:
341  case BuiltinType::LongDouble:
342  case BuiltinType::UInt128:
343  case BuiltinType::NullPtr:
344  case BuiltinType::ObjCClass:
345  case BuiltinType::ObjCId:
346  case BuiltinType::ObjCSel:
347  case BuiltinType::OCLImage1d:
348  case BuiltinType::OCLImage1dArray:
349  case BuiltinType::OCLImage1dBuffer:
350  case BuiltinType::OCLImage2d:
351  case BuiltinType::OCLImage2dArray:
352  case BuiltinType::OCLImage3d:
353  case BuiltinType::OCLSampler:
354  case BuiltinType::OCLEvent:
355  case BuiltinType::BoundMember:
356  case BuiltinType::Dependent:
357  case BuiltinType::Overload:
358  case BuiltinType::UnknownAny:
359  case BuiltinType::ARCUnbridgedCast:
360  case BuiltinType::Half:
361  case BuiltinType::PseudoObject:
362  case BuiltinType::BuiltinFn:
363    break;
364  }
365
366  return None;
367}
368
369/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
370bool NSAPI::isObjCBOOLType(QualType T) const {
371  return isObjCTypedef(T, "BOOL", BOOLId);
372}
373/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
374bool NSAPI::isObjCNSIntegerType(QualType T) const {
375  return isObjCTypedef(T, "NSInteger", NSIntegerId);
376}
377/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
378bool NSAPI::isObjCNSUIntegerType(QualType T) const {
379  return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
380}
381
382bool NSAPI::isObjCTypedef(QualType T,
383                          StringRef name, IdentifierInfo *&II) const {
384  if (!Ctx.getLangOpts().ObjC1)
385    return false;
386  if (T.isNull())
387    return false;
388
389  if (!II)
390    II = &Ctx.Idents.get(name);
391
392  while (const TypedefType *TDT = T->getAs<TypedefType>()) {
393    if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
394      return true;
395    T = TDT->desugar();
396  }
397
398  return false;
399}
400
401bool NSAPI::isObjCEnumerator(const Expr *E,
402                             StringRef name, IdentifierInfo *&II) const {
403  if (!Ctx.getLangOpts().ObjC1)
404    return false;
405  if (!E)
406    return false;
407
408  if (!II)
409    II = &Ctx.Idents.get(name);
410
411  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
412    if (const EnumConstantDecl *
413          EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
414      return EnumD->getIdentifier() == II;
415
416  return false;
417}
418
419Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
420                                  Selector &Sel) const {
421  if (Sel.isNull()) {
422    SmallVector<IdentifierInfo *, 4> Idents;
423    for (ArrayRef<StringRef>::const_iterator
424           I = Ids.begin(), E = Ids.end(); I != E; ++I)
425      Idents.push_back(&Ctx.Idents.get(*I));
426    Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
427  }
428  return Sel;
429}
430