diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp')
| -rw-r--r-- | contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp | 470 | 
1 files changed, 445 insertions, 25 deletions
diff --git a/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp index 534e9288cc71..53b22297ee0e 100644 --- a/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp @@ -38,6 +38,14 @@ void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {      Paren[Key] = std::move(*Obj);  } +/// Helper function to inject a StringRef \p String into an object \p Paren at +/// position \p Key +void serializeString(Object &Paren, StringRef Key, +                     std::optional<std::string> String) { +  if (String) +    Paren[Key] = std::move(*String); +} +  /// Helper function to inject a JSON array \p Array into object \p Paren at  /// position \p Key.  void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) { @@ -101,8 +109,8 @@ Object serializeSourcePosition(const PresumedLoc &Loc) {    assert(Loc.isValid() && "invalid source position");    Object SourcePosition; -  SourcePosition["line"] = Loc.getLine(); -  SourcePosition["character"] = Loc.getColumn(); +  SourcePosition["line"] = Loc.getLine() - 1; +  SourcePosition["character"] = Loc.getColumn() - 1;    return SourcePosition;  } @@ -169,11 +177,11 @@ serializeAvailability(const AvailabilitySet &Availabilities) {      if (AvailInfo.Unavailable)        Availability["isUnconditionallyUnavailable"] = true;      else { -      serializeObject(Availability, "introducedVersion", +      serializeObject(Availability, "introduced",                        serializeSemanticVersion(AvailInfo.Introduced)); -      serializeObject(Availability, "deprecatedVersion", +      serializeObject(Availability, "deprecated",                        serializeSemanticVersion(AvailInfo.Deprecated)); -      serializeObject(Availability, "obsoletedVersion", +      serializeObject(Availability, "obsoleted",                        serializeSemanticVersion(AvailInfo.Obsoleted));      }      AvailabilityArray.emplace_back(std::move(Availability)); @@ -189,10 +197,12 @@ StringRef getLanguageName(Language Lang) {      return "c";    case Language::ObjC:      return "objective-c"; - -  // Unsupported language currently    case Language::CXX: +    return "c++";    case Language::ObjCXX: +    return "objective-c++"; + +  // Unsupported language currently    case Language::OpenCL:    case Language::OpenCLCXX:    case Language::CUDA: @@ -319,7 +329,13 @@ serializeDeclarationFragments(const DeclarationFragments &DF) {  ///     Objective-C methods). Can be used as sub-headings for documentation.  Object serializeNames(const APIRecord &Record) {    Object Names; -  Names["title"] = Record.Name; +  if (auto *CategoryRecord = +          dyn_cast_or_null<const ObjCCategoryRecord>(&Record)) +    Names["title"] = +        (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str(); +  else +    Names["title"] = Record.Name; +    serializeArray(Names, "subHeading",                   serializeDeclarationFragments(Record.SubHeading));    DeclarationFragments NavigatorFragments; @@ -342,10 +358,34 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {    case APIRecord::RK_Unknown:      llvm_unreachable("Records should have an explicit kind");      break; +  case APIRecord::RK_Namespace: +    Kind["identifier"] = AddLangPrefix("namespace"); +    Kind["displayName"] = "Namespace"; +    break;    case APIRecord::RK_GlobalFunction:      Kind["identifier"] = AddLangPrefix("func");      Kind["displayName"] = "Function";      break; +  case APIRecord::RK_GlobalFunctionTemplate: +    Kind["identifier"] = AddLangPrefix("func"); +    Kind["displayName"] = "Function Template"; +    break; +  case APIRecord::RK_GlobalFunctionTemplateSpecialization: +    Kind["identifier"] = AddLangPrefix("func"); +    Kind["displayName"] = "Function Template Specialization"; +    break; +  case APIRecord::RK_GlobalVariableTemplate: +    Kind["identifier"] = AddLangPrefix("var"); +    Kind["displayName"] = "Global Variable Template"; +    break; +  case APIRecord::RK_GlobalVariableTemplateSpecialization: +    Kind["identifier"] = AddLangPrefix("var"); +    Kind["displayName"] = "Global Variable Template Specialization"; +    break; +  case APIRecord::RK_GlobalVariableTemplatePartialSpecialization: +    Kind["identifier"] = AddLangPrefix("var"); +    Kind["displayName"] = "Global Variable Template Partial Specialization"; +    break;    case APIRecord::RK_GlobalVariable:      Kind["identifier"] = AddLangPrefix("var");      Kind["displayName"] = "Global Variable"; @@ -366,6 +406,57 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {      Kind["identifier"] = AddLangPrefix("struct");      Kind["displayName"] = "Structure";      break; +  case APIRecord::RK_CXXField: +    Kind["identifier"] = AddLangPrefix("property"); +    Kind["displayName"] = "Instance Property"; +    break; +  case APIRecord::RK_Union: +    Kind["identifier"] = AddLangPrefix("union"); +    Kind["displayName"] = "Union"; +    break; +  case APIRecord::RK_StaticField: +    Kind["identifier"] = AddLangPrefix("type.property"); +    Kind["displayName"] = "Type Property"; +    break; +  case APIRecord::RK_ClassTemplate: +  case APIRecord::RK_ClassTemplateSpecialization: +  case APIRecord::RK_ClassTemplatePartialSpecialization: +  case APIRecord::RK_CXXClass: +    Kind["identifier"] = AddLangPrefix("class"); +    Kind["displayName"] = "Class"; +    break; +  case APIRecord::RK_CXXMethodTemplate: +    Kind["identifier"] = AddLangPrefix("method"); +    Kind["displayName"] = "Method Template"; +    break; +  case APIRecord::RK_CXXMethodTemplateSpecialization: +    Kind["identifier"] = AddLangPrefix("method"); +    Kind["displayName"] = "Method Template Specialization"; +    break; +  case APIRecord::RK_CXXFieldTemplate: +    Kind["identifier"] = AddLangPrefix("property"); +    Kind["displayName"] = "Template Property"; +    break; +  case APIRecord::RK_Concept: +    Kind["identifier"] = AddLangPrefix("concept"); +    Kind["displayName"] = "Concept"; +    break; +  case APIRecord::RK_CXXStaticMethod: +    Kind["identifier"] = AddLangPrefix("type.method"); +    Kind["displayName"] = "Static Method"; +    break; +  case APIRecord::RK_CXXInstanceMethod: +    Kind["identifier"] = AddLangPrefix("method"); +    Kind["displayName"] = "Instance Method"; +    break; +  case APIRecord::RK_CXXConstructorMethod: +    Kind["identifier"] = AddLangPrefix("method"); +    Kind["displayName"] = "Constructor"; +    break; +  case APIRecord::RK_CXXDestructorMethod: +    Kind["identifier"] = AddLangPrefix("method"); +    Kind["displayName"] = "Destructor"; +    break;    case APIRecord::RK_ObjCIvar:      Kind["identifier"] = AddLangPrefix("ivar");      Kind["displayName"] = "Instance Variable"; @@ -391,9 +482,12 @@ Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {      Kind["displayName"] = "Class";      break;    case APIRecord::RK_ObjCCategory: -    // We don't serialize out standalone Objective-C category symbols yet. -    llvm_unreachable("Serializing standalone Objective-C category symbols is " -                     "not supported."); +    Kind["identifier"] = AddLangPrefix("class.extension"); +    Kind["displayName"] = "Class Extension"; +    break; +  case APIRecord::RK_ObjCCategoryModule: +    Kind["identifier"] = AddLangPrefix("module.extension"); +    Kind["displayName"] = "Module Extension";      break;    case APIRecord::RK_ObjCProtocol:      Kind["identifier"] = AddLangPrefix("protocol"); @@ -470,6 +564,77 @@ void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {                        Record, has_function_signature<RecordTy>()));  } +template <typename RecordTy> +std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, +                                                    std::true_type) { +  const auto &AccessControl = Record.Access; +  std::string Access; +  if (AccessControl.empty()) +    return std::nullopt; +  Access = AccessControl.getAccess(); +  return Access; +} + +template <typename RecordTy> +std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, +                                                    std::false_type) { +  return std::nullopt; +} + +template <typename RecordTy> +void serializeAccessMixin(Object &Paren, const RecordTy &Record) { +  auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>()); +  if (!accessLevel.has_value()) +    accessLevel = "public"; +  serializeString(Paren, "accessLevel", accessLevel); +} + +template <typename RecordTy> +std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, +                                                 std::true_type) { +  const auto &Template = Record.Templ; +  if (Template.empty()) +    return std::nullopt; + +  Object Generics; +  Array GenericParameters; +  for (const auto &Param : Template.getParameters()) { +    Object Parameter; +    Parameter["name"] = Param.Name; +    Parameter["index"] = Param.Index; +    Parameter["depth"] = Param.Depth; +    GenericParameters.emplace_back(std::move(Parameter)); +  } +  if (!GenericParameters.empty()) +    Generics["parameters"] = std::move(GenericParameters); + +  Array GenericConstraints; +  for (const auto &Constr : Template.getConstraints()) { +    Object Constraint; +    Constraint["kind"] = Constr.Kind; +    Constraint["lhs"] = Constr.LHS; +    Constraint["rhs"] = Constr.RHS; +    GenericConstraints.emplace_back(std::move(Constraint)); +  } + +  if (!GenericConstraints.empty()) +    Generics["constraints"] = std::move(GenericConstraints); + +  return Generics; +} + +template <typename RecordTy> +std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, +                                                 std::false_type) { +  return std::nullopt; +} + +template <typename RecordTy> +void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { +  serializeObject(Paren, "swiftGenerics", +                  serializeTemplateMixinImpl(Record, has_template<RecordTy>())); +} +  struct PathComponent {    StringRef USR;    StringRef Name; @@ -497,14 +662,16 @@ bool generatePathComponents(      if (!ParentRecord)        ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); -    // If the parent is a category then we need to pretend this belongs to the -    // associated interface. +    // If the parent is a category extended from internal module then we need to +    // pretend this belongs to the associated interface.      if (auto *CategoryRecord =              dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) { -      ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); -      CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, -                                             CategoryRecord->Interface.Name, -                                             APIRecord::RK_ObjCInterface); +      if (!CategoryRecord->IsFromExternalModule) { +        ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); +        CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, +                                               CategoryRecord->Interface.Name, +                                               APIRecord::RK_ObjCInterface); +      }      }      // The parent record doesn't exist which means the symbol shouldn't be @@ -543,7 +710,6 @@ Array generateParentContexts(const RecordTy &Record, const APISet &API,    return ParentContexts;  } -  } // namespace  /// Defines the format version emitted by SymbolGraphSerializer. @@ -577,7 +743,7 @@ bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {    // Filter out symbols prefixed with an underscored as they are understood to    // be symbols clients should not use. -  if (Record.Name.startswith("_")) +  if (Record.Name.starts_with("_"))      return true;    return false; @@ -602,9 +768,6 @@ SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {    serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));    serializeArray(Obj, "declarationFragments",                   serializeDeclarationFragments(Record.Declaration)); -  // TODO: Once we keep track of symbol access information serialize it -  // correctly here. -  Obj["accessLevel"] = "public";    SmallVector<StringRef, 4> PathComponentsNames;    // If this returns true it indicates that we couldn't find a symbol in the    // hierarchy. @@ -617,6 +780,8 @@ SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {    serializeArray(Obj, "pathComponents", Array(PathComponentsNames));    serializeFunctionSignatureMixin(Obj, Record); +  serializeAccessMixin(Obj, Record); +  serializeTemplateMixin(Obj, Record);    return Obj;  } @@ -646,10 +811,22 @@ StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {      return "inheritsFrom";    case RelationshipKind::ConformsTo:      return "conformsTo"; +  case RelationshipKind::ExtensionTo: +    return "extensionTo";    }    llvm_unreachable("Unhandled relationship kind");  } +StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { +  switch (Kind) { +  case ConstraintKind::Conformance: +    return "conformance"; +  case ConstraintKind::ConditionalConformance: +    return "conditionalConformance"; +  } +  llvm_unreachable("Unhandled constraint kind"); +} +  void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,                                                    SymbolReference Source,                                                    SymbolReference Target) { @@ -662,6 +839,17 @@ void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,    Relationships.emplace_back(std::move(Relationship));  } +void SymbolGraphSerializer::visitNamespaceRecord( +    const NamespaceRecord &Record) { +  auto Namespace = serializeAPIRecord(Record); +  if (!Namespace) +    return; +  Symbols.emplace_back(std::move(*Namespace)); +  if (!Record.ParentInformation.empty()) +    serializeRelationship(RelationshipKind::MemberOf, Record, +                          Record.ParentInformation.ParentRecord); +} +  void SymbolGraphSerializer::visitGlobalFunctionRecord(      const GlobalFunctionRecord &Record) {    auto Obj = serializeAPIRecord(Record); @@ -698,6 +886,193 @@ void SymbolGraphSerializer::visitStructRecord(const StructRecord &Record) {    serializeMembers(Record, Record.Fields);  } +void SymbolGraphSerializer::visitStaticFieldRecord( +    const StaticFieldRecord &Record) { +  auto StaticField = serializeAPIRecord(Record); +  if (!StaticField) +    return; +  Symbols.emplace_back(std::move(*StaticField)); +  serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context); +} + +void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) { +  auto Class = serializeAPIRecord(Record); +  if (!Class) +    return; + +  Symbols.emplace_back(std::move(*Class)); +  for (const auto &Base : Record.Bases) +    serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); +  if (!Record.ParentInformation.empty()) +    serializeRelationship(RelationshipKind::MemberOf, Record, +                          Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitClassTemplateRecord( +    const ClassTemplateRecord &Record) { +  auto Class = serializeAPIRecord(Record); +  if (!Class) +    return; + +  Symbols.emplace_back(std::move(*Class)); +  for (const auto &Base : Record.Bases) +    serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); +  if (!Record.ParentInformation.empty()) +    serializeRelationship(RelationshipKind::MemberOf, Record, +                          Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitClassTemplateSpecializationRecord( +    const ClassTemplateSpecializationRecord &Record) { +  auto Class = serializeAPIRecord(Record); +  if (!Class) +    return; + +  Symbols.emplace_back(std::move(*Class)); + +  for (const auto &Base : Record.Bases) +    serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); +  if (!Record.ParentInformation.empty()) +    serializeRelationship(RelationshipKind::MemberOf, Record, +                          Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( +    const ClassTemplatePartialSpecializationRecord &Record) { +  auto Class = serializeAPIRecord(Record); +  if (!Class) +    return; + +  Symbols.emplace_back(std::move(*Class)); + +  for (const auto &Base : Record.Bases) +    serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); +  if (!Record.ParentInformation.empty()) +    serializeRelationship(RelationshipKind::MemberOf, Record, +                          Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitCXXInstanceMethodRecord( +    const CXXInstanceMethodRecord &Record) { +  auto InstanceMethod = serializeAPIRecord(Record); +  if (!InstanceMethod) +    return; + +  Symbols.emplace_back(std::move(*InstanceMethod)); +  serializeRelationship(RelationshipKind::MemberOf, Record, +                        Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitCXXStaticMethodRecord( +    const CXXStaticMethodRecord &Record) { +  auto StaticMethod = serializeAPIRecord(Record); +  if (!StaticMethod) +    return; + +  Symbols.emplace_back(std::move(*StaticMethod)); +  serializeRelationship(RelationshipKind::MemberOf, Record, +                        Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitMethodTemplateRecord( +    const CXXMethodTemplateRecord &Record) { +  if (!ShouldRecurse) +    // Ignore child symbols +    return; +  auto MethodTemplate = serializeAPIRecord(Record); +  if (!MethodTemplate) +    return; +  Symbols.emplace_back(std::move(*MethodTemplate)); +  serializeRelationship(RelationshipKind::MemberOf, Record, +                        Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord( +    const CXXMethodTemplateSpecializationRecord &Record) { +  if (!ShouldRecurse) +    // Ignore child symbols +    return; +  auto MethodTemplateSpecialization = serializeAPIRecord(Record); +  if (!MethodTemplateSpecialization) +    return; +  Symbols.emplace_back(std::move(*MethodTemplateSpecialization)); +  serializeRelationship(RelationshipKind::MemberOf, Record, +                        Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) { +  if (!ShouldRecurse) +    return; +  auto CXXField = serializeAPIRecord(Record); +  if (!CXXField) +    return; +  Symbols.emplace_back(std::move(*CXXField)); +  serializeRelationship(RelationshipKind::MemberOf, Record, +                        Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitCXXFieldTemplateRecord( +    const CXXFieldTemplateRecord &Record) { +  if (!ShouldRecurse) +    // Ignore child symbols +    return; +  auto CXXFieldTemplate = serializeAPIRecord(Record); +  if (!CXXFieldTemplate) +    return; +  Symbols.emplace_back(std::move(*CXXFieldTemplate)); +  serializeRelationship(RelationshipKind::MemberOf, Record, +                        Record.ParentInformation.ParentRecord); +} + +void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { +  auto Concept = serializeAPIRecord(Record); +  if (!Concept) +    return; + +  Symbols.emplace_back(std::move(*Concept)); +} + +void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( +    const GlobalVariableTemplateRecord &Record) { +  auto GlobalVariableTemplate = serializeAPIRecord(Record); +  if (!GlobalVariableTemplate) +    return; +  Symbols.emplace_back(std::move(*GlobalVariableTemplate)); +} + +void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord( +    const GlobalVariableTemplateSpecializationRecord &Record) { +  auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record); +  if (!GlobalVariableTemplateSpecialization) +    return; +  Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization)); +} + +void SymbolGraphSerializer:: +    visitGlobalVariableTemplatePartialSpecializationRecord( +        const GlobalVariableTemplatePartialSpecializationRecord &Record) { +  auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record); +  if (!GlobalVariableTemplatePartialSpecialization) +    return; +  Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization)); +} + +void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( +    const GlobalFunctionTemplateRecord &Record) { +  auto GlobalFunctionTemplate = serializeAPIRecord(Record); +  if (!GlobalFunctionTemplate) +    return; +  Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); +} + +void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord( +    const GlobalFunctionTemplateSpecializationRecord &Record) { +  auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record); +  if (!GlobalFunctionTemplateSpecialization) +    return; +  Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization)); +} +  void SymbolGraphSerializer::visitObjCContainerRecord(      const ObjCContainerRecord &Record) {    auto ObjCContainer = serializeAPIRecord(Record); @@ -735,6 +1110,45 @@ void SymbolGraphSerializer::visitObjCContainerRecord(    }  } +void SymbolGraphSerializer::visitObjCCategoryRecord( +    const ObjCCategoryRecord &Record) { +  if (!Record.IsFromExternalModule) +    return; + +  // Check if the current Category' parent has been visited before, if so skip. +  if (!visitedCategories.contains(Record.Interface.Name)) { +    visitedCategories.insert(Record.Interface.Name); +    Object Obj; +    serializeObject(Obj, "identifier", +                    serializeIdentifier(Record, API.getLanguage())); +    serializeObject(Obj, "kind", +                    serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, +                                        API.getLanguage())); +    Obj["accessLevel"] = "public"; +    Symbols.emplace_back(std::move(Obj)); +  } + +  Object Relationship; +  Relationship["source"] = Record.USR; +  Relationship["target"] = Record.Interface.USR; +  Relationship["targetFallback"] = Record.Interface.Name; +  Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo); +  Relationships.emplace_back(std::move(Relationship)); + +  auto ObjCCategory = serializeAPIRecord(Record); + +  if (!ObjCCategory) +    return; + +  Symbols.emplace_back(std::move(*ObjCCategory)); +  serializeMembers(Record, Record.Methods); +  serializeMembers(Record, Record.Properties); + +  // Surface the protocols of the category to the interface. +  for (const auto &Protocol : Record.Protocols) +    serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); +} +  void SymbolGraphSerializer::visitMacroDefinitionRecord(      const MacroDefinitionRecord &Record) {    auto Macro = serializeAPIRecord(Record); @@ -761,12 +1175,21 @@ void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {    case APIRecord::RK_Struct:      visitStructRecord(*cast<StructRecord>(Record));      break; +  case APIRecord::RK_StaticField: +    visitStaticFieldRecord(*cast<StaticFieldRecord>(Record)); +    break; +  case APIRecord::RK_CXXClass: +    visitCXXClassRecord(*cast<CXXClassRecord>(Record)); +    break;    case APIRecord::RK_ObjCInterface:      visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));      break;    case APIRecord::RK_ObjCProtocol:      visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));      break; +  case APIRecord::RK_ObjCCategory: +    visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record)); +    break;    case APIRecord::RK_MacroDefinition:      visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));      break; @@ -835,9 +1258,6 @@ SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,    if (!Record)      return {}; -  if (isa<ObjCCategoryRecord>(Record)) -    return {}; -    Object Root;    APIIgnoresList EmptyIgnores;    SymbolGraphSerializer Serializer(API, EmptyIgnores,  | 
