1*89f6b26fSZixu Wang //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===//
2*89f6b26fSZixu Wang //
3*89f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*89f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information.
5*89f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*89f6b26fSZixu Wang //
7*89f6b26fSZixu Wang //===----------------------------------------------------------------------===//
8*89f6b26fSZixu Wang ///
9*89f6b26fSZixu Wang /// \file
10*89f6b26fSZixu Wang /// This file implements the SymbolGraphSerializer.
11*89f6b26fSZixu Wang ///
12*89f6b26fSZixu Wang //===----------------------------------------------------------------------===//
13*89f6b26fSZixu Wang 
14*89f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
15*89f6b26fSZixu Wang #include "clang/Basic/Version.h"
16*89f6b26fSZixu Wang #include "clang/ExtractAPI/API.h"
17*89f6b26fSZixu Wang #include "llvm/Support/JSON.h"
18*89f6b26fSZixu Wang #include "llvm/Support/Path.h"
19*89f6b26fSZixu Wang #include "llvm/Support/VersionTuple.h"
20*89f6b26fSZixu Wang 
21*89f6b26fSZixu Wang using namespace clang;
22*89f6b26fSZixu Wang using namespace clang::extractapi;
23*89f6b26fSZixu Wang using namespace llvm;
24*89f6b26fSZixu Wang using namespace llvm::json;
25*89f6b26fSZixu Wang 
26*89f6b26fSZixu Wang namespace {
27*89f6b26fSZixu Wang 
28*89f6b26fSZixu Wang /// Helper function to inject a JSON object \p Obj into another object \p Paren
29*89f6b26fSZixu Wang /// at position \p Key.
30*89f6b26fSZixu Wang void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) {
31*89f6b26fSZixu Wang   if (Obj)
32*89f6b26fSZixu Wang     Paren[Key] = std::move(Obj.getValue());
33*89f6b26fSZixu Wang }
34*89f6b26fSZixu Wang 
35*89f6b26fSZixu Wang /// Helper function to inject a JSON array \p Array into object \p Paren at
36*89f6b26fSZixu Wang /// position \p Key.
37*89f6b26fSZixu Wang void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) {
38*89f6b26fSZixu Wang   if (Array)
39*89f6b26fSZixu Wang     Paren[Key] = std::move(Array.getValue());
40*89f6b26fSZixu Wang }
41*89f6b26fSZixu Wang 
42*89f6b26fSZixu Wang /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
43*89f6b26fSZixu Wang /// format.
44*89f6b26fSZixu Wang ///
45*89f6b26fSZixu Wang /// A semantic version object contains three numeric fields, representing the
46*89f6b26fSZixu Wang /// \c major, \c minor, and \c patch parts of the version tuple.
47*89f6b26fSZixu Wang /// For example version tuple 1.0.3 is serialized as:
48*89f6b26fSZixu Wang /// \code
49*89f6b26fSZixu Wang ///   {
50*89f6b26fSZixu Wang ///     "major" : 1,
51*89f6b26fSZixu Wang ///     "minor" : 0,
52*89f6b26fSZixu Wang ///     "patch" : 3
53*89f6b26fSZixu Wang ///   }
54*89f6b26fSZixu Wang /// \endcode
55*89f6b26fSZixu Wang ///
56*89f6b26fSZixu Wang /// \returns \c None if the version \p V is empty, or an \c Object containing
57*89f6b26fSZixu Wang /// the semantic version representation of \p V.
58*89f6b26fSZixu Wang Optional<Object> serializeSemanticVersion(const VersionTuple &V) {
59*89f6b26fSZixu Wang   if (V.empty())
60*89f6b26fSZixu Wang     return None;
61*89f6b26fSZixu Wang 
62*89f6b26fSZixu Wang   Object Version;
63*89f6b26fSZixu Wang   Version["major"] = V.getMajor();
64*89f6b26fSZixu Wang   Version["minor"] = V.getMinor().getValueOr(0);
65*89f6b26fSZixu Wang   Version["patch"] = V.getSubminor().getValueOr(0);
66*89f6b26fSZixu Wang   return Version;
67*89f6b26fSZixu Wang }
68*89f6b26fSZixu Wang 
69*89f6b26fSZixu Wang /// Serialize the OS information in the Symbol Graph platform property.
70*89f6b26fSZixu Wang ///
71*89f6b26fSZixu Wang /// The OS information in Symbol Graph contains the \c name of the OS, and an
72*89f6b26fSZixu Wang /// optional \c minimumVersion semantic version field.
73*89f6b26fSZixu Wang Object serializeOperatingSystem(const Triple &T) {
74*89f6b26fSZixu Wang   Object OS;
75*89f6b26fSZixu Wang   OS["name"] = T.getOSTypeName(T.getOS());
76*89f6b26fSZixu Wang   serializeObject(OS, "minimumVersion",
77*89f6b26fSZixu Wang                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
78*89f6b26fSZixu Wang   return OS;
79*89f6b26fSZixu Wang }
80*89f6b26fSZixu Wang 
81*89f6b26fSZixu Wang /// Serialize the platform information in the Symbol Graph module section.
82*89f6b26fSZixu Wang ///
83*89f6b26fSZixu Wang /// The platform object describes a target platform triple in corresponding
84*89f6b26fSZixu Wang /// three fields: \c architecture, \c vendor, and \c operatingSystem.
85*89f6b26fSZixu Wang Object serializePlatform(const Triple &T) {
86*89f6b26fSZixu Wang   Object Platform;
87*89f6b26fSZixu Wang   Platform["architecture"] = T.getArchName();
88*89f6b26fSZixu Wang   Platform["vendor"] = T.getVendorName();
89*89f6b26fSZixu Wang   Platform["operatingSystem"] = serializeOperatingSystem(T);
90*89f6b26fSZixu Wang   return Platform;
91*89f6b26fSZixu Wang }
92*89f6b26fSZixu Wang 
93*89f6b26fSZixu Wang /// Serialize a source location in file.
94*89f6b26fSZixu Wang ///
95*89f6b26fSZixu Wang /// \param Loc The presumed location to serialize.
96*89f6b26fSZixu Wang /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
97*89f6b26fSZixu Wang /// Defaults to false.
98*89f6b26fSZixu Wang Object serializeSourcePosition(const PresumedLoc &Loc,
99*89f6b26fSZixu Wang                                bool IncludeFileURI = false) {
100*89f6b26fSZixu Wang   assert(Loc.isValid() && "invalid source position");
101*89f6b26fSZixu Wang 
102*89f6b26fSZixu Wang   Object SourcePosition;
103*89f6b26fSZixu Wang   SourcePosition["line"] = Loc.getLine();
104*89f6b26fSZixu Wang   SourcePosition["character"] = Loc.getColumn();
105*89f6b26fSZixu Wang 
106*89f6b26fSZixu Wang   if (IncludeFileURI) {
107*89f6b26fSZixu Wang     std::string FileURI = "file://";
108*89f6b26fSZixu Wang     // Normalize file path to use forward slashes for the URI.
109*89f6b26fSZixu Wang     FileURI += sys::path::convert_to_slash(Loc.getFilename());
110*89f6b26fSZixu Wang     SourcePosition["uri"] = FileURI;
111*89f6b26fSZixu Wang   }
112*89f6b26fSZixu Wang 
113*89f6b26fSZixu Wang   return SourcePosition;
114*89f6b26fSZixu Wang }
115*89f6b26fSZixu Wang 
116*89f6b26fSZixu Wang /// Serialize a source range with begin and end locations.
117*89f6b26fSZixu Wang Object serializeSourceRange(const PresumedLoc &BeginLoc,
118*89f6b26fSZixu Wang                             const PresumedLoc &EndLoc) {
119*89f6b26fSZixu Wang   Object SourceRange;
120*89f6b26fSZixu Wang   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
121*89f6b26fSZixu Wang   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
122*89f6b26fSZixu Wang   return SourceRange;
123*89f6b26fSZixu Wang }
124*89f6b26fSZixu Wang 
125*89f6b26fSZixu Wang /// Serialize the availability attributes of a symbol.
126*89f6b26fSZixu Wang ///
127*89f6b26fSZixu Wang /// Availability information contains the introduced, deprecated, and obsoleted
128*89f6b26fSZixu Wang /// versions of the symbol as semantic versions, if not default.
129*89f6b26fSZixu Wang /// Availability information also contains flags to indicate if the symbol is
130*89f6b26fSZixu Wang /// unconditionally unavailable or deprecated,
131*89f6b26fSZixu Wang /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
132*89f6b26fSZixu Wang ///
133*89f6b26fSZixu Wang /// \returns \c None if the symbol has default availability attributes, or
134*89f6b26fSZixu Wang /// an \c Object containing the formatted availability information.
135*89f6b26fSZixu Wang Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) {
136*89f6b26fSZixu Wang   if (Avail.isDefault())
137*89f6b26fSZixu Wang     return None;
138*89f6b26fSZixu Wang 
139*89f6b26fSZixu Wang   Object Availbility;
140*89f6b26fSZixu Wang   serializeObject(Availbility, "introducedVersion",
141*89f6b26fSZixu Wang                   serializeSemanticVersion(Avail.Introduced));
142*89f6b26fSZixu Wang   serializeObject(Availbility, "deprecatedVersion",
143*89f6b26fSZixu Wang                   serializeSemanticVersion(Avail.Deprecated));
144*89f6b26fSZixu Wang   serializeObject(Availbility, "obsoletedVersion",
145*89f6b26fSZixu Wang                   serializeSemanticVersion(Avail.Obsoleted));
146*89f6b26fSZixu Wang   if (Avail.isUnavailable())
147*89f6b26fSZixu Wang     Availbility["isUnconditionallyUnavailable"] = true;
148*89f6b26fSZixu Wang   if (Avail.isUnconditionallyDeprecated())
149*89f6b26fSZixu Wang     Availbility["isUnconditionallyDeprecated"] = true;
150*89f6b26fSZixu Wang 
151*89f6b26fSZixu Wang   return Availbility;
152*89f6b26fSZixu Wang }
153*89f6b26fSZixu Wang 
154*89f6b26fSZixu Wang /// Get the short language name string for interface language references.
155*89f6b26fSZixu Wang StringRef getLanguageName(const LangOptions &LangOpts) {
156*89f6b26fSZixu Wang   auto Language =
157*89f6b26fSZixu Wang       LangStandard::getLangStandardForKind(LangOpts.LangStd).getLanguage();
158*89f6b26fSZixu Wang   switch (Language) {
159*89f6b26fSZixu Wang   case Language::C:
160*89f6b26fSZixu Wang     return "c";
161*89f6b26fSZixu Wang   case Language::ObjC:
162*89f6b26fSZixu Wang     return "objc";
163*89f6b26fSZixu Wang 
164*89f6b26fSZixu Wang   // Unsupported language currently
165*89f6b26fSZixu Wang   case Language::CXX:
166*89f6b26fSZixu Wang   case Language::ObjCXX:
167*89f6b26fSZixu Wang   case Language::OpenCL:
168*89f6b26fSZixu Wang   case Language::OpenCLCXX:
169*89f6b26fSZixu Wang   case Language::CUDA:
170*89f6b26fSZixu Wang   case Language::RenderScript:
171*89f6b26fSZixu Wang   case Language::HIP:
172*89f6b26fSZixu Wang 
173*89f6b26fSZixu Wang   // Languages that the frontend cannot parse and compile
174*89f6b26fSZixu Wang   case Language::Unknown:
175*89f6b26fSZixu Wang   case Language::Asm:
176*89f6b26fSZixu Wang   case Language::LLVM_IR:
177*89f6b26fSZixu Wang     llvm_unreachable("Unsupported language kind");
178*89f6b26fSZixu Wang   }
179*89f6b26fSZixu Wang 
180*89f6b26fSZixu Wang   llvm_unreachable("Unhandled language kind");
181*89f6b26fSZixu Wang }
182*89f6b26fSZixu Wang 
183*89f6b26fSZixu Wang /// Serialize the identifier object as specified by the Symbol Graph format.
184*89f6b26fSZixu Wang ///
185*89f6b26fSZixu Wang /// The identifier property of a symbol contains the USR for precise and unique
186*89f6b26fSZixu Wang /// references, and the interface language name.
187*89f6b26fSZixu Wang Object serializeIdentifier(const APIRecord &Record,
188*89f6b26fSZixu Wang                            const LangOptions &LangOpts) {
189*89f6b26fSZixu Wang   Object Identifier;
190*89f6b26fSZixu Wang   Identifier["precise"] = Record.USR;
191*89f6b26fSZixu Wang   Identifier["interfaceLanguage"] = getLanguageName(LangOpts);
192*89f6b26fSZixu Wang 
193*89f6b26fSZixu Wang   return Identifier;
194*89f6b26fSZixu Wang }
195*89f6b26fSZixu Wang 
196*89f6b26fSZixu Wang /// Serialize the documentation comments attached to a symbol, as specified by
197*89f6b26fSZixu Wang /// the Symbol Graph format.
198*89f6b26fSZixu Wang ///
199*89f6b26fSZixu Wang /// The Symbol Graph \c docComment object contains an array of lines. Each line
200*89f6b26fSZixu Wang /// represents one line of striped documentation comment, with source range
201*89f6b26fSZixu Wang /// information.
202*89f6b26fSZixu Wang /// e.g.
203*89f6b26fSZixu Wang /// \code
204*89f6b26fSZixu Wang ///   /// This is a documentation comment
205*89f6b26fSZixu Wang ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
206*89f6b26fSZixu Wang ///   ///     with multiple lines.
207*89f6b26fSZixu Wang ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
208*89f6b26fSZixu Wang /// \endcode
209*89f6b26fSZixu Wang ///
210*89f6b26fSZixu Wang /// \returns \c None if \p Comment is empty, or an \c Object containing the
211*89f6b26fSZixu Wang /// formatted lines.
212*89f6b26fSZixu Wang Optional<Object> serializeDocComment(const DocComment &Comment) {
213*89f6b26fSZixu Wang   if (Comment.empty())
214*89f6b26fSZixu Wang     return None;
215*89f6b26fSZixu Wang 
216*89f6b26fSZixu Wang   Object DocComment;
217*89f6b26fSZixu Wang   Array LinesArray;
218*89f6b26fSZixu Wang   for (const auto &CommentLine : Comment) {
219*89f6b26fSZixu Wang     Object Line;
220*89f6b26fSZixu Wang     Line["text"] = CommentLine.Text;
221*89f6b26fSZixu Wang     serializeObject(Line, "range",
222*89f6b26fSZixu Wang                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
223*89f6b26fSZixu Wang     LinesArray.emplace_back(std::move(Line));
224*89f6b26fSZixu Wang   }
225*89f6b26fSZixu Wang   serializeArray(DocComment, "lines", LinesArray);
226*89f6b26fSZixu Wang 
227*89f6b26fSZixu Wang   return DocComment;
228*89f6b26fSZixu Wang }
229*89f6b26fSZixu Wang 
230*89f6b26fSZixu Wang /// Serialize the declaration fragments of a symbol.
231*89f6b26fSZixu Wang ///
232*89f6b26fSZixu Wang /// The Symbol Graph declaration fragments is an array of tagged important
233*89f6b26fSZixu Wang /// parts of a symbol's declaration. The fragments sequence can be joined to
234*89f6b26fSZixu Wang /// form spans of declaration text, with attached information useful for
235*89f6b26fSZixu Wang /// purposes like syntax-highlighting etc. For example:
236*89f6b26fSZixu Wang /// \code
237*89f6b26fSZixu Wang ///   const int pi; -> "declarationFragments" : [
238*89f6b26fSZixu Wang ///                      {
239*89f6b26fSZixu Wang ///                        "kind" : "keyword",
240*89f6b26fSZixu Wang ///                        "spelling" : "const"
241*89f6b26fSZixu Wang ///                      },
242*89f6b26fSZixu Wang ///                      {
243*89f6b26fSZixu Wang ///                        "kind" : "text",
244*89f6b26fSZixu Wang ///                        "spelling" : " "
245*89f6b26fSZixu Wang ///                      },
246*89f6b26fSZixu Wang ///                      {
247*89f6b26fSZixu Wang ///                        "kind" : "typeIdentifier",
248*89f6b26fSZixu Wang ///                        "preciseIdentifier" : "c:I",
249*89f6b26fSZixu Wang ///                        "spelling" : "int"
250*89f6b26fSZixu Wang ///                      },
251*89f6b26fSZixu Wang ///                      {
252*89f6b26fSZixu Wang ///                        "kind" : "text",
253*89f6b26fSZixu Wang ///                        "spelling" : " "
254*89f6b26fSZixu Wang ///                      },
255*89f6b26fSZixu Wang ///                      {
256*89f6b26fSZixu Wang ///                        "kind" : "identifier",
257*89f6b26fSZixu Wang ///                        "spelling" : "pi"
258*89f6b26fSZixu Wang ///                      }
259*89f6b26fSZixu Wang ///                    ]
260*89f6b26fSZixu Wang /// \endcode
261*89f6b26fSZixu Wang ///
262*89f6b26fSZixu Wang /// \returns \c None if \p DF is empty, or an \c Array containing the formatted
263*89f6b26fSZixu Wang /// declaration fragments array.
264*89f6b26fSZixu Wang Optional<Array> serializeDeclarationFragments(const DeclarationFragments &DF) {
265*89f6b26fSZixu Wang   if (DF.getFragments().empty())
266*89f6b26fSZixu Wang     return None;
267*89f6b26fSZixu Wang 
268*89f6b26fSZixu Wang   Array Fragments;
269*89f6b26fSZixu Wang   for (const auto &F : DF.getFragments()) {
270*89f6b26fSZixu Wang     Object Fragment;
271*89f6b26fSZixu Wang     Fragment["spelling"] = F.Spelling;
272*89f6b26fSZixu Wang     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
273*89f6b26fSZixu Wang     if (!F.PreciseIdentifier.empty())
274*89f6b26fSZixu Wang       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
275*89f6b26fSZixu Wang     Fragments.emplace_back(std::move(Fragment));
276*89f6b26fSZixu Wang   }
277*89f6b26fSZixu Wang 
278*89f6b26fSZixu Wang   return Fragments;
279*89f6b26fSZixu Wang }
280*89f6b26fSZixu Wang 
281*89f6b26fSZixu Wang /// Serialize the function signature field of a function, as specified by the
282*89f6b26fSZixu Wang /// Symbol Graph format.
283*89f6b26fSZixu Wang ///
284*89f6b26fSZixu Wang /// The Symbol Graph function signature property contains two arrays.
285*89f6b26fSZixu Wang ///   - The \c returns array is the declaration fragments of the return type;
286*89f6b26fSZixu Wang ///   - The \c parameters array contains names and declaration fragments of the
287*89f6b26fSZixu Wang ///     parameters.
288*89f6b26fSZixu Wang ///
289*89f6b26fSZixu Wang /// \returns \c None if \p FS is empty, or an \c Object containing the
290*89f6b26fSZixu Wang /// formatted function signature.
291*89f6b26fSZixu Wang Optional<Object> serializeFunctionSignature(const FunctionSignature &FS) {
292*89f6b26fSZixu Wang   if (FS.empty())
293*89f6b26fSZixu Wang     return None;
294*89f6b26fSZixu Wang 
295*89f6b26fSZixu Wang   Object Signature;
296*89f6b26fSZixu Wang   serializeArray(Signature, "returns",
297*89f6b26fSZixu Wang                  serializeDeclarationFragments(FS.getReturnType()));
298*89f6b26fSZixu Wang 
299*89f6b26fSZixu Wang   Array Parameters;
300*89f6b26fSZixu Wang   for (const auto &P : FS.getParameters()) {
301*89f6b26fSZixu Wang     Object Parameter;
302*89f6b26fSZixu Wang     Parameter["name"] = P.Name;
303*89f6b26fSZixu Wang     serializeArray(Parameter, "declarationFragments",
304*89f6b26fSZixu Wang                    serializeDeclarationFragments(P.Fragments));
305*89f6b26fSZixu Wang     Parameters.emplace_back(std::move(Parameter));
306*89f6b26fSZixu Wang   }
307*89f6b26fSZixu Wang 
308*89f6b26fSZixu Wang   if (!Parameters.empty())
309*89f6b26fSZixu Wang     Signature["parameters"] = std::move(Parameters);
310*89f6b26fSZixu Wang 
311*89f6b26fSZixu Wang   return Signature;
312*89f6b26fSZixu Wang }
313*89f6b26fSZixu Wang 
314*89f6b26fSZixu Wang /// Serialize the \c names field of a symbol as specified by the Symbol Graph
315*89f6b26fSZixu Wang /// format.
316*89f6b26fSZixu Wang ///
317*89f6b26fSZixu Wang /// The Symbol Graph names field contains multiple representations of a symbol
318*89f6b26fSZixu Wang /// that can be used for different applications:
319*89f6b26fSZixu Wang ///   - \c title : The simple declared name of the symbol;
320*89f6b26fSZixu Wang ///   - \c subHeading : An array of declaration fragments that provides tags,
321*89f6b26fSZixu Wang ///     and potentially more tokens (for example the \c +/- symbol for
322*89f6b26fSZixu Wang ///     Objective-C methods). Can be used as sub-headings for documentation.
323*89f6b26fSZixu Wang Object serializeNames(const APIRecord &Record) {
324*89f6b26fSZixu Wang   Object Names;
325*89f6b26fSZixu Wang   Names["title"] = Record.Name;
326*89f6b26fSZixu Wang   serializeArray(Names, "subHeading",
327*89f6b26fSZixu Wang                  serializeDeclarationFragments(Record.SubHeading));
328*89f6b26fSZixu Wang 
329*89f6b26fSZixu Wang   return Names;
330*89f6b26fSZixu Wang }
331*89f6b26fSZixu Wang 
332*89f6b26fSZixu Wang /// Serialize the symbol kind information.
333*89f6b26fSZixu Wang ///
334*89f6b26fSZixu Wang /// The Symbol Graph symbol kind property contains a shorthand \c identifier
335*89f6b26fSZixu Wang /// which is prefixed by the source language name, useful for tooling to parse
336*89f6b26fSZixu Wang /// the kind, and a \c displayName for rendering human-readable names.
337*89f6b26fSZixu Wang Object serializeSymbolKind(const APIRecord &Record,
338*89f6b26fSZixu Wang                            const LangOptions &LangOpts) {
339*89f6b26fSZixu Wang   Object Kind;
340*89f6b26fSZixu Wang   switch (Record.getKind()) {
341*89f6b26fSZixu Wang   case APIRecord::RK_Global:
342*89f6b26fSZixu Wang     auto *GR = dyn_cast<GlobalRecord>(&Record);
343*89f6b26fSZixu Wang     switch (GR->GlobalKind) {
344*89f6b26fSZixu Wang     case GVKind::Function:
345*89f6b26fSZixu Wang       Kind["identifier"] = (getLanguageName(LangOpts) + ".func").str();
346*89f6b26fSZixu Wang       Kind["displayName"] = "Function";
347*89f6b26fSZixu Wang       break;
348*89f6b26fSZixu Wang     case GVKind::Variable:
349*89f6b26fSZixu Wang       Kind["identifier"] = (getLanguageName(LangOpts) + ".var").str();
350*89f6b26fSZixu Wang       Kind["displayName"] = "Global Variable";
351*89f6b26fSZixu Wang       break;
352*89f6b26fSZixu Wang     case GVKind::Unknown:
353*89f6b26fSZixu Wang       // Unknown global kind
354*89f6b26fSZixu Wang       break;
355*89f6b26fSZixu Wang     }
356*89f6b26fSZixu Wang     break;
357*89f6b26fSZixu Wang   }
358*89f6b26fSZixu Wang 
359*89f6b26fSZixu Wang   return Kind;
360*89f6b26fSZixu Wang }
361*89f6b26fSZixu Wang 
362*89f6b26fSZixu Wang } // namespace
363*89f6b26fSZixu Wang 
364*89f6b26fSZixu Wang void SymbolGraphSerializer::anchor() {}
365*89f6b26fSZixu Wang 
366*89f6b26fSZixu Wang /// Defines the format version emitted by SymbolGraphSerializer.
367*89f6b26fSZixu Wang const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
368*89f6b26fSZixu Wang 
369*89f6b26fSZixu Wang Object SymbolGraphSerializer::serializeMetadata() const {
370*89f6b26fSZixu Wang   Object Metadata;
371*89f6b26fSZixu Wang   serializeObject(Metadata, "formatVersion",
372*89f6b26fSZixu Wang                   serializeSemanticVersion(FormatVersion));
373*89f6b26fSZixu Wang   Metadata["generator"] = clang::getClangFullVersion();
374*89f6b26fSZixu Wang   return Metadata;
375*89f6b26fSZixu Wang }
376*89f6b26fSZixu Wang 
377*89f6b26fSZixu Wang Object SymbolGraphSerializer::serializeModule() const {
378*89f6b26fSZixu Wang   Object Module;
379*89f6b26fSZixu Wang   // FIXME: We might not be building a module, some Clang-based languages might
380*89f6b26fSZixu Wang   // not have a "module" concept. Figure out a way to provide a name to
381*89f6b26fSZixu Wang   // describe the API set.
382*89f6b26fSZixu Wang   Module["name"] = "";
383*89f6b26fSZixu Wang   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
384*89f6b26fSZixu Wang   return Module;
385*89f6b26fSZixu Wang }
386*89f6b26fSZixu Wang 
387*89f6b26fSZixu Wang bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
388*89f6b26fSZixu Wang   // Skip unconditionally unavailable symbols
389*89f6b26fSZixu Wang   if (Record.Availability.isUnconditionallyUnavailable())
390*89f6b26fSZixu Wang     return true;
391*89f6b26fSZixu Wang 
392*89f6b26fSZixu Wang   return false;
393*89f6b26fSZixu Wang }
394*89f6b26fSZixu Wang 
395*89f6b26fSZixu Wang Optional<Object>
396*89f6b26fSZixu Wang SymbolGraphSerializer::serializeAPIRecord(const APIRecord &Record) const {
397*89f6b26fSZixu Wang   if (shouldSkip(Record))
398*89f6b26fSZixu Wang     return None;
399*89f6b26fSZixu Wang 
400*89f6b26fSZixu Wang   Object Obj;
401*89f6b26fSZixu Wang   serializeObject(Obj, "identifier",
402*89f6b26fSZixu Wang                   serializeIdentifier(Record, API.getLangOpts()));
403*89f6b26fSZixu Wang   serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLangOpts()));
404*89f6b26fSZixu Wang   serializeObject(Obj, "names", serializeNames(Record));
405*89f6b26fSZixu Wang   serializeObject(
406*89f6b26fSZixu Wang       Obj, "location",
407*89f6b26fSZixu Wang       serializeSourcePosition(Record.Location, /*IncludeFileURI=*/true));
408*89f6b26fSZixu Wang   serializeObject(Obj, "availbility",
409*89f6b26fSZixu Wang                   serializeAvailability(Record.Availability));
410*89f6b26fSZixu Wang   serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
411*89f6b26fSZixu Wang   serializeArray(Obj, "declarationFragments",
412*89f6b26fSZixu Wang                  serializeDeclarationFragments(Record.Declaration));
413*89f6b26fSZixu Wang 
414*89f6b26fSZixu Wang   return Obj;
415*89f6b26fSZixu Wang }
416*89f6b26fSZixu Wang 
417*89f6b26fSZixu Wang void SymbolGraphSerializer::serializeGlobalRecord(const GlobalRecord &Record) {
418*89f6b26fSZixu Wang   auto Obj = serializeAPIRecord(Record);
419*89f6b26fSZixu Wang   if (!Obj)
420*89f6b26fSZixu Wang     return;
421*89f6b26fSZixu Wang 
422*89f6b26fSZixu Wang   if (Record.GlobalKind == GVKind::Function)
423*89f6b26fSZixu Wang     serializeObject(*Obj, "parameters",
424*89f6b26fSZixu Wang                     serializeFunctionSignature(Record.Signature));
425*89f6b26fSZixu Wang 
426*89f6b26fSZixu Wang   Symbols.emplace_back(std::move(*Obj));
427*89f6b26fSZixu Wang }
428*89f6b26fSZixu Wang 
429*89f6b26fSZixu Wang Object SymbolGraphSerializer::serialize() {
430*89f6b26fSZixu Wang   Object Root;
431*89f6b26fSZixu Wang   serializeObject(Root, "metadata", serializeMetadata());
432*89f6b26fSZixu Wang   serializeObject(Root, "module", serializeModule());
433*89f6b26fSZixu Wang 
434*89f6b26fSZixu Wang   // Serialize global records in the API set.
435*89f6b26fSZixu Wang   for (const auto &Global : API.getGlobals())
436*89f6b26fSZixu Wang     serializeGlobalRecord(*Global.second);
437*89f6b26fSZixu Wang 
438*89f6b26fSZixu Wang   Root["symbols"] = std::move(Symbols);
439*89f6b26fSZixu Wang   Root["relationhips"] = std::move(Relationships);
440*89f6b26fSZixu Wang 
441*89f6b26fSZixu Wang   return Root;
442*89f6b26fSZixu Wang }
443*89f6b26fSZixu Wang 
444*89f6b26fSZixu Wang void SymbolGraphSerializer::serialize(raw_ostream &os) {
445*89f6b26fSZixu Wang   Object root = serialize();
446*89f6b26fSZixu Wang   if (Options.Compact)
447*89f6b26fSZixu Wang     os << formatv("{0}", Value(std::move(root))) << "\n";
448*89f6b26fSZixu Wang   else
449*89f6b26fSZixu Wang     os << formatv("{0:2}", Value(std::move(root))) << "\n";
450*89f6b26fSZixu Wang }
451