evelez7 created this revision.
Herald added a reviewer: ributzka.
Herald added a project: All.
evelez7 requested review of this revision.
Herald added a reviewer: dang.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Refactor SerializerBase and SymbolGraphSerializer to use a visitor pattern 
described by the CRTP.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D151293

Files:
  clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
  clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
  clang/lib/ExtractAPI/CMakeLists.txt
  clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
  clang/lib/ExtractAPI/Serialization/SerializerBase.cpp
  clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp

Index: clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
+++ clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp
@@ -38,14 +38,14 @@
 
 /// Helper function to inject a JSON object \p Obj into another object \p Paren
 /// at position \p Key.
-void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
+void visitObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
   if (Obj)
     Paren[Key] = std::move(*Obj);
 }
 
 /// 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) {
+void visitArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
   if (Array)
     Paren[Key] = std::move(*Array);
 }
@@ -66,7 +66,7 @@
 ///
 /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
 /// containing the semantic version representation of \p V.
-std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
+std::optional<Object> visitSemanticVersion(const VersionTuple &V) {
   if (V.empty())
     return std::nullopt;
 
@@ -81,11 +81,11 @@
 ///
 /// The OS information in Symbol Graph contains the \c name of the OS, and an
 /// optional \c minimumVersion semantic version field.
-Object serializeOperatingSystem(const Triple &T) {
+Object visitOperatingSystem(const Triple &T) {
   Object OS;
   OS["name"] = T.getOSTypeName(T.getOS());
-  serializeObject(OS, "minimumVersion",
-                  serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
+  visitObject(OS, "minimumVersion",
+              visitSemanticVersion(T.getMinimumSupportedOSVersion()));
   return OS;
 }
 
@@ -93,16 +93,16 @@
 ///
 /// The platform object describes a target platform triple in corresponding
 /// three fields: \c architecture, \c vendor, and \c operatingSystem.
-Object serializePlatform(const Triple &T) {
+Object visitPlatform(const Triple &T) {
   Object Platform;
   Platform["architecture"] = T.getArchName();
   Platform["vendor"] = T.getVendorName();
-  Platform["operatingSystem"] = serializeOperatingSystem(T);
+  Platform["operatingSystem"] = visitOperatingSystem(T);
   return Platform;
 }
 
 /// Serialize a source position.
-Object serializeSourcePosition(const PresumedLoc &Loc) {
+Object visitSourcePosition(const PresumedLoc &Loc) {
   assert(Loc.isValid() && "invalid source position");
 
   Object SourcePosition;
@@ -117,10 +117,10 @@
 /// \param Loc The presumed location to serialize.
 /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
 /// Defaults to false.
-Object serializeSourceLocation(const PresumedLoc &Loc,
-                               bool IncludeFileURI = false) {
+Object visitSourceLocation(const PresumedLoc &Loc,
+                           bool IncludeFileURI = false) {
   Object SourceLocation;
-  serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
+  visitObject(SourceLocation, "position", visitSourcePosition(Loc));
 
   if (IncludeFileURI) {
     std::string FileURI = "file://";
@@ -133,11 +133,11 @@
 }
 
 /// Serialize a source range with begin and end locations.
-Object serializeSourceRange(const PresumedLoc &BeginLoc,
-                            const PresumedLoc &EndLoc) {
+Object visitSourceRange(const PresumedLoc &BeginLoc,
+                        const PresumedLoc &EndLoc) {
   Object SourceRange;
-  serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
-  serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
+  visitObject(SourceRange, "start", visitSourcePosition(BeginLoc));
+  visitObject(SourceRange, "end", visitSourcePosition(EndLoc));
   return SourceRange;
 }
 
@@ -152,8 +152,7 @@
 ///
 /// \returns \c std::nullopt if the symbol has default availability attributes,
 /// or an \c Array containing the formatted availability information.
-std::optional<Array>
-serializeAvailability(const AvailabilitySet &Availabilities) {
+std::optional<Array> visitAvailability(const AvailabilitySet &Availabilities) {
   if (Availabilities.isDefault())
     return std::nullopt;
 
@@ -174,12 +173,12 @@
     if (AvailInfo.Unavailable)
       Availability["isUnconditionallyUnavailable"] = true;
     else {
-      serializeObject(Availability, "introducedVersion",
-                      serializeSemanticVersion(AvailInfo.Introduced));
-      serializeObject(Availability, "deprecatedVersion",
-                      serializeSemanticVersion(AvailInfo.Deprecated));
-      serializeObject(Availability, "obsoletedVersion",
-                      serializeSemanticVersion(AvailInfo.Obsoleted));
+      visitObject(Availability, "introducedVersion",
+                  visitSemanticVersion(AvailInfo.Introduced));
+      visitObject(Availability, "deprecatedVersion",
+                  visitSemanticVersion(AvailInfo.Deprecated));
+      visitObject(Availability, "obsoletedVersion",
+                  visitSemanticVersion(AvailInfo.Obsoleted));
     }
     AvailabilityArray.emplace_back(std::move(Availability));
   }
@@ -219,7 +218,7 @@
 ///
 /// The identifier property of a symbol contains the USR for precise and unique
 /// references, and the interface language name.
-Object serializeIdentifier(const APIRecord &Record, Language Lang) {
+Object visitIdentifier(const APIRecord &Record, Language Lang) {
   Object Identifier;
   Identifier["precise"] = Record.USR;
   Identifier["interfaceLanguage"] = getLanguageName(Lang);
@@ -243,7 +242,7 @@
 ///
 /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
 /// the formatted lines.
-std::optional<Object> serializeDocComment(const DocComment &Comment) {
+std::optional<Object> visitDocComment(const DocComment &Comment) {
   if (Comment.empty())
     return std::nullopt;
 
@@ -252,11 +251,11 @@
   for (const auto &CommentLine : Comment) {
     Object Line;
     Line["text"] = CommentLine.Text;
-    serializeObject(Line, "range",
-                    serializeSourceRange(CommentLine.Begin, CommentLine.End));
+    visitObject(Line, "range",
+                visitSourceRange(CommentLine.Begin, CommentLine.End));
     LinesArray.emplace_back(std::move(Line));
   }
-  serializeArray(DocComment, "lines", LinesArray);
+  visitArray(DocComment, "lines", LinesArray);
 
   return DocComment;
 }
@@ -295,8 +294,7 @@
 ///
 /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
 /// formatted declaration fragments array.
-std::optional<Array>
-serializeDeclarationFragments(const DeclarationFragments &DF) {
+std::optional<Array> visitDeclarationFragments(const DeclarationFragments &DF) {
   if (DF.getFragments().empty())
     return std::nullopt;
 
@@ -322,22 +320,20 @@
 ///   - \c subHeading : An array of declaration fragments that provides tags,
 ///     and potentially more tokens (for example the \c +/- symbol for
 ///     Objective-C methods). Can be used as sub-headings for documentation.
-Object serializeNames(const APIRecord &Record) {
+Object visitNames(const APIRecord &Record) {
   Object Names;
   Names["title"] = Record.Name;
-  serializeArray(Names, "subHeading",
-                 serializeDeclarationFragments(Record.SubHeading));
+  visitArray(Names, "subHeading", visitDeclarationFragments(Record.SubHeading));
   DeclarationFragments NavigatorFragments;
   NavigatorFragments.append(Record.Name,
                             DeclarationFragments::FragmentKind::Identifier,
                             /*PreciseIdentifier*/ "");
-  serializeArray(Names, "navigator",
-                 serializeDeclarationFragments(NavigatorFragments));
+  visitArray(Names, "navigator", visitDeclarationFragments(NavigatorFragments));
 
   return Names;
 }
 
-Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
+Object visitSymbolKind(APIRecord::RecordKind RK, Language Lang) {
   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
     return (getLanguageName(Lang) + "." + S).str();
   };
@@ -422,27 +418,27 @@
 /// The Symbol Graph symbol kind property contains a shorthand \c identifier
 /// which is prefixed by the source language name, useful for tooling to parse
 /// the kind, and a \c displayName for rendering human-readable names.
-Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
-  return serializeSymbolKind(Record.getKind(), Lang);
+Object visitSymbolKind(const APIRecord &Record, Language Lang) {
+  return visitSymbolKind(Record.getKind(), Lang);
 }
 
 template <typename RecordTy>
-std::optional<Object>
-serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
+std::optional<Object> visitFunctionSignatureMixinImpl(const RecordTy &Record,
+                                                      std::true_type) {
   const auto &FS = Record.Signature;
   if (FS.empty())
     return std::nullopt;
 
   Object Signature;
-  serializeArray(Signature, "returns",
-                 serializeDeclarationFragments(FS.getReturnType()));
+  visitArray(Signature, "returns",
+             visitDeclarationFragments(FS.getReturnType()));
 
   Array Parameters;
   for (const auto &P : FS.getParameters()) {
     Object Parameter;
     Parameter["name"] = P.Name;
-    serializeArray(Parameter, "declarationFragments",
-                   serializeDeclarationFragments(P.Fragments));
+    visitArray(Parameter, "declarationFragments",
+               visitDeclarationFragments(P.Fragments));
     Parameters.emplace_back(std::move(Parameter));
   }
 
@@ -453,8 +449,8 @@
 }
 
 template <typename RecordTy>
-std::optional<Object>
-serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
+std::optional<Object> visitFunctionSignatureMixinImpl(const RecordTy &Record,
+                                                      std::false_type) {
   return std::nullopt;
 }
 
@@ -469,10 +465,10 @@
 /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
 /// formatted function signature.
 template <typename RecordTy>
-void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
-  serializeObject(Paren, "functionSignature",
-                  serializeFunctionSignatureMixinImpl(
-                      Record, has_function_signature<RecordTy>()));
+void visitFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
+  visitObject(Paren, "functionSignature",
+              visitFunctionSignatureMixinImpl(
+                  Record, has_function_signature<RecordTy>()));
 }
 
 struct PathComponent {
@@ -529,11 +525,11 @@
   return FailedToFindParent;
 }
 
-Object serializeParentContext(const PathComponent &PC, Language Lang) {
+Object visitParentContext(const PathComponent &PC, Language Lang) {
   Object ParentContextElem;
   ParentContextElem["usr"] = PC.USR;
   ParentContextElem["name"] = PC.Name;
-  ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
+  ParentContextElem["kind"] = visitSymbolKind(PC.Kind, Lang)["identifier"];
   return ParentContextElem;
 }
 
@@ -541,11 +537,10 @@
 Array generateParentContexts(const RecordTy &Record, const APISet &API,
                              Language Lang) {
   Array ParentContexts;
-  generatePathComponents(Record, API,
-                         [Lang, &ParentContexts](const PathComponent &PC) {
-                           ParentContexts.push_back(
-                               serializeParentContext(PC, Lang));
-                         });
+  generatePathComponents(
+      Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
+        ParentContexts.push_back(visitParentContext(PC, Lang));
+      });
 
   return ParentContexts;
 }
@@ -557,20 +552,19 @@
 /// Defines the format version emitted by SymbolGraphSerializer.
 const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
 
-Object SymbolGraphSerializer::serializeMetadata() const {
+Object SymbolGraphSerializer::visitMetadata() const {
   Object Metadata;
-  serializeObject(Metadata, "formatVersion",
-                  serializeSemanticVersion(FormatVersion));
+  visitObject(Metadata, "formatVersion", visitSemanticVersion(FormatVersion));
   Metadata["generator"] = clang::getClangFullVersion();
   return Metadata;
 }
 
-Object SymbolGraphSerializer::serializeModule() const {
+Object SymbolGraphSerializer::visitModule() const {
   Object Module;
   // The user is expected to always pass `--product-name=` on the command line
   // to populate this field.
   Module["name"] = API.ProductName;
-  serializeObject(Module, "platform", serializePlatform(API.getTarget()));
+  visitObject(Module, "platform", visitPlatform(API.getTarget()));
   return Module;
 }
 
@@ -593,23 +587,20 @@
 
 template <typename RecordTy>
 std::optional<Object>
-SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
+SymbolGraphSerializer::visitAPIRecord(const RecordTy &Record) const {
   if (shouldSkip(Record))
     return std::nullopt;
 
   Object Obj;
-  serializeObject(Obj, "identifier",
-                  serializeIdentifier(Record, API.getLanguage()));
-  serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
-  serializeObject(Obj, "names", serializeNames(Record));
-  serializeObject(
-      Obj, "location",
-      serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
-  serializeArray(Obj, "availability",
-                 serializeAvailability(Record.Availabilities));
-  serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
-  serializeArray(Obj, "declarationFragments",
-                 serializeDeclarationFragments(Record.Declaration));
+  visitObject(Obj, "identifier", visitIdentifier(Record, API.getLanguage()));
+  visitObject(Obj, "kind", visitSymbolKind(Record, API.getLanguage()));
+  visitObject(Obj, "names", visitNames(Record));
+  visitObject(Obj, "location",
+              visitSourceLocation(Record.Location, /*IncludeFileURI=*/true));
+  visitArray(Obj, "availability", visitAvailability(Record.Availabilities));
+  visitObject(Obj, "docComment", visitDocComment(Record.Comment));
+  visitArray(Obj, "declarationFragments",
+             visitDeclarationFragments(Record.Declaration));
   // TODO: Once we keep track of symbol access information serialize it
   // correctly here.
   Obj["accessLevel"] = "public";
@@ -622,27 +613,27 @@
                              }))
     return {};
 
-  serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
+  visitArray(Obj, "pathComponents", Array(PathComponentsNames));
 
-  serializeFunctionSignatureMixin(Obj, Record);
+  visitFunctionSignatureMixin(Obj, Record);
 
   return Obj;
 }
 
 template <typename MemberTy>
-void SymbolGraphSerializer::serializeMembers(
+void SymbolGraphSerializer::visitMembers(
     const APIRecord &Record,
     const SmallVector<std::unique_ptr<MemberTy>> &Members) {
   // Members should not be serialized if we aren't recursing.
   if (!ShouldRecurse)
     return;
   for (const auto &Member : Members) {
-    auto MemberRecord = serializeAPIRecord(*Member);
+    auto MemberRecord = visitAPIRecord(*Member);
     if (!MemberRecord)
       continue;
 
     Symbols.emplace_back(std::move(*MemberRecord));
-    serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
+    visitRelationship(RelationshipKind::MemberOf, *Member, Record);
   }
 }
 
@@ -658,9 +649,9 @@
   llvm_unreachable("Unhandled relationship kind");
 }
 
-void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
-                                                  SymbolReference Source,
-                                                  SymbolReference Target) {
+void SymbolGraphSerializer::visitRelationship(RelationshipKind Kind,
+                                              SymbolReference Source,
+                                              SymbolReference Target) {
   Object Relationship;
   Relationship["source"] = Source.USR;
   Relationship["target"] = Target.USR;
@@ -670,82 +661,82 @@
   Relationships.emplace_back(std::move(Relationship));
 }
 
-void SymbolGraphSerializer::serializeGlobalFunctionRecord(
+void SymbolGraphSerializer::visitGlobalFunctionRecord(
     const GlobalFunctionRecord &Record) {
-  auto Obj = serializeAPIRecord(Record);
+  auto Obj = visitAPIRecord(Record);
   if (!Obj)
     return;
 
   Symbols.emplace_back(std::move(*Obj));
 }
 
-void SymbolGraphSerializer::serializeGlobalVariableRecord(
+void SymbolGraphSerializer::visitGlobalVariableRecord(
     const GlobalVariableRecord &Record) {
-  auto Obj = serializeAPIRecord(Record);
+  auto Obj = visitAPIRecord(Record);
   if (!Obj)
     return;
 
   Symbols.emplace_back(std::move(*Obj));
 }
 
-void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
-  auto Enum = serializeAPIRecord(Record);
+void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) {
+  auto Enum = visitAPIRecord(Record);
   if (!Enum)
     return;
 
   Symbols.emplace_back(std::move(*Enum));
-  serializeMembers(Record, Record.Constants);
+  visitMembers(Record, Record.Constants);
 }
 
-void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
-  auto Struct = serializeAPIRecord(Record);
+void SymbolGraphSerializer::visitStructRecord(const StructRecord &Record) {
+  auto Struct = visitAPIRecord(Record);
   if (!Struct)
     return;
 
   Symbols.emplace_back(std::move(*Struct));
-  serializeMembers(Record, Record.Fields);
+  visitMembers(Record, Record.Fields);
 }
 
-void SymbolGraphSerializer::serializeObjCContainerRecord(
+void SymbolGraphSerializer::visitObjCContainerRecord(
     const ObjCContainerRecord &Record) {
-  auto ObjCContainer = serializeAPIRecord(Record);
+  auto ObjCContainer = visitAPIRecord(Record);
   if (!ObjCContainer)
     return;
 
   Symbols.emplace_back(std::move(*ObjCContainer));
 
-  serializeMembers(Record, Record.Ivars);
-  serializeMembers(Record, Record.Methods);
-  serializeMembers(Record, Record.Properties);
+  visitMembers(Record, Record.Ivars);
+  visitMembers(Record, Record.Methods);
+  visitMembers(Record, Record.Properties);
 
   for (const auto &Protocol : Record.Protocols)
     // Record that Record conforms to Protocol.
-    serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
+    visitRelationship(RelationshipKind::ConformsTo, Record, Protocol);
 
   if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
     if (!ObjCInterface->SuperClass.empty())
       // If Record is an Objective-C interface record and it has a super class,
       // record that Record is inherited from SuperClass.
-      serializeRelationship(RelationshipKind::InheritsFrom, Record,
-                            ObjCInterface->SuperClass);
+      visitRelationship(RelationshipKind::InheritsFrom, Record,
+                        ObjCInterface->SuperClass);
 
     // Members of categories extending an interface are serialized as members of
     // the interface.
     for (const auto *Category : ObjCInterface->Categories) {
-      serializeMembers(Record, Category->Ivars);
-      serializeMembers(Record, Category->Methods);
-      serializeMembers(Record, Category->Properties);
+      visitMembers(Record, Category->Ivars);
+      visitMembers(Record, Category->Methods);
+      visitMembers(Record, Category->Properties);
 
       // Surface the protocols of the category to the interface.
       for (const auto &Protocol : Category->Protocols)
-        serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
+        visitRelationship(RelationshipKind::ConformsTo, Record, Protocol);
     }
   }
 }
 
-void SymbolGraphSerializer::serializeMacroDefinitionRecord(
+void SymbolGraphSerializer::visitMacroDefinitionRecord(
     const MacroDefinitionRecord &Record) {
-  auto Macro = serializeAPIRecord(Record);
+  auto Macro = visitAPIRecord(Record);
 
   if (!Macro)
     return;
@@ -753,48 +744,47 @@
   Symbols.emplace_back(std::move(*Macro));
 }
 
-void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
+void SymbolGraphSerializer::visitSingleRecord(const APIRecord *Record) {
   switch (Record->getKind()) {
   case APIRecord::RK_Unknown:
     llvm_unreachable("Records should have a known kind!");
   case APIRecord::RK_GlobalFunction:
-    serializeGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
+    visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
     break;
   case APIRecord::RK_GlobalVariable:
-    serializeGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
+    visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
     break;
   case APIRecord::RK_Enum:
-    serializeEnumRecord(*cast<EnumRecord>(Record));
+    visitEnumRecord(*cast<EnumRecord>(Record));
     break;
   case APIRecord::RK_Struct:
-    serializeStructRecord(*cast<StructRecord>(Record));
+    visitStructRecord(*cast<StructRecord>(Record));
     break;
   case APIRecord::RK_ObjCInterface:
-    serializeObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
+    visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
     break;
   case APIRecord::RK_ObjCProtocol:
-    serializeObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
+    visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
     break;
   case APIRecord::RK_MacroDefinition:
-    serializeMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
+    visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
     break;
   case APIRecord::RK_Typedef:
-    serializeTypedefRecord(*cast<TypedefRecord>(Record));
+    visitTypedefRecord(*cast<TypedefRecord>(Record));
     break;
   default:
-    if (auto Obj = serializeAPIRecord(*Record)) {
+    if (auto Obj = visitAPIRecord(*Record)) {
       Symbols.emplace_back(std::move(*Obj));
       auto &ParentInformation = Record->ParentInformation;
       if (!ParentInformation.empty())
-        serializeRelationship(RelationshipKind::MemberOf, *Record,
-                              *ParentInformation.ParentRecord);
+        visitRelationship(RelationshipKind::MemberOf, *Record,
+                          *ParentInformation.ParentRecord);
     }
     break;
   }
 }
 
-void SymbolGraphSerializer::serializeTypedefRecord(
-    const TypedefRecord &Record) {
+void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) {
   // Typedefs of anonymous types have their entries unified with the underlying
   // type.
   bool ShouldDrop = Record.UnderlyingType.Name.empty();
@@ -804,7 +794,7 @@
   if (ShouldDrop)
     return;
 
-  auto Typedef = serializeAPIRecord(Record);
+  auto Typedef = visitAPIRecord(Record);
   if (!Typedef)
     return;
 
@@ -813,43 +803,15 @@
   Symbols.emplace_back(std::move(*Typedef));
 }
 
-Object SymbolGraphSerializer::serialize() {
-  // Serialize global variables in the API set.
-  for (const auto &GlobalVar : API.getGlobalVariables())
-    serializeGlobalVariableRecord(*GlobalVar.second);
-
-  for (const auto &GlobalFunction : API.getGlobalFunctions())
-    serializeGlobalFunctionRecord(*GlobalFunction.second);
-
-  // Serialize enum records in the API set.
-  for (const auto &Enum : API.getEnums())
-    serializeEnumRecord(*Enum.second);
-
-  // Serialize struct records in the API set.
-  for (const auto &Struct : API.getStructs())
-    serializeStructRecord(*Struct.second);
-
-  // Serialize Objective-C interface records in the API set.
-  for (const auto &ObjCInterface : API.getObjCInterfaces())
-    serializeObjCContainerRecord(*ObjCInterface.second);
-
-  // Serialize Objective-C protocol records in the API set.
-  for (const auto &ObjCProtocol : API.getObjCProtocols())
-    serializeObjCContainerRecord(*ObjCProtocol.second);
-
-  for (const auto &Macro : API.getMacros())
-    serializeMacroDefinitionRecord(*Macro.second);
-
-  for (const auto &Typedef : API.getTypedefs())
-    serializeTypedefRecord(*Typedef.second);
-
-  return serializeCurrentGraph();
+Object SymbolGraphSerializer::traverse() {
+  APISetVisitor::traverseAPISet();
+  return visitCurrentGraph();
 }
 
-Object SymbolGraphSerializer::serializeCurrentGraph() {
+Object SymbolGraphSerializer::visitCurrentGraph() {
   Object Root;
-  serializeObject(Root, "metadata", serializeMetadata());
-  serializeObject(Root, "module", serializeModule());
+  visitObject(Root, "metadata", visitMetadata());
+  visitObject(Root, "module", visitModule());
 
   Root["symbols"] = std::move(Symbols);
   Root["relationships"] = std::move(Relationships);
@@ -857,8 +819,8 @@
   return Root;
 }
 
-void SymbolGraphSerializer::serialize(raw_ostream &os) {
-  Object root = serialize();
+void SymbolGraphSerializer::traverseAPISet(raw_ostream &os) {
+  Object root = traverse();
   if (Options.Compact)
     os << formatv("{0}", Value(std::move(root))) << "\n";
   else
@@ -880,12 +842,12 @@
   SymbolGraphSerializer Serializer(API, EmptyIgnores,
                                    /*Options.Compact*/ {true},
                                    /*ShouldRecurse*/ false);
-  Serializer.serializeSingleRecord(Record);
-  serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
+  Serializer.visitSingleRecord(Record);
+  visitObject(Root, "symbolGraph", Serializer.visitCurrentGraph());
 
   Language Lang = API.getLanguage();
-  serializeArray(Root, "parentContexts",
-                 generateParentContexts(*Record, API, Lang));
+  visitArray(Root, "parentContexts",
+             generateParentContexts(*Record, API, Lang));
 
   Array RelatedSymbols;
 
@@ -909,11 +871,11 @@
     RelatedSymbol["moduleName"] = API.ProductName;
     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
 
-    serializeArray(RelatedSymbol, "parentContexts",
-                   generateParentContexts(*RelatedRecord, API, Lang));
+    visitArray(RelatedSymbol, "parentContexts",
+               generateParentContexts(*RelatedRecord, API, Lang));
     RelatedSymbols.push_back(std::move(RelatedSymbol));
   }
 
-  serializeArray(Root, "relatedSymbols", RelatedSymbols);
+  visitArray(Root, "relatedSymbols", RelatedSymbols);
   return Root;
 }
Index: clang/lib/ExtractAPI/Serialization/SerializerBase.cpp
===================================================================
--- clang/lib/ExtractAPI/Serialization/SerializerBase.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-//===- ExtractAPI/Serialization/SerializerBase.cpp --------------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// This file implements the APISerializer interface.
-///
-//===----------------------------------------------------------------------===//
-
-#include "clang/ExtractAPI/Serialization/SerializerBase.h"
-#include "llvm/Support/raw_ostream.h"
-
-using namespace clang::extractapi;
-
-void APISerializer::serialize(llvm::raw_ostream &os) {}
Index: clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
===================================================================
--- clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
+++ clang/lib/ExtractAPI/ExtractAPIConsumer.cpp
@@ -446,7 +446,7 @@
   // the Symbol Graph format.
   // FIXME: Make the kind of APISerializer configurable.
   SymbolGraphSerializer SGSerializer(*API, IgnoresList);
-  SGSerializer.serialize(*OS);
+  SGSerializer.traverseAPISet(*OS);
   OS.reset();
 }
 
Index: clang/lib/ExtractAPI/CMakeLists.txt
===================================================================
--- clang/lib/ExtractAPI/CMakeLists.txt
+++ clang/lib/ExtractAPI/CMakeLists.txt
@@ -9,7 +9,6 @@
   AvailabilityInfo.cpp
   ExtractAPIConsumer.cpp
   DeclarationFragments.cpp
-  Serialization/SerializerBase.cpp
   Serialization/SymbolGraphSerializer.cpp
   TypedefUnderlyingTypeResolver.cpp
 
Index: clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
+++ clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h
@@ -9,7 +9,7 @@
 /// \file
 /// This file defines the SymbolGraphSerializer class.
 ///
-/// Implement an APISerializer for the Symbol Graph format for ExtractAPI.
+/// Implement an APISetVisitor for the Symbol Graph format for ExtractAPI.
 /// See https://github.com/apple/swift-docc-symbolkit.
 ///
 //===----------------------------------------------------------------------===//
@@ -31,12 +31,12 @@
 
 using namespace llvm::json;
 
-/// The serializer that organizes API information in the Symbol Graph format.
+/// The visitor that organizes API information in the Symbol Graph format.
 ///
 /// The Symbol Graph format (https://github.com/apple/swift-docc-symbolkit)
 /// models an API set as a directed graph, where nodes are symbol declarations,
 /// and edges are relationships between the connected symbols.
-class SymbolGraphSerializer : public APISerializer {
+class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
   virtual void anchor();
 
   /// A JSON array of formatted symbols in \c APISet.
@@ -48,7 +48,7 @@
   /// The Symbol Graph format version used by this serializer.
   static const VersionTuple FormatVersion;
 
-  /// Indicates whether child symbols should be serialized. This is mainly
+  /// Indicates whether child symbols should be visited. This is mainly
   /// useful for \c serializeSingleSymbolSGF.
   bool ShouldRecurse;
 
@@ -57,11 +57,11 @@
   ///
   /// \returns a JSON object that contains the root of the formatted
   /// Symbol Graph.
-  Object serialize();
+  Object traverse();
 
-  /// Implement the APISerializer::serialize interface. Wrap serialize(void) and
-  /// write out the serialized JSON object to \p os.
-  void serialize(raw_ostream &os) override;
+  /// Implement the APISetVisitor::traverseAPISet interface. Wrap
+  /// serialize(void) and write out the serialized JSON object to \p os.
+  void traverseAPISet(raw_ostream &os);
 
   /// Serialize a single symbol SGF. This is primarily used for libclang.
   ///
@@ -91,13 +91,13 @@
 
 private:
   /// Just serialize the currently recorded objects in Symbol Graph format.
-  Object serializeCurrentGraph();
+  Object visitCurrentGraph();
 
   /// Synthesize the metadata section of the Symbol Graph format.
   ///
   /// The metadata section describes information about the Symbol Graph itself,
   /// including the format version and the generator information.
-  Object serializeMetadata() const;
+  Object visitMetadata() const;
 
   /// Synthesize the module section of the Symbol Graph format.
   ///
@@ -105,7 +105,7 @@
   /// by the given API set.
   /// Note that "module" here is not to be confused with the Clang/C++ module
   /// concept.
-  Object serializeModule() const;
+  Object visitModule() const;
 
   /// Determine if the given \p Record should be skipped during serialization.
   bool shouldSkip(const APIRecord &Record) const;
@@ -121,49 +121,50 @@
   /// \returns \c std::nullopt if this \p Record should be skipped, or a JSON
   /// object containing common symbol information of \p Record.
   template <typename RecordTy>
-  std::optional<Object> serializeAPIRecord(const RecordTy &Record) const;
+  std::optional<Object> visitAPIRecord(const RecordTy &Record) const;
 
   /// Helper method to serialize second-level member records of \p Record and
   /// the member-of relationships.
   template <typename MemberTy>
-  void serializeMembers(const APIRecord &Record,
-                        const SmallVector<std::unique_ptr<MemberTy>> &Members);
+  void visitMembers(const APIRecord &Record,
+                    const SmallVector<std::unique_ptr<MemberTy>> &Members);
 
   /// Serialize the \p Kind relationship between \p Source and \p Target.
   ///
   /// Record the relationship between the two symbols in
   /// SymbolGraphSerializer::Relationships.
-  void serializeRelationship(RelationshipKind Kind, SymbolReference Source,
-                             SymbolReference Target);
+  void visitRelationship(RelationshipKind Kind, SymbolReference Source,
+                         SymbolReference Target);
 
-  /// Serialize a global function record.
-  void serializeGlobalFunctionRecord(const GlobalFunctionRecord &Record);
+public:
+  /// Visit a global function record.
+  void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record);
 
-  /// Serialize a global variable record.
-  void serializeGlobalVariableRecord(const GlobalVariableRecord &Record);
+  /// Visit a global variable record.
+  void visitGlobalVariableRecord(const GlobalVariableRecord &Record);
 
-  /// Serialize an enum record.
-  void serializeEnumRecord(const EnumRecord &Record);
+  /// Visit an enum record.
+  void visitEnumRecord(const EnumRecord &Record);
 
-  /// Serialize a struct record.
-  void serializeStructRecord(const StructRecord &Record);
+  /// Visit a struct record.
+  void visitStructRecord(const StructRecord &Record);
 
-  /// Serialize an Objective-C container record.
-  void serializeObjCContainerRecord(const ObjCContainerRecord &Record);
+  /// Visit an Objective-C container record.
+  void visitObjCContainerRecord(const ObjCContainerRecord &Record);
 
-  /// Serialize a macro definition record.
-  void serializeMacroDefinitionRecord(const MacroDefinitionRecord &Record);
+  /// Visit a macro definition record.
+  void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record);
 
-  /// Serialize a typedef record.
-  void serializeTypedefRecord(const TypedefRecord &Record);
+  /// Visit a typedef record.
+  void visitTypedefRecord(const TypedefRecord &Record);
 
-  void serializeSingleRecord(const APIRecord *Record);
+  /// Visit a single record.
+  void visitSingleRecord(const APIRecord *Record);
 
-public:
   SymbolGraphSerializer(const APISet &API, const APIIgnoresList &IgnoresList,
-                        APISerializerOption Options = {},
+                        APISetVisitorOption Options = {},
                         bool ShouldRecurse = true)
-      : APISerializer(API, IgnoresList, Options), ShouldRecurse(ShouldRecurse) {
+      : APISetVisitor(API, IgnoresList, Options), ShouldRecurse(ShouldRecurse) {
   }
 };
 
Index: clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
===================================================================
--- clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
+++ clang/include/clang/ExtractAPI/Serialization/SerializerBase.h
@@ -7,7 +7,7 @@
 //===----------------------------------------------------------------------===//
 ///
 /// \file
-/// This file defines the ExtractAPI APISerializer interface.
+/// This file defines the ExtractAPI APISetVisitor interface.
 ///
 //===----------------------------------------------------------------------===//
 
@@ -16,22 +16,106 @@
 
 #include "clang/ExtractAPI/API.h"
 #include "clang/ExtractAPI/APIIgnoresList.h"
+#include "llvm/Support/JSON.h"
 #include "llvm/Support/raw_ostream.h"
 
+using namespace llvm::json;
+
 namespace clang {
 namespace extractapi {
 
-/// Common options to customize the serializer output.
-struct APISerializerOption {
+/// Common options to customize the visitor output.
+struct APISetVisitorOption {
   /// Do not include unnecessary whitespaces to save space.
   bool Compact;
 };
 
-/// The base interface of serializers for API information.
-class APISerializer {
+/// The base interface of visitors for API information.
+template <typename Derived> class APISetVisitor {
 public:
-  /// Serialize the API information to \p os.
-  virtual void serialize(raw_ostream &os) = 0;
+  /// Traverse the API information to output to \p os.
+  void traverseAPISet(raw_ostream &os){};
+
+  void traverseAPISet() {
+    getDerived()->traverseGlobalVariableRecords();
+
+    getDerived()->traverseGlobalFunctionRecords();
+
+    getDerived()->traverseEnumRecords();
+
+    getDerived()->traverseStructRecords();
+
+    getDerived()->traverseObjCInterfaces();
+
+    getDerived()->traverseObjCProtocols();
+
+    getDerived()->traverseMacroDefinitionRecords();
+
+    getDerived()->traverseTypedefRecords();
+  }
+
+  void traverseGlobalFunctionRecords() {
+    for (const auto &GlobalFunction : API.getGlobalFunctions())
+      getDerived()->visitGlobalFunctionRecord(*GlobalFunction.second);
+  }
+
+  void traverseGlobalVariableRecords() {
+    for (const auto &GlobalVariable : API.getGlobalVariables())
+      getDerived()->visitGlobalVariableRecord(*GlobalVariable.second);
+  }
+
+  void traverseEnumRecords() {
+    for (const auto &Enum : API.getEnums())
+      getDerived()->visitEnumRecord(*Enum.second);
+  }
+
+  void traverseStructRecords() {
+    for (const auto &Struct : API.getStructs())
+      getDerived()->visitStructRecord(*Struct.second);
+  }
+
+  void traverseObjCInterfaces() {
+    for (const auto &Interface : API.getObjCInterfaces())
+      getDerived()->visitObjCContainerRecord(*Interface.second);
+  }
+
+  void traverseObjCProtocols() {
+    for (const auto &Protocol : API.getObjCProtocols())
+      getDerived()->visitObjCContainerRecord(*Protocol.second);
+  }
+
+  void traverseMacroDefinitionRecords() {
+    for (const auto &Macro : API.getMacros())
+      getDerived()->visitMacroDefinitionRecord(*Macro.second);
+  }
+
+  void traverseTypedefRecords() {
+    for (const auto &Typedef : API.getTypedefs())
+      getDerived()->visitTypedefRecord(*Typedef.second);
+  }
+  /// Visit a global function record.
+  void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record){};
+
+  /// Visit a global variable record.
+  void visitGlobalVariableRecord(const GlobalVariableRecord &Record);
+
+  /// Visit an enum record.
+  void visitEnumRecord(const EnumRecord &Record){};
+
+  /// Visit a struct record.
+  void visitStructRecord(const StructRecord &Record){};
+
+  /// Visit an Objective-C container record.
+  void visitObjCContainerRecord(const ObjCContainerRecord &Record){};
+
+  /// Visit a macro definition record.
+  void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record){};
+
+  /// Visit a typedef record.
+  void visitTypedefRecord(const TypedefRecord &Record){};
+
+  /// Visit a single record.
+  void visitSingleRecord(const APIRecord *Record){};
 
 protected:
   const APISet &API;
@@ -41,21 +125,22 @@
   /// Note: This should be consulted before emitting a symbol.
   const APIIgnoresList &IgnoresList;
 
-  APISerializerOption Options;
+  APISetVisitorOption Options;
 
 public:
-  APISerializer() = delete;
-  APISerializer(const APISerializer &) = delete;
-  APISerializer(APISerializer &&) = delete;
-  APISerializer &operator=(const APISerializer &) = delete;
-  APISerializer &operator=(APISerializer &&) = delete;
+  APISetVisitor() = delete;
+  APISetVisitor(const APISetVisitor &) = delete;
+  APISetVisitor(APISetVisitor &&) = delete;
+  APISetVisitor &operator=(const APISetVisitor &) = delete;
+  APISetVisitor &operator=(APISetVisitor &&) = delete;
 
 protected:
-  APISerializer(const APISet &API, const APIIgnoresList &IgnoresList,
-                APISerializerOption Options = {})
+  APISetVisitor(const APISet &API, const APIIgnoresList &IgnoresList,
+                APISetVisitorOption Options = {})
       : API(API), IgnoresList(IgnoresList), Options(Options) {}
 
-  virtual ~APISerializer() = default;
+  virtual ~APISetVisitor() = default;
+  Derived *getDerived() { return static_cast<Derived *>(this); };
 };
 
 } // namespace extractapi
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to