|  | //===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "clang/Index/IndexSymbol.h" | 
|  | #include "clang/AST/Attr.h" | 
|  | #include "clang/AST/DeclCXX.h" | 
|  | #include "clang/AST/DeclObjC.h" | 
|  | #include "clang/AST/DeclTemplate.h" | 
|  | #include "clang/AST/PrettyPrinter.h" | 
|  | #include "clang/Lex/MacroInfo.h" | 
|  |  | 
|  | using namespace clang; | 
|  | using namespace clang::index; | 
|  |  | 
|  | /// \returns true if \c D is a subclass of 'XCTestCase'. | 
|  | static bool isUnitTestCase(const ObjCInterfaceDecl *D) { | 
|  | if (!D) | 
|  | return false; | 
|  | while (const ObjCInterfaceDecl *SuperD = D->getSuperClass()) { | 
|  | if (SuperD->getName() == "XCTestCase") | 
|  | return true; | 
|  | D = SuperD; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// \returns true if \c D is in a subclass of 'XCTestCase', returns void, has | 
|  | /// no parameters, and its name starts with 'test'. | 
|  | static bool isUnitTest(const ObjCMethodDecl *D) { | 
|  | if (!D->parameters().empty()) | 
|  | return false; | 
|  | if (!D->getReturnType()->isVoidType()) | 
|  | return false; | 
|  | if (!D->getSelector().getNameForSlot(0).starts_with("test")) | 
|  | return false; | 
|  | return isUnitTestCase(D->getClassInterface()); | 
|  | } | 
|  |  | 
|  | static void checkForIBOutlets(const Decl *D, SymbolPropertySet &PropSet) { | 
|  | if (D->hasAttr<IBOutletAttr>()) { | 
|  | PropSet |= (SymbolPropertySet)SymbolProperty::IBAnnotated; | 
|  | } else if (D->hasAttr<IBOutletCollectionAttr>()) { | 
|  | PropSet |= (SymbolPropertySet)SymbolProperty::IBAnnotated; | 
|  | PropSet |= (SymbolPropertySet)SymbolProperty::IBOutletCollection; | 
|  | } | 
|  | } | 
|  |  | 
|  | bool index::isFunctionLocalSymbol(const Decl *D) { | 
|  | assert(D); | 
|  |  | 
|  | if (isa<ParmVarDecl>(D)) | 
|  | return true; | 
|  |  | 
|  | if (isa<ObjCTypeParamDecl>(D)) | 
|  | return true; | 
|  |  | 
|  | if (isa<UsingDirectiveDecl>(D)) | 
|  | return false; | 
|  | if (!D->getParentFunctionOrMethod()) | 
|  | return false; | 
|  |  | 
|  | if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) { | 
|  | switch (ND->getFormalLinkage()) { | 
|  | case Linkage::Invalid: | 
|  | llvm_unreachable("Linkage hasn't been computed!"); | 
|  | case Linkage::None: | 
|  | case Linkage::Internal: | 
|  | return true; | 
|  | case Linkage::VisibleNone: | 
|  | case Linkage::UniqueExternal: | 
|  | llvm_unreachable("Not a sema linkage"); | 
|  | case Linkage::Module: | 
|  | case Linkage::External: | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | SymbolInfo index::getSymbolInfo(const Decl *D) { | 
|  | assert(D); | 
|  | SymbolInfo Info; | 
|  | Info.Kind = SymbolKind::Unknown; | 
|  | Info.SubKind = SymbolSubKind::None; | 
|  | Info.Properties = SymbolPropertySet(); | 
|  | Info.Lang = SymbolLanguage::C; | 
|  |  | 
|  | if (isFunctionLocalSymbol(D)) { | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Local; | 
|  | } | 
|  | if (isa<ObjCProtocolDecl>(D->getDeclContext())) { | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::ProtocolInterface; | 
|  | } | 
|  |  | 
|  | if (auto *VT = dyn_cast<VarTemplateDecl>(D)) { | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | // All other fields are filled from the templated decl. | 
|  | D = VT->getTemplatedDecl(); | 
|  | } | 
|  |  | 
|  | if (const TagDecl *TD = dyn_cast<TagDecl>(D)) { | 
|  | switch (TD->getTagKind()) { | 
|  | case TagTypeKind::Struct: | 
|  | Info.Kind = SymbolKind::Struct; break; | 
|  | case TagTypeKind::Union: | 
|  | Info.Kind = SymbolKind::Union; break; | 
|  | case TagTypeKind::Class: | 
|  | Info.Kind = SymbolKind::Class; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case TagTypeKind::Interface: | 
|  | Info.Kind = SymbolKind::Protocol; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case TagTypeKind::Enum: | 
|  | Info.Kind = SymbolKind::Enum; break; | 
|  | } | 
|  |  | 
|  | if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) { | 
|  | if (!CXXRec->isCLike()) { | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | if (CXXRec->getDescribedClassTemplate()) { | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (isa<ClassTemplatePartialSpecializationDecl>(D)) { | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | Info.Properties |= | 
|  | (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization; | 
|  | } else if (isa<ClassTemplateSpecializationDecl>(D)) { | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | Info.Properties |= | 
|  | (SymbolPropertySet)SymbolProperty::TemplateSpecialization; | 
|  | } | 
|  |  | 
|  | } else if (auto *VD = dyn_cast<VarDecl>(D)) { | 
|  | Info.Kind = SymbolKind::Variable; | 
|  | if (isa<ParmVarDecl>(D)) { | 
|  | Info.Kind = SymbolKind::Parameter; | 
|  | } else if (isa<CXXRecordDecl>(D->getDeclContext())) { | 
|  | Info.Kind = SymbolKind::StaticProperty; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | } | 
|  |  | 
|  | if (isa<VarTemplatePartialSpecializationDecl>(D)) { | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | Info.Properties |= | 
|  | (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization; | 
|  | } else if (isa<VarTemplateSpecializationDecl>(D)) { | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | Info.Properties |= | 
|  | (SymbolPropertySet)SymbolProperty::TemplateSpecialization; | 
|  | } else if (VD->getDescribedVarTemplate()) { | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | } | 
|  |  | 
|  | } else { | 
|  | switch (D->getKind()) { | 
|  | case Decl::Import: | 
|  | Info.Kind = SymbolKind::Module; | 
|  | break; | 
|  | case Decl::Typedef: | 
|  | Info.Kind = SymbolKind::TypeAlias; break; // Lang = C | 
|  | case Decl::Function: | 
|  | Info.Kind = SymbolKind::Function; | 
|  | break; | 
|  | case Decl::Field: | 
|  | case Decl::IndirectField: | 
|  | Info.Kind = SymbolKind::Field; | 
|  | if (const CXXRecordDecl * | 
|  | CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) { | 
|  | if (!CXXRec->isCLike()) | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | } | 
|  | break; | 
|  | case Decl::EnumConstant: | 
|  | Info.Kind = SymbolKind::EnumConstant; break; | 
|  | case Decl::ObjCInterface: | 
|  | case Decl::ObjCImplementation: { | 
|  | Info.Kind = SymbolKind::Class; | 
|  | Info.Lang = SymbolLanguage::ObjC; | 
|  | const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D); | 
|  | if (!ClsD) | 
|  | ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface(); | 
|  | if (isUnitTestCase(ClsD)) | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest; | 
|  | break; | 
|  | } | 
|  | case Decl::ObjCProtocol: | 
|  | Info.Kind = SymbolKind::Protocol; | 
|  | Info.Lang = SymbolLanguage::ObjC; | 
|  | break; | 
|  | case Decl::ObjCCategory: | 
|  | case Decl::ObjCCategoryImpl: { | 
|  | Info.Kind = SymbolKind::Extension; | 
|  | Info.Lang = SymbolLanguage::ObjC; | 
|  | const ObjCInterfaceDecl *ClsD = nullptr; | 
|  | if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D)) | 
|  | ClsD = CatD->getClassInterface(); | 
|  | else | 
|  | ClsD = cast<ObjCCategoryImplDecl>(D)->getClassInterface(); | 
|  | if (isUnitTestCase(ClsD)) | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest; | 
|  | break; | 
|  | } | 
|  | case Decl::ObjCMethod: { | 
|  | const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D); | 
|  | Info.Kind = MD->isInstanceMethod() ? SymbolKind::InstanceMethod : SymbolKind::ClassMethod; | 
|  | if (MD->isPropertyAccessor()) { | 
|  | if (MD->param_size()) | 
|  | Info.SubKind = SymbolSubKind::AccessorSetter; | 
|  | else | 
|  | Info.SubKind = SymbolSubKind::AccessorGetter; | 
|  | } | 
|  | Info.Lang = SymbolLanguage::ObjC; | 
|  | if (isUnitTest(MD)) | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest; | 
|  | if (D->hasAttr<IBActionAttr>()) | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::IBAnnotated; | 
|  | break; | 
|  | } | 
|  | case Decl::ObjCProperty: | 
|  | Info.Kind = SymbolKind::InstanceProperty; | 
|  | Info.Lang = SymbolLanguage::ObjC; | 
|  | checkForIBOutlets(D, Info.Properties); | 
|  | if (auto *Annot = D->getAttr<AnnotateAttr>()) { | 
|  | if (Annot->getAnnotation() == "gk_inspectable") | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::GKInspectable; | 
|  | } | 
|  | break; | 
|  | case Decl::ObjCIvar: | 
|  | Info.Kind = SymbolKind::Field; | 
|  | Info.Lang = SymbolLanguage::ObjC; | 
|  | checkForIBOutlets(D, Info.Properties); | 
|  | break; | 
|  | case Decl::Namespace: | 
|  | Info.Kind = SymbolKind::Namespace; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case Decl::NamespaceAlias: | 
|  | Info.Kind = SymbolKind::NamespaceAlias; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case Decl::CXXConstructor: { | 
|  | Info.Kind = SymbolKind::Constructor; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | auto *CD = cast<CXXConstructorDecl>(D); | 
|  | if (CD->isCopyConstructor()) | 
|  | Info.SubKind = SymbolSubKind::CXXCopyConstructor; | 
|  | else if (CD->isMoveConstructor()) | 
|  | Info.SubKind = SymbolSubKind::CXXMoveConstructor; | 
|  | break; | 
|  | } | 
|  | case Decl::CXXDestructor: | 
|  | Info.Kind = SymbolKind::Destructor; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case Decl::CXXConversion: | 
|  | Info.Kind = SymbolKind::ConversionFunction; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case Decl::CXXMethod: { | 
|  | const CXXMethodDecl *MD = cast<CXXMethodDecl>(D); | 
|  | if (MD->isStatic()) | 
|  | Info.Kind = SymbolKind::StaticMethod; | 
|  | else | 
|  | Info.Kind = SymbolKind::InstanceMethod; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | } | 
|  | case Decl::ClassTemplate: | 
|  | Info.Kind = SymbolKind::Class; | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case Decl::FunctionTemplate: | 
|  | Info.Kind = SymbolKind::Function; | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>( | 
|  | cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) { | 
|  | if (isa<CXXConstructorDecl>(MD)) | 
|  | Info.Kind = SymbolKind::Constructor; | 
|  | else if (isa<CXXDestructorDecl>(MD)) | 
|  | Info.Kind = SymbolKind::Destructor; | 
|  | else if (isa<CXXConversionDecl>(MD)) | 
|  | Info.Kind = SymbolKind::ConversionFunction; | 
|  | else { | 
|  | if (MD->isStatic()) | 
|  | Info.Kind = SymbolKind::StaticMethod; | 
|  | else | 
|  | Info.Kind = SymbolKind::InstanceMethod; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case Decl::TypeAliasTemplate: | 
|  | Info.Kind = SymbolKind::TypeAlias; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | break; | 
|  | case Decl::TypeAlias: | 
|  | Info.Kind = SymbolKind::TypeAlias; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case Decl::UnresolvedUsingTypename: | 
|  | Info.Kind = SymbolKind::Using; | 
|  | Info.SubKind = SymbolSubKind::UsingTypename; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | break; | 
|  | case Decl::UnresolvedUsingValue: | 
|  | Info.Kind = SymbolKind::Using; | 
|  | Info.SubKind = SymbolSubKind::UsingValue; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | break; | 
|  | case Decl::Using: | 
|  | Info.Kind = SymbolKind::Using; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case Decl::UsingEnum: | 
|  | Info.Kind = SymbolKind::Using; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | Info.SubKind = SymbolSubKind::UsingEnum; | 
|  | break; | 
|  | case Decl::Binding: | 
|  | Info.Kind = SymbolKind::Variable; | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | break; | 
|  | case Decl::MSProperty: | 
|  | Info.Kind = SymbolKind::InstanceProperty; | 
|  | if (const CXXRecordDecl *CXXRec = | 
|  | dyn_cast<CXXRecordDecl>(D->getDeclContext())) { | 
|  | if (!CXXRec->isCLike()) | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  | } | 
|  | break; | 
|  | case Decl::ClassTemplatePartialSpecialization: | 
|  | case Decl::ClassTemplateSpecialization: | 
|  | case Decl::CXXRecord: | 
|  | case Decl::Enum: | 
|  | case Decl::Record: | 
|  | llvm_unreachable("records handled before"); | 
|  | break; | 
|  | case Decl::VarTemplateSpecialization: | 
|  | case Decl::VarTemplatePartialSpecialization: | 
|  | case Decl::ImplicitParam: | 
|  | case Decl::ParmVar: | 
|  | case Decl::Var: | 
|  | case Decl::VarTemplate: | 
|  | llvm_unreachable("variables handled before"); | 
|  | break; | 
|  | case Decl::TemplateTypeParm: | 
|  | Info.Kind = SymbolKind::TemplateTypeParm; | 
|  | break; | 
|  | case Decl::TemplateTemplateParm: | 
|  | Info.Kind = SymbolKind::TemplateTemplateParm; | 
|  | break; | 
|  | case Decl::NonTypeTemplateParm: | 
|  | Info.Kind = SymbolKind::NonTypeTemplateParm; | 
|  | break; | 
|  | case Decl::Concept: | 
|  | Info.Kind = SymbolKind::Concept; | 
|  | break; | 
|  | // Other decls get the 'unknown' kind. | 
|  | default: | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Info.Kind == SymbolKind::Unknown) | 
|  | return Info; | 
|  |  | 
|  | if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { | 
|  | if (FD->getTemplatedKind() == | 
|  | FunctionDecl::TK_FunctionTemplateSpecialization) { | 
|  | Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic; | 
|  | Info.Properties |= | 
|  | (SymbolPropertySet)SymbolProperty::TemplateSpecialization; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Info.Properties & (SymbolPropertySet)SymbolProperty::Generic) | 
|  | Info.Lang = SymbolLanguage::CXX; | 
|  |  | 
|  | if (auto *attr = D->getExternalSourceSymbolAttr()) { | 
|  | if (attr->getLanguage() == "Swift") | 
|  | Info.Lang = SymbolLanguage::Swift; | 
|  | } | 
|  |  | 
|  | return Info; | 
|  | } | 
|  |  | 
|  | SymbolInfo index::getSymbolInfoForMacro(const MacroInfo &) { | 
|  | SymbolInfo Info; | 
|  | Info.Kind = SymbolKind::Macro; | 
|  | Info.SubKind = SymbolSubKind::None; | 
|  | Info.Properties = SymbolPropertySet(); | 
|  | Info.Lang = SymbolLanguage::C; | 
|  | return Info; | 
|  | } | 
|  |  | 
|  | bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles, | 
|  | llvm::function_ref<bool(SymbolRole)> Fn) { | 
|  | #define APPLY_FOR_ROLE(Role) \ | 
|  | if (Roles & (unsigned)SymbolRole::Role) \ | 
|  | if (!Fn(SymbolRole::Role)) \ | 
|  | return false; | 
|  |  | 
|  | APPLY_FOR_ROLE(Declaration); | 
|  | APPLY_FOR_ROLE(Definition); | 
|  | APPLY_FOR_ROLE(Reference); | 
|  | APPLY_FOR_ROLE(Read); | 
|  | APPLY_FOR_ROLE(Write); | 
|  | APPLY_FOR_ROLE(Call); | 
|  | APPLY_FOR_ROLE(Dynamic); | 
|  | APPLY_FOR_ROLE(AddressOf); | 
|  | APPLY_FOR_ROLE(Implicit); | 
|  | APPLY_FOR_ROLE(Undefinition); | 
|  | APPLY_FOR_ROLE(RelationChildOf); | 
|  | APPLY_FOR_ROLE(RelationBaseOf); | 
|  | APPLY_FOR_ROLE(RelationOverrideOf); | 
|  | APPLY_FOR_ROLE(RelationReceivedBy); | 
|  | APPLY_FOR_ROLE(RelationCalledBy); | 
|  | APPLY_FOR_ROLE(RelationExtendedBy); | 
|  | APPLY_FOR_ROLE(RelationAccessorOf); | 
|  | APPLY_FOR_ROLE(RelationContainedBy); | 
|  | APPLY_FOR_ROLE(RelationIBTypeOf); | 
|  | APPLY_FOR_ROLE(RelationSpecializationOf); | 
|  | APPLY_FOR_ROLE(NameReference); | 
|  |  | 
|  | #undef APPLY_FOR_ROLE | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void index::applyForEachSymbolRole(SymbolRoleSet Roles, | 
|  | llvm::function_ref<void(SymbolRole)> Fn) { | 
|  | applyForEachSymbolRoleInterruptible(Roles, [&](SymbolRole r) -> bool { | 
|  | Fn(r); | 
|  | return true; | 
|  | }); | 
|  | } | 
|  |  | 
|  | void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) { | 
|  | bool VisitedOnce = false; | 
|  | applyForEachSymbolRole(Roles, [&](SymbolRole Role) { | 
|  | if (VisitedOnce) | 
|  | OS << ','; | 
|  | else | 
|  | VisitedOnce = true; | 
|  | switch (Role) { | 
|  | case SymbolRole::Declaration: OS << "Decl"; break; | 
|  | case SymbolRole::Definition: OS << "Def"; break; | 
|  | case SymbolRole::Reference: OS << "Ref"; break; | 
|  | case SymbolRole::Read: OS << "Read"; break; | 
|  | case SymbolRole::Write: OS << "Writ"; break; | 
|  | case SymbolRole::Call: OS << "Call"; break; | 
|  | case SymbolRole::Dynamic: OS << "Dyn"; break; | 
|  | case SymbolRole::AddressOf: OS << "Addr"; break; | 
|  | case SymbolRole::Implicit: OS << "Impl"; break; | 
|  | case SymbolRole::Undefinition: OS << "Undef"; break; | 
|  | case SymbolRole::RelationChildOf: OS << "RelChild"; break; | 
|  | case SymbolRole::RelationBaseOf: OS << "RelBase"; break; | 
|  | case SymbolRole::RelationOverrideOf: OS << "RelOver"; break; | 
|  | case SymbolRole::RelationReceivedBy: OS << "RelRec"; break; | 
|  | case SymbolRole::RelationCalledBy: OS << "RelCall"; break; | 
|  | case SymbolRole::RelationExtendedBy: OS << "RelExt"; break; | 
|  | case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break; | 
|  | case SymbolRole::RelationContainedBy: OS << "RelCont"; break; | 
|  | case SymbolRole::RelationIBTypeOf: OS << "RelIBType"; break; | 
|  | case SymbolRole::RelationSpecializationOf: OS << "RelSpecialization"; break; | 
|  | case SymbolRole::NameReference: OS << "NameReference"; break; | 
|  | } | 
|  | }); | 
|  | } | 
|  |  | 
|  | bool index::printSymbolName(const Decl *D, const LangOptions &LO, | 
|  | raw_ostream &OS) { | 
|  | if (auto *ND = dyn_cast<NamedDecl>(D)) { | 
|  | PrintingPolicy Policy(LO); | 
|  | // Forward references can have different template argument names. Suppress | 
|  | // the template argument names in constructors to make their name more | 
|  | // stable. | 
|  | Policy.SuppressTemplateArgsInCXXConstructors = true; | 
|  | DeclarationName DeclName = ND->getDeclName(); | 
|  | if (DeclName.isEmpty()) | 
|  | return true; | 
|  | DeclName.print(OS, Policy); | 
|  | return false; | 
|  | } else { | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | StringRef index::getSymbolKindString(SymbolKind K) { | 
|  | switch (K) { | 
|  | case SymbolKind::Unknown: return "<unknown>"; | 
|  | case SymbolKind::Module: return "module"; | 
|  | case SymbolKind::Namespace: return "namespace"; | 
|  | case SymbolKind::NamespaceAlias: return "namespace-alias"; | 
|  | case SymbolKind::Macro: return "macro"; | 
|  | case SymbolKind::Enum: return "enum"; | 
|  | case SymbolKind::Struct: return "struct"; | 
|  | case SymbolKind::Class: return "class"; | 
|  | case SymbolKind::Protocol: return "protocol"; | 
|  | case SymbolKind::Extension: return "extension"; | 
|  | case SymbolKind::Union: return "union"; | 
|  | case SymbolKind::TypeAlias: return "type-alias"; | 
|  | case SymbolKind::Function: return "function"; | 
|  | case SymbolKind::Variable: return "variable"; | 
|  | case SymbolKind::Field: return "field"; | 
|  | case SymbolKind::EnumConstant: return "enumerator"; | 
|  | case SymbolKind::InstanceMethod: return "instance-method"; | 
|  | case SymbolKind::ClassMethod: return "class-method"; | 
|  | case SymbolKind::StaticMethod: return "static-method"; | 
|  | case SymbolKind::InstanceProperty: return "instance-property"; | 
|  | case SymbolKind::ClassProperty: return "class-property"; | 
|  | case SymbolKind::StaticProperty: return "static-property"; | 
|  | case SymbolKind::Constructor: return "constructor"; | 
|  | case SymbolKind::Destructor: return "destructor"; | 
|  | case SymbolKind::ConversionFunction: return "conversion-func"; | 
|  | case SymbolKind::Parameter: return "param"; | 
|  | case SymbolKind::Using: return "using"; | 
|  | case SymbolKind::TemplateTypeParm: return "template-type-param"; | 
|  | case SymbolKind::TemplateTemplateParm: return "template-template-param"; | 
|  | case SymbolKind::NonTypeTemplateParm: return "non-type-template-param"; | 
|  | case SymbolKind::Concept: | 
|  | return "concept"; | 
|  | } | 
|  | llvm_unreachable("invalid symbol kind"); | 
|  | } | 
|  |  | 
|  | StringRef index::getSymbolSubKindString(SymbolSubKind K) { | 
|  | switch (K) { | 
|  | case SymbolSubKind::None: return "<none>"; | 
|  | case SymbolSubKind::CXXCopyConstructor: return "cxx-copy-ctor"; | 
|  | case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor"; | 
|  | case SymbolSubKind::AccessorGetter: return "acc-get"; | 
|  | case SymbolSubKind::AccessorSetter: return "acc-set"; | 
|  | case SymbolSubKind::UsingTypename: return "using-typename"; | 
|  | case SymbolSubKind::UsingValue: return "using-value"; | 
|  | case SymbolSubKind::UsingEnum: | 
|  | return "using-enum"; | 
|  | } | 
|  | llvm_unreachable("invalid symbol subkind"); | 
|  | } | 
|  |  | 
|  | StringRef index::getSymbolLanguageString(SymbolLanguage K) { | 
|  | switch (K) { | 
|  | case SymbolLanguage::C: return "C"; | 
|  | case SymbolLanguage::ObjC: return "ObjC"; | 
|  | case SymbolLanguage::CXX: return "C++"; | 
|  | case SymbolLanguage::Swift: return "Swift"; | 
|  | } | 
|  | llvm_unreachable("invalid symbol language kind"); | 
|  | } | 
|  |  | 
|  | void index::applyForEachSymbolProperty(SymbolPropertySet Props, | 
|  | llvm::function_ref<void(SymbolProperty)> Fn) { | 
|  | #define APPLY_FOR_PROPERTY(K)                                                  \ | 
|  | if (Props & (SymbolPropertySet)SymbolProperty::K)                            \ | 
|  | Fn(SymbolProperty::K) | 
|  |  | 
|  | APPLY_FOR_PROPERTY(Generic); | 
|  | APPLY_FOR_PROPERTY(TemplatePartialSpecialization); | 
|  | APPLY_FOR_PROPERTY(TemplateSpecialization); | 
|  | APPLY_FOR_PROPERTY(UnitTest); | 
|  | APPLY_FOR_PROPERTY(IBAnnotated); | 
|  | APPLY_FOR_PROPERTY(IBOutletCollection); | 
|  | APPLY_FOR_PROPERTY(GKInspectable); | 
|  | APPLY_FOR_PROPERTY(Local); | 
|  | APPLY_FOR_PROPERTY(ProtocolInterface); | 
|  |  | 
|  | #undef APPLY_FOR_PROPERTY | 
|  | } | 
|  |  | 
|  | void index::printSymbolProperties(SymbolPropertySet Props, raw_ostream &OS) { | 
|  | bool VisitedOnce = false; | 
|  | applyForEachSymbolProperty(Props, [&](SymbolProperty Prop) { | 
|  | if (VisitedOnce) | 
|  | OS << ','; | 
|  | else | 
|  | VisitedOnce = true; | 
|  | switch (Prop) { | 
|  | case SymbolProperty::Generic: OS << "Gen"; break; | 
|  | case SymbolProperty::TemplatePartialSpecialization: OS << "TPS"; break; | 
|  | case SymbolProperty::TemplateSpecialization: OS << "TS"; break; | 
|  | case SymbolProperty::UnitTest: OS << "test"; break; | 
|  | case SymbolProperty::IBAnnotated: OS << "IB"; break; | 
|  | case SymbolProperty::IBOutletCollection: OS << "IBColl"; break; | 
|  | case SymbolProperty::GKInspectable: OS << "GKI"; break; | 
|  | case SymbolProperty::Local: OS << "local"; break; | 
|  | case SymbolProperty::ProtocolInterface: OS << "protocol"; break; | 
|  | } | 
|  | }); | 
|  | } |