xref: /freebsd/contrib/llvm-project/clang/lib/AST/NSAPI.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 #include <optional>
15 
16 using namespace clang;
17 
NSAPI(ASTContext & ctx)18 NSAPI::NSAPI(ASTContext &ctx)
19   : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr),
20     NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr),
21     NSUTF8StringEncodingId(nullptr) {}
22 
getNSClassId(NSClassIdKindKind K) const23 IdentifierInfo *NSAPI::getNSClassId(NSClassIdKindKind K) const {
24   static const char *ClassName[NumClassIds] = {
25     "NSObject",
26     "NSString",
27     "NSArray",
28     "NSMutableArray",
29     "NSDictionary",
30     "NSMutableDictionary",
31     "NSNumber",
32     "NSMutableSet",
33     "NSMutableOrderedSet",
34     "NSValue"
35   };
36 
37   if (!ClassIds[K])
38     return (ClassIds[K] = &Ctx.Idents.get(ClassName[K]));
39 
40   return ClassIds[K];
41 }
42 
getNSStringSelector(NSStringMethodKind MK) const43 Selector NSAPI::getNSStringSelector(NSStringMethodKind MK) const {
44   if (NSStringSelectors[MK].isNull()) {
45     Selector Sel;
46     switch (MK) {
47     case NSStr_stringWithString:
48       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithString"));
49       break;
50     case NSStr_stringWithUTF8String:
51       Sel = Ctx.Selectors.getUnarySelector(
52                                        &Ctx.Idents.get("stringWithUTF8String"));
53       break;
54     case NSStr_initWithUTF8String:
55       Sel = Ctx.Selectors.getUnarySelector(
56                                        &Ctx.Idents.get("initWithUTF8String"));
57       break;
58     case NSStr_stringWithCStringEncoding: {
59       const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("stringWithCString"),
60                                            &Ctx.Idents.get("encoding")};
61       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
62       break;
63     }
64     case NSStr_stringWithCString:
65       Sel= Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("stringWithCString"));
66       break;
67     case NSStr_initWithString:
68       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithString"));
69       break;
70     }
71     return (NSStringSelectors[MK] = Sel);
72   }
73 
74   return NSStringSelectors[MK];
75 }
76 
getNSArraySelector(NSArrayMethodKind MK) const77 Selector NSAPI::getNSArraySelector(NSArrayMethodKind MK) const {
78   if (NSArraySelectors[MK].isNull()) {
79     Selector Sel;
80     switch (MK) {
81     case NSArr_array:
82       Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("array"));
83       break;
84     case NSArr_arrayWithArray:
85       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithArray"));
86       break;
87     case NSArr_arrayWithObject:
88       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObject"));
89       break;
90     case NSArr_arrayWithObjects:
91       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("arrayWithObjects"));
92       break;
93     case NSArr_arrayWithObjectsCount: {
94       const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("arrayWithObjects"),
95                                            &Ctx.Idents.get("count")};
96       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
97       break;
98     }
99     case NSArr_initWithArray:
100       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithArray"));
101       break;
102     case NSArr_initWithObjects:
103       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("initWithObjects"));
104       break;
105     case NSArr_objectAtIndex:
106       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectAtIndex"));
107       break;
108     case NSMutableArr_replaceObjectAtIndex: {
109       const IdentifierInfo *KeyIdents[] = {
110           &Ctx.Idents.get("replaceObjectAtIndex"),
111           &Ctx.Idents.get("withObject")};
112       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
113       break;
114     }
115     case NSMutableArr_addObject:
116       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
117       break;
118     case NSMutableArr_insertObjectAtIndex: {
119       const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"),
120                                            &Ctx.Idents.get("atIndex")};
121       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
122       break;
123     }
124     case NSMutableArr_setObjectAtIndexedSubscript: {
125       const IdentifierInfo *KeyIdents[] = {
126           &Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")};
127       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
128       break;
129     }
130     }
131     return (NSArraySelectors[MK] = Sel);
132   }
133 
134   return NSArraySelectors[MK];
135 }
136 
137 std::optional<NSAPI::NSArrayMethodKind>
getNSArrayMethodKind(Selector Sel)138 NSAPI::getNSArrayMethodKind(Selector Sel) {
139   for (unsigned i = 0; i != NumNSArrayMethods; ++i) {
140     NSArrayMethodKind MK = NSArrayMethodKind(i);
141     if (Sel == getNSArraySelector(MK))
142       return MK;
143   }
144 
145   return std::nullopt;
146 }
147 
getNSDictionarySelector(NSDictionaryMethodKind MK) const148 Selector NSAPI::getNSDictionarySelector(
149                                        NSDictionaryMethodKind MK) const {
150   if (NSDictionarySelectors[MK].isNull()) {
151     Selector Sel;
152     switch (MK) {
153     case NSDict_dictionary:
154       Sel = Ctx.Selectors.getNullarySelector(&Ctx.Idents.get("dictionary"));
155       break;
156     case NSDict_dictionaryWithDictionary:
157       Sel = Ctx.Selectors.getUnarySelector(
158                                    &Ctx.Idents.get("dictionaryWithDictionary"));
159       break;
160     case NSDict_dictionaryWithObjectForKey: {
161       const IdentifierInfo *KeyIdents[] = {
162           &Ctx.Idents.get("dictionaryWithObject"), &Ctx.Idents.get("forKey")};
163       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
164       break;
165     }
166     case NSDict_dictionaryWithObjectsForKeys: {
167       const IdentifierInfo *KeyIdents[] = {
168           &Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys")};
169       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
170       break;
171     }
172     case NSDict_dictionaryWithObjectsForKeysCount: {
173       const IdentifierInfo *KeyIdents[] = {
174           &Ctx.Idents.get("dictionaryWithObjects"), &Ctx.Idents.get("forKeys"),
175           &Ctx.Idents.get("count")};
176       Sel = Ctx.Selectors.getSelector(3, KeyIdents);
177       break;
178     }
179     case NSDict_dictionaryWithObjectsAndKeys:
180       Sel = Ctx.Selectors.getUnarySelector(
181                                &Ctx.Idents.get("dictionaryWithObjectsAndKeys"));
182       break;
183     case NSDict_initWithDictionary:
184       Sel = Ctx.Selectors.getUnarySelector(
185                                          &Ctx.Idents.get("initWithDictionary"));
186       break;
187     case NSDict_initWithObjectsAndKeys:
188       Sel = Ctx.Selectors.getUnarySelector(
189                                      &Ctx.Idents.get("initWithObjectsAndKeys"));
190       break;
191     case NSDict_initWithObjectsForKeys: {
192       const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("initWithObjects"),
193                                            &Ctx.Idents.get("forKeys")};
194       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
195       break;
196     }
197     case NSDict_objectForKey:
198       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("objectForKey"));
199       break;
200     case NSMutableDict_setObjectForKey: {
201       const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"),
202                                            &Ctx.Idents.get("forKey")};
203       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
204       break;
205     }
206     case NSMutableDict_setObjectForKeyedSubscript: {
207       const IdentifierInfo *KeyIdents[] = {
208           &Ctx.Idents.get("setObject"), &Ctx.Idents.get("forKeyedSubscript")};
209       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
210       break;
211     }
212     case NSMutableDict_setValueForKey: {
213       const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setValue"),
214                                            &Ctx.Idents.get("forKey")};
215       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
216       break;
217     }
218     }
219     return (NSDictionarySelectors[MK] = Sel);
220   }
221 
222   return NSDictionarySelectors[MK];
223 }
224 
225 std::optional<NSAPI::NSDictionaryMethodKind>
getNSDictionaryMethodKind(Selector Sel)226 NSAPI::getNSDictionaryMethodKind(Selector Sel) {
227   for (unsigned i = 0; i != NumNSDictionaryMethods; ++i) {
228     NSDictionaryMethodKind MK = NSDictionaryMethodKind(i);
229     if (Sel == getNSDictionarySelector(MK))
230       return MK;
231   }
232 
233   return std::nullopt;
234 }
235 
getNSSetSelector(NSSetMethodKind MK) const236 Selector NSAPI::getNSSetSelector(NSSetMethodKind MK) const {
237   if (NSSetSelectors[MK].isNull()) {
238     Selector Sel;
239     switch (MK) {
240     case NSMutableSet_addObject:
241       Sel = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get("addObject"));
242       break;
243     case NSOrderedSet_insertObjectAtIndex: {
244       const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("insertObject"),
245                                            &Ctx.Idents.get("atIndex")};
246       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
247       break;
248     }
249     case NSOrderedSet_setObjectAtIndex: {
250       const IdentifierInfo *KeyIdents[] = {&Ctx.Idents.get("setObject"),
251                                            &Ctx.Idents.get("atIndex")};
252       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
253       break;
254     }
255     case NSOrderedSet_setObjectAtIndexedSubscript: {
256       const IdentifierInfo *KeyIdents[] = {
257           &Ctx.Idents.get("setObject"), &Ctx.Idents.get("atIndexedSubscript")};
258       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
259       break;
260     }
261     case NSOrderedSet_replaceObjectAtIndexWithObject: {
262       const IdentifierInfo *KeyIdents[] = {
263           &Ctx.Idents.get("replaceObjectAtIndex"),
264           &Ctx.Idents.get("withObject")};
265       Sel = Ctx.Selectors.getSelector(2, KeyIdents);
266       break;
267     }
268     }
269     return (NSSetSelectors[MK] = Sel);
270   }
271 
272   return NSSetSelectors[MK];
273 }
274 
getNSSetMethodKind(Selector Sel)275 std::optional<NSAPI::NSSetMethodKind> NSAPI::getNSSetMethodKind(Selector Sel) {
276   for (unsigned i = 0; i != NumNSSetMethods; ++i) {
277     NSSetMethodKind MK = NSSetMethodKind(i);
278     if (Sel == getNSSetSelector(MK))
279       return MK;
280   }
281 
282   return std::nullopt;
283 }
284 
getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,bool Instance) const285 Selector NSAPI::getNSNumberLiteralSelector(NSNumberLiteralMethodKind MK,
286                                            bool Instance) const {
287   static const char *ClassSelectorName[NumNSNumberLiteralMethods] = {
288     "numberWithChar",
289     "numberWithUnsignedChar",
290     "numberWithShort",
291     "numberWithUnsignedShort",
292     "numberWithInt",
293     "numberWithUnsignedInt",
294     "numberWithLong",
295     "numberWithUnsignedLong",
296     "numberWithLongLong",
297     "numberWithUnsignedLongLong",
298     "numberWithFloat",
299     "numberWithDouble",
300     "numberWithBool",
301     "numberWithInteger",
302     "numberWithUnsignedInteger"
303   };
304   static const char *InstanceSelectorName[NumNSNumberLiteralMethods] = {
305     "initWithChar",
306     "initWithUnsignedChar",
307     "initWithShort",
308     "initWithUnsignedShort",
309     "initWithInt",
310     "initWithUnsignedInt",
311     "initWithLong",
312     "initWithUnsignedLong",
313     "initWithLongLong",
314     "initWithUnsignedLongLong",
315     "initWithFloat",
316     "initWithDouble",
317     "initWithBool",
318     "initWithInteger",
319     "initWithUnsignedInteger"
320   };
321 
322   Selector *Sels;
323   const char **Names;
324   if (Instance) {
325     Sels = NSNumberInstanceSelectors;
326     Names = InstanceSelectorName;
327   } else {
328     Sels = NSNumberClassSelectors;
329     Names = ClassSelectorName;
330   }
331 
332   if (Sels[MK].isNull())
333     Sels[MK] = Ctx.Selectors.getUnarySelector(&Ctx.Idents.get(Names[MK]));
334   return Sels[MK];
335 }
336 
337 std::optional<NSAPI::NSNumberLiteralMethodKind>
getNSNumberLiteralMethodKind(Selector Sel) const338 NSAPI::getNSNumberLiteralMethodKind(Selector Sel) const {
339   for (unsigned i = 0; i != NumNSNumberLiteralMethods; ++i) {
340     NSNumberLiteralMethodKind MK = NSNumberLiteralMethodKind(i);
341     if (isNSNumberLiteralSelector(MK, Sel))
342       return MK;
343   }
344 
345   return std::nullopt;
346 }
347 
348 std::optional<NSAPI::NSNumberLiteralMethodKind>
getNSNumberFactoryMethodKind(QualType T) const349 NSAPI::getNSNumberFactoryMethodKind(QualType T) const {
350   const BuiltinType *BT = T->getAs<BuiltinType>();
351   if (!BT)
352     return std::nullopt;
353 
354   const TypedefType *TDT = T->getAs<TypedefType>();
355   if (TDT) {
356     QualType TDTTy = QualType(TDT, 0);
357     if (isObjCBOOLType(TDTTy))
358       return NSAPI::NSNumberWithBool;
359     if (isObjCNSIntegerType(TDTTy))
360       return NSAPI::NSNumberWithInteger;
361     if (isObjCNSUIntegerType(TDTTy))
362       return NSAPI::NSNumberWithUnsignedInteger;
363   }
364 
365   switch (BT->getKind()) {
366   case BuiltinType::Char_S:
367   case BuiltinType::SChar:
368     return NSAPI::NSNumberWithChar;
369   case BuiltinType::Char_U:
370   case BuiltinType::UChar:
371     return NSAPI::NSNumberWithUnsignedChar;
372   case BuiltinType::Short:
373     return NSAPI::NSNumberWithShort;
374   case BuiltinType::UShort:
375     return NSAPI::NSNumberWithUnsignedShort;
376   case BuiltinType::Int:
377     return NSAPI::NSNumberWithInt;
378   case BuiltinType::UInt:
379     return NSAPI::NSNumberWithUnsignedInt;
380   case BuiltinType::Long:
381     return NSAPI::NSNumberWithLong;
382   case BuiltinType::ULong:
383     return NSAPI::NSNumberWithUnsignedLong;
384   case BuiltinType::LongLong:
385     return NSAPI::NSNumberWithLongLong;
386   case BuiltinType::ULongLong:
387     return NSAPI::NSNumberWithUnsignedLongLong;
388   case BuiltinType::Float:
389     return NSAPI::NSNumberWithFloat;
390   case BuiltinType::Double:
391     return NSAPI::NSNumberWithDouble;
392   case BuiltinType::Bool:
393     return NSAPI::NSNumberWithBool;
394 
395   case BuiltinType::Void:
396   case BuiltinType::WChar_U:
397   case BuiltinType::WChar_S:
398   case BuiltinType::Char8:
399   case BuiltinType::Char16:
400   case BuiltinType::Char32:
401   case BuiltinType::Int128:
402   case BuiltinType::LongDouble:
403   case BuiltinType::ShortAccum:
404   case BuiltinType::Accum:
405   case BuiltinType::LongAccum:
406   case BuiltinType::UShortAccum:
407   case BuiltinType::UAccum:
408   case BuiltinType::ULongAccum:
409   case BuiltinType::ShortFract:
410   case BuiltinType::Fract:
411   case BuiltinType::LongFract:
412   case BuiltinType::UShortFract:
413   case BuiltinType::UFract:
414   case BuiltinType::ULongFract:
415   case BuiltinType::SatShortAccum:
416   case BuiltinType::SatAccum:
417   case BuiltinType::SatLongAccum:
418   case BuiltinType::SatUShortAccum:
419   case BuiltinType::SatUAccum:
420   case BuiltinType::SatULongAccum:
421   case BuiltinType::SatShortFract:
422   case BuiltinType::SatFract:
423   case BuiltinType::SatLongFract:
424   case BuiltinType::SatUShortFract:
425   case BuiltinType::SatUFract:
426   case BuiltinType::SatULongFract:
427   case BuiltinType::UInt128:
428   case BuiltinType::Float16:
429   case BuiltinType::Float128:
430   case BuiltinType::Ibm128:
431   case BuiltinType::NullPtr:
432   case BuiltinType::ObjCClass:
433   case BuiltinType::ObjCId:
434   case BuiltinType::ObjCSel:
435 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
436   case BuiltinType::Id:
437 #include "clang/Basic/OpenCLImageTypes.def"
438 #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \
439   case BuiltinType::Id:
440 #include "clang/Basic/OpenCLExtensionTypes.def"
441   case BuiltinType::OCLSampler:
442   case BuiltinType::OCLEvent:
443   case BuiltinType::OCLClkEvent:
444   case BuiltinType::OCLQueue:
445   case BuiltinType::OCLReserveID:
446 #define SVE_TYPE(Name, Id, SingletonId) \
447   case BuiltinType::Id:
448 #include "clang/Basic/AArch64SVEACLETypes.def"
449 #define PPC_VECTOR_TYPE(Name, Id, Size) \
450   case BuiltinType::Id:
451 #include "clang/Basic/PPCTypes.def"
452 #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
453 #include "clang/Basic/RISCVVTypes.def"
454 #define WASM_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
455 #include "clang/Basic/WebAssemblyReferenceTypes.def"
456 #define AMDGPU_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
457 #include "clang/Basic/AMDGPUTypes.def"
458   case BuiltinType::BoundMember:
459   case BuiltinType::UnresolvedTemplate:
460   case BuiltinType::Dependent:
461   case BuiltinType::Overload:
462   case BuiltinType::UnknownAny:
463   case BuiltinType::ARCUnbridgedCast:
464   case BuiltinType::Half:
465   case BuiltinType::PseudoObject:
466   case BuiltinType::BuiltinFn:
467   case BuiltinType::IncompleteMatrixIdx:
468   case BuiltinType::ArraySection:
469   case BuiltinType::OMPArrayShaping:
470   case BuiltinType::OMPIterator:
471   case BuiltinType::BFloat16:
472     break;
473   }
474 
475   return std::nullopt;
476 }
477 
478 /// Returns true if \param T is a typedef of "BOOL" in objective-c.
isObjCBOOLType(QualType T) const479 bool NSAPI::isObjCBOOLType(QualType T) const {
480   return isObjCTypedef(T, "BOOL", BOOLId);
481 }
482 /// Returns true if \param T is a typedef of "NSInteger" in objective-c.
isObjCNSIntegerType(QualType T) const483 bool NSAPI::isObjCNSIntegerType(QualType T) const {
484   return isObjCTypedef(T, "NSInteger", NSIntegerId);
485 }
486 /// Returns true if \param T is a typedef of "NSUInteger" in objective-c.
isObjCNSUIntegerType(QualType T) const487 bool NSAPI::isObjCNSUIntegerType(QualType T) const {
488   return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
489 }
490 
GetNSIntegralKind(QualType T) const491 StringRef NSAPI::GetNSIntegralKind(QualType T) const {
492   if (!Ctx.getLangOpts().ObjC || T.isNull())
493     return StringRef();
494 
495   while (const TypedefType *TDT = T->getAs<TypedefType>()) {
496     StringRef NSIntegralResust =
497       llvm::StringSwitch<StringRef>(
498         TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName())
499     .Case("int8_t", "int8_t")
500     .Case("int16_t", "int16_t")
501     .Case("int32_t", "int32_t")
502     .Case("NSInteger", "NSInteger")
503     .Case("int64_t", "int64_t")
504     .Case("uint8_t", "uint8_t")
505     .Case("uint16_t", "uint16_t")
506     .Case("uint32_t", "uint32_t")
507     .Case("NSUInteger", "NSUInteger")
508     .Case("uint64_t", "uint64_t")
509     .Default(StringRef());
510     if (!NSIntegralResust.empty())
511       return NSIntegralResust;
512     T = TDT->desugar();
513   }
514   return StringRef();
515 }
516 
isMacroDefined(StringRef Id) const517 bool NSAPI::isMacroDefined(StringRef Id) const {
518   // FIXME: Check whether the relevant module macros are visible.
519   return Ctx.Idents.get(Id).hasMacroDefinition();
520 }
521 
isSubclassOfNSClass(ObjCInterfaceDecl * InterfaceDecl,NSClassIdKindKind NSClassKind) const522 bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl,
523                                 NSClassIdKindKind NSClassKind) const {
524   if (!InterfaceDecl) {
525     return false;
526   }
527 
528   IdentifierInfo *NSClassID = getNSClassId(NSClassKind);
529 
530   bool IsSubclass = false;
531   do {
532     IsSubclass = NSClassID == InterfaceDecl->getIdentifier();
533 
534     if (IsSubclass) {
535       break;
536     }
537   } while ((InterfaceDecl = InterfaceDecl->getSuperClass()));
538 
539   return IsSubclass;
540 }
541 
isObjCTypedef(QualType T,StringRef name,IdentifierInfo * & II) const542 bool NSAPI::isObjCTypedef(QualType T,
543                           StringRef name, IdentifierInfo *&II) const {
544   if (!Ctx.getLangOpts().ObjC)
545     return false;
546   if (T.isNull())
547     return false;
548 
549   if (!II)
550     II = &Ctx.Idents.get(name);
551 
552   while (const TypedefType *TDT = T->getAs<TypedefType>()) {
553     if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II)
554       return true;
555     T = TDT->desugar();
556   }
557 
558   return false;
559 }
560 
isObjCEnumerator(const Expr * E,StringRef name,IdentifierInfo * & II) const561 bool NSAPI::isObjCEnumerator(const Expr *E,
562                              StringRef name, IdentifierInfo *&II) const {
563   if (!Ctx.getLangOpts().ObjC)
564     return false;
565   if (!E)
566     return false;
567 
568   if (!II)
569     II = &Ctx.Idents.get(name);
570 
571   if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
572     if (const EnumConstantDecl *
573           EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl()))
574       return EnumD->getIdentifier() == II;
575 
576   return false;
577 }
578 
getOrInitSelector(ArrayRef<StringRef> Ids,Selector & Sel) const579 Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids,
580                                   Selector &Sel) const {
581   if (Sel.isNull()) {
582     SmallVector<const IdentifierInfo *, 4> Idents;
583     for (ArrayRef<StringRef>::const_iterator
584            I = Ids.begin(), E = Ids.end(); I != E; ++I)
585       Idents.push_back(&Ctx.Idents.get(*I));
586     Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data());
587   }
588   return Sel;
589 }
590 
getOrInitNullarySelector(StringRef Id,Selector & Sel) const591 Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const {
592   if (Sel.isNull()) {
593     const IdentifierInfo *Ident = &Ctx.Idents.get(Id);
594     Sel = Ctx.Selectors.getSelector(0, &Ident);
595   }
596   return Sel;
597 }
598