1 //===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===// 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/Index/IndexSymbol.h" 10 #include "clang/AST/DeclCXX.h" 11 #include "clang/AST/DeclObjC.h" 12 #include "clang/AST/DeclTemplate.h" 13 #include "clang/AST/PrettyPrinter.h" 14 #include "clang/Lex/MacroInfo.h" 15 16 using namespace clang; 17 using namespace clang::index; 18 19 /// \returns true if \c D is a subclass of 'XCTestCase'. 20 static bool isUnitTestCase(const ObjCInterfaceDecl *D) { 21 if (!D) 22 return false; 23 while (const ObjCInterfaceDecl *SuperD = D->getSuperClass()) { 24 if (SuperD->getName() == "XCTestCase") 25 return true; 26 D = SuperD; 27 } 28 return false; 29 } 30 31 /// \returns true if \c D is in a subclass of 'XCTestCase', returns void, has 32 /// no parameters, and its name starts with 'test'. 33 static bool isUnitTest(const ObjCMethodDecl *D) { 34 if (!D->parameters().empty()) 35 return false; 36 if (!D->getReturnType()->isVoidType()) 37 return false; 38 if (!D->getSelector().getNameForSlot(0).startswith("test")) 39 return false; 40 return isUnitTestCase(D->getClassInterface()); 41 } 42 43 static void checkForIBOutlets(const Decl *D, SymbolPropertySet &PropSet) { 44 if (D->hasAttr<IBOutletAttr>()) { 45 PropSet |= (SymbolPropertySet)SymbolProperty::IBAnnotated; 46 } else if (D->hasAttr<IBOutletCollectionAttr>()) { 47 PropSet |= (SymbolPropertySet)SymbolProperty::IBAnnotated; 48 PropSet |= (SymbolPropertySet)SymbolProperty::IBOutletCollection; 49 } 50 } 51 52 bool index::isFunctionLocalSymbol(const Decl *D) { 53 assert(D); 54 55 if (isa<ParmVarDecl>(D)) 56 return true; 57 58 if (isa<ObjCTypeParamDecl>(D)) 59 return true; 60 61 if (isa<UsingDirectiveDecl>(D)) 62 return false; 63 if (!D->getParentFunctionOrMethod()) 64 return false; 65 66 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { 67 switch (ND->getFormalLinkage()) { 68 case NoLinkage: 69 case InternalLinkage: 70 return true; 71 case VisibleNoLinkage: 72 case UniqueExternalLinkage: 73 case ModuleInternalLinkage: 74 llvm_unreachable("Not a sema linkage"); 75 case ModuleLinkage: 76 case ExternalLinkage: 77 return false; 78 } 79 } 80 81 return true; 82 } 83 84 SymbolInfo index::getSymbolInfo(const Decl *D) { 85 assert(D); 86 SymbolInfo Info; 87 Info.Kind = SymbolKind::Unknown; 88 Info.SubKind = SymbolSubKind::None; 89 Info.Properties = SymbolPropertySet(); 90 Info.Lang = SymbolLanguage::C; 91 92 if (isFunctionLocalSymbol(D)) { 93 Info.Properties |= (SymbolPropertySet)SymbolProperty::Local; 94 } 95 if (isa<ObjCProtocolDecl>(D->getDeclContext())) { 96 Info.Properties |= (SymbolPropertySet)SymbolProperty::ProtocolInterface; 97 } 98 99 if (auto *VT = dyn_cast<VarTemplateDecl>(D)) { 100 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 101 Info.Lang = SymbolLanguage::CXX; 102 // All other fields are filled from the templated decl. 103 D = VT->getTemplatedDecl(); 104 } 105 106 if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { 107 switch (TD->getTagKind()) { 108 case TTK_Struct: 109 Info.Kind = SymbolKind::Struct; break; 110 case TTK_Union: 111 Info.Kind = SymbolKind::Union; break; 112 case TTK_Class: 113 Info.Kind = SymbolKind::Class; 114 Info.Lang = SymbolLanguage::CXX; 115 break; 116 case TTK_Interface: 117 Info.Kind = SymbolKind::Protocol; 118 Info.Lang = SymbolLanguage::CXX; 119 break; 120 case TTK_Enum: 121 Info.Kind = SymbolKind::Enum; break; 122 } 123 124 if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) { 125 if (!CXXRec->isCLike()) { 126 Info.Lang = SymbolLanguage::CXX; 127 if (CXXRec->getDescribedClassTemplate()) { 128 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 129 } 130 } 131 } 132 133 if (isa<ClassTemplatePartialSpecializationDecl>(D)) { 134 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 135 Info.Properties |= 136 (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization; 137 } else if (isa<ClassTemplateSpecializationDecl>(D)) { 138 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 139 Info.Properties |= 140 (SymbolPropertySet)SymbolProperty::TemplateSpecialization; 141 } 142 143 } else if (auto *VD = dyn_cast<VarDecl>(D)) { 144 Info.Kind = SymbolKind::Variable; 145 if (isa<ParmVarDecl>(D)) { 146 Info.Kind = SymbolKind::Parameter; 147 } else if (isa<CXXRecordDecl>(D->getDeclContext())) { 148 Info.Kind = SymbolKind::StaticProperty; 149 Info.Lang = SymbolLanguage::CXX; 150 } 151 152 if (isa<VarTemplatePartialSpecializationDecl>(D)) { 153 Info.Lang = SymbolLanguage::CXX; 154 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 155 Info.Properties |= 156 (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization; 157 } else if (isa<VarTemplateSpecializationDecl>(D)) { 158 Info.Lang = SymbolLanguage::CXX; 159 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 160 Info.Properties |= 161 (SymbolPropertySet)SymbolProperty::TemplateSpecialization; 162 } else if (VD->getDescribedVarTemplate()) { 163 Info.Lang = SymbolLanguage::CXX; 164 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 165 } 166 167 } else { 168 switch (D->getKind()) { 169 case Decl::Import: 170 Info.Kind = SymbolKind::Module; 171 break; 172 case Decl::Typedef: 173 Info.Kind = SymbolKind::TypeAlias; break; // Lang = C 174 case Decl::Function: 175 Info.Kind = SymbolKind::Function; 176 break; 177 case Decl::Field: 178 case Decl::IndirectField: 179 Info.Kind = SymbolKind::Field; 180 if (const CXXRecordDecl * 181 CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { 182 if (!CXXRec->isCLike()) 183 Info.Lang = SymbolLanguage::CXX; 184 } 185 break; 186 case Decl::EnumConstant: 187 Info.Kind = SymbolKind::EnumConstant; break; 188 case Decl::ObjCInterface: 189 case Decl::ObjCImplementation: { 190 Info.Kind = SymbolKind::Class; 191 Info.Lang = SymbolLanguage::ObjC; 192 const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D); 193 if (!ClsD) 194 ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface(); 195 if (isUnitTestCase(ClsD)) 196 Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest; 197 break; 198 } 199 case Decl::ObjCProtocol: 200 Info.Kind = SymbolKind::Protocol; 201 Info.Lang = SymbolLanguage::ObjC; 202 break; 203 case Decl::ObjCCategory: 204 case Decl::ObjCCategoryImpl: { 205 Info.Kind = SymbolKind::Extension; 206 Info.Lang = SymbolLanguage::ObjC; 207 const ObjCInterfaceDecl *ClsD = nullptr; 208 if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D)) 209 ClsD = CatD->getClassInterface(); 210 else 211 ClsD = cast<ObjCCategoryImplDecl>(D)->getClassInterface(); 212 if (isUnitTestCase(ClsD)) 213 Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest; 214 break; 215 } 216 case Decl::ObjCMethod: { 217 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D); 218 Info.Kind = MD->isInstanceMethod() ? SymbolKind::InstanceMethod : SymbolKind::ClassMethod; 219 if (MD->isPropertyAccessor()) { 220 if (MD->param_size()) 221 Info.SubKind = SymbolSubKind::AccessorSetter; 222 else 223 Info.SubKind = SymbolSubKind::AccessorGetter; 224 } 225 Info.Lang = SymbolLanguage::ObjC; 226 if (isUnitTest(MD)) 227 Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest; 228 if (D->hasAttr<IBActionAttr>()) 229 Info.Properties |= (SymbolPropertySet)SymbolProperty::IBAnnotated; 230 break; 231 } 232 case Decl::ObjCProperty: 233 Info.Kind = SymbolKind::InstanceProperty; 234 Info.Lang = SymbolLanguage::ObjC; 235 checkForIBOutlets(D, Info.Properties); 236 if (auto *Annot = D->getAttr<AnnotateAttr>()) { 237 if (Annot->getAnnotation() == "gk_inspectable") 238 Info.Properties |= (SymbolPropertySet)SymbolProperty::GKInspectable; 239 } 240 break; 241 case Decl::ObjCIvar: 242 Info.Kind = SymbolKind::Field; 243 Info.Lang = SymbolLanguage::ObjC; 244 checkForIBOutlets(D, Info.Properties); 245 break; 246 case Decl::Namespace: 247 Info.Kind = SymbolKind::Namespace; 248 Info.Lang = SymbolLanguage::CXX; 249 break; 250 case Decl::NamespaceAlias: 251 Info.Kind = SymbolKind::NamespaceAlias; 252 Info.Lang = SymbolLanguage::CXX; 253 break; 254 case Decl::CXXConstructor: { 255 Info.Kind = SymbolKind::Constructor; 256 Info.Lang = SymbolLanguage::CXX; 257 auto *CD = cast<CXXConstructorDecl>(D); 258 if (CD->isCopyConstructor()) 259 Info.SubKind = SymbolSubKind::CXXCopyConstructor; 260 else if (CD->isMoveConstructor()) 261 Info.SubKind = SymbolSubKind::CXXMoveConstructor; 262 break; 263 } 264 case Decl::CXXDestructor: 265 Info.Kind = SymbolKind::Destructor; 266 Info.Lang = SymbolLanguage::CXX; 267 break; 268 case Decl::CXXConversion: 269 Info.Kind = SymbolKind::ConversionFunction; 270 Info.Lang = SymbolLanguage::CXX; 271 break; 272 case Decl::CXXMethod: { 273 const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); 274 if (MD->isStatic()) 275 Info.Kind = SymbolKind::StaticMethod; 276 else 277 Info.Kind = SymbolKind::InstanceMethod; 278 Info.Lang = SymbolLanguage::CXX; 279 break; 280 } 281 case Decl::ClassTemplate: 282 Info.Kind = SymbolKind::Class; 283 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 284 Info.Lang = SymbolLanguage::CXX; 285 break; 286 case Decl::FunctionTemplate: 287 Info.Kind = SymbolKind::Function; 288 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 289 Info.Lang = SymbolLanguage::CXX; 290 if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>( 291 cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) { 292 if (isa<CXXConstructorDecl>(MD)) 293 Info.Kind = SymbolKind::Constructor; 294 else if (isa<CXXDestructorDecl>(MD)) 295 Info.Kind = SymbolKind::Destructor; 296 else if (isa<CXXConversionDecl>(MD)) 297 Info.Kind = SymbolKind::ConversionFunction; 298 else { 299 if (MD->isStatic()) 300 Info.Kind = SymbolKind::StaticMethod; 301 else 302 Info.Kind = SymbolKind::InstanceMethod; 303 } 304 } 305 break; 306 case Decl::TypeAliasTemplate: 307 Info.Kind = SymbolKind::TypeAlias; 308 Info.Lang = SymbolLanguage::CXX; 309 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 310 break; 311 case Decl::TypeAlias: 312 Info.Kind = SymbolKind::TypeAlias; 313 Info.Lang = SymbolLanguage::CXX; 314 break; 315 case Decl::UnresolvedUsingTypename: 316 Info.Kind = SymbolKind::Using; 317 Info.SubKind = SymbolSubKind::UsingTypename; 318 Info.Lang = SymbolLanguage::CXX; 319 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 320 break; 321 case Decl::UnresolvedUsingValue: 322 Info.Kind = SymbolKind::Using; 323 Info.SubKind = SymbolSubKind::UsingValue; 324 Info.Lang = SymbolLanguage::CXX; 325 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 326 break; 327 case Decl::Using: 328 Info.Kind = SymbolKind::Using; 329 Info.Lang = SymbolLanguage::CXX; 330 break; 331 case Decl::Binding: 332 Info.Kind = SymbolKind::Variable; 333 Info.Lang = SymbolLanguage::CXX; 334 break; 335 case Decl::MSProperty: 336 Info.Kind = SymbolKind::InstanceProperty; 337 if (const CXXRecordDecl *CXXRec = 338 dyn_cast<CXXRecordDecl>(D->getDeclContext())) { 339 if (!CXXRec->isCLike()) 340 Info.Lang = SymbolLanguage::CXX; 341 } 342 break; 343 case Decl::ClassTemplatePartialSpecialization: 344 case Decl::ClassScopeFunctionSpecialization: 345 case Decl::ClassTemplateSpecialization: 346 case Decl::CXXRecord: 347 case Decl::Enum: 348 case Decl::Record: 349 llvm_unreachable("records handled before"); 350 break; 351 case Decl::VarTemplateSpecialization: 352 case Decl::VarTemplatePartialSpecialization: 353 case Decl::ImplicitParam: 354 case Decl::ParmVar: 355 case Decl::Var: 356 case Decl::VarTemplate: 357 llvm_unreachable("variables handled before"); 358 break; 359 // Other decls get the 'unknown' kind. 360 default: 361 break; 362 } 363 } 364 365 if (Info.Kind == SymbolKind::Unknown) 366 return Info; 367 368 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 369 if (FD->getTemplatedKind() == 370 FunctionDecl::TK_FunctionTemplateSpecialization) { 371 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; 372 Info.Properties |= 373 (SymbolPropertySet)SymbolProperty::TemplateSpecialization; 374 } 375 } 376 377 if (Info.Properties & (SymbolPropertySet)SymbolProperty::Generic) 378 Info.Lang = SymbolLanguage::CXX; 379 380 if (auto *attr = D->getExternalSourceSymbolAttr()) { 381 if (attr->getLanguage() == "Swift") 382 Info.Lang = SymbolLanguage::Swift; 383 } 384 385 return Info; 386 } 387 388 SymbolInfo index::getSymbolInfoForMacro(const MacroInfo &) { 389 SymbolInfo Info; 390 Info.Kind = SymbolKind::Macro; 391 Info.SubKind = SymbolSubKind::None; 392 Info.Properties = SymbolPropertySet(); 393 Info.Lang = SymbolLanguage::C; 394 return Info; 395 } 396 397 bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles, 398 llvm::function_ref<bool(SymbolRole)> Fn) { 399 #define APPLY_FOR_ROLE(Role) \ 400 if (Roles & (unsigned)SymbolRole::Role) \ 401 if (!Fn(SymbolRole::Role)) \ 402 return false; 403 404 APPLY_FOR_ROLE(Declaration); 405 APPLY_FOR_ROLE(Definition); 406 APPLY_FOR_ROLE(Reference); 407 APPLY_FOR_ROLE(Read); 408 APPLY_FOR_ROLE(Write); 409 APPLY_FOR_ROLE(Call); 410 APPLY_FOR_ROLE(Dynamic); 411 APPLY_FOR_ROLE(AddressOf); 412 APPLY_FOR_ROLE(Implicit); 413 APPLY_FOR_ROLE(Undefinition); 414 APPLY_FOR_ROLE(RelationChildOf); 415 APPLY_FOR_ROLE(RelationBaseOf); 416 APPLY_FOR_ROLE(RelationOverrideOf); 417 APPLY_FOR_ROLE(RelationReceivedBy); 418 APPLY_FOR_ROLE(RelationCalledBy); 419 APPLY_FOR_ROLE(RelationExtendedBy); 420 APPLY_FOR_ROLE(RelationAccessorOf); 421 APPLY_FOR_ROLE(RelationContainedBy); 422 APPLY_FOR_ROLE(RelationIBTypeOf); 423 APPLY_FOR_ROLE(RelationSpecializationOf); 424 APPLY_FOR_ROLE(NameReference); 425 426 #undef APPLY_FOR_ROLE 427 428 return true; 429 } 430 431 void index::applyForEachSymbolRole(SymbolRoleSet Roles, 432 llvm::function_ref<void(SymbolRole)> Fn) { 433 applyForEachSymbolRoleInterruptible(Roles, [&](SymbolRole r) -> bool { 434 Fn(r); 435 return true; 436 }); 437 } 438 439 void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) { 440 bool VisitedOnce = false; 441 applyForEachSymbolRole(Roles, [&](SymbolRole Role) { 442 if (VisitedOnce) 443 OS << ','; 444 else 445 VisitedOnce = true; 446 switch (Role) { 447 case SymbolRole::Declaration: OS << "Decl"; break; 448 case SymbolRole::Definition: OS << "Def"; break; 449 case SymbolRole::Reference: OS << "Ref"; break; 450 case SymbolRole::Read: OS << "Read"; break; 451 case SymbolRole::Write: OS << "Writ"; break; 452 case SymbolRole::Call: OS << "Call"; break; 453 case SymbolRole::Dynamic: OS << "Dyn"; break; 454 case SymbolRole::AddressOf: OS << "Addr"; break; 455 case SymbolRole::Implicit: OS << "Impl"; break; 456 case SymbolRole::Undefinition: OS << "Undef"; break; 457 case SymbolRole::RelationChildOf: OS << "RelChild"; break; 458 case SymbolRole::RelationBaseOf: OS << "RelBase"; break; 459 case SymbolRole::RelationOverrideOf: OS << "RelOver"; break; 460 case SymbolRole::RelationReceivedBy: OS << "RelRec"; break; 461 case SymbolRole::RelationCalledBy: OS << "RelCall"; break; 462 case SymbolRole::RelationExtendedBy: OS << "RelExt"; break; 463 case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break; 464 case SymbolRole::RelationContainedBy: OS << "RelCont"; break; 465 case SymbolRole::RelationIBTypeOf: OS << "RelIBType"; break; 466 case SymbolRole::RelationSpecializationOf: OS << "RelSpecialization"; break; 467 case SymbolRole::NameReference: OS << "NameReference"; break; 468 } 469 }); 470 } 471 472 bool index::printSymbolName(const Decl *D, const LangOptions &LO, 473 raw_ostream &OS) { 474 if (auto *ND = dyn_cast<NamedDecl>(D)) { 475 PrintingPolicy Policy(LO); 476 // Forward references can have different template argument names. Suppress 477 // the template argument names in constructors to make their name more 478 // stable. 479 Policy.SuppressTemplateArgsInCXXConstructors = true; 480 DeclarationName DeclName = ND->getDeclName(); 481 if (DeclName.isEmpty()) 482 return true; 483 DeclName.print(OS, Policy); 484 return false; 485 } else { 486 return true; 487 } 488 } 489 490 StringRef index::getSymbolKindString(SymbolKind K) { 491 switch (K) { 492 case SymbolKind::Unknown: return "<unknown>"; 493 case SymbolKind::Module: return "module"; 494 case SymbolKind::Namespace: return "namespace"; 495 case SymbolKind::NamespaceAlias: return "namespace-alias"; 496 case SymbolKind::Macro: return "macro"; 497 case SymbolKind::Enum: return "enum"; 498 case SymbolKind::Struct: return "struct"; 499 case SymbolKind::Class: return "class"; 500 case SymbolKind::Protocol: return "protocol"; 501 case SymbolKind::Extension: return "extension"; 502 case SymbolKind::Union: return "union"; 503 case SymbolKind::TypeAlias: return "type-alias"; 504 case SymbolKind::Function: return "function"; 505 case SymbolKind::Variable: return "variable"; 506 case SymbolKind::Field: return "field"; 507 case SymbolKind::EnumConstant: return "enumerator"; 508 case SymbolKind::InstanceMethod: return "instance-method"; 509 case SymbolKind::ClassMethod: return "class-method"; 510 case SymbolKind::StaticMethod: return "static-method"; 511 case SymbolKind::InstanceProperty: return "instance-property"; 512 case SymbolKind::ClassProperty: return "class-property"; 513 case SymbolKind::StaticProperty: return "static-property"; 514 case SymbolKind::Constructor: return "constructor"; 515 case SymbolKind::Destructor: return "destructor"; 516 case SymbolKind::ConversionFunction: return "conversion-func"; 517 case SymbolKind::Parameter: return "param"; 518 case SymbolKind::Using: return "using"; 519 } 520 llvm_unreachable("invalid symbol kind"); 521 } 522 523 StringRef index::getSymbolSubKindString(SymbolSubKind K) { 524 switch (K) { 525 case SymbolSubKind::None: return "<none>"; 526 case SymbolSubKind::CXXCopyConstructor: return "cxx-copy-ctor"; 527 case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor"; 528 case SymbolSubKind::AccessorGetter: return "acc-get"; 529 case SymbolSubKind::AccessorSetter: return "acc-set"; 530 case SymbolSubKind::UsingTypename: return "using-typename"; 531 case SymbolSubKind::UsingValue: return "using-value"; 532 } 533 llvm_unreachable("invalid symbol subkind"); 534 } 535 536 StringRef index::getSymbolLanguageString(SymbolLanguage K) { 537 switch (K) { 538 case SymbolLanguage::C: return "C"; 539 case SymbolLanguage::ObjC: return "ObjC"; 540 case SymbolLanguage::CXX: return "C++"; 541 case SymbolLanguage::Swift: return "Swift"; 542 } 543 llvm_unreachable("invalid symbol language kind"); 544 } 545 546 void index::applyForEachSymbolProperty(SymbolPropertySet Props, 547 llvm::function_ref<void(SymbolProperty)> Fn) { 548 #define APPLY_FOR_PROPERTY(K) \ 549 if (Props & (SymbolPropertySet)SymbolProperty::K) \ 550 Fn(SymbolProperty::K) 551 552 APPLY_FOR_PROPERTY(Generic); 553 APPLY_FOR_PROPERTY(TemplatePartialSpecialization); 554 APPLY_FOR_PROPERTY(TemplateSpecialization); 555 APPLY_FOR_PROPERTY(UnitTest); 556 APPLY_FOR_PROPERTY(IBAnnotated); 557 APPLY_FOR_PROPERTY(IBOutletCollection); 558 APPLY_FOR_PROPERTY(GKInspectable); 559 APPLY_FOR_PROPERTY(Local); 560 APPLY_FOR_PROPERTY(ProtocolInterface); 561 562 #undef APPLY_FOR_PROPERTY 563 } 564 565 void index::printSymbolProperties(SymbolPropertySet Props, raw_ostream &OS) { 566 bool VisitedOnce = false; 567 applyForEachSymbolProperty(Props, [&](SymbolProperty Prop) { 568 if (VisitedOnce) 569 OS << ','; 570 else 571 VisitedOnce = true; 572 switch (Prop) { 573 case SymbolProperty::Generic: OS << "Gen"; break; 574 case SymbolProperty::TemplatePartialSpecialization: OS << "TPS"; break; 575 case SymbolProperty::TemplateSpecialization: OS << "TS"; break; 576 case SymbolProperty::UnitTest: OS << "test"; break; 577 case SymbolProperty::IBAnnotated: OS << "IB"; break; 578 case SymbolProperty::IBOutletCollection: OS << "IBColl"; break; 579 case SymbolProperty::GKInspectable: OS << "GKI"; break; 580 case SymbolProperty::Local: OS << "local"; break; 581 case SymbolProperty::ProtocolInterface: OS << "protocol"; break; 582 } 583 }); 584 } 585