1*12c85518Srobert //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===//
2*12c85518Srobert //
3*12c85518Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*12c85518Srobert // See https://llvm.org/LICENSE.txt for license information.
5*12c85518Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*12c85518Srobert //
7*12c85518Srobert //===----------------------------------------------------------------------===//
8*12c85518Srobert ///
9*12c85518Srobert /// \file
10*12c85518Srobert /// This file implements the SymbolGraphSerializer.
11*12c85518Srobert ///
12*12c85518Srobert //===----------------------------------------------------------------------===//
13*12c85518Srobert
14*12c85518Srobert #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
15*12c85518Srobert #include "clang/Basic/SourceLocation.h"
16*12c85518Srobert #include "clang/Basic/Version.h"
17*12c85518Srobert #include "clang/ExtractAPI/API.h"
18*12c85518Srobert #include "clang/ExtractAPI/APIIgnoresList.h"
19*12c85518Srobert #include "clang/ExtractAPI/DeclarationFragments.h"
20*12c85518Srobert #include "clang/ExtractAPI/Serialization/SerializerBase.h"
21*12c85518Srobert #include "llvm/ADT/STLExtras.h"
22*12c85518Srobert #include "llvm/ADT/STLFunctionalExtras.h"
23*12c85518Srobert #include "llvm/ADT/SmallVector.h"
24*12c85518Srobert #include "llvm/Support/Casting.h"
25*12c85518Srobert #include "llvm/Support/Compiler.h"
26*12c85518Srobert #include "llvm/Support/JSON.h"
27*12c85518Srobert #include "llvm/Support/Path.h"
28*12c85518Srobert #include "llvm/Support/VersionTuple.h"
29*12c85518Srobert #include <optional>
30*12c85518Srobert #include <type_traits>
31*12c85518Srobert
32*12c85518Srobert using namespace clang;
33*12c85518Srobert using namespace clang::extractapi;
34*12c85518Srobert using namespace llvm;
35*12c85518Srobert using namespace llvm::json;
36*12c85518Srobert
37*12c85518Srobert namespace {
38*12c85518Srobert
39*12c85518Srobert /// Helper function to inject a JSON object \p Obj into another object \p Paren
40*12c85518Srobert /// at position \p Key.
serializeObject(Object & Paren,StringRef Key,std::optional<Object> Obj)41*12c85518Srobert void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
42*12c85518Srobert if (Obj)
43*12c85518Srobert Paren[Key] = std::move(*Obj);
44*12c85518Srobert }
45*12c85518Srobert
46*12c85518Srobert /// Helper function to inject a JSON array \p Array into object \p Paren at
47*12c85518Srobert /// position \p Key.
serializeArray(Object & Paren,StringRef Key,std::optional<Array> Array)48*12c85518Srobert void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
49*12c85518Srobert if (Array)
50*12c85518Srobert Paren[Key] = std::move(*Array);
51*12c85518Srobert }
52*12c85518Srobert
53*12c85518Srobert /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
54*12c85518Srobert /// format.
55*12c85518Srobert ///
56*12c85518Srobert /// A semantic version object contains three numeric fields, representing the
57*12c85518Srobert /// \c major, \c minor, and \c patch parts of the version tuple.
58*12c85518Srobert /// For example version tuple 1.0.3 is serialized as:
59*12c85518Srobert /// \code
60*12c85518Srobert /// {
61*12c85518Srobert /// "major" : 1,
62*12c85518Srobert /// "minor" : 0,
63*12c85518Srobert /// "patch" : 3
64*12c85518Srobert /// }
65*12c85518Srobert /// \endcode
66*12c85518Srobert ///
67*12c85518Srobert /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
68*12c85518Srobert /// containing the semantic version representation of \p V.
serializeSemanticVersion(const VersionTuple & V)69*12c85518Srobert std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
70*12c85518Srobert if (V.empty())
71*12c85518Srobert return std::nullopt;
72*12c85518Srobert
73*12c85518Srobert Object Version;
74*12c85518Srobert Version["major"] = V.getMajor();
75*12c85518Srobert Version["minor"] = V.getMinor().value_or(0);
76*12c85518Srobert Version["patch"] = V.getSubminor().value_or(0);
77*12c85518Srobert return Version;
78*12c85518Srobert }
79*12c85518Srobert
80*12c85518Srobert /// Serialize the OS information in the Symbol Graph platform property.
81*12c85518Srobert ///
82*12c85518Srobert /// The OS information in Symbol Graph contains the \c name of the OS, and an
83*12c85518Srobert /// optional \c minimumVersion semantic version field.
serializeOperatingSystem(const Triple & T)84*12c85518Srobert Object serializeOperatingSystem(const Triple &T) {
85*12c85518Srobert Object OS;
86*12c85518Srobert OS["name"] = T.getOSTypeName(T.getOS());
87*12c85518Srobert serializeObject(OS, "minimumVersion",
88*12c85518Srobert serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
89*12c85518Srobert return OS;
90*12c85518Srobert }
91*12c85518Srobert
92*12c85518Srobert /// Serialize the platform information in the Symbol Graph module section.
93*12c85518Srobert ///
94*12c85518Srobert /// The platform object describes a target platform triple in corresponding
95*12c85518Srobert /// three fields: \c architecture, \c vendor, and \c operatingSystem.
serializePlatform(const Triple & T)96*12c85518Srobert Object serializePlatform(const Triple &T) {
97*12c85518Srobert Object Platform;
98*12c85518Srobert Platform["architecture"] = T.getArchName();
99*12c85518Srobert Platform["vendor"] = T.getVendorName();
100*12c85518Srobert Platform["operatingSystem"] = serializeOperatingSystem(T);
101*12c85518Srobert return Platform;
102*12c85518Srobert }
103*12c85518Srobert
104*12c85518Srobert /// Serialize a source position.
serializeSourcePosition(const PresumedLoc & Loc)105*12c85518Srobert Object serializeSourcePosition(const PresumedLoc &Loc) {
106*12c85518Srobert assert(Loc.isValid() && "invalid source position");
107*12c85518Srobert
108*12c85518Srobert Object SourcePosition;
109*12c85518Srobert SourcePosition["line"] = Loc.getLine();
110*12c85518Srobert SourcePosition["character"] = Loc.getColumn();
111*12c85518Srobert
112*12c85518Srobert return SourcePosition;
113*12c85518Srobert }
114*12c85518Srobert
115*12c85518Srobert /// Serialize a source location in file.
116*12c85518Srobert ///
117*12c85518Srobert /// \param Loc The presumed location to serialize.
118*12c85518Srobert /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
119*12c85518Srobert /// Defaults to false.
serializeSourceLocation(const PresumedLoc & Loc,bool IncludeFileURI=false)120*12c85518Srobert Object serializeSourceLocation(const PresumedLoc &Loc,
121*12c85518Srobert bool IncludeFileURI = false) {
122*12c85518Srobert Object SourceLocation;
123*12c85518Srobert serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
124*12c85518Srobert
125*12c85518Srobert if (IncludeFileURI) {
126*12c85518Srobert std::string FileURI = "file://";
127*12c85518Srobert // Normalize file path to use forward slashes for the URI.
128*12c85518Srobert FileURI += sys::path::convert_to_slash(Loc.getFilename());
129*12c85518Srobert SourceLocation["uri"] = FileURI;
130*12c85518Srobert }
131*12c85518Srobert
132*12c85518Srobert return SourceLocation;
133*12c85518Srobert }
134*12c85518Srobert
135*12c85518Srobert /// Serialize a source range with begin and end locations.
serializeSourceRange(const PresumedLoc & BeginLoc,const PresumedLoc & EndLoc)136*12c85518Srobert Object serializeSourceRange(const PresumedLoc &BeginLoc,
137*12c85518Srobert const PresumedLoc &EndLoc) {
138*12c85518Srobert Object SourceRange;
139*12c85518Srobert serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
140*12c85518Srobert serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
141*12c85518Srobert return SourceRange;
142*12c85518Srobert }
143*12c85518Srobert
144*12c85518Srobert /// Serialize the availability attributes of a symbol.
145*12c85518Srobert ///
146*12c85518Srobert /// Availability information contains the introduced, deprecated, and obsoleted
147*12c85518Srobert /// versions of the symbol for a given domain (roughly corresponds to a
148*12c85518Srobert /// platform) as semantic versions, if not default. Availability information
149*12c85518Srobert /// also contains flags to indicate if the symbol is unconditionally unavailable
150*12c85518Srobert /// or deprecated, i.e. \c __attribute__((unavailable)) and \c
151*12c85518Srobert /// __attribute__((deprecated)).
152*12c85518Srobert ///
153*12c85518Srobert /// \returns \c std::nullopt if the symbol has default availability attributes,
154*12c85518Srobert /// or an \c Array containing the formatted availability information.
155*12c85518Srobert std::optional<Array>
serializeAvailability(const AvailabilitySet & Availabilities)156*12c85518Srobert serializeAvailability(const AvailabilitySet &Availabilities) {
157*12c85518Srobert if (Availabilities.isDefault())
158*12c85518Srobert return std::nullopt;
159*12c85518Srobert
160*12c85518Srobert Array AvailabilityArray;
161*12c85518Srobert
162*12c85518Srobert if (Availabilities.isUnconditionallyDeprecated()) {
163*12c85518Srobert Object UnconditionallyDeprecated;
164*12c85518Srobert UnconditionallyDeprecated["domain"] = "*";
165*12c85518Srobert UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
166*12c85518Srobert AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
167*12c85518Srobert }
168*12c85518Srobert
169*12c85518Srobert // Note unconditionally unavailable records are skipped.
170*12c85518Srobert
171*12c85518Srobert for (const auto &AvailInfo : Availabilities) {
172*12c85518Srobert Object Availability;
173*12c85518Srobert Availability["domain"] = AvailInfo.Domain;
174*12c85518Srobert serializeObject(Availability, "introducedVersion",
175*12c85518Srobert serializeSemanticVersion(AvailInfo.Introduced));
176*12c85518Srobert serializeObject(Availability, "deprecatedVersion",
177*12c85518Srobert serializeSemanticVersion(AvailInfo.Deprecated));
178*12c85518Srobert serializeObject(Availability, "obsoletedVersion",
179*12c85518Srobert serializeSemanticVersion(AvailInfo.Obsoleted));
180*12c85518Srobert AvailabilityArray.emplace_back(std::move(Availability));
181*12c85518Srobert }
182*12c85518Srobert
183*12c85518Srobert return AvailabilityArray;
184*12c85518Srobert }
185*12c85518Srobert
186*12c85518Srobert /// Get the language name string for interface language references.
getLanguageName(Language Lang)187*12c85518Srobert StringRef getLanguageName(Language Lang) {
188*12c85518Srobert switch (Lang) {
189*12c85518Srobert case Language::C:
190*12c85518Srobert return "c";
191*12c85518Srobert case Language::ObjC:
192*12c85518Srobert return "objective-c";
193*12c85518Srobert
194*12c85518Srobert // Unsupported language currently
195*12c85518Srobert case Language::CXX:
196*12c85518Srobert case Language::ObjCXX:
197*12c85518Srobert case Language::OpenCL:
198*12c85518Srobert case Language::OpenCLCXX:
199*12c85518Srobert case Language::CUDA:
200*12c85518Srobert case Language::RenderScript:
201*12c85518Srobert case Language::HIP:
202*12c85518Srobert case Language::HLSL:
203*12c85518Srobert
204*12c85518Srobert // Languages that the frontend cannot parse and compile
205*12c85518Srobert case Language::Unknown:
206*12c85518Srobert case Language::Asm:
207*12c85518Srobert case Language::LLVM_IR:
208*12c85518Srobert llvm_unreachable("Unsupported language kind");
209*12c85518Srobert }
210*12c85518Srobert
211*12c85518Srobert llvm_unreachable("Unhandled language kind");
212*12c85518Srobert }
213*12c85518Srobert
214*12c85518Srobert /// Serialize the identifier object as specified by the Symbol Graph format.
215*12c85518Srobert ///
216*12c85518Srobert /// The identifier property of a symbol contains the USR for precise and unique
217*12c85518Srobert /// references, and the interface language name.
serializeIdentifier(const APIRecord & Record,Language Lang)218*12c85518Srobert Object serializeIdentifier(const APIRecord &Record, Language Lang) {
219*12c85518Srobert Object Identifier;
220*12c85518Srobert Identifier["precise"] = Record.USR;
221*12c85518Srobert Identifier["interfaceLanguage"] = getLanguageName(Lang);
222*12c85518Srobert
223*12c85518Srobert return Identifier;
224*12c85518Srobert }
225*12c85518Srobert
226*12c85518Srobert /// Serialize the documentation comments attached to a symbol, as specified by
227*12c85518Srobert /// the Symbol Graph format.
228*12c85518Srobert ///
229*12c85518Srobert /// The Symbol Graph \c docComment object contains an array of lines. Each line
230*12c85518Srobert /// represents one line of striped documentation comment, with source range
231*12c85518Srobert /// information.
232*12c85518Srobert /// e.g.
233*12c85518Srobert /// \code
234*12c85518Srobert /// /// This is a documentation comment
235*12c85518Srobert /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line.
236*12c85518Srobert /// /// with multiple lines.
237*12c85518Srobert /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line.
238*12c85518Srobert /// \endcode
239*12c85518Srobert ///
240*12c85518Srobert /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
241*12c85518Srobert /// the formatted lines.
serializeDocComment(const DocComment & Comment)242*12c85518Srobert std::optional<Object> serializeDocComment(const DocComment &Comment) {
243*12c85518Srobert if (Comment.empty())
244*12c85518Srobert return std::nullopt;
245*12c85518Srobert
246*12c85518Srobert Object DocComment;
247*12c85518Srobert Array LinesArray;
248*12c85518Srobert for (const auto &CommentLine : Comment) {
249*12c85518Srobert Object Line;
250*12c85518Srobert Line["text"] = CommentLine.Text;
251*12c85518Srobert serializeObject(Line, "range",
252*12c85518Srobert serializeSourceRange(CommentLine.Begin, CommentLine.End));
253*12c85518Srobert LinesArray.emplace_back(std::move(Line));
254*12c85518Srobert }
255*12c85518Srobert serializeArray(DocComment, "lines", LinesArray);
256*12c85518Srobert
257*12c85518Srobert return DocComment;
258*12c85518Srobert }
259*12c85518Srobert
260*12c85518Srobert /// Serialize the declaration fragments of a symbol.
261*12c85518Srobert ///
262*12c85518Srobert /// The Symbol Graph declaration fragments is an array of tagged important
263*12c85518Srobert /// parts of a symbol's declaration. The fragments sequence can be joined to
264*12c85518Srobert /// form spans of declaration text, with attached information useful for
265*12c85518Srobert /// purposes like syntax-highlighting etc. For example:
266*12c85518Srobert /// \code
267*12c85518Srobert /// const int pi; -> "declarationFragments" : [
268*12c85518Srobert /// {
269*12c85518Srobert /// "kind" : "keyword",
270*12c85518Srobert /// "spelling" : "const"
271*12c85518Srobert /// },
272*12c85518Srobert /// {
273*12c85518Srobert /// "kind" : "text",
274*12c85518Srobert /// "spelling" : " "
275*12c85518Srobert /// },
276*12c85518Srobert /// {
277*12c85518Srobert /// "kind" : "typeIdentifier",
278*12c85518Srobert /// "preciseIdentifier" : "c:I",
279*12c85518Srobert /// "spelling" : "int"
280*12c85518Srobert /// },
281*12c85518Srobert /// {
282*12c85518Srobert /// "kind" : "text",
283*12c85518Srobert /// "spelling" : " "
284*12c85518Srobert /// },
285*12c85518Srobert /// {
286*12c85518Srobert /// "kind" : "identifier",
287*12c85518Srobert /// "spelling" : "pi"
288*12c85518Srobert /// }
289*12c85518Srobert /// ]
290*12c85518Srobert /// \endcode
291*12c85518Srobert ///
292*12c85518Srobert /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
293*12c85518Srobert /// formatted declaration fragments array.
294*12c85518Srobert std::optional<Array>
serializeDeclarationFragments(const DeclarationFragments & DF)295*12c85518Srobert serializeDeclarationFragments(const DeclarationFragments &DF) {
296*12c85518Srobert if (DF.getFragments().empty())
297*12c85518Srobert return std::nullopt;
298*12c85518Srobert
299*12c85518Srobert Array Fragments;
300*12c85518Srobert for (const auto &F : DF.getFragments()) {
301*12c85518Srobert Object Fragment;
302*12c85518Srobert Fragment["spelling"] = F.Spelling;
303*12c85518Srobert Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
304*12c85518Srobert if (!F.PreciseIdentifier.empty())
305*12c85518Srobert Fragment["preciseIdentifier"] = F.PreciseIdentifier;
306*12c85518Srobert Fragments.emplace_back(std::move(Fragment));
307*12c85518Srobert }
308*12c85518Srobert
309*12c85518Srobert return Fragments;
310*12c85518Srobert }
311*12c85518Srobert
312*12c85518Srobert /// Serialize the \c names field of a symbol as specified by the Symbol Graph
313*12c85518Srobert /// format.
314*12c85518Srobert ///
315*12c85518Srobert /// The Symbol Graph names field contains multiple representations of a symbol
316*12c85518Srobert /// that can be used for different applications:
317*12c85518Srobert /// - \c title : The simple declared name of the symbol;
318*12c85518Srobert /// - \c subHeading : An array of declaration fragments that provides tags,
319*12c85518Srobert /// and potentially more tokens (for example the \c +/- symbol for
320*12c85518Srobert /// Objective-C methods). Can be used as sub-headings for documentation.
serializeNames(const APIRecord & Record)321*12c85518Srobert Object serializeNames(const APIRecord &Record) {
322*12c85518Srobert Object Names;
323*12c85518Srobert Names["title"] = Record.Name;
324*12c85518Srobert serializeArray(Names, "subHeading",
325*12c85518Srobert serializeDeclarationFragments(Record.SubHeading));
326*12c85518Srobert DeclarationFragments NavigatorFragments;
327*12c85518Srobert NavigatorFragments.append(Record.Name,
328*12c85518Srobert DeclarationFragments::FragmentKind::Identifier,
329*12c85518Srobert /*PreciseIdentifier*/ "");
330*12c85518Srobert serializeArray(Names, "navigator",
331*12c85518Srobert serializeDeclarationFragments(NavigatorFragments));
332*12c85518Srobert
333*12c85518Srobert return Names;
334*12c85518Srobert }
335*12c85518Srobert
serializeSymbolKind(APIRecord::RecordKind RK,Language Lang)336*12c85518Srobert Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
337*12c85518Srobert auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
338*12c85518Srobert return (getLanguageName(Lang) + "." + S).str();
339*12c85518Srobert };
340*12c85518Srobert
341*12c85518Srobert Object Kind;
342*12c85518Srobert switch (RK) {
343*12c85518Srobert case APIRecord::RK_Unknown:
344*12c85518Srobert llvm_unreachable("Records should have an explicit kind");
345*12c85518Srobert break;
346*12c85518Srobert case APIRecord::RK_GlobalFunction:
347*12c85518Srobert Kind["identifier"] = AddLangPrefix("func");
348*12c85518Srobert Kind["displayName"] = "Function";
349*12c85518Srobert break;
350*12c85518Srobert case APIRecord::RK_GlobalVariable:
351*12c85518Srobert Kind["identifier"] = AddLangPrefix("var");
352*12c85518Srobert Kind["displayName"] = "Global Variable";
353*12c85518Srobert break;
354*12c85518Srobert case APIRecord::RK_EnumConstant:
355*12c85518Srobert Kind["identifier"] = AddLangPrefix("enum.case");
356*12c85518Srobert Kind["displayName"] = "Enumeration Case";
357*12c85518Srobert break;
358*12c85518Srobert case APIRecord::RK_Enum:
359*12c85518Srobert Kind["identifier"] = AddLangPrefix("enum");
360*12c85518Srobert Kind["displayName"] = "Enumeration";
361*12c85518Srobert break;
362*12c85518Srobert case APIRecord::RK_StructField:
363*12c85518Srobert Kind["identifier"] = AddLangPrefix("property");
364*12c85518Srobert Kind["displayName"] = "Instance Property";
365*12c85518Srobert break;
366*12c85518Srobert case APIRecord::RK_Struct:
367*12c85518Srobert Kind["identifier"] = AddLangPrefix("struct");
368*12c85518Srobert Kind["displayName"] = "Structure";
369*12c85518Srobert break;
370*12c85518Srobert case APIRecord::RK_ObjCIvar:
371*12c85518Srobert Kind["identifier"] = AddLangPrefix("ivar");
372*12c85518Srobert Kind["displayName"] = "Instance Variable";
373*12c85518Srobert break;
374*12c85518Srobert case APIRecord::RK_ObjCInstanceMethod:
375*12c85518Srobert Kind["identifier"] = AddLangPrefix("method");
376*12c85518Srobert Kind["displayName"] = "Instance Method";
377*12c85518Srobert break;
378*12c85518Srobert case APIRecord::RK_ObjCClassMethod:
379*12c85518Srobert Kind["identifier"] = AddLangPrefix("type.method");
380*12c85518Srobert Kind["displayName"] = "Type Method";
381*12c85518Srobert break;
382*12c85518Srobert case APIRecord::RK_ObjCInstanceProperty:
383*12c85518Srobert Kind["identifier"] = AddLangPrefix("property");
384*12c85518Srobert Kind["displayName"] = "Instance Property";
385*12c85518Srobert break;
386*12c85518Srobert case APIRecord::RK_ObjCClassProperty:
387*12c85518Srobert Kind["identifier"] = AddLangPrefix("type.property");
388*12c85518Srobert Kind["displayName"] = "Type Property";
389*12c85518Srobert break;
390*12c85518Srobert case APIRecord::RK_ObjCInterface:
391*12c85518Srobert Kind["identifier"] = AddLangPrefix("class");
392*12c85518Srobert Kind["displayName"] = "Class";
393*12c85518Srobert break;
394*12c85518Srobert case APIRecord::RK_ObjCCategory:
395*12c85518Srobert // We don't serialize out standalone Objective-C category symbols yet.
396*12c85518Srobert llvm_unreachable("Serializing standalone Objective-C category symbols is "
397*12c85518Srobert "not supported.");
398*12c85518Srobert break;
399*12c85518Srobert case APIRecord::RK_ObjCProtocol:
400*12c85518Srobert Kind["identifier"] = AddLangPrefix("protocol");
401*12c85518Srobert Kind["displayName"] = "Protocol";
402*12c85518Srobert break;
403*12c85518Srobert case APIRecord::RK_MacroDefinition:
404*12c85518Srobert Kind["identifier"] = AddLangPrefix("macro");
405*12c85518Srobert Kind["displayName"] = "Macro";
406*12c85518Srobert break;
407*12c85518Srobert case APIRecord::RK_Typedef:
408*12c85518Srobert Kind["identifier"] = AddLangPrefix("typealias");
409*12c85518Srobert Kind["displayName"] = "Type Alias";
410*12c85518Srobert break;
411*12c85518Srobert }
412*12c85518Srobert
413*12c85518Srobert return Kind;
414*12c85518Srobert }
415*12c85518Srobert
416*12c85518Srobert /// Serialize the symbol kind information.
417*12c85518Srobert ///
418*12c85518Srobert /// The Symbol Graph symbol kind property contains a shorthand \c identifier
419*12c85518Srobert /// which is prefixed by the source language name, useful for tooling to parse
420*12c85518Srobert /// the kind, and a \c displayName for rendering human-readable names.
serializeSymbolKind(const APIRecord & Record,Language Lang)421*12c85518Srobert Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
422*12c85518Srobert return serializeSymbolKind(Record.getKind(), Lang);
423*12c85518Srobert }
424*12c85518Srobert
425*12c85518Srobert template <typename RecordTy>
426*12c85518Srobert std::optional<Object>
serializeFunctionSignatureMixinImpl(const RecordTy & Record,std::true_type)427*12c85518Srobert serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
428*12c85518Srobert const auto &FS = Record.Signature;
429*12c85518Srobert if (FS.empty())
430*12c85518Srobert return std::nullopt;
431*12c85518Srobert
432*12c85518Srobert Object Signature;
433*12c85518Srobert serializeArray(Signature, "returns",
434*12c85518Srobert serializeDeclarationFragments(FS.getReturnType()));
435*12c85518Srobert
436*12c85518Srobert Array Parameters;
437*12c85518Srobert for (const auto &P : FS.getParameters()) {
438*12c85518Srobert Object Parameter;
439*12c85518Srobert Parameter["name"] = P.Name;
440*12c85518Srobert serializeArray(Parameter, "declarationFragments",
441*12c85518Srobert serializeDeclarationFragments(P.Fragments));
442*12c85518Srobert Parameters.emplace_back(std::move(Parameter));
443*12c85518Srobert }
444*12c85518Srobert
445*12c85518Srobert if (!Parameters.empty())
446*12c85518Srobert Signature["parameters"] = std::move(Parameters);
447*12c85518Srobert
448*12c85518Srobert return Signature;
449*12c85518Srobert }
450*12c85518Srobert
451*12c85518Srobert template <typename RecordTy>
452*12c85518Srobert std::optional<Object>
serializeFunctionSignatureMixinImpl(const RecordTy & Record,std::false_type)453*12c85518Srobert serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
454*12c85518Srobert return std::nullopt;
455*12c85518Srobert }
456*12c85518Srobert
457*12c85518Srobert /// Serialize the function signature field, as specified by the
458*12c85518Srobert /// Symbol Graph format.
459*12c85518Srobert ///
460*12c85518Srobert /// The Symbol Graph function signature property contains two arrays.
461*12c85518Srobert /// - The \c returns array is the declaration fragments of the return type;
462*12c85518Srobert /// - The \c parameters array contains names and declaration fragments of the
463*12c85518Srobert /// parameters.
464*12c85518Srobert ///
465*12c85518Srobert /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
466*12c85518Srobert /// formatted function signature.
467*12c85518Srobert template <typename RecordTy>
serializeFunctionSignatureMixin(Object & Paren,const RecordTy & Record)468*12c85518Srobert void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
469*12c85518Srobert serializeObject(Paren, "functionSignature",
470*12c85518Srobert serializeFunctionSignatureMixinImpl(
471*12c85518Srobert Record, has_function_signature<RecordTy>()));
472*12c85518Srobert }
473*12c85518Srobert
474*12c85518Srobert struct PathComponent {
475*12c85518Srobert StringRef USR;
476*12c85518Srobert StringRef Name;
477*12c85518Srobert APIRecord::RecordKind Kind;
478*12c85518Srobert
PathComponent__anonf8a10d840111::PathComponent479*12c85518Srobert PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
480*12c85518Srobert : USR(USR), Name(Name), Kind(Kind) {}
481*12c85518Srobert };
482*12c85518Srobert
483*12c85518Srobert template <typename RecordTy>
generatePathComponents(const RecordTy & Record,const APISet & API,function_ref<void (const PathComponent &)> ComponentTransformer)484*12c85518Srobert bool generatePathComponents(
485*12c85518Srobert const RecordTy &Record, const APISet &API,
486*12c85518Srobert function_ref<void(const PathComponent &)> ComponentTransformer) {
487*12c85518Srobert SmallVector<PathComponent, 4> ReverseComponenents;
488*12c85518Srobert ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
489*12c85518Srobert const auto *CurrentParent = &Record.ParentInformation;
490*12c85518Srobert while (CurrentParent && !CurrentParent->empty()) {
491*12c85518Srobert PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
492*12c85518Srobert CurrentParent->ParentName,
493*12c85518Srobert CurrentParent->ParentKind);
494*12c85518Srobert
495*12c85518Srobert auto *ParentRecord = CurrentParent->ParentRecord;
496*12c85518Srobert // Slow path if we don't have a direct reference to the ParentRecord
497*12c85518Srobert if (!ParentRecord)
498*12c85518Srobert ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
499*12c85518Srobert
500*12c85518Srobert // If the parent is a category then we need to pretend this belongs to the
501*12c85518Srobert // associated interface.
502*12c85518Srobert if (auto *CategoryRecord =
503*12c85518Srobert dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
504*12c85518Srobert ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
505*12c85518Srobert CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
506*12c85518Srobert CategoryRecord->Interface.Name,
507*12c85518Srobert APIRecord::RK_ObjCInterface);
508*12c85518Srobert }
509*12c85518Srobert
510*12c85518Srobert // The parent record doesn't exist which means the symbol shouldn't be
511*12c85518Srobert // treated as part of the current product.
512*12c85518Srobert if (!ParentRecord)
513*12c85518Srobert return true;
514*12c85518Srobert
515*12c85518Srobert ReverseComponenents.push_back(std::move(CurrentParentComponent));
516*12c85518Srobert CurrentParent = &ParentRecord->ParentInformation;
517*12c85518Srobert }
518*12c85518Srobert
519*12c85518Srobert for (const auto &PC : reverse(ReverseComponenents))
520*12c85518Srobert ComponentTransformer(PC);
521*12c85518Srobert
522*12c85518Srobert return false;
523*12c85518Srobert }
serializeParentContext(const PathComponent & PC,Language Lang)524*12c85518Srobert Object serializeParentContext(const PathComponent &PC, Language Lang) {
525*12c85518Srobert Object ParentContextElem;
526*12c85518Srobert ParentContextElem["usr"] = PC.USR;
527*12c85518Srobert ParentContextElem["name"] = PC.Name;
528*12c85518Srobert ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
529*12c85518Srobert return ParentContextElem;
530*12c85518Srobert }
531*12c85518Srobert
532*12c85518Srobert template <typename RecordTy>
generateParentContexts(const RecordTy & Record,const APISet & API,Language Lang)533*12c85518Srobert Array generateParentContexts(const RecordTy &Record, const APISet &API,
534*12c85518Srobert Language Lang) {
535*12c85518Srobert Array ParentContexts;
536*12c85518Srobert if (generatePathComponents(
537*12c85518Srobert Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
538*12c85518Srobert ParentContexts.push_back(serializeParentContext(PC, Lang));
539*12c85518Srobert }))
540*12c85518Srobert ParentContexts.clear();
541*12c85518Srobert ParentContexts.pop_back();
542*12c85518Srobert
543*12c85518Srobert return ParentContexts;
544*12c85518Srobert }
545*12c85518Srobert
546*12c85518Srobert } // namespace
547*12c85518Srobert
anchor()548*12c85518Srobert void SymbolGraphSerializer::anchor() {}
549*12c85518Srobert
550*12c85518Srobert /// Defines the format version emitted by SymbolGraphSerializer.
551*12c85518Srobert const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
552*12c85518Srobert
serializeMetadata() const553*12c85518Srobert Object SymbolGraphSerializer::serializeMetadata() const {
554*12c85518Srobert Object Metadata;
555*12c85518Srobert serializeObject(Metadata, "formatVersion",
556*12c85518Srobert serializeSemanticVersion(FormatVersion));
557*12c85518Srobert Metadata["generator"] = clang::getClangFullVersion();
558*12c85518Srobert return Metadata;
559*12c85518Srobert }
560*12c85518Srobert
serializeModule() const561*12c85518Srobert Object SymbolGraphSerializer::serializeModule() const {
562*12c85518Srobert Object Module;
563*12c85518Srobert // The user is expected to always pass `--product-name=` on the command line
564*12c85518Srobert // to populate this field.
565*12c85518Srobert Module["name"] = API.ProductName;
566*12c85518Srobert serializeObject(Module, "platform", serializePlatform(API.getTarget()));
567*12c85518Srobert return Module;
568*12c85518Srobert }
569*12c85518Srobert
shouldSkip(const APIRecord & Record) const570*12c85518Srobert bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
571*12c85518Srobert // Skip explicitly ignored symbols.
572*12c85518Srobert if (IgnoresList.shouldIgnore(Record.Name))
573*12c85518Srobert return true;
574*12c85518Srobert
575*12c85518Srobert // Skip unconditionally unavailable symbols
576*12c85518Srobert if (Record.Availabilities.isUnconditionallyUnavailable())
577*12c85518Srobert return true;
578*12c85518Srobert
579*12c85518Srobert // Filter out symbols prefixed with an underscored as they are understood to
580*12c85518Srobert // be symbols clients should not use.
581*12c85518Srobert if (Record.Name.startswith("_"))
582*12c85518Srobert return true;
583*12c85518Srobert
584*12c85518Srobert return false;
585*12c85518Srobert }
586*12c85518Srobert
587*12c85518Srobert template <typename RecordTy>
588*12c85518Srobert std::optional<Object>
serializeAPIRecord(const RecordTy & Record) const589*12c85518Srobert SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
590*12c85518Srobert if (shouldSkip(Record))
591*12c85518Srobert return std::nullopt;
592*12c85518Srobert
593*12c85518Srobert Object Obj;
594*12c85518Srobert serializeObject(Obj, "identifier",
595*12c85518Srobert serializeIdentifier(Record, API.getLanguage()));
596*12c85518Srobert serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
597*12c85518Srobert serializeObject(Obj, "names", serializeNames(Record));
598*12c85518Srobert serializeObject(
599*12c85518Srobert Obj, "location",
600*12c85518Srobert serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
601*12c85518Srobert serializeArray(Obj, "availability",
602*12c85518Srobert serializeAvailability(Record.Availabilities));
603*12c85518Srobert serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
604*12c85518Srobert serializeArray(Obj, "declarationFragments",
605*12c85518Srobert serializeDeclarationFragments(Record.Declaration));
606*12c85518Srobert // TODO: Once we keep track of symbol access information serialize it
607*12c85518Srobert // correctly here.
608*12c85518Srobert Obj["accessLevel"] = "public";
609*12c85518Srobert SmallVector<StringRef, 4> PathComponentsNames;
610*12c85518Srobert // If this returns true it indicates that we couldn't find a symbol in the
611*12c85518Srobert // hierarchy.
612*12c85518Srobert if (generatePathComponents(Record, API,
613*12c85518Srobert [&PathComponentsNames](const PathComponent &PC) {
614*12c85518Srobert PathComponentsNames.push_back(PC.Name);
615*12c85518Srobert }))
616*12c85518Srobert return {};
617*12c85518Srobert
618*12c85518Srobert serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
619*12c85518Srobert
620*12c85518Srobert serializeFunctionSignatureMixin(Obj, Record);
621*12c85518Srobert
622*12c85518Srobert return Obj;
623*12c85518Srobert }
624*12c85518Srobert
625*12c85518Srobert template <typename MemberTy>
serializeMembers(const APIRecord & Record,const SmallVector<std::unique_ptr<MemberTy>> & Members)626*12c85518Srobert void SymbolGraphSerializer::serializeMembers(
627*12c85518Srobert const APIRecord &Record,
628*12c85518Srobert const SmallVector<std::unique_ptr<MemberTy>> &Members) {
629*12c85518Srobert // Members should not be serialized if we aren't recursing.
630*12c85518Srobert if (!ShouldRecurse)
631*12c85518Srobert return;
632*12c85518Srobert for (const auto &Member : Members) {
633*12c85518Srobert auto MemberRecord = serializeAPIRecord(*Member);
634*12c85518Srobert if (!MemberRecord)
635*12c85518Srobert continue;
636*12c85518Srobert
637*12c85518Srobert Symbols.emplace_back(std::move(*MemberRecord));
638*12c85518Srobert serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
639*12c85518Srobert }
640*12c85518Srobert }
641*12c85518Srobert
getRelationshipString(RelationshipKind Kind)642*12c85518Srobert StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
643*12c85518Srobert switch (Kind) {
644*12c85518Srobert case RelationshipKind::MemberOf:
645*12c85518Srobert return "memberOf";
646*12c85518Srobert case RelationshipKind::InheritsFrom:
647*12c85518Srobert return "inheritsFrom";
648*12c85518Srobert case RelationshipKind::ConformsTo:
649*12c85518Srobert return "conformsTo";
650*12c85518Srobert }
651*12c85518Srobert llvm_unreachable("Unhandled relationship kind");
652*12c85518Srobert }
653*12c85518Srobert
serializeRelationship(RelationshipKind Kind,SymbolReference Source,SymbolReference Target)654*12c85518Srobert void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
655*12c85518Srobert SymbolReference Source,
656*12c85518Srobert SymbolReference Target) {
657*12c85518Srobert Object Relationship;
658*12c85518Srobert Relationship["source"] = Source.USR;
659*12c85518Srobert Relationship["target"] = Target.USR;
660*12c85518Srobert Relationship["targetFallback"] = Target.Name;
661*12c85518Srobert Relationship["kind"] = getRelationshipString(Kind);
662*12c85518Srobert
663*12c85518Srobert Relationships.emplace_back(std::move(Relationship));
664*12c85518Srobert }
665*12c85518Srobert
serializeGlobalFunctionRecord(const GlobalFunctionRecord & Record)666*12c85518Srobert void SymbolGraphSerializer::serializeGlobalFunctionRecord(
667*12c85518Srobert const GlobalFunctionRecord &Record) {
668*12c85518Srobert auto Obj = serializeAPIRecord(Record);
669*12c85518Srobert if (!Obj)
670*12c85518Srobert return;
671*12c85518Srobert
672*12c85518Srobert Symbols.emplace_back(std::move(*Obj));
673*12c85518Srobert }
674*12c85518Srobert
serializeGlobalVariableRecord(const GlobalVariableRecord & Record)675*12c85518Srobert void SymbolGraphSerializer::serializeGlobalVariableRecord(
676*12c85518Srobert const GlobalVariableRecord &Record) {
677*12c85518Srobert auto Obj = serializeAPIRecord(Record);
678*12c85518Srobert if (!Obj)
679*12c85518Srobert return;
680*12c85518Srobert
681*12c85518Srobert Symbols.emplace_back(std::move(*Obj));
682*12c85518Srobert }
683*12c85518Srobert
serializeEnumRecord(const EnumRecord & Record)684*12c85518Srobert void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
685*12c85518Srobert auto Enum = serializeAPIRecord(Record);
686*12c85518Srobert if (!Enum)
687*12c85518Srobert return;
688*12c85518Srobert
689*12c85518Srobert Symbols.emplace_back(std::move(*Enum));
690*12c85518Srobert serializeMembers(Record, Record.Constants);
691*12c85518Srobert }
692*12c85518Srobert
serializeStructRecord(const StructRecord & Record)693*12c85518Srobert void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
694*12c85518Srobert auto Struct = serializeAPIRecord(Record);
695*12c85518Srobert if (!Struct)
696*12c85518Srobert return;
697*12c85518Srobert
698*12c85518Srobert Symbols.emplace_back(std::move(*Struct));
699*12c85518Srobert serializeMembers(Record, Record.Fields);
700*12c85518Srobert }
701*12c85518Srobert
serializeObjCContainerRecord(const ObjCContainerRecord & Record)702*12c85518Srobert void SymbolGraphSerializer::serializeObjCContainerRecord(
703*12c85518Srobert const ObjCContainerRecord &Record) {
704*12c85518Srobert auto ObjCContainer = serializeAPIRecord(Record);
705*12c85518Srobert if (!ObjCContainer)
706*12c85518Srobert return;
707*12c85518Srobert
708*12c85518Srobert Symbols.emplace_back(std::move(*ObjCContainer));
709*12c85518Srobert
710*12c85518Srobert serializeMembers(Record, Record.Ivars);
711*12c85518Srobert serializeMembers(Record, Record.Methods);
712*12c85518Srobert serializeMembers(Record, Record.Properties);
713*12c85518Srobert
714*12c85518Srobert for (const auto &Protocol : Record.Protocols)
715*12c85518Srobert // Record that Record conforms to Protocol.
716*12c85518Srobert serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
717*12c85518Srobert
718*12c85518Srobert if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
719*12c85518Srobert if (!ObjCInterface->SuperClass.empty())
720*12c85518Srobert // If Record is an Objective-C interface record and it has a super class,
721*12c85518Srobert // record that Record is inherited from SuperClass.
722*12c85518Srobert serializeRelationship(RelationshipKind::InheritsFrom, Record,
723*12c85518Srobert ObjCInterface->SuperClass);
724*12c85518Srobert
725*12c85518Srobert // Members of categories extending an interface are serialized as members of
726*12c85518Srobert // the interface.
727*12c85518Srobert for (const auto *Category : ObjCInterface->Categories) {
728*12c85518Srobert serializeMembers(Record, Category->Ivars);
729*12c85518Srobert serializeMembers(Record, Category->Methods);
730*12c85518Srobert serializeMembers(Record, Category->Properties);
731*12c85518Srobert
732*12c85518Srobert // Surface the protocols of the category to the interface.
733*12c85518Srobert for (const auto &Protocol : Category->Protocols)
734*12c85518Srobert serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
735*12c85518Srobert }
736*12c85518Srobert }
737*12c85518Srobert }
738*12c85518Srobert
serializeMacroDefinitionRecord(const MacroDefinitionRecord & Record)739*12c85518Srobert void SymbolGraphSerializer::serializeMacroDefinitionRecord(
740*12c85518Srobert const MacroDefinitionRecord &Record) {
741*12c85518Srobert auto Macro = serializeAPIRecord(Record);
742*12c85518Srobert
743*12c85518Srobert if (!Macro)
744*12c85518Srobert return;
745*12c85518Srobert
746*12c85518Srobert Symbols.emplace_back(std::move(*Macro));
747*12c85518Srobert }
748*12c85518Srobert
serializeSingleRecord(const APIRecord * Record)749*12c85518Srobert void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
750*12c85518Srobert switch (Record->getKind()) {
751*12c85518Srobert case APIRecord::RK_Unknown:
752*12c85518Srobert llvm_unreachable("Records should have a known kind!");
753*12c85518Srobert case APIRecord::RK_GlobalFunction:
754*12c85518Srobert serializeGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
755*12c85518Srobert break;
756*12c85518Srobert case APIRecord::RK_GlobalVariable:
757*12c85518Srobert serializeGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
758*12c85518Srobert break;
759*12c85518Srobert case APIRecord::RK_Enum:
760*12c85518Srobert serializeEnumRecord(*cast<EnumRecord>(Record));
761*12c85518Srobert break;
762*12c85518Srobert case APIRecord::RK_Struct:
763*12c85518Srobert serializeStructRecord(*cast<StructRecord>(Record));
764*12c85518Srobert break;
765*12c85518Srobert case APIRecord::RK_ObjCInterface:
766*12c85518Srobert serializeObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
767*12c85518Srobert break;
768*12c85518Srobert case APIRecord::RK_ObjCProtocol:
769*12c85518Srobert serializeObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
770*12c85518Srobert break;
771*12c85518Srobert case APIRecord::RK_MacroDefinition:
772*12c85518Srobert serializeMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
773*12c85518Srobert break;
774*12c85518Srobert case APIRecord::RK_Typedef:
775*12c85518Srobert serializeTypedefRecord(*cast<TypedefRecord>(Record));
776*12c85518Srobert break;
777*12c85518Srobert default:
778*12c85518Srobert if (auto Obj = serializeAPIRecord(*Record)) {
779*12c85518Srobert Symbols.emplace_back(std::move(*Obj));
780*12c85518Srobert auto &ParentInformation = Record->ParentInformation;
781*12c85518Srobert if (!ParentInformation.empty())
782*12c85518Srobert serializeRelationship(RelationshipKind::MemberOf, *Record,
783*12c85518Srobert *ParentInformation.ParentRecord);
784*12c85518Srobert }
785*12c85518Srobert break;
786*12c85518Srobert }
787*12c85518Srobert }
788*12c85518Srobert
serializeTypedefRecord(const TypedefRecord & Record)789*12c85518Srobert void SymbolGraphSerializer::serializeTypedefRecord(
790*12c85518Srobert const TypedefRecord &Record) {
791*12c85518Srobert // Typedefs of anonymous types have their entries unified with the underlying
792*12c85518Srobert // type.
793*12c85518Srobert bool ShouldDrop = Record.UnderlyingType.Name.empty();
794*12c85518Srobert // enums declared with `NS_OPTION` have a named enum and a named typedef, with
795*12c85518Srobert // the same name
796*12c85518Srobert ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
797*12c85518Srobert if (ShouldDrop)
798*12c85518Srobert return;
799*12c85518Srobert
800*12c85518Srobert auto Typedef = serializeAPIRecord(Record);
801*12c85518Srobert if (!Typedef)
802*12c85518Srobert return;
803*12c85518Srobert
804*12c85518Srobert (*Typedef)["type"] = Record.UnderlyingType.USR;
805*12c85518Srobert
806*12c85518Srobert Symbols.emplace_back(std::move(*Typedef));
807*12c85518Srobert }
808*12c85518Srobert
serialize()809*12c85518Srobert Object SymbolGraphSerializer::serialize() {
810*12c85518Srobert // Serialize global variables in the API set.
811*12c85518Srobert for (const auto &GlobalVar : API.getGlobalVariables())
812*12c85518Srobert serializeGlobalVariableRecord(*GlobalVar.second);
813*12c85518Srobert
814*12c85518Srobert for (const auto &GlobalFunction : API.getGlobalFunctions())
815*12c85518Srobert serializeGlobalFunctionRecord(*GlobalFunction.second);
816*12c85518Srobert
817*12c85518Srobert // Serialize enum records in the API set.
818*12c85518Srobert for (const auto &Enum : API.getEnums())
819*12c85518Srobert serializeEnumRecord(*Enum.second);
820*12c85518Srobert
821*12c85518Srobert // Serialize struct records in the API set.
822*12c85518Srobert for (const auto &Struct : API.getStructs())
823*12c85518Srobert serializeStructRecord(*Struct.second);
824*12c85518Srobert
825*12c85518Srobert // Serialize Objective-C interface records in the API set.
826*12c85518Srobert for (const auto &ObjCInterface : API.getObjCInterfaces())
827*12c85518Srobert serializeObjCContainerRecord(*ObjCInterface.second);
828*12c85518Srobert
829*12c85518Srobert // Serialize Objective-C protocol records in the API set.
830*12c85518Srobert for (const auto &ObjCProtocol : API.getObjCProtocols())
831*12c85518Srobert serializeObjCContainerRecord(*ObjCProtocol.second);
832*12c85518Srobert
833*12c85518Srobert for (const auto &Macro : API.getMacros())
834*12c85518Srobert serializeMacroDefinitionRecord(*Macro.second);
835*12c85518Srobert
836*12c85518Srobert for (const auto &Typedef : API.getTypedefs())
837*12c85518Srobert serializeTypedefRecord(*Typedef.second);
838*12c85518Srobert
839*12c85518Srobert return serializeCurrentGraph();
840*12c85518Srobert }
841*12c85518Srobert
serializeCurrentGraph()842*12c85518Srobert Object SymbolGraphSerializer::serializeCurrentGraph() {
843*12c85518Srobert Object Root;
844*12c85518Srobert serializeObject(Root, "metadata", serializeMetadata());
845*12c85518Srobert serializeObject(Root, "module", serializeModule());
846*12c85518Srobert
847*12c85518Srobert Root["symbols"] = std::move(Symbols);
848*12c85518Srobert Root["relationships"] = std::move(Relationships);
849*12c85518Srobert
850*12c85518Srobert return Root;
851*12c85518Srobert }
852*12c85518Srobert
serialize(raw_ostream & os)853*12c85518Srobert void SymbolGraphSerializer::serialize(raw_ostream &os) {
854*12c85518Srobert Object root = serialize();
855*12c85518Srobert if (Options.Compact)
856*12c85518Srobert os << formatv("{0}", Value(std::move(root))) << "\n";
857*12c85518Srobert else
858*12c85518Srobert os << formatv("{0:2}", Value(std::move(root))) << "\n";
859*12c85518Srobert }
860*12c85518Srobert
861*12c85518Srobert std::optional<Object>
serializeSingleSymbolSGF(StringRef USR,const APISet & API)862*12c85518Srobert SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
863*12c85518Srobert const APISet &API) {
864*12c85518Srobert APIRecord *Record = API.findRecordForUSR(USR);
865*12c85518Srobert if (!Record)
866*12c85518Srobert return {};
867*12c85518Srobert
868*12c85518Srobert Object Root;
869*12c85518Srobert APIIgnoresList EmptyIgnores;
870*12c85518Srobert SymbolGraphSerializer Serializer(API, EmptyIgnores,
871*12c85518Srobert /*Options.Compact*/ {true},
872*12c85518Srobert /*ShouldRecurse*/ false);
873*12c85518Srobert Serializer.serializeSingleRecord(Record);
874*12c85518Srobert serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
875*12c85518Srobert
876*12c85518Srobert Language Lang = API.getLanguage();
877*12c85518Srobert serializeArray(Root, "parentContexts",
878*12c85518Srobert generateParentContexts(*Record, API, Lang));
879*12c85518Srobert
880*12c85518Srobert Array RelatedSymbols;
881*12c85518Srobert
882*12c85518Srobert for (const auto &Fragment : Record->Declaration.getFragments()) {
883*12c85518Srobert // If we don't have a USR there isn't much we can do.
884*12c85518Srobert if (Fragment.PreciseIdentifier.empty())
885*12c85518Srobert continue;
886*12c85518Srobert
887*12c85518Srobert APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
888*12c85518Srobert
889*12c85518Srobert // If we can't find the record let's skip.
890*12c85518Srobert if (!RelatedRecord)
891*12c85518Srobert continue;
892*12c85518Srobert
893*12c85518Srobert Object RelatedSymbol;
894*12c85518Srobert RelatedSymbol["usr"] = RelatedRecord->USR;
895*12c85518Srobert RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
896*12c85518Srobert // TODO: once we record this properly let's serialize it right.
897*12c85518Srobert RelatedSymbol["accessLevel"] = "public";
898*12c85518Srobert RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
899*12c85518Srobert RelatedSymbol["moduleName"] = API.ProductName;
900*12c85518Srobert RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
901*12c85518Srobert
902*12c85518Srobert serializeArray(RelatedSymbol, "parentContexts",
903*12c85518Srobert generateParentContexts(*RelatedRecord, API, Lang));
904*12c85518Srobert RelatedSymbols.push_back(std::move(RelatedSymbol));
905*12c85518Srobert }
906*12c85518Srobert
907*12c85518Srobert serializeArray(Root, "relatedSymbols", RelatedSymbols);
908*12c85518Srobert return Root;
909*12c85518Srobert }
910