Clang Project

clang_source_code/lib/Index/IndexSymbol.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-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
16using namespace clang;
17using namespace clang::index;
18
19/// \returns true if \c D is a subclass of 'XCTestCase'.
20static 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'.
33static 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
43static void checkForIBOutlets(const Decl *DSymbolPropertySet &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
52bool 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
84SymbolInfo 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 (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
100    switch (TD->getTagKind()) {
101    case TTK_Struct:
102      Info.Kind = SymbolKind::Structbreak;
103    case TTK_Union:
104      Info.Kind = SymbolKind::Unionbreak;
105    case TTK_Class:
106      Info.Kind = SymbolKind::Class;
107      Info.Lang = SymbolLanguage::CXX;
108      break;
109    case TTK_Interface:
110      Info.Kind = SymbolKind::Protocol;
111      Info.Lang = SymbolLanguage::CXX;
112      break;
113    case TTK_Enum:
114      Info.Kind = SymbolKind::Enumbreak;
115    }
116
117    if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) {
118      if (!CXXRec->isCLike()) {
119        Info.Lang = SymbolLanguage::CXX;
120        if (CXXRec->getDescribedClassTemplate()) {
121          Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
122        }
123      }
124    }
125
126    if (isa<ClassTemplatePartialSpecializationDecl>(D)) {
127      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
128      Info.Properties |=
129          (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization;
130    } else if (isa<ClassTemplateSpecializationDecl>(D)) {
131      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
132      Info.Properties |=
133          (SymbolPropertySet)SymbolProperty::TemplateSpecialization;
134    }
135
136  } else if (auto *VD = dyn_cast<VarDecl>(D)) {
137    Info.Kind = SymbolKind::Variable;
138    if (isa<ParmVarDecl>(D)) {
139      Info.Kind = SymbolKind::Parameter;
140    } else if (isa<CXXRecordDecl>(D->getDeclContext())) {
141      Info.Kind = SymbolKind::StaticProperty;
142      Info.Lang = SymbolLanguage::CXX;
143    }
144
145    if (isa<VarTemplatePartialSpecializationDecl>(D)) {
146      Info.Lang = SymbolLanguage::CXX;
147      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
148      Info.Properties |=
149          (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization;
150    } else if (isa<VarTemplateSpecializationDecl>(D)) {
151      Info.Lang = SymbolLanguage::CXX;
152      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
153      Info.Properties |=
154          (SymbolPropertySet)SymbolProperty::TemplateSpecialization;
155    } else if (VD->getDescribedVarTemplate()) {
156      Info.Lang = SymbolLanguage::CXX;
157      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
158    }
159
160  } else {
161    switch (D->getKind()) {
162    case Decl::Import:
163      Info.Kind = SymbolKind::Module;
164      break;
165    case Decl::Typedef:
166      Info.Kind = SymbolKind::TypeAliasbreak// Lang = C
167    case Decl::Function:
168      Info.Kind = SymbolKind::Function;
169      break;
170    case Decl::Field:
171      Info.Kind = SymbolKind::Field;
172      if (const CXXRecordDecl *
173            CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
174        if (!CXXRec->isCLike())
175          Info.Lang = SymbolLanguage::CXX;
176      }
177      break;
178    case Decl::EnumConstant:
179      Info.Kind = SymbolKind::EnumConstantbreak;
180    case Decl::ObjCInterface:
181    case Decl::ObjCImplementation: {
182      Info.Kind = SymbolKind::Class;
183      Info.Lang = SymbolLanguage::ObjC;
184      const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D);
185      if (!ClsD)
186        ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface();
187      if (isUnitTestCase(ClsD))
188        Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;
189      break;
190    }
191    case Decl::ObjCProtocol:
192      Info.Kind = SymbolKind::Protocol;
193      Info.Lang = SymbolLanguage::ObjC;
194      break;
195    case Decl::ObjCCategory:
196    case Decl::ObjCCategoryImpl: {
197      Info.Kind = SymbolKind::Extension;
198      Info.Lang = SymbolLanguage::ObjC;
199      const ObjCInterfaceDecl *ClsD = nullptr;
200      if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D))
201        ClsD = CatD->getClassInterface();
202      else
203        ClsD = cast<ObjCCategoryImplDecl>(D)->getClassInterface();
204      if (isUnitTestCase(ClsD))
205        Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;
206      break;
207    }
208    case Decl::ObjCMethod: {
209      const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
210      Info.Kind = MD->isInstanceMethod() ? SymbolKind::InstanceMethod : SymbolKind::ClassMethod;
211      if (MD->isPropertyAccessor()) {
212        if (MD->param_size())
213          Info.SubKind = SymbolSubKind::AccessorSetter;
214        else
215          Info.SubKind = SymbolSubKind::AccessorGetter;
216      }
217      Info.Lang = SymbolLanguage::ObjC;
218      if (isUnitTest(MD))
219        Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;
220      if (D->hasAttr<IBActionAttr>())
221        Info.Properties |= (SymbolPropertySet)SymbolProperty::IBAnnotated;
222      break;
223    }
224    case Decl::ObjCProperty:
225      Info.Kind = SymbolKind::InstanceProperty;
226      Info.Lang = SymbolLanguage::ObjC;
227      checkForIBOutlets(DInfo.Properties);
228      if (auto *Annot = D->getAttr<AnnotateAttr>()) {
229        if (Annot->getAnnotation() == "gk_inspectable")
230          Info.Properties |= (SymbolPropertySet)SymbolProperty::GKInspectable;
231      }
232      break;
233    case Decl::ObjCIvar:
234      Info.Kind = SymbolKind::Field;
235      Info.Lang = SymbolLanguage::ObjC;
236      checkForIBOutlets(DInfo.Properties);
237      break;
238    case Decl::Namespace:
239      Info.Kind = SymbolKind::Namespace;
240      Info.Lang = SymbolLanguage::CXX;
241      break;
242    case Decl::NamespaceAlias:
243      Info.Kind = SymbolKind::NamespaceAlias;
244      Info.Lang = SymbolLanguage::CXX;
245      break;
246    case Decl::CXXConstructor: {
247      Info.Kind = SymbolKind::Constructor;
248      Info.Lang = SymbolLanguage::CXX;
249      auto *CD = cast<CXXConstructorDecl>(D);
250      if (CD->isCopyConstructor())
251        Info.SubKind = SymbolSubKind::CXXCopyConstructor;
252      else if (CD->isMoveConstructor())
253        Info.SubKind = SymbolSubKind::CXXMoveConstructor;
254      break;
255    }
256    case Decl::CXXDestructor:
257      Info.Kind = SymbolKind::Destructor;
258      Info.Lang = SymbolLanguage::CXX;
259      break;
260    case Decl::CXXConversion:
261      Info.Kind = SymbolKind::ConversionFunction;
262      Info.Lang = SymbolLanguage::CXX;
263      break;
264    case Decl::CXXMethod: {
265      const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
266      if (MD->isStatic())
267        Info.Kind = SymbolKind::StaticMethod;
268      else
269        Info.Kind = SymbolKind::InstanceMethod;
270      Info.Lang = SymbolLanguage::CXX;
271      break;
272    }
273    case Decl::ClassTemplate:
274      Info.Kind = SymbolKind::Class;
275      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
276      Info.Lang = SymbolLanguage::CXX;
277      break;
278    case Decl::FunctionTemplate:
279      Info.Kind = SymbolKind::Function;
280      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
281      Info.Lang = SymbolLanguage::CXX;
282      if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(
283                           cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) {
284        if (isa<CXXConstructorDecl>(MD))
285          Info.Kind = SymbolKind::Constructor;
286        else if (isa<CXXDestructorDecl>(MD))
287          Info.Kind = SymbolKind::Destructor;
288        else if (isa<CXXConversionDecl>(MD))
289          Info.Kind = SymbolKind::ConversionFunction;
290        else {
291          if (MD->isStatic())
292            Info.Kind = SymbolKind::StaticMethod;
293          else
294            Info.Kind = SymbolKind::InstanceMethod;
295        }
296      }
297      break;
298    case Decl::TypeAliasTemplate:
299      Info.Kind = SymbolKind::TypeAlias;
300      Info.Lang = SymbolLanguage::CXX;
301      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
302      break;
303    case Decl::TypeAlias:
304      Info.Kind = SymbolKind::TypeAlias;
305      Info.Lang = SymbolLanguage::CXX;
306      break;
307    case Decl::UnresolvedUsingTypename:
308      Info.Kind = SymbolKind::Using;
309      Info.SubKind = SymbolSubKind::UsingTypename;
310      Info.Lang = SymbolLanguage::CXX;
311      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
312      break;
313    case Decl::UnresolvedUsingValue:
314      Info.Kind = SymbolKind::Using;
315      Info.SubKind = SymbolSubKind::UsingValue;
316      Info.Lang = SymbolLanguage::CXX;
317      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
318      break;
319    case Decl::Using:
320      Info.Kind = SymbolKind::Using;
321      Info.Lang = SymbolLanguage::CXX;
322      break;
323    case Decl::Binding:
324      Info.Kind = SymbolKind::Variable;
325      Info.Lang = SymbolLanguage::CXX;
326      break;
327    case Decl::MSProperty:
328      Info.Kind = SymbolKind::InstanceProperty;
329      if (const CXXRecordDecl *CXXRec =
330              dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
331        if (!CXXRec->isCLike())
332          Info.Lang = SymbolLanguage::CXX;
333      }
334      break;
335    default:
336      break;
337    }
338  }
339
340  if (Info.Kind == SymbolKind::Unknown)
341    return Info;
342
343  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
344    if (FD->getTemplatedKind() ==
345          FunctionDecl::TK_FunctionTemplateSpecialization) {
346      Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
347      Info.Properties |=
348          (SymbolPropertySet)SymbolProperty::TemplateSpecialization;
349    }
350  }
351
352  if (Info.Properties & (SymbolPropertySet)SymbolProperty::Generic)
353    Info.Lang = SymbolLanguage::CXX;
354
355  if (auto *attr = D->getExternalSourceSymbolAttr()) {
356    if (attr->getLanguage() == "Swift")
357      Info.Lang = SymbolLanguage::Swift;
358  }
359
360  return Info;
361}
362
363SymbolInfo index::getSymbolInfoForMacro(const MacroInfo &) {
364  SymbolInfo Info;
365  Info.Kind = SymbolKind::Macro;
366  Info.SubKind = SymbolSubKind::None;
367  Info.Properties = SymbolPropertySet();
368  Info.Lang = SymbolLanguage::C;
369  return Info;
370}
371
372bool index::applyForEachSymbolRoleInterruptible(SymbolRoleSet Roles,
373                                   llvm::function_ref<bool(SymbolRole)> Fn) {
374#define APPLY_FOR_ROLE(Role) \
375  if (Roles & (unsigned)SymbolRole::Role) \
376    if (!Fn(SymbolRole::Role)) \
377      return false;
378
379  APPLY_FOR_ROLE(Declaration);
380  APPLY_FOR_ROLE(Definition);
381  APPLY_FOR_ROLE(Reference);
382  APPLY_FOR_ROLE(Read);
383  APPLY_FOR_ROLE(Write);
384  APPLY_FOR_ROLE(Call);
385  APPLY_FOR_ROLE(Dynamic);
386  APPLY_FOR_ROLE(AddressOf);
387  APPLY_FOR_ROLE(Implicit);
388  APPLY_FOR_ROLE(Undefinition);
389  APPLY_FOR_ROLE(RelationChildOf);
390  APPLY_FOR_ROLE(RelationBaseOf);
391  APPLY_FOR_ROLE(RelationOverrideOf);
392  APPLY_FOR_ROLE(RelationReceivedBy);
393  APPLY_FOR_ROLE(RelationCalledBy);
394  APPLY_FOR_ROLE(RelationExtendedBy);
395  APPLY_FOR_ROLE(RelationAccessorOf);
396  APPLY_FOR_ROLE(RelationContainedBy);
397  APPLY_FOR_ROLE(RelationIBTypeOf);
398  APPLY_FOR_ROLE(RelationSpecializationOf);
399  APPLY_FOR_ROLE(NameReference);
400
401#undef APPLY_FOR_ROLE
402
403  return true;
404}
405
406void index::applyForEachSymbolRole(SymbolRoleSet Roles,
407                                   llvm::function_ref<void(SymbolRole)> Fn) {
408  applyForEachSymbolRoleInterruptible(Roles, [&](SymbolRole r) -> bool {
409    Fn(r);
410    return true;
411  });
412}
413
414void index::printSymbolRoles(SymbolRoleSet Rolesraw_ostream &OS) {
415  bool VisitedOnce = false;
416  applyForEachSymbolRole(Roles, [&](SymbolRole Role) {
417    if (VisitedOnce)
418      OS << ',';
419    else
420      VisitedOnce = true;
421    switch (Role) {
422    case SymbolRole::DeclarationOS << "Decl"break;
423    case SymbolRole::DefinitionOS << "Def"break;
424    case SymbolRole::ReferenceOS << "Ref"break;
425    case SymbolRole::ReadOS << "Read"break;
426    case SymbolRole::WriteOS << "Writ"break;
427    case SymbolRole::CallOS << "Call"break;
428    case SymbolRole::DynamicOS << "Dyn"break;
429    case SymbolRole::AddressOfOS << "Addr"break;
430    case SymbolRole::ImplicitOS << "Impl"break;
431    case SymbolRole::UndefinitionOS << "Undef"break;
432    case SymbolRole::RelationChildOfOS << "RelChild"break;
433    case SymbolRole::RelationBaseOfOS << "RelBase"break;
434    case SymbolRole::RelationOverrideOfOS << "RelOver"break;
435    case SymbolRole::RelationReceivedByOS << "RelRec"break;
436    case SymbolRole::RelationCalledByOS << "RelCall"break;
437    case SymbolRole::RelationExtendedByOS << "RelExt"break;
438    case SymbolRole::RelationAccessorOfOS << "RelAcc"break;
439    case SymbolRole::RelationContainedByOS << "RelCont"break;
440    case SymbolRole::RelationIBTypeOfOS << "RelIBType"break;
441    case SymbolRole::RelationSpecializationOfOS << "RelSpecialization"break;
442    case SymbolRole::NameReferenceOS << "NameReference"break;
443    }
444  });
445}
446
447bool index::printSymbolName(const Decl *Dconst LangOptions &LO,
448                            raw_ostream &OS) {
449  if (auto *ND = dyn_cast<NamedDecl>(D)) {
450    PrintingPolicy Policy(LO);
451    // Forward references can have different template argument names. Suppress
452    // the template argument names in constructors to make their name more
453    // stable.
454    Policy.SuppressTemplateArgsInCXXConstructors = true;
455    DeclarationName DeclName = ND->getDeclName();
456    if (DeclName.isEmpty())
457      return true;
458    DeclName.print(OSPolicy);
459    return false;
460  } else {
461    return true;
462  }
463}
464
465StringRef index::getSymbolKindString(SymbolKind K) {
466  switch (K) {
467  case SymbolKind::Unknownreturn "<unknown>";
468  case SymbolKind::Modulereturn "module";
469  case SymbolKind::Namespacereturn "namespace";
470  case SymbolKind::NamespaceAliasreturn "namespace-alias";
471  case SymbolKind::Macroreturn "macro";
472  case SymbolKind::Enumreturn "enum";
473  case SymbolKind::Structreturn "struct";
474  case SymbolKind::Classreturn "class";
475  case SymbolKind::Protocolreturn "protocol";
476  case SymbolKind::Extensionreturn "extension";
477  case SymbolKind::Unionreturn "union";
478  case SymbolKind::TypeAliasreturn "type-alias";
479  case SymbolKind::Functionreturn "function";
480  case SymbolKind::Variablereturn "variable";
481  case SymbolKind::Fieldreturn "field";
482  case SymbolKind::EnumConstantreturn "enumerator";
483  case SymbolKind::InstanceMethodreturn "instance-method";
484  case SymbolKind::ClassMethodreturn "class-method";
485  case SymbolKind::StaticMethodreturn "static-method";
486  case SymbolKind::InstancePropertyreturn "instance-property";
487  case SymbolKind::ClassPropertyreturn "class-property";
488  case SymbolKind::StaticPropertyreturn "static-property";
489  case SymbolKind::Constructorreturn "constructor";
490  case SymbolKind::Destructorreturn "destructor";
491  case SymbolKind::ConversionFunctionreturn "coversion-func";
492  case SymbolKind::Parameterreturn "param";
493  case SymbolKind::Usingreturn "using";
494  }
495  llvm_unreachable("invalid symbol kind");
496}
497
498StringRef index::getSymbolSubKindString(SymbolSubKind K) {
499  switch (K) {
500  case SymbolSubKind::Nonereturn "<none>";
501  case SymbolSubKind::CXXCopyConstructorreturn "cxx-copy-ctor";
502  case SymbolSubKind::CXXMoveConstructorreturn "cxx-move-ctor";
503  case SymbolSubKind::AccessorGetterreturn "acc-get";
504  case SymbolSubKind::AccessorSetterreturn "acc-set";
505  case SymbolSubKind::UsingTypenamereturn "using-typename";
506  case SymbolSubKind::UsingValuereturn "using-value";
507  }
508  llvm_unreachable("invalid symbol subkind");
509}
510
511StringRef index::getSymbolLanguageString(SymbolLanguage K) {
512  switch (K) {
513  case SymbolLanguage::Creturn "C";
514  case SymbolLanguage::ObjCreturn "ObjC";
515  case SymbolLanguage::CXXreturn "C++";
516  case SymbolLanguage::Swiftreturn "Swift";
517  }
518  llvm_unreachable("invalid symbol language kind");
519}
520
521void index::applyForEachSymbolProperty(SymbolPropertySet Props,
522                                  llvm::function_ref<void(SymbolProperty)> Fn) {
523#define APPLY_FOR_PROPERTY(K)                                                  \
524  if (Props & (SymbolPropertySet)SymbolProperty::K)                            \
525  Fn(SymbolProperty::K)
526
527  APPLY_FOR_PROPERTY(Generic);
528  APPLY_FOR_PROPERTY(TemplatePartialSpecialization);
529  APPLY_FOR_PROPERTY(TemplateSpecialization);
530  APPLY_FOR_PROPERTY(UnitTest);
531  APPLY_FOR_PROPERTY(IBAnnotated);
532  APPLY_FOR_PROPERTY(IBOutletCollection);
533  APPLY_FOR_PROPERTY(GKInspectable);
534  APPLY_FOR_PROPERTY(Local);
535  APPLY_FOR_PROPERTY(ProtocolInterface);
536
537#undef APPLY_FOR_PROPERTY
538}
539
540void index::printSymbolProperties(SymbolPropertySet Propsraw_ostream &OS) {
541  bool VisitedOnce = false;
542  applyForEachSymbolProperty(Props, [&](SymbolProperty Prop) {
543    if (VisitedOnce)
544      OS << ',';
545    else
546      VisitedOnce = true;
547    switch (Prop) {
548    case SymbolProperty::GenericOS << "Gen"break;
549    case SymbolProperty::TemplatePartialSpecializationOS << "TPS"break;
550    case SymbolProperty::TemplateSpecializationOS << "TS"break;
551    case SymbolProperty::UnitTestOS << "test"break;
552    case SymbolProperty::IBAnnotatedOS << "IB"break;
553    case SymbolProperty::IBOutletCollectionOS << "IBColl"break;
554    case SymbolProperty::GKInspectableOS << "GKI"break;
555    case SymbolProperty::LocalOS << "local"break;
556    case SymbolProperty::ProtocolInterfaceOS << "protocol"break;
557    }
558  });
559}
560