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 17 NSAPI::NSAPI(ASTContext &ctx) 18 : Ctx(ctx), ClassIds(), BOOLId(nullptr), NSIntegerId(nullptr), 19 NSUIntegerId(nullptr), NSASCIIStringEncodingId(nullptr), 20 NSUTF8StringEncodingId(nullptr) {} 21 22 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 42 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 78 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 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 155 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> 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 257 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> 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 314 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> 367 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> 378 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::Void: 425 case BuiltinType::WChar_U: 426 case BuiltinType::WChar_S: 427 case BuiltinType::Char8: 428 case BuiltinType::Char16: 429 case BuiltinType::Char32: 430 case BuiltinType::Int128: 431 case BuiltinType::LongDouble: 432 case BuiltinType::ShortAccum: 433 case BuiltinType::Accum: 434 case BuiltinType::LongAccum: 435 case BuiltinType::UShortAccum: 436 case BuiltinType::UAccum: 437 case BuiltinType::ULongAccum: 438 case BuiltinType::ShortFract: 439 case BuiltinType::Fract: 440 case BuiltinType::LongFract: 441 case BuiltinType::UShortFract: 442 case BuiltinType::UFract: 443 case BuiltinType::ULongFract: 444 case BuiltinType::SatShortAccum: 445 case BuiltinType::SatAccum: 446 case BuiltinType::SatLongAccum: 447 case BuiltinType::SatUShortAccum: 448 case BuiltinType::SatUAccum: 449 case BuiltinType::SatULongAccum: 450 case BuiltinType::SatShortFract: 451 case BuiltinType::SatFract: 452 case BuiltinType::SatLongFract: 453 case BuiltinType::SatUShortFract: 454 case BuiltinType::SatUFract: 455 case BuiltinType::SatULongFract: 456 case BuiltinType::UInt128: 457 case BuiltinType::Float16: 458 case BuiltinType::Float128: 459 case BuiltinType::NullPtr: 460 case BuiltinType::ObjCClass: 461 case BuiltinType::ObjCId: 462 case BuiltinType::ObjCSel: 463 #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ 464 case BuiltinType::Id: 465 #include "clang/Basic/OpenCLImageTypes.def" 466 #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ 467 case BuiltinType::Id: 468 #include "clang/Basic/OpenCLExtensionTypes.def" 469 case BuiltinType::OCLSampler: 470 case BuiltinType::OCLEvent: 471 case BuiltinType::OCLClkEvent: 472 case BuiltinType::OCLQueue: 473 case BuiltinType::OCLReserveID: 474 #define SVE_TYPE(Name, Id, SingletonId) \ 475 case BuiltinType::Id: 476 #include "clang/Basic/AArch64SVEACLETypes.def" 477 #define PPC_VECTOR_TYPE(Name, Id, Size) \ 478 case BuiltinType::Id: 479 #include "clang/Basic/PPCTypes.def" 480 #define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id: 481 #include "clang/Basic/RISCVVTypes.def" 482 case BuiltinType::BoundMember: 483 case BuiltinType::Dependent: 484 case BuiltinType::Overload: 485 case BuiltinType::UnknownAny: 486 case BuiltinType::ARCUnbridgedCast: 487 case BuiltinType::Half: 488 case BuiltinType::PseudoObject: 489 case BuiltinType::BuiltinFn: 490 case BuiltinType::IncompleteMatrixIdx: 491 case BuiltinType::OMPArraySection: 492 case BuiltinType::OMPArrayShaping: 493 case BuiltinType::OMPIterator: 494 case BuiltinType::BFloat16: 495 break; 496 } 497 498 return None; 499 } 500 501 /// Returns true if \param T is a typedef of "BOOL" in objective-c. 502 bool NSAPI::isObjCBOOLType(QualType T) const { 503 return isObjCTypedef(T, "BOOL", BOOLId); 504 } 505 /// Returns true if \param T is a typedef of "NSInteger" in objective-c. 506 bool NSAPI::isObjCNSIntegerType(QualType T) const { 507 return isObjCTypedef(T, "NSInteger", NSIntegerId); 508 } 509 /// Returns true if \param T is a typedef of "NSUInteger" in objective-c. 510 bool NSAPI::isObjCNSUIntegerType(QualType T) const { 511 return isObjCTypedef(T, "NSUInteger", NSUIntegerId); 512 } 513 514 StringRef NSAPI::GetNSIntegralKind(QualType T) const { 515 if (!Ctx.getLangOpts().ObjC || T.isNull()) 516 return StringRef(); 517 518 while (const TypedefType *TDT = T->getAs<TypedefType>()) { 519 StringRef NSIntegralResust = 520 llvm::StringSwitch<StringRef>( 521 TDT->getDecl()->getDeclName().getAsIdentifierInfo()->getName()) 522 .Case("int8_t", "int8_t") 523 .Case("int16_t", "int16_t") 524 .Case("int32_t", "int32_t") 525 .Case("NSInteger", "NSInteger") 526 .Case("int64_t", "int64_t") 527 .Case("uint8_t", "uint8_t") 528 .Case("uint16_t", "uint16_t") 529 .Case("uint32_t", "uint32_t") 530 .Case("NSUInteger", "NSUInteger") 531 .Case("uint64_t", "uint64_t") 532 .Default(StringRef()); 533 if (!NSIntegralResust.empty()) 534 return NSIntegralResust; 535 T = TDT->desugar(); 536 } 537 return StringRef(); 538 } 539 540 bool NSAPI::isMacroDefined(StringRef Id) const { 541 // FIXME: Check whether the relevant module macros are visible. 542 return Ctx.Idents.get(Id).hasMacroDefinition(); 543 } 544 545 bool NSAPI::isSubclassOfNSClass(ObjCInterfaceDecl *InterfaceDecl, 546 NSClassIdKindKind NSClassKind) const { 547 if (!InterfaceDecl) { 548 return false; 549 } 550 551 IdentifierInfo *NSClassID = getNSClassId(NSClassKind); 552 553 bool IsSubclass = false; 554 do { 555 IsSubclass = NSClassID == InterfaceDecl->getIdentifier(); 556 557 if (IsSubclass) { 558 break; 559 } 560 } while ((InterfaceDecl = InterfaceDecl->getSuperClass())); 561 562 return IsSubclass; 563 } 564 565 bool NSAPI::isObjCTypedef(QualType T, 566 StringRef name, IdentifierInfo *&II) const { 567 if (!Ctx.getLangOpts().ObjC) 568 return false; 569 if (T.isNull()) 570 return false; 571 572 if (!II) 573 II = &Ctx.Idents.get(name); 574 575 while (const TypedefType *TDT = T->getAs<TypedefType>()) { 576 if (TDT->getDecl()->getDeclName().getAsIdentifierInfo() == II) 577 return true; 578 T = TDT->desugar(); 579 } 580 581 return false; 582 } 583 584 bool NSAPI::isObjCEnumerator(const Expr *E, 585 StringRef name, IdentifierInfo *&II) const { 586 if (!Ctx.getLangOpts().ObjC) 587 return false; 588 if (!E) 589 return false; 590 591 if (!II) 592 II = &Ctx.Idents.get(name); 593 594 if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) 595 if (const EnumConstantDecl * 596 EnumD = dyn_cast_or_null<EnumConstantDecl>(DRE->getDecl())) 597 return EnumD->getIdentifier() == II; 598 599 return false; 600 } 601 602 Selector NSAPI::getOrInitSelector(ArrayRef<StringRef> Ids, 603 Selector &Sel) const { 604 if (Sel.isNull()) { 605 SmallVector<IdentifierInfo *, 4> Idents; 606 for (ArrayRef<StringRef>::const_iterator 607 I = Ids.begin(), E = Ids.end(); I != E; ++I) 608 Idents.push_back(&Ctx.Idents.get(*I)); 609 Sel = Ctx.Selectors.getSelector(Idents.size(), Idents.data()); 610 } 611 return Sel; 612 } 613 614 Selector NSAPI::getOrInitNullarySelector(StringRef Id, Selector &Sel) const { 615 if (Sel.isNull()) { 616 IdentifierInfo *Ident = &Ctx.Idents.get(Id); 617 Sel = Ctx.Selectors.getSelector(0, &Ident); 618 } 619 return Sel; 620 } 621