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

source code of clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h