1 //===- ExtractAPI/Serialization/SymbolGraphSerializer.h ---------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file defines the SymbolGraphSerializer class. 11 /// 12 /// Implement an APISerializer for the Symbol Graph format for ExtractAPI. 13 /// See https://github.com/apple/swift-docc-symbolkit. 14 /// 15 //===----------------------------------------------------------------------===// 16 17 #ifndef LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H 18 #define LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H 19 20 #include "clang/ExtractAPI/API.h" 21 #include "clang/ExtractAPI/Serialization/SerializerBase.h" 22 #include "llvm/ADT/SmallVector.h" 23 #include "llvm/Support/JSON.h" 24 #include "llvm/Support/VersionTuple.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 namespace clang { 28 namespace extractapi { 29 30 using namespace llvm::json; 31 32 /// The serializer that organizes API information in the Symbol Graph format. 33 /// 34 /// The Symbol Graph format (https://github.com/apple/swift-docc-symbolkit) 35 /// models an API set as a directed graph, where nodes are symbol declarations, 36 /// and edges are relationships between the connected symbols. 37 class SymbolGraphSerializer : public APISerializer { 38 virtual void anchor(); 39 40 /// A JSON array of formatted symbols in \c APISet. 41 Array Symbols; 42 43 /// A JSON array of formatted symbol relationships in \c APISet. 44 Array Relationships; 45 46 /// The Symbol Graph format version used by this serializer. 47 static const VersionTuple FormatVersion; 48 49 using PathComponentStack = llvm::SmallVector<llvm::StringRef, 4>; 50 /// The current path component stack. 51 /// 52 /// Note: this is used to serialize the ``pathComponents`` field of symbols in 53 /// the Symbol Graph. 54 PathComponentStack PathComponents; 55 56 /// A helper type to manage PathComponents correctly using RAII. 57 struct PathComponentGuard { 58 PathComponentGuard(PathComponentStack &PC, StringRef Component) : PC(PC) { 59 PC.emplace_back(Component); 60 } 61 62 ~PathComponentGuard() { PC.pop_back(); } 63 64 private: 65 PathComponentStack &PC; 66 }; 67 68 public: 69 /// Serialize the APIs in \c APISet in the Symbol Graph format. 70 /// 71 /// \returns a JSON object that contains the root of the formatted 72 /// Symbol Graph. 73 Object serialize(); 74 75 /// Implement the APISerializer::serialize interface. Wrap serialize(void) and 76 /// write out the serialized JSON object to \p os. 77 void serialize(raw_ostream &os) override; 78 79 /// The kind of a relationship between two symbols. 80 enum RelationshipKind { 81 /// The source symbol is a member of the target symbol. 82 /// For example enum constants are members of the enum, class/instance 83 /// methods are members of the class, etc. 84 MemberOf, 85 86 /// The source symbol is inherited from the target symbol. 87 InheritsFrom, 88 89 /// The source symbol conforms to the target symbol. 90 /// For example Objective-C protocol conformances. 91 ConformsTo, 92 }; 93 94 /// Get the string representation of the relationship kind. 95 static StringRef getRelationshipString(RelationshipKind Kind); 96 97 private: 98 /// Synthesize the metadata section of the Symbol Graph format. 99 /// 100 /// The metadata section describes information about the Symbol Graph itself, 101 /// including the format version and the generator information. 102 Object serializeMetadata() const; 103 104 /// Synthesize the module section of the Symbol Graph format. 105 /// 106 /// The module section contains information about the product that is defined 107 /// by the given API set. 108 /// Note that "module" here is not to be confused with the Clang/C++ module 109 /// concept. 110 Object serializeModule() const; 111 112 /// Determine if the given \p Record should be skipped during serialization. 113 bool shouldSkip(const APIRecord &Record) const; 114 115 /// Format the common API information for \p Record. 116 /// 117 /// This handles the shared information of all kinds of API records, 118 /// for example identifier and source location. The resulting object is then 119 /// augmented with kind-specific symbol information by the caller. 120 /// This method also checks if the given \p Record should be skipped during 121 /// serialization. 122 /// 123 /// \returns \c None if this \p Record should be skipped, or a JSON object 124 /// containing common symbol information of \p Record. 125 template <typename RecordTy> 126 Optional<Object> serializeAPIRecord(const RecordTy &Record) const; 127 128 /// Helper method to serialize second-level member records of \p Record and 129 /// the member-of relationships. 130 template <typename MemberTy> 131 void serializeMembers(const APIRecord &Record, 132 const SmallVector<std::unique_ptr<MemberTy>> &Members); 133 134 /// Serialize the \p Kind relationship between \p Source and \p Target. 135 /// 136 /// Record the relationship between the two symbols in 137 /// SymbolGraphSerializer::Relationships. 138 void serializeRelationship(RelationshipKind Kind, SymbolReference Source, 139 SymbolReference Target); 140 141 /// Serialize a global function record. 142 void serializeGlobalFunctionRecord(const GlobalFunctionRecord &Record); 143 144 /// Serialize a global variable record. 145 void serializeGlobalVariableRecord(const GlobalVariableRecord &Record); 146 147 /// Serialize an enum record. 148 void serializeEnumRecord(const EnumRecord &Record); 149 150 /// Serialize a struct record. 151 void serializeStructRecord(const StructRecord &Record); 152 153 /// Serialize an Objective-C container record. 154 void serializeObjCContainerRecord(const ObjCContainerRecord &Record); 155 156 /// Serialize a macro defintion record. 157 void serializeMacroDefinitionRecord(const MacroDefinitionRecord &Record); 158 159 /// Serialize a typedef record. 160 void serializeTypedefRecord(const TypedefRecord &Record); 161 162 /// Push a component to the current path components stack. 163 /// 164 /// \param Component The component to push onto the path components stack. 165 /// \return A PathComponentGuard responsible for removing the latest 166 /// component from the stack on scope exit. 167 LLVM_NODISCARD PathComponentGuard makePathComponentGuard(StringRef Component); 168 169 public: 170 SymbolGraphSerializer(const APISet &API, StringRef ProductName, 171 APISerializerOption Options = {}) 172 : APISerializer(API, ProductName, Options) {} 173 }; 174 175 } // namespace extractapi 176 } // namespace clang 177 178 #endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H 179