1 //===--- NSAPI.cpp - NSFoundation APIs ------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "clang/AST/NSAPI.h"
10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/DeclObjC.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     "NSMutableOrderedSet",
33     "NSValue"
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 
getNSArraySelector(NSArrayMethodKind MK) const78 Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
79   if (NSArraySelectors[MK].isNull()) {
80     Selector Sel;
81     switch (MK) {
82     case NSArr_array:
83       Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array"));
84       break;
85     case NSArr_arrayWithArray:
86       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray"));
87       break;
88     case NSArr_arrayWithObject:
89       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject"));
90       break;
91     case NSArr_arrayWithObjects:
92       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));
93       break;
94     case NSArr_arrayWithObjectsCount: {
95       IdentifierInfo *KeyIdents[] = {
96         &Ctx.Idents.get("arrayWithObjects"),
97         &Ctx.Idents.get("count")
98       };
99       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
100       break;
101     }
102     case NSArr_initWithArray:
103       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray"));
104       break;
105     case NSArr_initWithObjects:
106       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects"));
107       break;
108     case NSArr_objectAtIndex:
109       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));
110       break;
111     case NSMutableArr_replaceObjectAtIndex: {
112       IdentifierInfo *KeyIdents[] = {
113         &Ctx.Idents.get("replaceObjectAtIndex"),
114         &Ctx.Idents.get("withObject")
115       };
116       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
117       break;
118     }
119     case NSMutableArr_addObject:
120       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
121       break;
122     case NSMutableArr_insertObjectAtIndex: {
123       IdentifierInfo *KeyIdents[] = {
124         &Ctx.Idents.get("insertObject"),
125         &Ctx.Idents.get("atIndex")
126       };
127       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
128       break;
129     }
130     case NSMutableArr_setObjectAtIndexedSubscript: {
131       IdentifierInfo *KeyIdents[] = {
132         &Ctx.Idents.get("setObject"),
133         &Ctx.Idents.get("atIndexedSubscript")
134       };
135       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
136       break;
137     }
138     }
139     return (NSArraySelectors[MK] = Sel);
140   }
141 
142   return NSArraySelectors[MK];
143 }
144 
getNSArrayMethodKind(Selector Sel)145 Optional<NSAPI::NSArrayMethodKind> NSAPI::getNSArrayMethodKind(Selector Sel) {
146   for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
147     NSArrayMethodKind MK = NSArrayMethodKind(i);
148     if (Sel == getNSArraySelector(MK))
149       return MK;
150   }
151 
152   return None;
153 }
154 
getNSDictionarySelector(NSDictionaryMethodKind MK) const155 Selector NSAPI::getNSDictionarySelector(
156                                        NSDictionaryMethodKind MK) const {
157   if (NSDictionarySelectors[MK].isNull()) {
158     Selector Sel;
159     switch (MK) {
160     case NSDict_dictionary:
161       Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));
162       break;
163     case NSDict_dictionaryWithDictionary:
164       Sel = Ctx.Selectors.getUnarySelector(
165                                    &Ctx.Idents.get("dictionaryWithDictionary"));
166       break;
167     case NSDict_dictionaryWithObjectForKey: {
168       IdentifierInfo *KeyIdents[] = {
169         &Ctx.Idents.get("dictionaryWithObject"),
170         &Ctx.Idents.get("forKey")
171       };
172       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
173       break;
174     }
175     case NSDict_dictionaryWithObjectsForKeys: {
176       IdentifierInfo *KeyIdents[] = {
177         &Ctx.Idents.get("dictionaryWithObjects"),
178         &Ctx.Idents.get("forKeys")
179       };
180       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
181       break;
182     }
183     case NSDict_dictionaryWithObjectsForKeysCount: {
184       IdentifierInfo *KeyIdents[] = {
185         &Ctx.Idents.get("dictionaryWithObjects"),
186         &Ctx.Idents.get("forKeys"),
187         &Ctx.Idents.get("count")
188       };
189       Sel = Ctx.Selectors.getSelector(3, KeyIdents);
190       break;
191     }
192     case NSDict_dictionaryWithObjectsAndKeys:
193       Sel = Ctx.Selectors.getUnarySelector(
194                                &Ctx.Idents.get("dictionaryWithObjectsAndKeys"));
195       break;
196     case NSDict_initWithDictionary:
197       Sel = Ctx.Selectors.getUnarySelector(
198                                          &Ctx.Idents.get("initWithDictionary"));
199       break;
200     case NSDict_initWithObjectsAndKeys:
201       Sel = Ctx.Selectors.getUnarySelector(
202                                      &Ctx.Idents.get("initWithObjectsAndKeys"));
203       break;
204     case NSDict_initWithObjectsForKeys: {
205       IdentifierInfo *KeyIdents[] = {
206         &Ctx.Idents.get("initWithObjects"),
207         &Ctx.Idents.get("forKeys")
208       };
209       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
210       break;
211     }
212     case NSDict_objectForKey:
213       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
214       break;
215     case NSMutableDict_setObjectForKey: {
216       IdentifierInfo *KeyIdents[] = {
217         &Ctx.Idents.get("setObject"),
218         &Ctx.Idents.get("forKey")
219       };
220       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
221       break;
222     }
223     case NSMutableDict_setObjectForKeyedSubscript: {
224       IdentifierInfo *KeyIdents[] = {
225         &Ctx.Idents.get("setObject"),
226         &Ctx.Idents.get("forKeyedSubscript")
227       };
228       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
229       break;
230     }
231     case NSMutableDict_setValueForKey: {
232       IdentifierInfo *KeyIdents[] = {
233         &Ctx.Idents.get("setValue"),
234         &Ctx.Idents.get("forKey")
235       };
236       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
237       break;
238     }
239     }
240     return (NSDictionarySelectors[MK] = Sel);
241   }
242 
243   return NSDictionarySelectors[MK];
244 }
245 
246 Optional<NSAPI::NSDictionaryMethodKind>
getNSDictionaryMethodKind(Selector Sel)247 NSAPI::getNSDictionaryMethodKind(Selector Sel) {
248   for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
249     NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
250     if (Sel == getNSDictionarySelector(MK))
251       return MK;
252   }
253 
254   return None;
255 }
256 
getNSSetSelector(NSSetMethodKind MK) const257 Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
258   if (NSSetSelectors[MK].isNull()) {
259     Selector Sel;
260     switch (MK) {
261     case NSMutableSet_addObject:
262       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
263       break;
264     case NSOrderedSet_insertObjectAtIndex: {
265       IdentifierInfo *KeyIdents[] = {
266         &Ctx.Idents.get("insertObject"),
267         &Ctx.Idents.get("atIndex")
268       };
269       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
270       break;
271     }
272     case NSOrderedSet_setObjectAtIndex: {
273       IdentifierInfo *KeyIdents[] = {
274         &Ctx.Idents.get("setObject"),
275         &Ctx.Idents.get("atIndex")
276       };
277       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
278       break;
279     }
280     case NSOrderedSet_setObjectAtIndexedSubscript: {
281       IdentifierInfo *KeyIdents[] = {
282         &Ctx.Idents.get("setObject"),
283         &Ctx.Idents.get("atIndexedSubscript")
284       };
285       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
286       break;
287     }
288     case NSOrderedSet_replaceObjectAtIndexWithObject: {
289       IdentifierInfo *KeyIdents[] = {
290         &Ctx.Idents.get("replaceObjectAtIndex"),
291         &Ctx.Idents.get("withObject")
292       };
293       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
294       break;
295     }
296     }
297     return (NSSetSelectors[MK] = Sel);
298   }
299 
300   return NSSetSelectors[MK];
301 }
302 
303 Optional<NSAPI::NSSetMethodKind>
getNSSetMethodKind(Selector Sel)304 NSAPI::getNSSetMethodKind(Selector Sel) {
305   for (unsigned i = 0; i != NumNSSetMethods; ++i) {
306     NSSetMethodKind MK = NSSetMethodKind(i);
307     if (Sel == getNSSetSelector(MK))
308       return MK;
309   }
310 
311   return None;
312 }
313 
getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,bool Instance) const314 Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
315                                            bool Instance) const {
316   static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
317     "numberWithChar",
318     "numberWithUnsignedChar",
319     "numberWithShort",
320     "numberWithUnsignedShort",
321     "numberWithInt",
322     "numberWithUnsignedInt",
323     "numberWithLong",
324     "numberWithUnsignedLong",
325     "numberWithLongLong",
326     "numberWithUnsignedLongLong",
327     "numberWithFloat",
328     "numberWithDouble",
329     "numberWithBool",
330     "numberWithInteger",
331     "numberWithUnsignedInteger"
332   };
333   static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
334     "initWithChar",
335     "initWithUnsignedChar",
336     "initWithShort",
337     "initWithUnsignedShort",
338     "initWithInt",
339     "initWithUnsignedInt",
340     "initWithLong",
341     "initWithUnsignedLong",
342     "initWithLongLong",
343     "initWithUnsignedLongLong",
344     "initWithFloat",
345     "initWithDouble",
346     "initWithBool",
347     "initWithInteger",
348     "initWithUnsignedInteger"
349   };
350 
351   Selector *Sels;
352   const char **Names;
353   if (Instance) {
354     Sels = NSNumberInstanceSelectors;
355     Names = InstanceSelectorName;
356   } else {
357     Sels = NSNumberClassSelectors;
358     Names = ClassSelectorName;
359   }
360 
361   if (Sels[MK].isNull())
362     Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
363   return Sels[MK];
364 }
365 
366 Optional<NSAPI::NSNumberLiteralMethodKind>
getNSNumberLiteralMethodKind(Selector Sel) const367 NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
368   for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
369     NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
370     if (isNSNumberLiteralSelector(MK, Sel))
371       return MK;
372   }
373 
374   return None;
375 }
376 
377 Optional<NSAPI::NSNumberLiteralMethodKind>
getNSNumberFactoryMethodKind(QualType T) const378 NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
379   const BuiltinType *BT = T->getAs<BuiltinType>();
380   if (!BT)
381     return None;
382 
383   const TypedefType *TDT = T->getAs<TypedefType>();
384   if (TDT) {
385     QualType TDTTy = QualType(TDT, 0);
386     if (isObjCBOOLType(TDTTy))
387       return NSAPI::NSNumberWithBool;
388     if (isObjCNSIntegerType(TDTTy))
389       return NSAPI::NSNumberWithInteger;
390     if (isObjCNSUIntegerType(TDTTy))
391       return NSAPI::NSNumberWithUnsignedInteger;
392   }
393 
394   switch (BT->getKind()) {
395   case BuiltinType::Char_S:
396   case BuiltinType::SChar:
397     return NSAPI::NSNumberWithChar;
398   case BuiltinType::Char_U:
399   case BuiltinType::UChar:
400     return NSAPI::NSNumberWithUnsignedChar;
401   case BuiltinType::Short:
402     return NSAPI::NSNumberWithShort;
403   case BuiltinType::UShort:
404     return NSAPI::NSNumberWithUnsignedShort;
405   case BuiltinType::Int:
406     return NSAPI::NSNumberWithInt;
407   case BuiltinType::UInt:
408     return NSAPI::NSNumberWithUnsignedInt;
409   case BuiltinType::Long:
410     return NSAPI::NSNumberWithLong;
411   case BuiltinType::ULong:
412     return NSAPI::NSNumberWithUnsignedLong;
413   case BuiltinType::LongLong:
414     return NSAPI::NSNumberWithLongLong;
415   case BuiltinType::ULongLong:
416     return NSAPI::NSNumberWithUnsignedLongLong;
417   case BuiltinType::Float:
418     return NSAPI::NSNumberWithFloat;
419   case BuiltinType::Double:
420     return NSAPI::NSNumberWithDouble;
421   case BuiltinType::Bool:
422     return NSAPI::NSNumberWithBool;
423 
424   case BuiltinType::IntCap:
425   case BuiltinType::UIntCap:
426   case BuiltinType::Void:
427   case BuiltinType::WChar_U:
428   case BuiltinType::WChar_S:
429   case BuiltinType::Char8:
430   case BuiltinType::Char16:
431   case BuiltinType::Char32:
432   case BuiltinType::Int128:
433   case BuiltinType::LongDouble:
434   case BuiltinType::ShortAccum:
435   case BuiltinType::Accum:
436   case BuiltinType::LongAccum:
437   case BuiltinType::UShortAccum:
438   case BuiltinType::UAccum:
439   case BuiltinType::ULongAccum:
440   case BuiltinType::ShortFract:
441   case BuiltinType::Fract:
442   case BuiltinType::LongFract:
443   case BuiltinType::UShortFract:
444   case BuiltinType::UFract:
445   case BuiltinType::ULongFract:
446   case BuiltinType::SatShortAccum:
447   case BuiltinType::SatAccum:
448   case BuiltinType::SatLongAccum:
449   case BuiltinType::SatUShortAccum:
450   case BuiltinType::SatUAccum:
451   case BuiltinType::SatULongAccum:
452   case BuiltinType::SatShortFract:
453   case BuiltinType::SatFract:
454   case BuiltinType::SatLongFract:
455   case BuiltinType::SatUShortFract:
456   case BuiltinType::SatUFract:
457   case BuiltinType::SatULongFract:
458   case BuiltinType::UInt128:
459   case BuiltinType::Float16:
460   case BuiltinType::Float128:
461   case BuiltinType::NullPtr:
462   case BuiltinType::ObjCClass:
463   case BuiltinType::ObjCId:
464   case BuiltinType::ObjCSel:
465 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
466   case BuiltinType::Id:
467 #include "clang/Basic/OpenCLImageTypes.def"
468 #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
469   case BuiltinType::Id:
470 #include "clang/Basic/OpenCLExtensionTypes.def"
471   case BuiltinType::OCLSampler:
472   case BuiltinType::OCLEvent:
473   case BuiltinType::OCLClkEvent:
474   case BuiltinType::OCLQueue:
475   case BuiltinType::OCLReserveID:
476 #define SVE_TYPE(Name, Id, SingletonId) \
477   case BuiltinType::Id:
478 #include "clang/Basic/AArch64SVEACLETypes.def"
479   case BuiltinType::BoundMember:
480   case BuiltinType::Dependent:
481   case BuiltinType::Overload:
482   case BuiltinType::UnknownAny:
483   case BuiltinType::ARCUnbridgedCast:
484   case BuiltinType::Half:
485   case BuiltinType::PseudoObject:
486   case BuiltinType::BuiltinFn:
487   case BuiltinType::IncompleteMatrixIdx:
488   case BuiltinType::OMPArraySection:
489   case BuiltinType::OMPArrayShaping:
490   case BuiltinType::OMPIterator:
491   case BuiltinType::BFloat16:
492     break;
493   }
494 
495   return None;
496 }
497 
498 /// Returns true if \param T is a typedef of "BOOL" in objective-c.
isObjCBOOLType(QualType T) const499 bool NSAPI::isObjCBOOLType(QualType T) const {
500   return isObjCTypedef(T, "BOOL", BOOLId);
501 }
502 /// Returns true if \param T is a typedef of "NSInteger" in objective-c.
isObjCNSIntegerType(QualType T) const503 bool NSAPI::isObjCNSIntegerType(QualType T) const {
504   return isObjCTypedef(T, "NSInteger", NSIntegerId);
505 }
506 /// Returns true if \param T is a typedef of "NSUInteger" in objective-c.
isObjCNSUIntegerType(QualType T) const507 bool NSAPI::isObjCNSUIntegerType(QualType T) const {
508   return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
509 }
510 
GetNSIntegralKind(QualType T) const511 StringRef NSAPI::GetNSIntegralKind(QualType T) const {
512   if (!Ctx.getLangOpts().ObjC || T.isNull())
513     return StringRef();
514 
515   while (const TypedefType *TDT = T->getAs<TypedefType>()) {
516     StringRef NSIntegralResust =
517       llvm::StringSwitch<StringRef>(
518         TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName())
519     .Case("int8_t", "int8_t")
520     .Case("int16_t", "int16_t")
521     .Case("int32_t", "int32_t")
522     .Case("NSInteger", "NSInteger")
523     .Case("int64_t", "int64_t")
524     .Case("uint8_t", "uint8_t")
525     .Case("uint16_t", "uint16_t")
526     .Case("uint32_t", "uint32_t")
527     .Case("NSUInteger", "NSUInteger")
528     .Case("uint64_t", "uint64_t")
529     .Default(StringRef());
530     if (!NSIntegralResust.empty())
531       return NSIntegralResust;
532     T = TDT->desugar();
533   }
534   return StringRef();
535 }
536 
isMacroDefined(StringRef Id) const537 bool NSAPI::isMacroDefined(StringRef Id) const {
538   // FIXME: Check whether the relevant module macros are visible.
539   return Ctx.Idents.get(Id).hasMacroDefinition();
540 }
541 
isSubclassOfNSClass(ObjCInterfaceDecl * InterfaceDecl,NSClassIdKindKind NSClassKind) const542 bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl,
543                                 NSClassIdKindKind NSClassKind) const {
544   if (!InterfaceDecl) {
545     return false;
546   }
547 
548   IdentifierInfo *NSClassID = getNSClassId(NSClassKind);
549 
550   bool IsSubclass = false;
551   do {
552     IsSubclass = NSClassID == InterfaceDecl->getIdentifier();
553 
554     if (IsSubclass) {
555       break;
556     }
557   } while ((InterfaceDecl = InterfaceDecl->getSuperClass()));
558 
559   return IsSubclass;
560 }
561 
isObjCTypedef(QualType T,StringRef name,IdentifierInfo * & II) const562 bool NSAPI::isObjCTypedef(QualType T,
563                           StringRef name, IdentifierInfo *&II) const {
564   if (!Ctx.getLangOpts().ObjC)
565     return false;
566   if (T.isNull())
567     return false;
568 
569   if (!II)
570     II = &Ctx.Idents.get(name);
571 
572   while (const TypedefType *TDT = T->getAs<TypedefType>()) {
573     if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
574       return true;
575     T = TDT->desugar();
576   }
577 
578   return false;
579 }
580 
isObjCEnumerator(const Expr * E,StringRef name,IdentifierInfo * & II) const581 bool NSAPI::isObjCEnumerator(const Expr *E,
582                              StringRef name, IdentifierInfo *&II) const {
583   if (!Ctx.getLangOpts().ObjC)
584     return false;
585   if (!E)
586     return false;
587 
588   if (!II)
589     II = &Ctx.Idents.get(name);
590 
591   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
592     if (const EnumConstantDecl *
593           EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
594       return EnumD->getIdentifier() == II;
595 
596   return false;
597 }
598 
getOrInitSelector(ArrayRef<StringRef> Ids,Selector & Sel) const599 Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
600                                   Selector &Sel) const {
601   if (Sel.isNull()) {
602     SmallVector<IdentifierInfo *, 4> Idents;
603     for (ArrayRef<StringRef>::const_iterator
604            I = Ids.begin(), E = Ids.end(); I != E; ++I)
605       Idents.push_back(&Ctx.Idents.get(*I));
606     Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
607   }
608   return Sel;
609 }
610 
getOrInitNullarySelector(StringRef Id,Selector & Sel) const611 Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const {
612   if (Sel.isNull()) {
613     IdentifierInfo *Ident = &Ctx.Idents.get(Id);
614     Sel = Ctx.Selectors.getSelector(0, &Ident);
615   }
616   return Sel;
617 }
618