Path: blob/main/contrib/llvm-project/clang/lib/Index/IndexSymbol.cpp
35234 views
//===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Index/IndexSymbol.h"9#include "clang/AST/Attr.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"1516using namespace clang;17using namespace clang::index;1819/// \returns true if \c D is a subclass of 'XCTestCase'.20static bool isUnitTestCase(const ObjCInterfaceDecl *D) {21if (!D)22return false;23while (const ObjCInterfaceDecl *SuperD = D->getSuperClass()) {24if (SuperD->getName() == "XCTestCase")25return true;26D = SuperD;27}28return false;29}3031/// \returns true if \c D is in a subclass of 'XCTestCase', returns void, has32/// no parameters, and its name starts with 'test'.33static bool isUnitTest(const ObjCMethodDecl *D) {34if (!D->parameters().empty())35return false;36if (!D->getReturnType()->isVoidType())37return false;38if (!D->getSelector().getNameForSlot(0).starts_with("test"))39return false;40return isUnitTestCase(D->getClassInterface());41}4243static void checkForIBOutlets(const Decl *D, SymbolPropertySet &PropSet) {44if (D->hasAttr<IBOutletAttr>()) {45PropSet |= (SymbolPropertySet)SymbolProperty::IBAnnotated;46} else if (D->hasAttr<IBOutletCollectionAttr>()) {47PropSet |= (SymbolPropertySet)SymbolProperty::IBAnnotated;48PropSet |= (SymbolPropertySet)SymbolProperty::IBOutletCollection;49}50}5152bool index::isFunctionLocalSymbol(const Decl *D) {53assert(D);5455if (isa<ParmVarDecl>(D))56return true;5758if (isa<ObjCTypeParamDecl>(D))59return true;6061if (isa<UsingDirectiveDecl>(D))62return false;63if (!D->getParentFunctionOrMethod())64return false;6566if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {67switch (ND->getFormalLinkage()) {68case Linkage::Invalid:69llvm_unreachable("Linkage hasn't been computed!");70case Linkage::None:71case Linkage::Internal:72return true;73case Linkage::VisibleNone:74case Linkage::UniqueExternal:75llvm_unreachable("Not a sema linkage");76case Linkage::Module:77case Linkage::External:78return false;79}80}8182return true;83}8485SymbolInfo index::getSymbolInfo(const Decl *D) {86assert(D);87SymbolInfo Info;88Info.Kind = SymbolKind::Unknown;89Info.SubKind = SymbolSubKind::None;90Info.Properties = SymbolPropertySet();91Info.Lang = SymbolLanguage::C;9293if (isFunctionLocalSymbol(D)) {94Info.Properties |= (SymbolPropertySet)SymbolProperty::Local;95}96if (isa<ObjCProtocolDecl>(D->getDeclContext())) {97Info.Properties |= (SymbolPropertySet)SymbolProperty::ProtocolInterface;98}99100if (auto *VT = dyn_cast<VarTemplateDecl>(D)) {101Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;102Info.Lang = SymbolLanguage::CXX;103// All other fields are filled from the templated decl.104D = VT->getTemplatedDecl();105}106107if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {108switch (TD->getTagKind()) {109case TagTypeKind::Struct:110Info.Kind = SymbolKind::Struct; break;111case TagTypeKind::Union:112Info.Kind = SymbolKind::Union; break;113case TagTypeKind::Class:114Info.Kind = SymbolKind::Class;115Info.Lang = SymbolLanguage::CXX;116break;117case TagTypeKind::Interface:118Info.Kind = SymbolKind::Protocol;119Info.Lang = SymbolLanguage::CXX;120break;121case TagTypeKind::Enum:122Info.Kind = SymbolKind::Enum; break;123}124125if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) {126if (!CXXRec->isCLike()) {127Info.Lang = SymbolLanguage::CXX;128if (CXXRec->getDescribedClassTemplate()) {129Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;130}131}132}133134if (isa<ClassTemplatePartialSpecializationDecl>(D)) {135Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;136Info.Properties |=137(SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization;138} else if (isa<ClassTemplateSpecializationDecl>(D)) {139Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;140Info.Properties |=141(SymbolPropertySet)SymbolProperty::TemplateSpecialization;142}143144} else if (auto *VD = dyn_cast<VarDecl>(D)) {145Info.Kind = SymbolKind::Variable;146if (isa<ParmVarDecl>(D)) {147Info.Kind = SymbolKind::Parameter;148} else if (isa<CXXRecordDecl>(D->getDeclContext())) {149Info.Kind = SymbolKind::StaticProperty;150Info.Lang = SymbolLanguage::CXX;151}152153if (isa<VarTemplatePartialSpecializationDecl>(D)) {154Info.Lang = SymbolLanguage::CXX;155Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;156Info.Properties |=157(SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization;158} else if (isa<VarTemplateSpecializationDecl>(D)) {159Info.Lang = SymbolLanguage::CXX;160Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;161Info.Properties |=162(SymbolPropertySet)SymbolProperty::TemplateSpecialization;163} else if (VD->getDescribedVarTemplate()) {164Info.Lang = SymbolLanguage::CXX;165Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;166}167168} else {169switch (D->getKind()) {170case Decl::Import:171Info.Kind = SymbolKind::Module;172break;173case Decl::Typedef:174Info.Kind = SymbolKind::TypeAlias; break; // Lang = C175case Decl::Function:176Info.Kind = SymbolKind::Function;177break;178case Decl::Field:179case Decl::IndirectField:180Info.Kind = SymbolKind::Field;181if (const CXXRecordDecl *182CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {183if (!CXXRec->isCLike())184Info.Lang = SymbolLanguage::CXX;185}186break;187case Decl::EnumConstant:188Info.Kind = SymbolKind::EnumConstant; break;189case Decl::ObjCInterface:190case Decl::ObjCImplementation: {191Info.Kind = SymbolKind::Class;192Info.Lang = SymbolLanguage::ObjC;193const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D);194if (!ClsD)195ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface();196if (isUnitTestCase(ClsD))197Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;198break;199}200case Decl::ObjCProtocol:201Info.Kind = SymbolKind::Protocol;202Info.Lang = SymbolLanguage::ObjC;203break;204case Decl::ObjCCategory:205case Decl::ObjCCategoryImpl: {206Info.Kind = SymbolKind::Extension;207Info.Lang = SymbolLanguage::ObjC;208const ObjCInterfaceDecl *ClsD = nullptr;209if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D))210ClsD = CatD->getClassInterface();211else212ClsD = cast<ObjCCategoryImplDecl>(D)->getClassInterface();213if (isUnitTestCase(ClsD))214Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;215break;216}217case Decl::ObjCMethod: {218const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);219Info.Kind = MD->isInstanceMethod() ? SymbolKind::InstanceMethod : SymbolKind::ClassMethod;220if (MD->isPropertyAccessor()) {221if (MD->param_size())222Info.SubKind = SymbolSubKind::AccessorSetter;223else224Info.SubKind = SymbolSubKind::AccessorGetter;225}226Info.Lang = SymbolLanguage::ObjC;227if (isUnitTest(MD))228Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;229if (D->hasAttr<IBActionAttr>())230Info.Properties |= (SymbolPropertySet)SymbolProperty::IBAnnotated;231break;232}233case Decl::ObjCProperty:234Info.Kind = SymbolKind::InstanceProperty;235Info.Lang = SymbolLanguage::ObjC;236checkForIBOutlets(D, Info.Properties);237if (auto *Annot = D->getAttr<AnnotateAttr>()) {238if (Annot->getAnnotation() == "gk_inspectable")239Info.Properties |= (SymbolPropertySet)SymbolProperty::GKInspectable;240}241break;242case Decl::ObjCIvar:243Info.Kind = SymbolKind::Field;244Info.Lang = SymbolLanguage::ObjC;245checkForIBOutlets(D, Info.Properties);246break;247case Decl::Namespace:248Info.Kind = SymbolKind::Namespace;249Info.Lang = SymbolLanguage::CXX;250break;251case Decl::NamespaceAlias:252Info.Kind = SymbolKind::NamespaceAlias;253Info.Lang = SymbolLanguage::CXX;254break;255case Decl::CXXConstructor: {256Info.Kind = SymbolKind::Constructor;257Info.Lang = SymbolLanguage::CXX;258auto *CD = cast<CXXConstructorDecl>(D);259if (CD->isCopyConstructor())260Info.SubKind = SymbolSubKind::CXXCopyConstructor;261else if (CD->isMoveConstructor())262Info.SubKind = SymbolSubKind::CXXMoveConstructor;263break;264}265case Decl::CXXDestructor:266Info.Kind = SymbolKind::Destructor;267Info.Lang = SymbolLanguage::CXX;268break;269case Decl::CXXConversion:270Info.Kind = SymbolKind::ConversionFunction;271Info.Lang = SymbolLanguage::CXX;272break;273case Decl::CXXMethod: {274const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);275if (MD->isStatic())276Info.Kind = SymbolKind::StaticMethod;277else278Info.Kind = SymbolKind::InstanceMethod;279Info.Lang = SymbolLanguage::CXX;280break;281}282case Decl::ClassTemplate:283Info.Kind = SymbolKind::Class;284Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;285Info.Lang = SymbolLanguage::CXX;286break;287case Decl::FunctionTemplate:288Info.Kind = SymbolKind::Function;289Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;290Info.Lang = SymbolLanguage::CXX;291if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(292cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) {293if (isa<CXXConstructorDecl>(MD))294Info.Kind = SymbolKind::Constructor;295else if (isa<CXXDestructorDecl>(MD))296Info.Kind = SymbolKind::Destructor;297else if (isa<CXXConversionDecl>(MD))298Info.Kind = SymbolKind::ConversionFunction;299else {300if (MD->isStatic())301Info.Kind = SymbolKind::StaticMethod;302else303Info.Kind = SymbolKind::InstanceMethod;304}305}306break;307case Decl::TypeAliasTemplate:308Info.Kind = SymbolKind::TypeAlias;309Info.Lang = SymbolLanguage::CXX;310Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;311break;312case Decl::TypeAlias:313Info.Kind = SymbolKind::TypeAlias;314Info.Lang = SymbolLanguage::CXX;315break;316case Decl::UnresolvedUsingTypename:317Info.Kind = SymbolKind::Using;318Info.SubKind = SymbolSubKind::UsingTypename;319Info.Lang = SymbolLanguage::CXX;320Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;321break;322case Decl::UnresolvedUsingValue:323Info.Kind = SymbolKind::Using;324Info.SubKind = SymbolSubKind::UsingValue;325Info.Lang = SymbolLanguage::CXX;326Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;327break;328case Decl::Using:329Info.Kind = SymbolKind::Using;330Info.Lang = SymbolLanguage::CXX;331break;332case Decl::UsingEnum:333Info.Kind = SymbolKind::Using;334Info.Lang = SymbolLanguage::CXX;335Info.SubKind = SymbolSubKind::UsingEnum;336break;337case Decl::Binding:338Info.Kind = SymbolKind::Variable;339Info.Lang = SymbolLanguage::CXX;340break;341case Decl::MSProperty:342Info.Kind = SymbolKind::InstanceProperty;343if (const CXXRecordDecl *CXXRec =344dyn_cast<CXXRecordDecl>(D->getDeclContext())) {345if (!CXXRec->isCLike())346Info.Lang = SymbolLanguage::CXX;347}348break;349case Decl::ClassTemplatePartialSpecialization:350case Decl::ClassTemplateSpecialization:351case Decl::CXXRecord:352case Decl::Enum:353case Decl::Record:354llvm_unreachable("records handled before");355break;356case Decl::VarTemplateSpecialization:357case Decl::VarTemplatePartialSpecialization:358case Decl::ImplicitParam:359case Decl::ParmVar:360case Decl::Var:361case Decl::VarTemplate:362llvm_unreachable("variables handled before");363break;364case Decl::TemplateTypeParm:365Info.Kind = SymbolKind::TemplateTypeParm;366break;367case Decl::TemplateTemplateParm:368Info.Kind = SymbolKind::TemplateTemplateParm;369break;370case Decl::NonTypeTemplateParm:371Info.Kind = SymbolKind::NonTypeTemplateParm;372break;373case Decl::Concept:374Info.Kind = SymbolKind::Concept;375break;376// Other decls get the 'unknown' kind.377default:378break;379}380}381382if (Info.Kind == SymbolKind::Unknown)383return Info;384385if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {386if (FD->getTemplatedKind() ==387FunctionDecl::TK_FunctionTemplateSpecialization) {388Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;389Info.Properties |=390(SymbolPropertySet)SymbolProperty::TemplateSpecialization;391}392}393394if (Info.Properties & (SymbolPropertySet)SymbolProperty::Generic)395Info.Lang = SymbolLanguage::CXX;396397if (auto *attr = D->getExternalSourceSymbolAttr()) {398if (attr->getLanguage() == "Swift")399Info.Lang = SymbolLanguage::Swift;400}401402return Info;403}404405SymbolInfo index::getSymbolInfoForMacro(const MacroInfo &) {406SymbolInfo Info;407Info.Kind = SymbolKind::Macro;408Info.SubKind = SymbolSubKind::None;409Info.Properties = SymbolPropertySet();410Info.Lang = SymbolLanguage::C;411return Info;412}413414bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles,415llvm::function_ref<bool(SymbolRole)> Fn) {416#define APPLY_FOR_ROLE(Role) \417if (Roles & (unsigned)SymbolRole::Role) \418if (!Fn(SymbolRole::Role)) \419return false;420421APPLY_FOR_ROLE(Declaration);422APPLY_FOR_ROLE(Definition);423APPLY_FOR_ROLE(Reference);424APPLY_FOR_ROLE(Read);425APPLY_FOR_ROLE(Write);426APPLY_FOR_ROLE(Call);427APPLY_FOR_ROLE(Dynamic);428APPLY_FOR_ROLE(AddressOf);429APPLY_FOR_ROLE(Implicit);430APPLY_FOR_ROLE(Undefinition);431APPLY_FOR_ROLE(RelationChildOf);432APPLY_FOR_ROLE(RelationBaseOf);433APPLY_FOR_ROLE(RelationOverrideOf);434APPLY_FOR_ROLE(RelationReceivedBy);435APPLY_FOR_ROLE(RelationCalledBy);436APPLY_FOR_ROLE(RelationExtendedBy);437APPLY_FOR_ROLE(RelationAccessorOf);438APPLY_FOR_ROLE(RelationContainedBy);439APPLY_FOR_ROLE(RelationIBTypeOf);440APPLY_FOR_ROLE(RelationSpecializationOf);441APPLY_FOR_ROLE(NameReference);442443#undef APPLY_FOR_ROLE444445return true;446}447448void index::applyForEachSymbolRole(SymbolRoleSet Roles,449llvm::function_ref<void(SymbolRole)> Fn) {450applyForEachSymbolRoleInterruptible(Roles, [&](SymbolRole r) -> bool {451Fn(r);452return true;453});454}455456void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {457bool VisitedOnce = false;458applyForEachSymbolRole(Roles, [&](SymbolRole Role) {459if (VisitedOnce)460OS << ',';461else462VisitedOnce = true;463switch (Role) {464case SymbolRole::Declaration: OS << "Decl"; break;465case SymbolRole::Definition: OS << "Def"; break;466case SymbolRole::Reference: OS << "Ref"; break;467case SymbolRole::Read: OS << "Read"; break;468case SymbolRole::Write: OS << "Writ"; break;469case SymbolRole::Call: OS << "Call"; break;470case SymbolRole::Dynamic: OS << "Dyn"; break;471case SymbolRole::AddressOf: OS << "Addr"; break;472case SymbolRole::Implicit: OS << "Impl"; break;473case SymbolRole::Undefinition: OS << "Undef"; break;474case SymbolRole::RelationChildOf: OS << "RelChild"; break;475case SymbolRole::RelationBaseOf: OS << "RelBase"; break;476case SymbolRole::RelationOverrideOf: OS << "RelOver"; break;477case SymbolRole::RelationReceivedBy: OS << "RelRec"; break;478case SymbolRole::RelationCalledBy: OS << "RelCall"; break;479case SymbolRole::RelationExtendedBy: OS << "RelExt"; break;480case SymbolRole::RelationAccessorOf: OS << "RelAcc"; break;481case SymbolRole::RelationContainedBy: OS << "RelCont"; break;482case SymbolRole::RelationIBTypeOf: OS << "RelIBType"; break;483case SymbolRole::RelationSpecializationOf: OS << "RelSpecialization"; break;484case SymbolRole::NameReference: OS << "NameReference"; break;485}486});487}488489bool index::printSymbolName(const Decl *D, const LangOptions &LO,490raw_ostream &OS) {491if (auto *ND = dyn_cast<NamedDecl>(D)) {492PrintingPolicy Policy(LO);493// Forward references can have different template argument names. Suppress494// the template argument names in constructors to make their name more495// stable.496Policy.SuppressTemplateArgsInCXXConstructors = true;497DeclarationName DeclName = ND->getDeclName();498if (DeclName.isEmpty())499return true;500DeclName.print(OS, Policy);501return false;502} else {503return true;504}505}506507StringRef index::getSymbolKindString(SymbolKind K) {508switch (K) {509case SymbolKind::Unknown: return "<unknown>";510case SymbolKind::Module: return "module";511case SymbolKind::Namespace: return "namespace";512case SymbolKind::NamespaceAlias: return "namespace-alias";513case SymbolKind::Macro: return "macro";514case SymbolKind::Enum: return "enum";515case SymbolKind::Struct: return "struct";516case SymbolKind::Class: return "class";517case SymbolKind::Protocol: return "protocol";518case SymbolKind::Extension: return "extension";519case SymbolKind::Union: return "union";520case SymbolKind::TypeAlias: return "type-alias";521case SymbolKind::Function: return "function";522case SymbolKind::Variable: return "variable";523case SymbolKind::Field: return "field";524case SymbolKind::EnumConstant: return "enumerator";525case SymbolKind::InstanceMethod: return "instance-method";526case SymbolKind::ClassMethod: return "class-method";527case SymbolKind::StaticMethod: return "static-method";528case SymbolKind::InstanceProperty: return "instance-property";529case SymbolKind::ClassProperty: return "class-property";530case SymbolKind::StaticProperty: return "static-property";531case SymbolKind::Constructor: return "constructor";532case SymbolKind::Destructor: return "destructor";533case SymbolKind::ConversionFunction: return "conversion-func";534case SymbolKind::Parameter: return "param";535case SymbolKind::Using: return "using";536case SymbolKind::TemplateTypeParm: return "template-type-param";537case SymbolKind::TemplateTemplateParm: return "template-template-param";538case SymbolKind::NonTypeTemplateParm: return "non-type-template-param";539case SymbolKind::Concept:540return "concept";541}542llvm_unreachable("invalid symbol kind");543}544545StringRef index::getSymbolSubKindString(SymbolSubKind K) {546switch (K) {547case SymbolSubKind::None: return "<none>";548case SymbolSubKind::CXXCopyConstructor: return "cxx-copy-ctor";549case SymbolSubKind::CXXMoveConstructor: return "cxx-move-ctor";550case SymbolSubKind::AccessorGetter: return "acc-get";551case SymbolSubKind::AccessorSetter: return "acc-set";552case SymbolSubKind::UsingTypename: return "using-typename";553case SymbolSubKind::UsingValue: return "using-value";554case SymbolSubKind::UsingEnum: return "using-enum";555}556llvm_unreachable("invalid symbol subkind");557}558559StringRef index::getSymbolLanguageString(SymbolLanguage K) {560switch (K) {561case SymbolLanguage::C: return "C";562case SymbolLanguage::ObjC: return "ObjC";563case SymbolLanguage::CXX: return "C++";564case SymbolLanguage::Swift: return "Swift";565}566llvm_unreachable("invalid symbol language kind");567}568569void index::applyForEachSymbolProperty(SymbolPropertySet Props,570llvm::function_ref<void(SymbolProperty)> Fn) {571#define APPLY_FOR_PROPERTY(K) \572if (Props & (SymbolPropertySet)SymbolProperty::K) \573Fn(SymbolProperty::K)574575APPLY_FOR_PROPERTY(Generic);576APPLY_FOR_PROPERTY(TemplatePartialSpecialization);577APPLY_FOR_PROPERTY(TemplateSpecialization);578APPLY_FOR_PROPERTY(UnitTest);579APPLY_FOR_PROPERTY(IBAnnotated);580APPLY_FOR_PROPERTY(IBOutletCollection);581APPLY_FOR_PROPERTY(GKInspectable);582APPLY_FOR_PROPERTY(Local);583APPLY_FOR_PROPERTY(ProtocolInterface);584585#undef APPLY_FOR_PROPERTY586}587588void index::printSymbolProperties(SymbolPropertySet Props, raw_ostream &OS) {589bool VisitedOnce = false;590applyForEachSymbolProperty(Props, [&](SymbolProperty Prop) {591if (VisitedOnce)592OS << ',';593else594VisitedOnce = true;595switch (Prop) {596case SymbolProperty::Generic: OS << "Gen"; break;597case SymbolProperty::TemplatePartialSpecialization: OS << "TPS"; break;598case SymbolProperty::TemplateSpecialization: OS << "TS"; break;599case SymbolProperty::UnitTest: OS << "test"; break;600case SymbolProperty::IBAnnotated: OS << "IB"; break;601case SymbolProperty::IBOutletCollection: OS << "IBColl"; break;602case SymbolProperty::GKInspectable: OS << "GKI"; break;603case SymbolProperty::Local: OS << "local"; break;604case SymbolProperty::ProtocolInterface: OS << "protocol"; break;605}606});607}608609610