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