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(0), NSIntegerId(0), NSUIntegerId(0),
18    NSASCIIStringEncodingId(0), NSUTF8StringEncodingId(0) {
19}
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
70llvm::Optional<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 llvm::Optional<NSStringMethodKind>();
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
129llvm::Optional<NSAPI::NSArrayMethodKind>
130NSAPI::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
140Selector 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
207llvm::Optional<NSAPI::NSDictionaryMethodKind>
208NSAPI::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
218Selector 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
270llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
271NSAPI::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
281llvm::Optional<NSAPI::NSNumberLiteralMethodKind>
282NSAPI::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.
355bool 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.
359bool 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.
363bool NSAPI::isObjCNSUIntegerType(QualType T) const {
364  return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
365}
366
367bool 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
386bool 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
404Selector 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