NSAPI.cpp revision 239462
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    break;
348  }
349
350  return llvm::Optional<NSAPI::NSNumberLiteralMethodKind>();
351}
352
353/// \brief Returns true if \param T is a typedef of "BOOL" in objective-c.
354bool NSAPI::isObjCBOOLType(QualType T) const {
355  return isObjCTypedef(T, "BOOL", BOOLId);
356}
357/// \brief Returns true if \param T is a typedef of "NSInteger" in objective-c.
358bool NSAPI::isObjCNSIntegerType(QualType T) const {
359  return isObjCTypedef(T, "NSInteger", NSIntegerId);
360}
361/// \brief Returns true if \param T is a typedef of "NSUInteger" in objective-c.
362bool NSAPI::isObjCNSUIntegerType(QualType T) const {
363  return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
364}
365
366bool NSAPI::isObjCTypedef(QualType T,
367                          StringRef name, IdentifierInfo *&II) const {
368  if (!Ctx.getLangOpts().ObjC1)
369    return false;
370  if (T.isNull())
371    return false;
372
373  if (!II)
374    II = &Ctx.Idents.get(name);
375
376  while (const TypedefType *TDT = T->getAs<TypedefType>()) {
377    if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
378      return true;
379    T = TDT->desugar();
380  }
381
382  return false;
383}
384
385bool NSAPI::isObjCEnumerator(const Expr *E,
386                             StringRef name, IdentifierInfo *&II) const {
387  if (!Ctx.getLangOpts().ObjC1)
388    return false;
389  if (!E)
390    return false;
391
392  if (!II)
393    II = &Ctx.Idents.get(name);
394
395  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
396    if (const EnumConstantDecl *
397          EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
398      return EnumD->getIdentifier() == II;
399
400  return false;
401}
402
403Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
404                                  Selector &Sel) const {
405  if (Sel.isNull()) {
406    SmallVector<IdentifierInfo *, 4> Idents;
407    for (ArrayRef<StringRef>::const_iterator
408           I = Ids.begin(), E = Ids.end(); I != E; ++I)
409      Idents.push_back(&Ctx.Idents.get(*I));
410    Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
411  }
412  return Sel;
413}
414