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 APISetVisitor to serialize the APISet into the Symbol Graph 13 /// format for ExtractAPI. 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/APIIgnoresList.h" 22 #include "clang/ExtractAPI/Serialization/APISetVisitor.h" 23 #include "llvm/ADT/DenseMap.h" 24 #include "llvm/ADT/SmallString.h" 25 #include "llvm/ADT/SmallVector.h" 26 #include "llvm/ADT/StringMap.h" 27 #include "llvm/ADT/StringRef.h" 28 #include "llvm/ADT/StringSet.h" 29 #include "llvm/ADT/Twine.h" 30 #include "llvm/Support/JSON.h" 31 #include "llvm/Support/VersionTuple.h" 32 #include "llvm/Support/raw_ostream.h" 33 #include <optional> 34 35 namespace clang { 36 namespace extractapi { 37 38 using namespace llvm::json; 39 40 /// Common options to customize the visitor output. 41 struct SymbolGraphSerializerOption { 42 /// Do not include unnecessary whitespaces to save space. 43 bool Compact = true; 44 bool EmitSymbolLabelsForTesting = false; 45 }; 46 47 /// A representation of the contents of a given module symbol graph 48 struct ExtendedModule { 49 ExtendedModule() = default; 50 ExtendedModule(ExtendedModule &&EM) = default; 51 ExtendedModule &operator=(ExtendedModule &&EM) = default; 52 // Copies are expensive so disable them. 53 ExtendedModule(const ExtendedModule &EM) = delete; 54 ExtendedModule &operator=(const ExtendedModule &EM) = delete; 55 56 /// Add a symbol to the module, do not store the resulting pointer or use it 57 /// across insertions. 58 Object *addSymbol(Object &&Symbol); 59 60 void addRelationship(Object &&Relationship); 61 62 /// A JSON array of formatted symbols from an \c APISet. 63 Array Symbols; 64 65 /// A JSON array of formatted symbol relationships from an \c APISet. 66 Array Relationships; 67 }; 68 69 /// The visitor that organizes API information in the Symbol Graph format. 70 /// 71 /// The Symbol Graph format (https://github.com/apple/swift-docc-symbolkit) 72 /// models an API set as a directed graph, where nodes are symbol declarations, 73 /// and edges are relationships between the connected symbols. 74 class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> { 75 private: 76 using Base = APISetVisitor<SymbolGraphSerializer>; 77 /// The main symbol graph that contains symbols that are either top-level or a 78 /// are related to symbols defined in this product/module. 79 ExtendedModule MainModule; 80 81 /// Additional symbol graphs that contain symbols that are related to symbols 82 /// defined in another product/module. The key of this map is the module name 83 /// of the extended module. 84 llvm::StringMap<ExtendedModule> ExtendedModules; 85 86 /// The Symbol Graph format version used by this serializer. 87 static const VersionTuple FormatVersion; 88 89 /// Indicates whether to take into account the extended module. This is only 90 /// useful for \c serializeSingleSymbolSGF. 91 bool ForceEmitToMainModule; 92 93 // Stores the references required to construct path components for the 94 // currently visited APIRecord. 95 llvm::SmallVector<SymbolReference, 8> Hierarchy; 96 97 /// The list of symbols to ignore. 98 /// 99 /// Note: This should be consulted before emitting a symbol. 100 const APIIgnoresList &IgnoresList; 101 102 const bool EmitSymbolLabelsForTesting = false; 103 104 const bool SkipSymbolsInCategoriesToExternalTypes = false; 105 106 /// The object instantiated by the last call to serializeAPIRecord. 107 Object *CurrentSymbol = nullptr; 108 109 /// The module to which \p CurrentSymbol belongs too. 110 ExtendedModule *ModuleForCurrentSymbol = nullptr; 111 112 public: 113 static void 114 serializeMainSymbolGraph(raw_ostream &OS, const APISet &API, 115 const APIIgnoresList &IgnoresList, 116 SymbolGraphSerializerOption Options = {}); 117 118 static void serializeWithExtensionGraphs( 119 raw_ostream &MainOutput, const APISet &API, 120 const APIIgnoresList &IgnoresList, 121 llvm::function_ref< 122 std::unique_ptr<llvm::raw_pwrite_stream>(llvm::Twine BaseFileName)> 123 CreateOutputStream, 124 SymbolGraphSerializerOption Options = {}); 125 126 /// Serialize a single symbol SGF. This is primarily used for libclang. 127 /// 128 /// \returns an optional JSON Object representing the payload that libclang 129 /// expects for providing symbol information for a single symbol. If this is 130 /// not a known symbol returns \c std::nullopt. 131 static std::optional<Object> serializeSingleSymbolSGF(StringRef USR, 132 const APISet &API); 133 134 private: 135 /// The kind of a relationship between two symbols. 136 enum RelationshipKind { 137 /// The source symbol is a member of the target symbol. 138 /// For example enum constants are members of the enum, class/instance 139 /// methods are members of the class, etc. 140 MemberOf, 141 142 /// The source symbol is inherited from the target symbol. 143 InheritsFrom, 144 145 /// The source symbol conforms to the target symbol. 146 /// For example Objective-C protocol conformances. 147 ConformsTo, 148 149 /// The source symbol is an extension to the target symbol. 150 /// For example Objective-C categories extending an external type. 151 ExtensionTo, 152 }; 153 154 /// Serialize a single record. 155 void serializeSingleRecord(const APIRecord *Record); 156 157 /// Get the string representation of the relationship kind. 158 static StringRef getRelationshipString(RelationshipKind Kind); 159 160 void serializeRelationship(RelationshipKind Kind, 161 const SymbolReference &Source, 162 const SymbolReference &Target, 163 ExtendedModule &Into); 164 165 enum ConstraintKind { Conformance, ConditionalConformance }; 166 167 static StringRef getConstraintString(ConstraintKind Kind); 168 169 /// Serialize the APIs in \c ExtendedModule. 170 /// 171 /// \returns a JSON object that contains the root of the formatted 172 /// Symbol Graph. 173 Object serializeGraph(StringRef ModuleName, ExtendedModule &&EM); 174 175 /// Serialize the APIs in \c ExtendedModule in the Symbol Graph format and 176 /// write them to the provide stream. 177 void serializeGraphToStream(raw_ostream &OS, 178 SymbolGraphSerializerOption Options, 179 StringRef ModuleName, ExtendedModule &&EM); 180 181 /// Synthesize the metadata section of the Symbol Graph format. 182 /// 183 /// The metadata section describes information about the Symbol Graph itself, 184 /// including the format version and the generator information. 185 Object serializeMetadata() const; 186 187 /// Synthesize the module section of the Symbol Graph format. 188 /// 189 /// The module section contains information about the product that is defined 190 /// by the given API set. 191 /// Note that "module" here is not to be confused with the Clang/C++ module 192 /// concept. 193 Object serializeModuleObject(StringRef ModuleName) const; 194 195 Array serializePathComponents(const APIRecord *Record) const; 196 197 /// Determine if the given \p Record should be skipped during serialization. 198 bool shouldSkip(const APIRecord *Record) const; 199 200 ExtendedModule &getModuleForCurrentSymbol(); 201 202 /// Format the common API information for \p Record. 203 /// 204 /// This handles the shared information of all kinds of API records, 205 /// for example identifier, source location and path components. The resulting 206 /// object is then augmented with kind-specific symbol information in 207 /// subsequent visit* methods by accessing the \p State member variable. This 208 /// method also checks if the given \p Record should be skipped during 209 /// serialization. This should be called only once per concrete APIRecord 210 /// instance and the first visit* method to be called is responsible for 211 /// calling this. This is normally visitAPIRecord unless a walkUpFromFoo 212 /// method is implemented along the inheritance hierarchy in which case the 213 /// visitFoo method needs to call this. 214 /// 215 /// \returns \c nullptr if this \p Record should be skipped, or a pointer to 216 /// JSON object containing common symbol information of \p Record. Do not 217 /// store the returned pointer only use it to augment the object with record 218 /// specific information as it directly points to the object in the 219 /// \p ExtendedModule, the pointer won't be valid as soon as another object is 220 /// inserted into the module. 221 void serializeAPIRecord(const APIRecord *Record); 222 223 public: 224 // Handle if records should be skipped at this level of the traversal to 225 // ensure that children of skipped records aren't serialized. 226 bool traverseAPIRecord(const APIRecord *Record); 227 228 bool visitAPIRecord(const APIRecord *Record); 229 230 /// Visit a global function record. 231 bool visitGlobalFunctionRecord(const GlobalFunctionRecord *Record); 232 233 bool visitCXXClassRecord(const CXXClassRecord *Record); 234 235 bool visitClassTemplateRecord(const ClassTemplateRecord *Record); 236 237 bool visitClassTemplatePartialSpecializationRecord( 238 const ClassTemplatePartialSpecializationRecord *Record); 239 240 bool visitCXXMethodRecord(const CXXMethodRecord *Record); 241 242 bool visitCXXMethodTemplateRecord(const CXXMethodTemplateRecord *Record); 243 244 bool visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord *Record); 245 246 bool visitConceptRecord(const ConceptRecord *Record); 247 248 bool 249 visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord *Record); 250 251 bool visitGlobalVariableTemplatePartialSpecializationRecord( 252 const GlobalVariableTemplatePartialSpecializationRecord *Record); 253 254 bool 255 visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord *Record); 256 257 bool visitObjCContainerRecord(const ObjCContainerRecord *Record); 258 259 bool visitObjCInterfaceRecord(const ObjCInterfaceRecord *Record); 260 261 bool traverseObjCCategoryRecord(const ObjCCategoryRecord *Record); 262 bool walkUpFromObjCCategoryRecord(const ObjCCategoryRecord *Record); 263 bool visitObjCCategoryRecord(const ObjCCategoryRecord *Record); 264 265 bool visitObjCMethodRecord(const ObjCMethodRecord *Record); 266 267 bool 268 visitObjCInstanceVariableRecord(const ObjCInstanceVariableRecord *Record); 269 270 bool walkUpFromTypedefRecord(const TypedefRecord *Record); 271 bool visitTypedefRecord(const TypedefRecord *Record); 272 273 SymbolGraphSerializer(const APISet &API, const APIIgnoresList &IgnoresList, 274 bool EmitSymbolLabelsForTesting = false, 275 bool ForceEmitToMainModule = false, 276 bool SkipSymbolsInCategoriesToExternalTypes = false) Base(API)277 : Base(API), ForceEmitToMainModule(ForceEmitToMainModule), 278 IgnoresList(IgnoresList), 279 EmitSymbolLabelsForTesting(EmitSymbolLabelsForTesting), 280 SkipSymbolsInCategoriesToExternalTypes( 281 SkipSymbolsInCategoriesToExternalTypes) {} 282 }; 283 284 } // namespace extractapi 285 } // namespace clang 286 287 #endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H 288