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/Support/JSON.h"
25 #include "llvm/Support/VersionTuple.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <optional>
28 
29 namespace clang {
30 namespace extractapi {
31 
32 using namespace llvm::json;
33 
34 /// Common options to customize the visitor output.
35 struct SymbolGraphSerializerOption {
36   /// Do not include unnecessary whitespaces to save space.
37   bool Compact;
38 };
39 
40 /// The visitor that organizes API information in the Symbol Graph format.
41 ///
42 /// The Symbol Graph format (https://github.com/apple/swift-docc-symbolkit)
43 /// models an API set as a directed graph, where nodes are symbol declarations,
44 /// and edges are relationships between the connected symbols.
45 class SymbolGraphSerializer : public APISetVisitor<SymbolGraphSerializer> {
46   /// A JSON array of formatted symbols in \c APISet.
47   Array Symbols;
48 
49   /// A JSON array of formatted symbol relationships in \c APISet.
50   Array Relationships;
51 
52   /// The Symbol Graph format version used by this serializer.
53   static const VersionTuple FormatVersion;
54 
55   /// Indicates whether child symbols should be visited. This is mainly
56   /// useful for \c serializeSingleSymbolSGF.
57   bool ShouldRecurse;
58 
59 public:
60   /// Serialize the APIs in \c APISet in the Symbol Graph format.
61   ///
62   /// \returns a JSON object that contains the root of the formatted
63   /// Symbol Graph.
64   Object serialize();
65 
66   ///  Wrap serialize(void) and write out the serialized JSON object to \p os.
67   void serialize(raw_ostream &os);
68 
69   /// Serialize a single symbol SGF. This is primarily used for libclang.
70   ///
71   /// \returns an optional JSON Object representing the payload that libclang
72   /// expects for providing symbol information for a single symbol. If this is
73   /// not a known symbol returns \c std::nullopt.
74   static std::optional<Object> serializeSingleSymbolSGF(StringRef USR,
75                                                         const APISet &API);
76 
77   /// The kind of a relationship between two symbols.
78   enum RelationshipKind {
79     /// The source symbol is a member of the target symbol.
80     /// For example enum constants are members of the enum, class/instance
81     /// methods are members of the class, etc.
82     MemberOf,
83 
84     /// The source symbol is inherited from the target symbol.
85     InheritsFrom,
86 
87     /// The source symbol conforms to the target symbol.
88     /// For example Objective-C protocol conformances.
89     ConformsTo,
90   };
91 
92   /// Get the string representation of the relationship kind.
93   static StringRef getRelationshipString(RelationshipKind Kind);
94 
95 private:
96   /// Just serialize the currently recorded objects in Symbol Graph format.
97   Object serializeCurrentGraph();
98 
99   /// Synthesize the metadata section of the Symbol Graph format.
100   ///
101   /// The metadata section describes information about the Symbol Graph itself,
102   /// including the format version and the generator information.
103   Object serializeMetadata() const;
104 
105   /// Synthesize the module section of the Symbol Graph format.
106   ///
107   /// The module section contains information about the product that is defined
108   /// by the given API set.
109   /// Note that "module" here is not to be confused with the Clang/C++ module
110   /// concept.
111   Object serializeModule() const;
112 
113   /// Determine if the given \p Record should be skipped during serialization.
114   bool shouldSkip(const APIRecord &Record) const;
115 
116   /// Format the common API information for \p Record.
117   ///
118   /// This handles the shared information of all kinds of API records,
119   /// for example identifier and source location. The resulting object is then
120   /// augmented with kind-specific symbol information by the caller.
121   /// This method also checks if the given \p Record should be skipped during
122   /// serialization.
123   ///
124   /// \returns \c std::nullopt if this \p Record should be skipped, or a JSON
125   /// object containing common symbol information of \p Record.
126   template <typename RecordTy>
127   std::optional<Object> serializeAPIRecord(const RecordTy &Record) const;
128 
129   /// Helper method to serialize second-level member records of \p Record and
130   /// the member-of relationships.
131   template <typename MemberTy>
132   void serializeMembers(const APIRecord &Record,
133                         const SmallVector<std::unique_ptr<MemberTy>> &Members);
134 
135   /// Serialize the \p Kind relationship between \p Source and \p Target.
136   ///
137   /// Record the relationship between the two symbols in
138   /// SymbolGraphSerializer::Relationships.
139   void serializeRelationship(RelationshipKind Kind, SymbolReference Source,
140                              SymbolReference Target);
141 
142 protected:
143   /// The list of symbols to ignore.
144   ///
145   /// Note: This should be consulted before emitting a symbol.
146   const APIIgnoresList &IgnoresList;
147 
148   SymbolGraphSerializerOption Options;
149 
150 public:
151   /// Visit a global function record.
152   void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record);
153 
154   /// Visit a global variable record.
155   void visitGlobalVariableRecord(const GlobalVariableRecord &Record);
156 
157   /// Visit an enum record.
158   void visitEnumRecord(const EnumRecord &Record);
159 
160   /// Visit a struct record.
161   void visitStructRecord(const StructRecord &Record);
162 
163   /// Visit an Objective-C container record.
164   void visitObjCContainerRecord(const ObjCContainerRecord &Record);
165 
166   /// Visit a macro definition record.
167   void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record);
168 
169   /// Visit a typedef record.
170   void visitTypedefRecord(const TypedefRecord &Record);
171 
172   /// Serialize a single record.
173   void serializeSingleRecord(const APIRecord *Record);
174 
175   SymbolGraphSerializer(const APISet &API, const APIIgnoresList &IgnoresList,
176                         SymbolGraphSerializerOption Options = {},
177                         bool ShouldRecurse = true)
178       : APISetVisitor(API), ShouldRecurse(ShouldRecurse),
179         IgnoresList(IgnoresList), Options(Options) {}
180 };
181 
182 } // namespace extractapi
183 } // namespace clang
184 
185 #endif // LLVM_CLANG_EXTRACTAPI_SERIALIZATION_SYMBOLGRAPHSERIALIZER_H
186