xref: /freebsd-src/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1*81ad6265SDimitry Andric //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===//
2*81ad6265SDimitry Andric //
3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*81ad6265SDimitry Andric //
7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
8*81ad6265SDimitry Andric ///
9*81ad6265SDimitry Andric /// \file
10*81ad6265SDimitry Andric /// This file implements the SymbolGraphSerializer.
11*81ad6265SDimitry Andric ///
12*81ad6265SDimitry Andric //===----------------------------------------------------------------------===//
13*81ad6265SDimitry Andric 
14*81ad6265SDimitry Andric #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
15*81ad6265SDimitry Andric #include "clang/Basic/Version.h"
16*81ad6265SDimitry Andric #include "clang/ExtractAPI/API.h"
17*81ad6265SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h"
18*81ad6265SDimitry Andric #include "llvm/Support/JSON.h"
19*81ad6265SDimitry Andric #include "llvm/Support/Path.h"
20*81ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h"
21*81ad6265SDimitry Andric #include <type_traits>
22*81ad6265SDimitry Andric 
23*81ad6265SDimitry Andric using namespace clang;
24*81ad6265SDimitry Andric using namespace clang::extractapi;
25*81ad6265SDimitry Andric using namespace llvm;
26*81ad6265SDimitry Andric using namespace llvm::json;
27*81ad6265SDimitry Andric 
28*81ad6265SDimitry Andric namespace {
29*81ad6265SDimitry Andric 
30*81ad6265SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren
31*81ad6265SDimitry Andric /// at position \p Key.
32*81ad6265SDimitry Andric void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) {
33*81ad6265SDimitry Andric   if (Obj)
34*81ad6265SDimitry Andric     Paren[Key] = std::move(Obj.getValue());
35*81ad6265SDimitry Andric }
36*81ad6265SDimitry Andric 
37*81ad6265SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at
38*81ad6265SDimitry Andric /// position \p Key.
39*81ad6265SDimitry Andric void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) {
40*81ad6265SDimitry Andric   if (Array)
41*81ad6265SDimitry Andric     Paren[Key] = std::move(Array.getValue());
42*81ad6265SDimitry Andric }
43*81ad6265SDimitry Andric 
44*81ad6265SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
45*81ad6265SDimitry Andric /// format.
46*81ad6265SDimitry Andric ///
47*81ad6265SDimitry Andric /// A semantic version object contains three numeric fields, representing the
48*81ad6265SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple.
49*81ad6265SDimitry Andric /// For example version tuple 1.0.3 is serialized as:
50*81ad6265SDimitry Andric /// \code
51*81ad6265SDimitry Andric ///   {
52*81ad6265SDimitry Andric ///     "major" : 1,
53*81ad6265SDimitry Andric ///     "minor" : 0,
54*81ad6265SDimitry Andric ///     "patch" : 3
55*81ad6265SDimitry Andric ///   }
56*81ad6265SDimitry Andric /// \endcode
57*81ad6265SDimitry Andric ///
58*81ad6265SDimitry Andric /// \returns \c None if the version \p V is empty, or an \c Object containing
59*81ad6265SDimitry Andric /// the semantic version representation of \p V.
60*81ad6265SDimitry Andric Optional<Object> serializeSemanticVersion(const VersionTuple &V) {
61*81ad6265SDimitry Andric   if (V.empty())
62*81ad6265SDimitry Andric     return None;
63*81ad6265SDimitry Andric 
64*81ad6265SDimitry Andric   Object Version;
65*81ad6265SDimitry Andric   Version["major"] = V.getMajor();
66*81ad6265SDimitry Andric   Version["minor"] = V.getMinor().value_or(0);
67*81ad6265SDimitry Andric   Version["patch"] = V.getSubminor().value_or(0);
68*81ad6265SDimitry Andric   return Version;
69*81ad6265SDimitry Andric }
70*81ad6265SDimitry Andric 
71*81ad6265SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property.
72*81ad6265SDimitry Andric ///
73*81ad6265SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an
74*81ad6265SDimitry Andric /// optional \c minimumVersion semantic version field.
75*81ad6265SDimitry Andric Object serializeOperatingSystem(const Triple &T) {
76*81ad6265SDimitry Andric   Object OS;
77*81ad6265SDimitry Andric   OS["name"] = T.getOSTypeName(T.getOS());
78*81ad6265SDimitry Andric   serializeObject(OS, "minimumVersion",
79*81ad6265SDimitry Andric                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
80*81ad6265SDimitry Andric   return OS;
81*81ad6265SDimitry Andric }
82*81ad6265SDimitry Andric 
83*81ad6265SDimitry Andric /// Serialize the platform information in the Symbol Graph module section.
84*81ad6265SDimitry Andric ///
85*81ad6265SDimitry Andric /// The platform object describes a target platform triple in corresponding
86*81ad6265SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem.
87*81ad6265SDimitry Andric Object serializePlatform(const Triple &T) {
88*81ad6265SDimitry Andric   Object Platform;
89*81ad6265SDimitry Andric   Platform["architecture"] = T.getArchName();
90*81ad6265SDimitry Andric   Platform["vendor"] = T.getVendorName();
91*81ad6265SDimitry Andric   Platform["operatingSystem"] = serializeOperatingSystem(T);
92*81ad6265SDimitry Andric   return Platform;
93*81ad6265SDimitry Andric }
94*81ad6265SDimitry Andric 
95*81ad6265SDimitry Andric /// Serialize a source position.
96*81ad6265SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) {
97*81ad6265SDimitry Andric   assert(Loc.isValid() && "invalid source position");
98*81ad6265SDimitry Andric 
99*81ad6265SDimitry Andric   Object SourcePosition;
100*81ad6265SDimitry Andric   SourcePosition["line"] = Loc.getLine();
101*81ad6265SDimitry Andric   SourcePosition["character"] = Loc.getColumn();
102*81ad6265SDimitry Andric 
103*81ad6265SDimitry Andric   return SourcePosition;
104*81ad6265SDimitry Andric }
105*81ad6265SDimitry Andric 
106*81ad6265SDimitry Andric /// Serialize a source location in file.
107*81ad6265SDimitry Andric ///
108*81ad6265SDimitry Andric /// \param Loc The presumed location to serialize.
109*81ad6265SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
110*81ad6265SDimitry Andric /// Defaults to false.
111*81ad6265SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc,
112*81ad6265SDimitry Andric                                bool IncludeFileURI = false) {
113*81ad6265SDimitry Andric   Object SourceLocation;
114*81ad6265SDimitry Andric   serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
115*81ad6265SDimitry Andric 
116*81ad6265SDimitry Andric   if (IncludeFileURI) {
117*81ad6265SDimitry Andric     std::string FileURI = "file://";
118*81ad6265SDimitry Andric     // Normalize file path to use forward slashes for the URI.
119*81ad6265SDimitry Andric     FileURI += sys::path::convert_to_slash(Loc.getFilename());
120*81ad6265SDimitry Andric     SourceLocation["uri"] = FileURI;
121*81ad6265SDimitry Andric   }
122*81ad6265SDimitry Andric 
123*81ad6265SDimitry Andric   return SourceLocation;
124*81ad6265SDimitry Andric }
125*81ad6265SDimitry Andric 
126*81ad6265SDimitry Andric /// Serialize a source range with begin and end locations.
127*81ad6265SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc,
128*81ad6265SDimitry Andric                             const PresumedLoc &EndLoc) {
129*81ad6265SDimitry Andric   Object SourceRange;
130*81ad6265SDimitry Andric   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
131*81ad6265SDimitry Andric   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
132*81ad6265SDimitry Andric   return SourceRange;
133*81ad6265SDimitry Andric }
134*81ad6265SDimitry Andric 
135*81ad6265SDimitry Andric /// Serialize the availability attributes of a symbol.
136*81ad6265SDimitry Andric ///
137*81ad6265SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted
138*81ad6265SDimitry Andric /// versions of the symbol as semantic versions, if not default.
139*81ad6265SDimitry Andric /// Availability information also contains flags to indicate if the symbol is
140*81ad6265SDimitry Andric /// unconditionally unavailable or deprecated,
141*81ad6265SDimitry Andric /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
142*81ad6265SDimitry Andric ///
143*81ad6265SDimitry Andric /// \returns \c None if the symbol has default availability attributes, or
144*81ad6265SDimitry Andric /// an \c Object containing the formatted availability information.
145*81ad6265SDimitry Andric Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) {
146*81ad6265SDimitry Andric   if (Avail.isDefault())
147*81ad6265SDimitry Andric     return None;
148*81ad6265SDimitry Andric 
149*81ad6265SDimitry Andric   Object Availbility;
150*81ad6265SDimitry Andric   serializeObject(Availbility, "introducedVersion",
151*81ad6265SDimitry Andric                   serializeSemanticVersion(Avail.Introduced));
152*81ad6265SDimitry Andric   serializeObject(Availbility, "deprecatedVersion",
153*81ad6265SDimitry Andric                   serializeSemanticVersion(Avail.Deprecated));
154*81ad6265SDimitry Andric   serializeObject(Availbility, "obsoletedVersion",
155*81ad6265SDimitry Andric                   serializeSemanticVersion(Avail.Obsoleted));
156*81ad6265SDimitry Andric   if (Avail.isUnavailable())
157*81ad6265SDimitry Andric     Availbility["isUnconditionallyUnavailable"] = true;
158*81ad6265SDimitry Andric   if (Avail.isUnconditionallyDeprecated())
159*81ad6265SDimitry Andric     Availbility["isUnconditionallyDeprecated"] = true;
160*81ad6265SDimitry Andric 
161*81ad6265SDimitry Andric   return Availbility;
162*81ad6265SDimitry Andric }
163*81ad6265SDimitry Andric 
164*81ad6265SDimitry Andric /// Get the language name string for interface language references.
165*81ad6265SDimitry Andric StringRef getLanguageName(Language Lang) {
166*81ad6265SDimitry Andric   switch (Lang) {
167*81ad6265SDimitry Andric   case Language::C:
168*81ad6265SDimitry Andric     return "c";
169*81ad6265SDimitry Andric   case Language::ObjC:
170*81ad6265SDimitry Andric     return "objective-c";
171*81ad6265SDimitry Andric 
172*81ad6265SDimitry Andric   // Unsupported language currently
173*81ad6265SDimitry Andric   case Language::CXX:
174*81ad6265SDimitry Andric   case Language::ObjCXX:
175*81ad6265SDimitry Andric   case Language::OpenCL:
176*81ad6265SDimitry Andric   case Language::OpenCLCXX:
177*81ad6265SDimitry Andric   case Language::CUDA:
178*81ad6265SDimitry Andric   case Language::RenderScript:
179*81ad6265SDimitry Andric   case Language::HIP:
180*81ad6265SDimitry Andric   case Language::HLSL:
181*81ad6265SDimitry Andric 
182*81ad6265SDimitry Andric   // Languages that the frontend cannot parse and compile
183*81ad6265SDimitry Andric   case Language::Unknown:
184*81ad6265SDimitry Andric   case Language::Asm:
185*81ad6265SDimitry Andric   case Language::LLVM_IR:
186*81ad6265SDimitry Andric     llvm_unreachable("Unsupported language kind");
187*81ad6265SDimitry Andric   }
188*81ad6265SDimitry Andric 
189*81ad6265SDimitry Andric   llvm_unreachable("Unhandled language kind");
190*81ad6265SDimitry Andric }
191*81ad6265SDimitry Andric 
192*81ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format.
193*81ad6265SDimitry Andric ///
194*81ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique
195*81ad6265SDimitry Andric /// references, and the interface language name.
196*81ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) {
197*81ad6265SDimitry Andric   Object Identifier;
198*81ad6265SDimitry Andric   Identifier["precise"] = Record.USR;
199*81ad6265SDimitry Andric   Identifier["interfaceLanguage"] = getLanguageName(Lang);
200*81ad6265SDimitry Andric 
201*81ad6265SDimitry Andric   return Identifier;
202*81ad6265SDimitry Andric }
203*81ad6265SDimitry Andric 
204*81ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by
205*81ad6265SDimitry Andric /// the Symbol Graph format.
206*81ad6265SDimitry Andric ///
207*81ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line
208*81ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range
209*81ad6265SDimitry Andric /// information.
210*81ad6265SDimitry Andric /// e.g.
211*81ad6265SDimitry Andric /// \code
212*81ad6265SDimitry Andric ///   /// This is a documentation comment
213*81ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
214*81ad6265SDimitry Andric ///   ///     with multiple lines.
215*81ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
216*81ad6265SDimitry Andric /// \endcode
217*81ad6265SDimitry Andric ///
218*81ad6265SDimitry Andric /// \returns \c None if \p Comment is empty, or an \c Object containing the
219*81ad6265SDimitry Andric /// formatted lines.
220*81ad6265SDimitry Andric Optional<Object> serializeDocComment(const DocComment &Comment) {
221*81ad6265SDimitry Andric   if (Comment.empty())
222*81ad6265SDimitry Andric     return None;
223*81ad6265SDimitry Andric 
224*81ad6265SDimitry Andric   Object DocComment;
225*81ad6265SDimitry Andric   Array LinesArray;
226*81ad6265SDimitry Andric   for (const auto &CommentLine : Comment) {
227*81ad6265SDimitry Andric     Object Line;
228*81ad6265SDimitry Andric     Line["text"] = CommentLine.Text;
229*81ad6265SDimitry Andric     serializeObject(Line, "range",
230*81ad6265SDimitry Andric                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
231*81ad6265SDimitry Andric     LinesArray.emplace_back(std::move(Line));
232*81ad6265SDimitry Andric   }
233*81ad6265SDimitry Andric   serializeArray(DocComment, "lines", LinesArray);
234*81ad6265SDimitry Andric 
235*81ad6265SDimitry Andric   return DocComment;
236*81ad6265SDimitry Andric }
237*81ad6265SDimitry Andric 
238*81ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol.
239*81ad6265SDimitry Andric ///
240*81ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important
241*81ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to
242*81ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for
243*81ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example:
244*81ad6265SDimitry Andric /// \code
245*81ad6265SDimitry Andric ///   const int pi; -> "declarationFragments" : [
246*81ad6265SDimitry Andric ///                      {
247*81ad6265SDimitry Andric ///                        "kind" : "keyword",
248*81ad6265SDimitry Andric ///                        "spelling" : "const"
249*81ad6265SDimitry Andric ///                      },
250*81ad6265SDimitry Andric ///                      {
251*81ad6265SDimitry Andric ///                        "kind" : "text",
252*81ad6265SDimitry Andric ///                        "spelling" : " "
253*81ad6265SDimitry Andric ///                      },
254*81ad6265SDimitry Andric ///                      {
255*81ad6265SDimitry Andric ///                        "kind" : "typeIdentifier",
256*81ad6265SDimitry Andric ///                        "preciseIdentifier" : "c:I",
257*81ad6265SDimitry Andric ///                        "spelling" : "int"
258*81ad6265SDimitry Andric ///                      },
259*81ad6265SDimitry Andric ///                      {
260*81ad6265SDimitry Andric ///                        "kind" : "text",
261*81ad6265SDimitry Andric ///                        "spelling" : " "
262*81ad6265SDimitry Andric ///                      },
263*81ad6265SDimitry Andric ///                      {
264*81ad6265SDimitry Andric ///                        "kind" : "identifier",
265*81ad6265SDimitry Andric ///                        "spelling" : "pi"
266*81ad6265SDimitry Andric ///                      }
267*81ad6265SDimitry Andric ///                    ]
268*81ad6265SDimitry Andric /// \endcode
269*81ad6265SDimitry Andric ///
270*81ad6265SDimitry Andric /// \returns \c None if \p DF is empty, or an \c Array containing the formatted
271*81ad6265SDimitry Andric /// declaration fragments array.
272*81ad6265SDimitry Andric Optional<Array> serializeDeclarationFragments(const DeclarationFragments &DF) {
273*81ad6265SDimitry Andric   if (DF.getFragments().empty())
274*81ad6265SDimitry Andric     return None;
275*81ad6265SDimitry Andric 
276*81ad6265SDimitry Andric   Array Fragments;
277*81ad6265SDimitry Andric   for (const auto &F : DF.getFragments()) {
278*81ad6265SDimitry Andric     Object Fragment;
279*81ad6265SDimitry Andric     Fragment["spelling"] = F.Spelling;
280*81ad6265SDimitry Andric     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
281*81ad6265SDimitry Andric     if (!F.PreciseIdentifier.empty())
282*81ad6265SDimitry Andric       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
283*81ad6265SDimitry Andric     Fragments.emplace_back(std::move(Fragment));
284*81ad6265SDimitry Andric   }
285*81ad6265SDimitry Andric 
286*81ad6265SDimitry Andric   return Fragments;
287*81ad6265SDimitry Andric }
288*81ad6265SDimitry Andric 
289*81ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph
290*81ad6265SDimitry Andric /// format.
291*81ad6265SDimitry Andric ///
292*81ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol
293*81ad6265SDimitry Andric /// that can be used for different applications:
294*81ad6265SDimitry Andric ///   - \c title : The simple declared name of the symbol;
295*81ad6265SDimitry Andric ///   - \c subHeading : An array of declaration fragments that provides tags,
296*81ad6265SDimitry Andric ///     and potentially more tokens (for example the \c +/- symbol for
297*81ad6265SDimitry Andric ///     Objective-C methods). Can be used as sub-headings for documentation.
298*81ad6265SDimitry Andric Object serializeNames(const APIRecord &Record) {
299*81ad6265SDimitry Andric   Object Names;
300*81ad6265SDimitry Andric   Names["title"] = Record.Name;
301*81ad6265SDimitry Andric   serializeArray(Names, "subHeading",
302*81ad6265SDimitry Andric                  serializeDeclarationFragments(Record.SubHeading));
303*81ad6265SDimitry Andric   DeclarationFragments NavigatorFragments;
304*81ad6265SDimitry Andric   NavigatorFragments.append(Record.Name,
305*81ad6265SDimitry Andric                             DeclarationFragments::FragmentKind::Identifier,
306*81ad6265SDimitry Andric                             /*PreciseIdentifier*/ "");
307*81ad6265SDimitry Andric   serializeArray(Names, "navigator",
308*81ad6265SDimitry Andric                  serializeDeclarationFragments(NavigatorFragments));
309*81ad6265SDimitry Andric 
310*81ad6265SDimitry Andric   return Names;
311*81ad6265SDimitry Andric }
312*81ad6265SDimitry Andric 
313*81ad6265SDimitry Andric /// Serialize the symbol kind information.
314*81ad6265SDimitry Andric ///
315*81ad6265SDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier
316*81ad6265SDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse
317*81ad6265SDimitry Andric /// the kind, and a \c displayName for rendering human-readable names.
318*81ad6265SDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
319*81ad6265SDimitry Andric   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
320*81ad6265SDimitry Andric     return (getLanguageName(Lang) + "." + S).str();
321*81ad6265SDimitry Andric   };
322*81ad6265SDimitry Andric 
323*81ad6265SDimitry Andric   Object Kind;
324*81ad6265SDimitry Andric   switch (Record.getKind()) {
325*81ad6265SDimitry Andric   case APIRecord::RK_GlobalFunction:
326*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
327*81ad6265SDimitry Andric     Kind["displayName"] = "Function";
328*81ad6265SDimitry Andric     break;
329*81ad6265SDimitry Andric   case APIRecord::RK_GlobalVariable:
330*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
331*81ad6265SDimitry Andric     Kind["displayName"] = "Global Variable";
332*81ad6265SDimitry Andric     break;
333*81ad6265SDimitry Andric   case APIRecord::RK_EnumConstant:
334*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum.case");
335*81ad6265SDimitry Andric     Kind["displayName"] = "Enumeration Case";
336*81ad6265SDimitry Andric     break;
337*81ad6265SDimitry Andric   case APIRecord::RK_Enum:
338*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum");
339*81ad6265SDimitry Andric     Kind["displayName"] = "Enumeration";
340*81ad6265SDimitry Andric     break;
341*81ad6265SDimitry Andric   case APIRecord::RK_StructField:
342*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
343*81ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
344*81ad6265SDimitry Andric     break;
345*81ad6265SDimitry Andric   case APIRecord::RK_Struct:
346*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("struct");
347*81ad6265SDimitry Andric     Kind["displayName"] = "Structure";
348*81ad6265SDimitry Andric     break;
349*81ad6265SDimitry Andric   case APIRecord::RK_ObjCIvar:
350*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("ivar");
351*81ad6265SDimitry Andric     Kind["displayName"] = "Instance Variable";
352*81ad6265SDimitry Andric     break;
353*81ad6265SDimitry Andric   case APIRecord::RK_ObjCMethod:
354*81ad6265SDimitry Andric     if (dyn_cast<ObjCMethodRecord>(&Record)->IsInstanceMethod) {
355*81ad6265SDimitry Andric       Kind["identifier"] = AddLangPrefix("method");
356*81ad6265SDimitry Andric       Kind["displayName"] = "Instance Method";
357*81ad6265SDimitry Andric     } else {
358*81ad6265SDimitry Andric       Kind["identifier"] = AddLangPrefix("type.method");
359*81ad6265SDimitry Andric       Kind["displayName"] = "Type Method";
360*81ad6265SDimitry Andric     }
361*81ad6265SDimitry Andric     break;
362*81ad6265SDimitry Andric   case APIRecord::RK_ObjCProperty:
363*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
364*81ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
365*81ad6265SDimitry Andric     break;
366*81ad6265SDimitry Andric   case APIRecord::RK_ObjCInterface:
367*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("class");
368*81ad6265SDimitry Andric     Kind["displayName"] = "Class";
369*81ad6265SDimitry Andric     break;
370*81ad6265SDimitry Andric   case APIRecord::RK_ObjCCategory:
371*81ad6265SDimitry Andric     // We don't serialize out standalone Objective-C category symbols yet.
372*81ad6265SDimitry Andric     llvm_unreachable("Serializing standalone Objective-C category symbols is "
373*81ad6265SDimitry Andric                      "not supported.");
374*81ad6265SDimitry Andric     break;
375*81ad6265SDimitry Andric   case APIRecord::RK_ObjCProtocol:
376*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("protocol");
377*81ad6265SDimitry Andric     Kind["displayName"] = "Protocol";
378*81ad6265SDimitry Andric     break;
379*81ad6265SDimitry Andric   case APIRecord::RK_MacroDefinition:
380*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("macro");
381*81ad6265SDimitry Andric     Kind["displayName"] = "Macro";
382*81ad6265SDimitry Andric     break;
383*81ad6265SDimitry Andric   case APIRecord::RK_Typedef:
384*81ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("typealias");
385*81ad6265SDimitry Andric     Kind["displayName"] = "Type Alias";
386*81ad6265SDimitry Andric     break;
387*81ad6265SDimitry Andric   }
388*81ad6265SDimitry Andric 
389*81ad6265SDimitry Andric   return Kind;
390*81ad6265SDimitry Andric }
391*81ad6265SDimitry Andric 
392*81ad6265SDimitry Andric template <typename RecordTy>
393*81ad6265SDimitry Andric Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record,
394*81ad6265SDimitry Andric                                                      std::true_type) {
395*81ad6265SDimitry Andric   const auto &FS = Record.Signature;
396*81ad6265SDimitry Andric   if (FS.empty())
397*81ad6265SDimitry Andric     return None;
398*81ad6265SDimitry Andric 
399*81ad6265SDimitry Andric   Object Signature;
400*81ad6265SDimitry Andric   serializeArray(Signature, "returns",
401*81ad6265SDimitry Andric                  serializeDeclarationFragments(FS.getReturnType()));
402*81ad6265SDimitry Andric 
403*81ad6265SDimitry Andric   Array Parameters;
404*81ad6265SDimitry Andric   for (const auto &P : FS.getParameters()) {
405*81ad6265SDimitry Andric     Object Parameter;
406*81ad6265SDimitry Andric     Parameter["name"] = P.Name;
407*81ad6265SDimitry Andric     serializeArray(Parameter, "declarationFragments",
408*81ad6265SDimitry Andric                    serializeDeclarationFragments(P.Fragments));
409*81ad6265SDimitry Andric     Parameters.emplace_back(std::move(Parameter));
410*81ad6265SDimitry Andric   }
411*81ad6265SDimitry Andric 
412*81ad6265SDimitry Andric   if (!Parameters.empty())
413*81ad6265SDimitry Andric     Signature["parameters"] = std::move(Parameters);
414*81ad6265SDimitry Andric 
415*81ad6265SDimitry Andric   return Signature;
416*81ad6265SDimitry Andric }
417*81ad6265SDimitry Andric 
418*81ad6265SDimitry Andric template <typename RecordTy>
419*81ad6265SDimitry Andric Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record,
420*81ad6265SDimitry Andric                                                      std::false_type) {
421*81ad6265SDimitry Andric   return None;
422*81ad6265SDimitry Andric }
423*81ad6265SDimitry Andric 
424*81ad6265SDimitry Andric /// Serialize the function signature field, as specified by the
425*81ad6265SDimitry Andric /// Symbol Graph format.
426*81ad6265SDimitry Andric ///
427*81ad6265SDimitry Andric /// The Symbol Graph function signature property contains two arrays.
428*81ad6265SDimitry Andric ///   - The \c returns array is the declaration fragments of the return type;
429*81ad6265SDimitry Andric ///   - The \c parameters array contains names and declaration fragments of the
430*81ad6265SDimitry Andric ///     parameters.
431*81ad6265SDimitry Andric ///
432*81ad6265SDimitry Andric /// \returns \c None if \p FS is empty, or an \c Object containing the
433*81ad6265SDimitry Andric /// formatted function signature.
434*81ad6265SDimitry Andric template <typename RecordTy>
435*81ad6265SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
436*81ad6265SDimitry Andric   serializeObject(Paren, "functionSignature",
437*81ad6265SDimitry Andric                   serializeFunctionSignatureMixinImpl(
438*81ad6265SDimitry Andric                       Record, has_function_signature<RecordTy>()));
439*81ad6265SDimitry Andric }
440*81ad6265SDimitry Andric 
441*81ad6265SDimitry Andric } // namespace
442*81ad6265SDimitry Andric 
443*81ad6265SDimitry Andric void SymbolGraphSerializer::anchor() {}
444*81ad6265SDimitry Andric 
445*81ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer.
446*81ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
447*81ad6265SDimitry Andric 
448*81ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const {
449*81ad6265SDimitry Andric   Object Metadata;
450*81ad6265SDimitry Andric   serializeObject(Metadata, "formatVersion",
451*81ad6265SDimitry Andric                   serializeSemanticVersion(FormatVersion));
452*81ad6265SDimitry Andric   Metadata["generator"] = clang::getClangFullVersion();
453*81ad6265SDimitry Andric   return Metadata;
454*81ad6265SDimitry Andric }
455*81ad6265SDimitry Andric 
456*81ad6265SDimitry Andric Object SymbolGraphSerializer::serializeModule() const {
457*81ad6265SDimitry Andric   Object Module;
458*81ad6265SDimitry Andric   // The user is expected to always pass `--product-name=` on the command line
459*81ad6265SDimitry Andric   // to populate this field.
460*81ad6265SDimitry Andric   Module["name"] = ProductName;
461*81ad6265SDimitry Andric   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
462*81ad6265SDimitry Andric   return Module;
463*81ad6265SDimitry Andric }
464*81ad6265SDimitry Andric 
465*81ad6265SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
466*81ad6265SDimitry Andric   // Skip unconditionally unavailable symbols
467*81ad6265SDimitry Andric   if (Record.Availability.isUnconditionallyUnavailable())
468*81ad6265SDimitry Andric     return true;
469*81ad6265SDimitry Andric 
470*81ad6265SDimitry Andric   // Filter out symbols prefixed with an underscored as they are understood to
471*81ad6265SDimitry Andric   // be symbols clients should not use.
472*81ad6265SDimitry Andric   if (Record.Name.startswith("_"))
473*81ad6265SDimitry Andric     return true;
474*81ad6265SDimitry Andric 
475*81ad6265SDimitry Andric   return false;
476*81ad6265SDimitry Andric }
477*81ad6265SDimitry Andric 
478*81ad6265SDimitry Andric template <typename RecordTy>
479*81ad6265SDimitry Andric Optional<Object>
480*81ad6265SDimitry Andric SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
481*81ad6265SDimitry Andric   if (shouldSkip(Record))
482*81ad6265SDimitry Andric     return None;
483*81ad6265SDimitry Andric 
484*81ad6265SDimitry Andric   Object Obj;
485*81ad6265SDimitry Andric   serializeObject(Obj, "identifier",
486*81ad6265SDimitry Andric                   serializeIdentifier(Record, API.getLanguage()));
487*81ad6265SDimitry Andric   serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
488*81ad6265SDimitry Andric   serializeObject(Obj, "names", serializeNames(Record));
489*81ad6265SDimitry Andric   serializeObject(
490*81ad6265SDimitry Andric       Obj, "location",
491*81ad6265SDimitry Andric       serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
492*81ad6265SDimitry Andric   serializeObject(Obj, "availbility",
493*81ad6265SDimitry Andric                   serializeAvailability(Record.Availability));
494*81ad6265SDimitry Andric   serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
495*81ad6265SDimitry Andric   serializeArray(Obj, "declarationFragments",
496*81ad6265SDimitry Andric                  serializeDeclarationFragments(Record.Declaration));
497*81ad6265SDimitry Andric   // TODO: Once we keep track of symbol access information serialize it
498*81ad6265SDimitry Andric   // correctly here.
499*81ad6265SDimitry Andric   Obj["accessLevel"] = "public";
500*81ad6265SDimitry Andric   serializeArray(Obj, "pathComponents", Array(PathComponents));
501*81ad6265SDimitry Andric 
502*81ad6265SDimitry Andric   serializeFunctionSignatureMixin(Obj, Record);
503*81ad6265SDimitry Andric 
504*81ad6265SDimitry Andric   return Obj;
505*81ad6265SDimitry Andric }
506*81ad6265SDimitry Andric 
507*81ad6265SDimitry Andric template <typename MemberTy>
508*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeMembers(
509*81ad6265SDimitry Andric     const APIRecord &Record,
510*81ad6265SDimitry Andric     const SmallVector<std::unique_ptr<MemberTy>> &Members) {
511*81ad6265SDimitry Andric   for (const auto &Member : Members) {
512*81ad6265SDimitry Andric     auto MemberPathComponentGuard = makePathComponentGuard(Member->Name);
513*81ad6265SDimitry Andric     auto MemberRecord = serializeAPIRecord(*Member);
514*81ad6265SDimitry Andric     if (!MemberRecord)
515*81ad6265SDimitry Andric       continue;
516*81ad6265SDimitry Andric 
517*81ad6265SDimitry Andric     Symbols.emplace_back(std::move(*MemberRecord));
518*81ad6265SDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
519*81ad6265SDimitry Andric   }
520*81ad6265SDimitry Andric }
521*81ad6265SDimitry Andric 
522*81ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
523*81ad6265SDimitry Andric   switch (Kind) {
524*81ad6265SDimitry Andric   case RelationshipKind::MemberOf:
525*81ad6265SDimitry Andric     return "memberOf";
526*81ad6265SDimitry Andric   case RelationshipKind::InheritsFrom:
527*81ad6265SDimitry Andric     return "inheritsFrom";
528*81ad6265SDimitry Andric   case RelationshipKind::ConformsTo:
529*81ad6265SDimitry Andric     return "conformsTo";
530*81ad6265SDimitry Andric   }
531*81ad6265SDimitry Andric   llvm_unreachable("Unhandled relationship kind");
532*81ad6265SDimitry Andric }
533*81ad6265SDimitry Andric 
534*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
535*81ad6265SDimitry Andric                                                   SymbolReference Source,
536*81ad6265SDimitry Andric                                                   SymbolReference Target) {
537*81ad6265SDimitry Andric   Object Relationship;
538*81ad6265SDimitry Andric   Relationship["source"] = Source.USR;
539*81ad6265SDimitry Andric   Relationship["target"] = Target.USR;
540*81ad6265SDimitry Andric   Relationship["kind"] = getRelationshipString(Kind);
541*81ad6265SDimitry Andric 
542*81ad6265SDimitry Andric   Relationships.emplace_back(std::move(Relationship));
543*81ad6265SDimitry Andric }
544*81ad6265SDimitry Andric 
545*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeGlobalFunctionRecord(
546*81ad6265SDimitry Andric     const GlobalFunctionRecord &Record) {
547*81ad6265SDimitry Andric   auto GlobalPathComponentGuard = makePathComponentGuard(Record.Name);
548*81ad6265SDimitry Andric 
549*81ad6265SDimitry Andric   auto Obj = serializeAPIRecord(Record);
550*81ad6265SDimitry Andric   if (!Obj)
551*81ad6265SDimitry Andric     return;
552*81ad6265SDimitry Andric 
553*81ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Obj));
554*81ad6265SDimitry Andric }
555*81ad6265SDimitry Andric 
556*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeGlobalVariableRecord(
557*81ad6265SDimitry Andric     const GlobalVariableRecord &Record) {
558*81ad6265SDimitry Andric   auto GlobalPathComponentGuard = makePathComponentGuard(Record.Name);
559*81ad6265SDimitry Andric 
560*81ad6265SDimitry Andric   auto Obj = serializeAPIRecord(Record);
561*81ad6265SDimitry Andric   if (!Obj)
562*81ad6265SDimitry Andric     return;
563*81ad6265SDimitry Andric 
564*81ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Obj));
565*81ad6265SDimitry Andric }
566*81ad6265SDimitry Andric 
567*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
568*81ad6265SDimitry Andric   auto EnumPathComponentGuard = makePathComponentGuard(Record.Name);
569*81ad6265SDimitry Andric   auto Enum = serializeAPIRecord(Record);
570*81ad6265SDimitry Andric   if (!Enum)
571*81ad6265SDimitry Andric     return;
572*81ad6265SDimitry Andric 
573*81ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Enum));
574*81ad6265SDimitry Andric   serializeMembers(Record, Record.Constants);
575*81ad6265SDimitry Andric }
576*81ad6265SDimitry Andric 
577*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
578*81ad6265SDimitry Andric   auto StructPathComponentGuard = makePathComponentGuard(Record.Name);
579*81ad6265SDimitry Andric   auto Struct = serializeAPIRecord(Record);
580*81ad6265SDimitry Andric   if (!Struct)
581*81ad6265SDimitry Andric     return;
582*81ad6265SDimitry Andric 
583*81ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Struct));
584*81ad6265SDimitry Andric   serializeMembers(Record, Record.Fields);
585*81ad6265SDimitry Andric }
586*81ad6265SDimitry Andric 
587*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeObjCContainerRecord(
588*81ad6265SDimitry Andric     const ObjCContainerRecord &Record) {
589*81ad6265SDimitry Andric   auto ObjCContainerPathComponentGuard = makePathComponentGuard(Record.Name);
590*81ad6265SDimitry Andric   auto ObjCContainer = serializeAPIRecord(Record);
591*81ad6265SDimitry Andric   if (!ObjCContainer)
592*81ad6265SDimitry Andric     return;
593*81ad6265SDimitry Andric 
594*81ad6265SDimitry Andric   Symbols.emplace_back(std::move(*ObjCContainer));
595*81ad6265SDimitry Andric 
596*81ad6265SDimitry Andric   serializeMembers(Record, Record.Ivars);
597*81ad6265SDimitry Andric   serializeMembers(Record, Record.Methods);
598*81ad6265SDimitry Andric   serializeMembers(Record, Record.Properties);
599*81ad6265SDimitry Andric 
600*81ad6265SDimitry Andric   for (const auto &Protocol : Record.Protocols)
601*81ad6265SDimitry Andric     // Record that Record conforms to Protocol.
602*81ad6265SDimitry Andric     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
603*81ad6265SDimitry Andric 
604*81ad6265SDimitry Andric   if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
605*81ad6265SDimitry Andric     if (!ObjCInterface->SuperClass.empty())
606*81ad6265SDimitry Andric       // If Record is an Objective-C interface record and it has a super class,
607*81ad6265SDimitry Andric       // record that Record is inherited from SuperClass.
608*81ad6265SDimitry Andric       serializeRelationship(RelationshipKind::InheritsFrom, Record,
609*81ad6265SDimitry Andric                             ObjCInterface->SuperClass);
610*81ad6265SDimitry Andric 
611*81ad6265SDimitry Andric     // Members of categories extending an interface are serialized as members of
612*81ad6265SDimitry Andric     // the interface.
613*81ad6265SDimitry Andric     for (const auto *Category : ObjCInterface->Categories) {
614*81ad6265SDimitry Andric       serializeMembers(Record, Category->Ivars);
615*81ad6265SDimitry Andric       serializeMembers(Record, Category->Methods);
616*81ad6265SDimitry Andric       serializeMembers(Record, Category->Properties);
617*81ad6265SDimitry Andric 
618*81ad6265SDimitry Andric       // Surface the protocols of the the category to the interface.
619*81ad6265SDimitry Andric       for (const auto &Protocol : Category->Protocols)
620*81ad6265SDimitry Andric         serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
621*81ad6265SDimitry Andric     }
622*81ad6265SDimitry Andric   }
623*81ad6265SDimitry Andric }
624*81ad6265SDimitry Andric 
625*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeMacroDefinitionRecord(
626*81ad6265SDimitry Andric     const MacroDefinitionRecord &Record) {
627*81ad6265SDimitry Andric   auto MacroPathComponentGuard = makePathComponentGuard(Record.Name);
628*81ad6265SDimitry Andric   auto Macro = serializeAPIRecord(Record);
629*81ad6265SDimitry Andric 
630*81ad6265SDimitry Andric   if (!Macro)
631*81ad6265SDimitry Andric     return;
632*81ad6265SDimitry Andric 
633*81ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Macro));
634*81ad6265SDimitry Andric }
635*81ad6265SDimitry Andric 
636*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeTypedefRecord(
637*81ad6265SDimitry Andric     const TypedefRecord &Record) {
638*81ad6265SDimitry Andric   // Typedefs of anonymous types have their entries unified with the underlying
639*81ad6265SDimitry Andric   // type.
640*81ad6265SDimitry Andric   bool ShouldDrop = Record.UnderlyingType.Name.empty();
641*81ad6265SDimitry Andric   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
642*81ad6265SDimitry Andric   // the same name
643*81ad6265SDimitry Andric   ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
644*81ad6265SDimitry Andric   if (ShouldDrop)
645*81ad6265SDimitry Andric     return;
646*81ad6265SDimitry Andric 
647*81ad6265SDimitry Andric   auto TypedefPathComponentGuard = makePathComponentGuard(Record.Name);
648*81ad6265SDimitry Andric   auto Typedef = serializeAPIRecord(Record);
649*81ad6265SDimitry Andric   if (!Typedef)
650*81ad6265SDimitry Andric     return;
651*81ad6265SDimitry Andric 
652*81ad6265SDimitry Andric   (*Typedef)["type"] = Record.UnderlyingType.USR;
653*81ad6265SDimitry Andric 
654*81ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Typedef));
655*81ad6265SDimitry Andric }
656*81ad6265SDimitry Andric 
657*81ad6265SDimitry Andric SymbolGraphSerializer::PathComponentGuard
658*81ad6265SDimitry Andric SymbolGraphSerializer::makePathComponentGuard(StringRef Component) {
659*81ad6265SDimitry Andric   return PathComponentGuard(PathComponents, Component);
660*81ad6265SDimitry Andric }
661*81ad6265SDimitry Andric 
662*81ad6265SDimitry Andric Object SymbolGraphSerializer::serialize() {
663*81ad6265SDimitry Andric   Object Root;
664*81ad6265SDimitry Andric   serializeObject(Root, "metadata", serializeMetadata());
665*81ad6265SDimitry Andric   serializeObject(Root, "module", serializeModule());
666*81ad6265SDimitry Andric 
667*81ad6265SDimitry Andric   // Serialize global variables in the API set.
668*81ad6265SDimitry Andric   for (const auto &GlobalVar : API.getGlobalVariables())
669*81ad6265SDimitry Andric     serializeGlobalVariableRecord(*GlobalVar.second);
670*81ad6265SDimitry Andric 
671*81ad6265SDimitry Andric   for (const auto &GlobalFunction : API.getGlobalFunctions())
672*81ad6265SDimitry Andric     serializeGlobalFunctionRecord(*GlobalFunction.second);
673*81ad6265SDimitry Andric 
674*81ad6265SDimitry Andric   // Serialize enum records in the API set.
675*81ad6265SDimitry Andric   for (const auto &Enum : API.getEnums())
676*81ad6265SDimitry Andric     serializeEnumRecord(*Enum.second);
677*81ad6265SDimitry Andric 
678*81ad6265SDimitry Andric   // Serialize struct records in the API set.
679*81ad6265SDimitry Andric   for (const auto &Struct : API.getStructs())
680*81ad6265SDimitry Andric     serializeStructRecord(*Struct.second);
681*81ad6265SDimitry Andric 
682*81ad6265SDimitry Andric   // Serialize Objective-C interface records in the API set.
683*81ad6265SDimitry Andric   for (const auto &ObjCInterface : API.getObjCInterfaces())
684*81ad6265SDimitry Andric     serializeObjCContainerRecord(*ObjCInterface.second);
685*81ad6265SDimitry Andric 
686*81ad6265SDimitry Andric   // Serialize Objective-C protocol records in the API set.
687*81ad6265SDimitry Andric   for (const auto &ObjCProtocol : API.getObjCProtocols())
688*81ad6265SDimitry Andric     serializeObjCContainerRecord(*ObjCProtocol.second);
689*81ad6265SDimitry Andric 
690*81ad6265SDimitry Andric   for (const auto &Macro : API.getMacros())
691*81ad6265SDimitry Andric     serializeMacroDefinitionRecord(*Macro.second);
692*81ad6265SDimitry Andric 
693*81ad6265SDimitry Andric   for (const auto &Typedef : API.getTypedefs())
694*81ad6265SDimitry Andric     serializeTypedefRecord(*Typedef.second);
695*81ad6265SDimitry Andric 
696*81ad6265SDimitry Andric   Root["symbols"] = std::move(Symbols);
697*81ad6265SDimitry Andric   Root["relationships"] = std::move(Relationships);
698*81ad6265SDimitry Andric 
699*81ad6265SDimitry Andric   return Root;
700*81ad6265SDimitry Andric }
701*81ad6265SDimitry Andric 
702*81ad6265SDimitry Andric void SymbolGraphSerializer::serialize(raw_ostream &os) {
703*81ad6265SDimitry Andric   Object root = serialize();
704*81ad6265SDimitry Andric   if (Options.Compact)
705*81ad6265SDimitry Andric     os << formatv("{0}", Value(std::move(root))) << "\n";
706*81ad6265SDimitry Andric   else
707*81ad6265SDimitry Andric     os << formatv("{0:2}", Value(std::move(root))) << "\n";
708*81ad6265SDimitry Andric }
709