brintos

brintos / llvm-project-archived public Read only

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