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
16using namespace clang;
17
18NSAPI::NSAPI(ASTContext &ctx)
19  : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr),
20    NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr),
21    NSUTF8StringEncodingId(nullptr) {}
22
23IdentifierInfo *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
43Selector 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
79Selector 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
146std::optional<NSAPI::NSArrayMethodKind>
147NSAPI::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
157Selector 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
248std::optional<NSAPI::NSDictionaryMethodKind>
249NSAPI::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
259Selector 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
305std::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
315Selector 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
367std::optional<NSAPI::NSNumberLiteralMethodKind>
368NSAPI::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
378std::optional<NSAPI::NSNumberLiteralMethodKind>
379NSAPI::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.
506bool 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.
510bool 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.
514bool NSAPI::isObjCNSUIntegerType(QualType T) const {
515  return isObjCTypedef(T, "NSUInteger", NSUIntegerId);
516}
517
518StringRef 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
544bool NSAPI::isMacroDefined(StringRef Id) const {
545  // FIXME: Check whether the relevant module macros are visible.
546  return Ctx.Idents.get(Id).hasMacroDefinition();
547}
548
549bool 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
569bool 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
588bool 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
606Selector 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
618Selector 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