1*67e74705SXin Li //===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li
10*67e74705SXin Li #include "clang/Index/IndexSymbol.h"
11*67e74705SXin Li #include "clang/AST/DeclCXX.h"
12*67e74705SXin Li #include "clang/AST/DeclObjC.h"
13*67e74705SXin Li #include "clang/AST/DeclTemplate.h"
14*67e74705SXin Li #include "clang/AST/PrettyPrinter.h"
15*67e74705SXin Li
16*67e74705SXin Li using namespace clang;
17*67e74705SXin Li using namespace clang::index;
18*67e74705SXin Li
19*67e74705SXin Li /// \returns true if \c D is a subclass of 'XCTestCase'.
isUnitTestCase(const ObjCInterfaceDecl * D)20*67e74705SXin Li static bool isUnitTestCase(const ObjCInterfaceDecl *D) {
21*67e74705SXin Li if (!D)
22*67e74705SXin Li return false;
23*67e74705SXin Li while (const ObjCInterfaceDecl *SuperD = D->getSuperClass()) {
24*67e74705SXin Li if (SuperD->getName() == "XCTestCase")
25*67e74705SXin Li return true;
26*67e74705SXin Li D = SuperD;
27*67e74705SXin Li }
28*67e74705SXin Li return false;
29*67e74705SXin Li }
30*67e74705SXin Li
31*67e74705SXin Li /// \returns true if \c D is in a subclass of 'XCTestCase', returns void, has
32*67e74705SXin Li /// no parameters, and its name starts with 'test'.
isUnitTest(const ObjCMethodDecl * D)33*67e74705SXin Li static bool isUnitTest(const ObjCMethodDecl *D) {
34*67e74705SXin Li if (!D->parameters().empty())
35*67e74705SXin Li return false;
36*67e74705SXin Li if (!D->getReturnType()->isVoidType())
37*67e74705SXin Li return false;
38*67e74705SXin Li if (!D->getSelector().getNameForSlot(0).startswith("test"))
39*67e74705SXin Li return false;
40*67e74705SXin Li return isUnitTestCase(D->getClassInterface());
41*67e74705SXin Li }
42*67e74705SXin Li
checkForIBOutlets(const Decl * D,SymbolSubKindSet & SubKindSet)43*67e74705SXin Li static void checkForIBOutlets(const Decl *D, SymbolSubKindSet &SubKindSet) {
44*67e74705SXin Li if (D->hasAttr<IBOutletAttr>()) {
45*67e74705SXin Li SubKindSet |= (unsigned)SymbolSubKind::IBAnnotated;
46*67e74705SXin Li } else if (D->hasAttr<IBOutletCollectionAttr>()) {
47*67e74705SXin Li SubKindSet |= (unsigned)SymbolSubKind::IBAnnotated;
48*67e74705SXin Li SubKindSet |= (unsigned)SymbolSubKind::IBOutletCollection;
49*67e74705SXin Li }
50*67e74705SXin Li }
51*67e74705SXin Li
getSymbolInfo(const Decl * D)52*67e74705SXin Li SymbolInfo index::getSymbolInfo(const Decl *D) {
53*67e74705SXin Li assert(D);
54*67e74705SXin Li SymbolInfo Info;
55*67e74705SXin Li Info.Kind = SymbolKind::Unknown;
56*67e74705SXin Li Info.SubKinds = SymbolSubKindSet();
57*67e74705SXin Li Info.Lang = SymbolLanguage::C;
58*67e74705SXin Li
59*67e74705SXin Li if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
60*67e74705SXin Li switch (TD->getTagKind()) {
61*67e74705SXin Li case TTK_Struct:
62*67e74705SXin Li Info.Kind = SymbolKind::Struct; break;
63*67e74705SXin Li case TTK_Union:
64*67e74705SXin Li Info.Kind = SymbolKind::Union; break;
65*67e74705SXin Li case TTK_Class:
66*67e74705SXin Li Info.Kind = SymbolKind::Class;
67*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
68*67e74705SXin Li break;
69*67e74705SXin Li case TTK_Interface:
70*67e74705SXin Li Info.Kind = SymbolKind::Protocol;
71*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
72*67e74705SXin Li break;
73*67e74705SXin Li case TTK_Enum:
74*67e74705SXin Li Info.Kind = SymbolKind::Enum; break;
75*67e74705SXin Li }
76*67e74705SXin Li
77*67e74705SXin Li if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D))
78*67e74705SXin Li if (!CXXRec->isCLike())
79*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
80*67e74705SXin Li
81*67e74705SXin Li if (isa<ClassTemplatePartialSpecializationDecl>(D)) {
82*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
83*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::TemplatePartialSpecialization;
84*67e74705SXin Li } else if (isa<ClassTemplateSpecializationDecl>(D)) {
85*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
86*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::TemplateSpecialization;
87*67e74705SXin Li }
88*67e74705SXin Li
89*67e74705SXin Li } else {
90*67e74705SXin Li switch (D->getKind()) {
91*67e74705SXin Li case Decl::Import:
92*67e74705SXin Li Info.Kind = SymbolKind::Module;
93*67e74705SXin Li break;
94*67e74705SXin Li case Decl::Typedef:
95*67e74705SXin Li Info.Kind = SymbolKind::TypeAlias; break; // Lang = C
96*67e74705SXin Li case Decl::Function:
97*67e74705SXin Li Info.Kind = SymbolKind::Function;
98*67e74705SXin Li break;
99*67e74705SXin Li case Decl::ParmVar:
100*67e74705SXin Li Info.Kind = SymbolKind::Variable;
101*67e74705SXin Li break;
102*67e74705SXin Li case Decl::Var:
103*67e74705SXin Li Info.Kind = SymbolKind::Variable;
104*67e74705SXin Li if (isa<CXXRecordDecl>(D->getDeclContext())) {
105*67e74705SXin Li Info.Kind = SymbolKind::StaticProperty;
106*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
107*67e74705SXin Li }
108*67e74705SXin Li break;
109*67e74705SXin Li case Decl::Field:
110*67e74705SXin Li Info.Kind = SymbolKind::Field;
111*67e74705SXin Li if (const CXXRecordDecl *
112*67e74705SXin Li CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
113*67e74705SXin Li if (!CXXRec->isCLike())
114*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
115*67e74705SXin Li }
116*67e74705SXin Li break;
117*67e74705SXin Li case Decl::EnumConstant:
118*67e74705SXin Li Info.Kind = SymbolKind::EnumConstant; break;
119*67e74705SXin Li case Decl::ObjCInterface:
120*67e74705SXin Li case Decl::ObjCImplementation: {
121*67e74705SXin Li Info.Kind = SymbolKind::Class;
122*67e74705SXin Li Info.Lang = SymbolLanguage::ObjC;
123*67e74705SXin Li const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D);
124*67e74705SXin Li if (!ClsD)
125*67e74705SXin Li ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface();
126*67e74705SXin Li if (isUnitTestCase(ClsD))
127*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::UnitTest;
128*67e74705SXin Li break;
129*67e74705SXin Li }
130*67e74705SXin Li case Decl::ObjCProtocol:
131*67e74705SXin Li Info.Kind = SymbolKind::Protocol;
132*67e74705SXin Li Info.Lang = SymbolLanguage::ObjC;
133*67e74705SXin Li break;
134*67e74705SXin Li case Decl::ObjCCategory:
135*67e74705SXin Li case Decl::ObjCCategoryImpl:
136*67e74705SXin Li Info.Kind = SymbolKind::Extension;
137*67e74705SXin Li Info.Lang = SymbolLanguage::ObjC;
138*67e74705SXin Li break;
139*67e74705SXin Li case Decl::ObjCMethod:
140*67e74705SXin Li if (cast<ObjCMethodDecl>(D)->isInstanceMethod())
141*67e74705SXin Li Info.Kind = SymbolKind::InstanceMethod;
142*67e74705SXin Li else
143*67e74705SXin Li Info.Kind = SymbolKind::ClassMethod;
144*67e74705SXin Li Info.Lang = SymbolLanguage::ObjC;
145*67e74705SXin Li if (isUnitTest(cast<ObjCMethodDecl>(D)))
146*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::UnitTest;
147*67e74705SXin Li if (D->hasAttr<IBActionAttr>())
148*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::IBAnnotated;
149*67e74705SXin Li break;
150*67e74705SXin Li case Decl::ObjCProperty:
151*67e74705SXin Li Info.Kind = SymbolKind::InstanceProperty;
152*67e74705SXin Li Info.Lang = SymbolLanguage::ObjC;
153*67e74705SXin Li checkForIBOutlets(D, Info.SubKinds);
154*67e74705SXin Li break;
155*67e74705SXin Li case Decl::ObjCIvar:
156*67e74705SXin Li Info.Kind = SymbolKind::Field;
157*67e74705SXin Li Info.Lang = SymbolLanguage::ObjC;
158*67e74705SXin Li checkForIBOutlets(D, Info.SubKinds);
159*67e74705SXin Li break;
160*67e74705SXin Li case Decl::Namespace:
161*67e74705SXin Li Info.Kind = SymbolKind::Namespace;
162*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
163*67e74705SXin Li break;
164*67e74705SXin Li case Decl::NamespaceAlias:
165*67e74705SXin Li Info.Kind = SymbolKind::NamespaceAlias;
166*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
167*67e74705SXin Li break;
168*67e74705SXin Li case Decl::CXXConstructor:
169*67e74705SXin Li Info.Kind = SymbolKind::Constructor;
170*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
171*67e74705SXin Li break;
172*67e74705SXin Li case Decl::CXXDestructor:
173*67e74705SXin Li Info.Kind = SymbolKind::Destructor;
174*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
175*67e74705SXin Li break;
176*67e74705SXin Li case Decl::CXXConversion:
177*67e74705SXin Li Info.Kind = SymbolKind::ConversionFunction;
178*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
179*67e74705SXin Li break;
180*67e74705SXin Li case Decl::CXXMethod: {
181*67e74705SXin Li const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
182*67e74705SXin Li if (MD->isStatic())
183*67e74705SXin Li Info.Kind = SymbolKind::StaticMethod;
184*67e74705SXin Li else
185*67e74705SXin Li Info.Kind = SymbolKind::InstanceMethod;
186*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
187*67e74705SXin Li break;
188*67e74705SXin Li }
189*67e74705SXin Li case Decl::ClassTemplate:
190*67e74705SXin Li Info.Kind = SymbolKind::Class;
191*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
192*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
193*67e74705SXin Li break;
194*67e74705SXin Li case Decl::FunctionTemplate:
195*67e74705SXin Li Info.Kind = SymbolKind::Function;
196*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
197*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
198*67e74705SXin Li if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(
199*67e74705SXin Li cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) {
200*67e74705SXin Li if (isa<CXXConstructorDecl>(MD))
201*67e74705SXin Li Info.Kind = SymbolKind::Constructor;
202*67e74705SXin Li else if (isa<CXXDestructorDecl>(MD))
203*67e74705SXin Li Info.Kind = SymbolKind::Destructor;
204*67e74705SXin Li else if (isa<CXXConversionDecl>(MD))
205*67e74705SXin Li Info.Kind = SymbolKind::ConversionFunction;
206*67e74705SXin Li else {
207*67e74705SXin Li if (MD->isStatic())
208*67e74705SXin Li Info.Kind = SymbolKind::StaticMethod;
209*67e74705SXin Li else
210*67e74705SXin Li Info.Kind = SymbolKind::InstanceMethod;
211*67e74705SXin Li }
212*67e74705SXin Li }
213*67e74705SXin Li break;
214*67e74705SXin Li case Decl::TypeAliasTemplate:
215*67e74705SXin Li Info.Kind = SymbolKind::TypeAlias;
216*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
217*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
218*67e74705SXin Li break;
219*67e74705SXin Li case Decl::TypeAlias:
220*67e74705SXin Li Info.Kind = SymbolKind::TypeAlias;
221*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
222*67e74705SXin Li break;
223*67e74705SXin Li default:
224*67e74705SXin Li break;
225*67e74705SXin Li }
226*67e74705SXin Li }
227*67e74705SXin Li
228*67e74705SXin Li if (Info.Kind == SymbolKind::Unknown)
229*67e74705SXin Li return Info;
230*67e74705SXin Li
231*67e74705SXin Li if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
232*67e74705SXin Li if (FD->getTemplatedKind() ==
233*67e74705SXin Li FunctionDecl::TK_FunctionTemplateSpecialization) {
234*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::Generic;
235*67e74705SXin Li Info.SubKinds |= (unsigned)SymbolSubKind::TemplateSpecialization;
236*67e74705SXin Li }
237*67e74705SXin Li }
238*67e74705SXin Li
239*67e74705SXin Li if (Info.SubKinds & (unsigned)SymbolSubKind::Generic)
240*67e74705SXin Li Info.Lang = SymbolLanguage::CXX;
241*67e74705SXin Li
242*67e74705SXin Li return Info;
243*67e74705SXin Li }
244*67e74705SXin Li
applyForEachSymbolRole(SymbolRoleSet Roles,llvm::function_ref<void (SymbolRole)> Fn)245*67e74705SXin Li void index::applyForEachSymbolRole(SymbolRoleSet Roles,
246*67e74705SXin Li llvm::function_ref<void(SymbolRole)> Fn) {
247*67e74705SXin Li #define APPLY_FOR_ROLE(Role) \
248*67e74705SXin Li if (Roles & (unsigned)SymbolRole::Role) \
249*67e74705SXin Li Fn(SymbolRole::Role)
250*67e74705SXin Li
251*67e74705SXin Li APPLY_FOR_ROLE(Declaration);
252*67e74705SXin Li APPLY_FOR_ROLE(Definition);
253*67e74705SXin Li APPLY_FOR_ROLE(Reference);
254*67e74705SXin Li APPLY_FOR_ROLE(Read);
255*67e74705SXin Li APPLY_FOR_ROLE(Write);
256*67e74705SXin Li APPLY_FOR_ROLE(Call);
257*67e74705SXin Li APPLY_FOR_ROLE(Dynamic);
258*67e74705SXin Li APPLY_FOR_ROLE(AddressOf);
259*67e74705SXin Li APPLY_FOR_ROLE(Implicit);
260*67e74705SXin Li APPLY_FOR_ROLE(RelationChildOf);
261*67e74705SXin Li APPLY_FOR_ROLE(RelationBaseOf);
262*67e74705SXin Li APPLY_FOR_ROLE(RelationOverrideOf);
263*67e74705SXin Li APPLY_FOR_ROLE(RelationReceivedBy);
264*67e74705SXin Li APPLY_FOR_ROLE(RelationCalledBy);
265*67e74705SXin Li
266*67e74705SXin Li #undef APPLY_FOR_ROLE
267*67e74705SXin Li }
268*67e74705SXin Li
printSymbolRoles(SymbolRoleSet Roles,raw_ostream & OS)269*67e74705SXin Li void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
270*67e74705SXin Li bool VisitedOnce = false;
271*67e74705SXin Li applyForEachSymbolRole(Roles, [&](SymbolRole Role) {
272*67e74705SXin Li if (VisitedOnce)
273*67e74705SXin Li OS << ',';
274*67e74705SXin Li else
275*67e74705SXin Li VisitedOnce = true;
276*67e74705SXin Li switch (Role) {
277*67e74705SXin Li case SymbolRole::Declaration: OS << "Decl"; break;
278*67e74705SXin Li case SymbolRole::Definition: OS << "Def"; break;
279*67e74705SXin Li case SymbolRole::Reference: OS << "Ref"; break;
280*67e74705SXin Li case SymbolRole::Read: OS << "Read"; break;
281*67e74705SXin Li case SymbolRole::Write: OS << "Writ"; break;
282*67e74705SXin Li case SymbolRole::Call: OS << "Call"; break;
283*67e74705SXin Li case SymbolRole::Dynamic: OS << "Dyn"; break;
284*67e74705SXin Li case SymbolRole::AddressOf: OS << "Addr"; break;
285*67e74705SXin Li case SymbolRole::Implicit: OS << "Impl"; break;
286*67e74705SXin Li case SymbolRole::RelationChildOf: OS << "RelChild"; break;
287*67e74705SXin Li case SymbolRole::RelationBaseOf: OS << "RelBase"; break;
288*67e74705SXin Li case SymbolRole::RelationOverrideOf: OS << "RelOver"; break;
289*67e74705SXin Li case SymbolRole::RelationReceivedBy: OS << "RelRec"; break;
290*67e74705SXin Li case SymbolRole::RelationCalledBy: OS << "RelCall"; break;
291*67e74705SXin Li }
292*67e74705SXin Li });
293*67e74705SXin Li }
294*67e74705SXin Li
printSymbolName(const Decl * D,const LangOptions & LO,raw_ostream & OS)295*67e74705SXin Li bool index::printSymbolName(const Decl *D, const LangOptions &LO,
296*67e74705SXin Li raw_ostream &OS) {
297*67e74705SXin Li if (auto *ND = dyn_cast<NamedDecl>(D)) {
298*67e74705SXin Li PrintingPolicy Policy(LO);
299*67e74705SXin Li // Forward references can have different template argument names. Suppress
300*67e74705SXin Li // the template argument names in constructors to make their name more
301*67e74705SXin Li // stable.
302*67e74705SXin Li Policy.SuppressTemplateArgsInCXXConstructors = true;
303*67e74705SXin Li DeclarationName DeclName = ND->getDeclName();
304*67e74705SXin Li if (DeclName.isEmpty())
305*67e74705SXin Li return true;
306*67e74705SXin Li DeclName.print(OS, Policy);
307*67e74705SXin Li return false;
308*67e74705SXin Li } else {
309*67e74705SXin Li return true;
310*67e74705SXin Li }
311*67e74705SXin Li }
312*67e74705SXin Li
getSymbolKindString(SymbolKind K)313*67e74705SXin Li StringRef index::getSymbolKindString(SymbolKind K) {
314*67e74705SXin Li switch (K) {
315*67e74705SXin Li case SymbolKind::Unknown: return "<unknown>";
316*67e74705SXin Li case SymbolKind::Module: return "module";
317*67e74705SXin Li case SymbolKind::Namespace: return "namespace";
318*67e74705SXin Li case SymbolKind::NamespaceAlias: return "namespace-alias";
319*67e74705SXin Li case SymbolKind::Macro: return "macro";
320*67e74705SXin Li case SymbolKind::Enum: return "enum";
321*67e74705SXin Li case SymbolKind::Struct: return "struct";
322*67e74705SXin Li case SymbolKind::Class: return "class";
323*67e74705SXin Li case SymbolKind::Protocol: return "protocol";
324*67e74705SXin Li case SymbolKind::Extension: return "extension";
325*67e74705SXin Li case SymbolKind::Union: return "union";
326*67e74705SXin Li case SymbolKind::TypeAlias: return "type-alias";
327*67e74705SXin Li case SymbolKind::Function: return "function";
328*67e74705SXin Li case SymbolKind::Variable: return "variable";
329*67e74705SXin Li case SymbolKind::Field: return "field";
330*67e74705SXin Li case SymbolKind::EnumConstant: return "enumerator";
331*67e74705SXin Li case SymbolKind::InstanceMethod: return "instance-method";
332*67e74705SXin Li case SymbolKind::ClassMethod: return "class-method";
333*67e74705SXin Li case SymbolKind::StaticMethod: return "static-method";
334*67e74705SXin Li case SymbolKind::InstanceProperty: return "instance-property";
335*67e74705SXin Li case SymbolKind::ClassProperty: return "class-property";
336*67e74705SXin Li case SymbolKind::StaticProperty: return "static-property";
337*67e74705SXin Li case SymbolKind::Constructor: return "constructor";
338*67e74705SXin Li case SymbolKind::Destructor: return "destructor";
339*67e74705SXin Li case SymbolKind::ConversionFunction: return "coversion-func";
340*67e74705SXin Li }
341*67e74705SXin Li llvm_unreachable("invalid symbol kind");
342*67e74705SXin Li }
343*67e74705SXin Li
getSymbolLanguageString(SymbolLanguage K)344*67e74705SXin Li StringRef index::getSymbolLanguageString(SymbolLanguage K) {
345*67e74705SXin Li switch (K) {
346*67e74705SXin Li case SymbolLanguage::C: return "C";
347*67e74705SXin Li case SymbolLanguage::ObjC: return "ObjC";
348*67e74705SXin Li case SymbolLanguage::CXX: return "C++";
349*67e74705SXin Li }
350*67e74705SXin Li llvm_unreachable("invalid symbol language kind");
351*67e74705SXin Li }
352*67e74705SXin Li
applyForEachSymbolSubKind(SymbolSubKindSet SubKinds,llvm::function_ref<void (SymbolSubKind)> Fn)353*67e74705SXin Li void index::applyForEachSymbolSubKind(SymbolSubKindSet SubKinds,
354*67e74705SXin Li llvm::function_ref<void(SymbolSubKind)> Fn) {
355*67e74705SXin Li #define APPLY_FOR_SUBKIND(K) \
356*67e74705SXin Li if (SubKinds & (unsigned)SymbolSubKind::K) \
357*67e74705SXin Li Fn(SymbolSubKind::K)
358*67e74705SXin Li
359*67e74705SXin Li APPLY_FOR_SUBKIND(Generic);
360*67e74705SXin Li APPLY_FOR_SUBKIND(TemplatePartialSpecialization);
361*67e74705SXin Li APPLY_FOR_SUBKIND(TemplateSpecialization);
362*67e74705SXin Li APPLY_FOR_SUBKIND(UnitTest);
363*67e74705SXin Li APPLY_FOR_SUBKIND(IBAnnotated);
364*67e74705SXin Li APPLY_FOR_SUBKIND(IBOutletCollection);
365*67e74705SXin Li
366*67e74705SXin Li #undef APPLY_FOR_SUBKIND
367*67e74705SXin Li }
368*67e74705SXin Li
printSymbolSubKinds(SymbolSubKindSet SubKinds,raw_ostream & OS)369*67e74705SXin Li void index::printSymbolSubKinds(SymbolSubKindSet SubKinds, raw_ostream &OS) {
370*67e74705SXin Li bool VisitedOnce = false;
371*67e74705SXin Li applyForEachSymbolSubKind(SubKinds, [&](SymbolSubKind SubKind) {
372*67e74705SXin Li if (VisitedOnce)
373*67e74705SXin Li OS << ',';
374*67e74705SXin Li else
375*67e74705SXin Li VisitedOnce = true;
376*67e74705SXin Li switch (SubKind) {
377*67e74705SXin Li case SymbolSubKind::Generic: OS << "Gen"; break;
378*67e74705SXin Li case SymbolSubKind::TemplatePartialSpecialization: OS << "TPS"; break;
379*67e74705SXin Li case SymbolSubKind::TemplateSpecialization: OS << "TS"; break;
380*67e74705SXin Li case SymbolSubKind::UnitTest: OS << "test"; break;
381*67e74705SXin Li case SymbolSubKind::IBAnnotated: OS << "IB"; break;
382*67e74705SXin Li case SymbolSubKind::IBOutletCollection: OS << "IBColl"; break;
383*67e74705SXin Li }
384*67e74705SXin Li });
385*67e74705SXin Li }
386