xref: /freebsd/contrib/llvm-project/clang/include/clang/ExtractAPI/Serialization/SymbolGraphSerializer.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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