• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/SerializerBase.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/ADT/StringSet.h"
25 #include "llvm/Support/JSON.h"
26 #include "llvm/Support/VersionTuple.h"
27 #include "llvm/Support/raw_ostream.h"
28 #include <optional>
29 
30 namespace clang {
31 namespace extractapi {
32 
33 using namespace llvm::json;
34 
35 /// Common options to customize the visitor output.
36 struct SymbolGraphSerializerOption {
37   /// Do not include unnecessary whitespaces to save space.
38   bool Compact;
39 };
40 
41 /// The visitor that organizes API information in the Symbol Graph format.
42 ///
43 /// The Symbol Graph format (https://github.com/apple/swift-docc-symbolkit)
44 /// models an API set as a directed graph, where nodes are symbol declarations,
45 /// and edges are relationships between the connected symbols.
46 class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
47   /// A JSON array of formatted symbols in \c APISet.
48   Array Symbols;
49 
50   /// A JSON array of formatted symbol relationships in \c APISet.
51   Array Relationships;
52 
53   /// The Symbol Graph format version used by this serializer.
54   static const VersionTuple FormatVersion;
55 
56   /// Indicates whether child symbols should be visited. This is mainly
57   /// useful for \c serializeSingleSymbolSGF.
58   bool ShouldRecurse;
59 
60 public:
61   /// Serialize the APIs in \c APISet in the Symbol Graph format.
62   ///
63   /// \returns a JSON object that contains the root of the formatted
64   /// Symbol Graph.
65   Object serialize();
66 
67   ///  Wrap serialize(void) and write out the serialized JSON object to \p os.
68   void serialize(raw_ostream &os);
69 
70   /// Serialize a single symbol SGF. This is primarily used for libclang.
71   ///
72   /// \returns an optional JSON Object representing the payload that libclang
73   /// expects for providing symbol information for a single symbol. If this is
74   /// not a known symbol returns \c std::nullopt.
75   static std::optional<Object> serializeSingleSymbolSGF(StringRef USR,
76                                                         const APISet &API);
77 
78   /// The kind of a relationship between two symbols.
79   enum RelationshipKind {
80     /// The source symbol is a member of the target symbol.
81     /// For example enum constants are members of the enum, class/instance
82     /// methods are members of the class, etc.
83     MemberOf,
84 
85     /// The source symbol is inherited from the target symbol.
86     InheritsFrom,
87 
88     /// The source symbol conforms to the target symbol.
89     /// For example Objective-C protocol conformances.
90     ConformsTo,
91 
92     /// The source symbol is an extension to the target symbol.
93     /// For example Objective-C categories extending an external type.
94     ExtensionTo,
95   };
96 
97   /// Get the string representation of the relationship kind.
98   static StringRef getRelationshipString(RelationshipKind Kind);
99 
100   enum ConstraintKind { Conformance, ConditionalConformance };
101 
102   static StringRef getConstraintString(ConstraintKind Kind);
103 
104 private:
105   /// Just serialize the currently recorded objects in Symbol Graph format.
106   Object serializeCurrentGraph();
107 
108   /// Synthesize the metadata section of the Symbol Graph format.
109   ///
110   /// The metadata section describes information about the Symbol Graph itself,
111   /// including the format version and the generator information.
112   Object serializeMetadata() const;
113 
114   /// Synthesize the module section of the Symbol Graph format.
115   ///
116   /// The module section contains information about the product that is defined
117   /// by the given API set.
118   /// Note that "module" here is not to be confused with the Clang/C++ module
119   /// concept.
120   Object serializeModule() const;
121 
122   /// Determine if the given \p Record should be skipped during serialization.
123   bool shouldSkip(const APIRecord &Record) const;
124 
125   /// Format the common API information for \p Record.
126   ///
127   /// This handles the shared information of all kinds of API records,
128   /// for example identifier and source location. The resulting object is then
129   /// augmented with kind-specific symbol information by the caller.
130   /// This method also checks if the given \p Record should be skipped during
131   /// serialization.
132   ///
133   /// \returns \c std::nullopt if this \p Record should be skipped, or a JSON
134   /// object containing common symbol information of \p Record.
135   template <typename RecordTy>
136   std::optional<Object> serializeAPIRecord(const RecordTy &Record) const;
137 
138   /// Helper method to serialize second-level member records of \p Record and
139   /// the member-of relationships.
140   template <typename MemberTy>
141   void serializeMembers(const APIRecord &Record,
142                         const SmallVector<std::unique_ptr<MemberTy>> &Members);
143 
144   /// Serialize the \p Kind relationship between \p Source and \p Target.
145   ///
146   /// Record the relationship between the two symbols in
147   /// SymbolGraphSerializer::Relationships.
148   void serializeRelationship(RelationshipKind Kind, SymbolReference Source,
149                              SymbolReference Target);
150 
151 protected:
152   /// The list of symbols to ignore.
153   ///
154   /// Note: This should be consulted before emitting a symbol.
155   const APIIgnoresList &IgnoresList;
156 
157   SymbolGraphSerializerOption Options;
158 
159   llvm::StringSet<> visitedCategories;
160 
161 public:
162   void visitNamespaceRecord(const NamespaceRecord &Record);
163 
164   /// Visit a global function record.
165   void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record);
166 
167   /// Visit a global variable record.
168   void visitGlobalVariableRecord(const GlobalVariableRecord &Record);
169 
170   /// Visit an enum record.
171   void visitEnumRecord(const EnumRecord &Record);
172 
173   /// Visit a record record.
174   void visitRecordRecord(const RecordRecord &Record);
175 
176   void visitStaticFieldRecord(const StaticFieldRecord &Record);
177 
178   void visitCXXClassRecord(const CXXClassRecord &Record);
179 
180   void visitClassTemplateRecord(const ClassTemplateRecord &Record);
181 
182   void visitClassTemplateSpecializationRecord(
183       const ClassTemplateSpecializationRecord &Record);
184 
185   void visitClassTemplatePartialSpecializationRecord(
186       const ClassTemplatePartialSpecializationRecord &Record);
187 
188   void visitCXXInstanceMethodRecord(const CXXInstanceMethodRecord &Record);
189 
190   void visitCXXStaticMethodRecord(const CXXStaticMethodRecord &Record);
191 
192   void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record);
193 
194   void visitMethodTemplateSpecializationRecord(
195       const CXXMethodTemplateSpecializationRecord &Record);
196 
197   void visitCXXFieldRecord(const CXXFieldRecord &Record);
198 
199   void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record);
200 
201   void visitConceptRecord(const ConceptRecord &Record);
202 
203   void
204   visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord &Record);
205 
206   void visitGlobalVariableTemplateSpecializationRecord(
207       const GlobalVariableTemplateSpecializationRecord &Record);
208 
209   void visitGlobalVariableTemplatePartialSpecializationRecord(
210       const GlobalVariableTemplatePartialSpecializationRecord &Record);
211 
212   void
213   visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord &Record);
214 
215   void visitGlobalFunctionTemplateSpecializationRecord(
216       const GlobalFunctionTemplateSpecializationRecord &Record);
217 
218   /// Visit an Objective-C container record.
219   void visitObjCContainerRecord(const ObjCContainerRecord &Record);
220 
221   /// Visit an Objective-C category record.
222   void visitObjCCategoryRecord(const ObjCCategoryRecord &Record);
223 
224   /// Visit a macro definition record.
225   void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record);
226 
227   /// Visit a typedef record.
228   void visitTypedefRecord(const TypedefRecord &Record);
229 
230   /// Serialize a single record.
231   void serializeSingleRecord(const APIRecord *Record);
232 
233   SymbolGraphSerializer(const APISet &API, const APIIgnoresList &IgnoresList,
234                         SymbolGraphSerializerOption Options = {},
235                         bool ShouldRecurse = true)
APISetVisitor(API)236       : APISetVisitor(API), ShouldRecurse(ShouldRecurse),
237         IgnoresList(IgnoresList), Options(Options) {}
238 };
239 
240 } // namespace extractapi
241 } // namespace clang
242 
243 #endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H
244