diff --git a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h b/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h --- a/clang/include/clang/ExtractAPI/Serialization/SerializerBase.h +++ b/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 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(this); }; }; } // namespace extractapi diff --git a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h b/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h --- a/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h +++ b/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 { 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 - std::optional serializeAPIRecord(const RecordTy &Record) const; + std::optional visitAPIRecord(const RecordTy &Record) const; /// Helper method to serialize second-level member records of \p Record and /// the member-of relationships. template - void serializeMembers(const APIRecord &Record, - const SmallVector> &Members); + void visitMembers(const APIRecord &Record, + const SmallVector> &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) { } }; diff --git a/clang/lib/ExtractAPI/CMakeLists.txt b/clang/lib/ExtractAPI/CMakeLists.txt --- a/clang/lib/ExtractAPI/CMakeLists.txt +++ b/clang/lib/ExtractAPI/CMakeLists.txt @@ -9,7 +9,6 @@ AvailabilityInfo.cpp ExtractAPIConsumer.cpp DeclarationFragments.cpp - Serialization/SerializerBase.cpp Serialization/SymbolGraphSerializer.cpp TypedefUnderlyingTypeResolver.cpp diff --git a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp b/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp --- a/clang/lib/ExtractAPI/ExtractAPIConsumer.cpp +++ b/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(); } diff --git a/clang/lib/ExtractAPI/Serialization/SerializerBase.cpp b/clang/lib/ExtractAPI/Serialization/SerializerBase.cpp deleted file mode 100644 --- a/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) {} diff --git a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp b/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp --- a/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp +++ b/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 Obj) { +void visitObject(Object &Paren, StringRef Key, std::optional 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) { +void visitArray(Object &Paren, StringRef Key, std::optional 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 serializeSemanticVersion(const VersionTuple &V) { +std::optional 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 -serializeAvailability(const AvailabilitySet &Availabilities) { +std::optional 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 serializeDocComment(const DocComment &Comment) { +std::optional 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 -serializeDeclarationFragments(const DeclarationFragments &DF) { +std::optional 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 -std::optional -serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { +std::optional 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 -std::optional -serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { +std::optional 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 -void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { - serializeObject(Paren, "functionSignature", - serializeFunctionSignatureMixinImpl( - Record, has_function_signature())); +void visitFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { + visitObject(Paren, "functionSignature", + visitFunctionSignatureMixinImpl( + Record, has_function_signature())); } 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 std::optional -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 -void SymbolGraphSerializer::serializeMembers( +void SymbolGraphSerializer::visitMembers( const APIRecord &Record, const SmallVector> &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(&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(Record)); + visitGlobalFunctionRecord(*cast(Record)); break; case APIRecord::RK_GlobalVariable: - serializeGlobalVariableRecord(*cast(Record)); + visitGlobalVariableRecord(*cast(Record)); break; case APIRecord::RK_Enum: - serializeEnumRecord(*cast(Record)); + visitEnumRecord(*cast(Record)); break; case APIRecord::RK_Struct: - serializeStructRecord(*cast(Record)); + visitStructRecord(*cast(Record)); break; case APIRecord::RK_ObjCInterface: - serializeObjCContainerRecord(*cast(Record)); + visitObjCContainerRecord(*cast(Record)); break; case APIRecord::RK_ObjCProtocol: - serializeObjCContainerRecord(*cast(Record)); + visitObjCContainerRecord(*cast(Record)); break; case APIRecord::RK_MacroDefinition: - serializeMacroDefinitionRecord(*cast(Record)); + visitMacroDefinitionRecord(*cast(Record)); break; case APIRecord::RK_Typedef: - serializeTypedefRecord(*cast(Record)); + visitTypedefRecord(*cast(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; }