xref: /llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision 209a1e8dfdf1c104dd53b50eb196d6bc0dd01659)
1 //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements the SymbolGraphSerializer.
11 ///
12 //===----------------------------------------------------------------------===//
13 
14 #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
15 #include "clang/Basic/SourceLocation.h"
16 #include "clang/Basic/Version.h"
17 #include "clang/ExtractAPI/DeclarationFragments.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/STLFunctionalExtras.h"
20 #include "llvm/Support/Casting.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/VersionTuple.h"
24 #include <optional>
25 #include <type_traits>
26 
27 using namespace clang;
28 using namespace clang::extractapi;
29 using namespace llvm;
30 using namespace llvm::json;
31 
32 namespace {
33 
34 /// Helper function to inject a JSON object \p Obj into another object \p Paren
35 /// at position \p Key.
36 void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
37   if (Obj)
38     Paren[Key] = std::move(*Obj);
39 }
40 
41 /// Helper function to inject a StringRef \p String into an object \p Paren at
42 /// position \p Key
43 void serializeString(Object &Paren, StringRef Key,
44                      std::optional<std::string> String) {
45   if (String)
46     Paren[Key] = std::move(*String);
47 }
48 
49 /// Helper function to inject a JSON array \p Array into object \p Paren at
50 /// position \p Key.
51 void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
52   if (Array)
53     Paren[Key] = std::move(*Array);
54 }
55 
56 /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
57 /// format.
58 ///
59 /// A semantic version object contains three numeric fields, representing the
60 /// \c major, \c minor, and \c patch parts of the version tuple.
61 /// For example version tuple 1.0.3 is serialized as:
62 /// \code
63 ///   {
64 ///     "major" : 1,
65 ///     "minor" : 0,
66 ///     "patch" : 3
67 ///   }
68 /// \endcode
69 ///
70 /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
71 /// containing the semantic version representation of \p V.
72 std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
73   if (V.empty())
74     return std::nullopt;
75 
76   Object Version;
77   Version["major"] = V.getMajor();
78   Version["minor"] = V.getMinor().value_or(0);
79   Version["patch"] = V.getSubminor().value_or(0);
80   return Version;
81 }
82 
83 /// Serialize the OS information in the Symbol Graph platform property.
84 ///
85 /// The OS information in Symbol Graph contains the \c name of the OS, and an
86 /// optional \c minimumVersion semantic version field.
87 Object serializeOperatingSystem(const Triple &T) {
88   Object OS;
89   OS["name"] = T.getOSTypeName(T.getOS());
90   serializeObject(OS, "minimumVersion",
91                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
92   return OS;
93 }
94 
95 /// Serialize the platform information in the Symbol Graph module section.
96 ///
97 /// The platform object describes a target platform triple in corresponding
98 /// three fields: \c architecture, \c vendor, and \c operatingSystem.
99 Object serializePlatform(const Triple &T) {
100   Object Platform;
101   Platform["architecture"] = T.getArchName();
102   Platform["vendor"] = T.getVendorName();
103   Platform["operatingSystem"] = serializeOperatingSystem(T);
104   return Platform;
105 }
106 
107 /// Serialize a source position.
108 Object serializeSourcePosition(const PresumedLoc &Loc) {
109   assert(Loc.isValid() && "invalid source position");
110 
111   Object SourcePosition;
112   SourcePosition["line"] = Loc.getLine() - 1;
113   SourcePosition["character"] = Loc.getColumn() - 1;
114 
115   return SourcePosition;
116 }
117 
118 /// Serialize a source location in file.
119 ///
120 /// \param Loc The presumed location to serialize.
121 /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
122 /// Defaults to false.
123 Object serializeSourceLocation(const PresumedLoc &Loc,
124                                bool IncludeFileURI = false) {
125   Object SourceLocation;
126   serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
127 
128   if (IncludeFileURI) {
129     std::string FileURI = "file://";
130     // Normalize file path to use forward slashes for the URI.
131     FileURI += sys::path::convert_to_slash(Loc.getFilename());
132     SourceLocation["uri"] = FileURI;
133   }
134 
135   return SourceLocation;
136 }
137 
138 /// Serialize a source range with begin and end locations.
139 Object serializeSourceRange(const PresumedLoc &BeginLoc,
140                             const PresumedLoc &EndLoc) {
141   Object SourceRange;
142   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
143   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
144   return SourceRange;
145 }
146 
147 /// Serialize the availability attributes of a symbol.
148 ///
149 /// Availability information contains the introduced, deprecated, and obsoleted
150 /// versions of the symbol as semantic versions, if not default.
151 /// Availability information also contains flags to indicate if the symbol is
152 /// unconditionally unavailable or deprecated,
153 /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
154 ///
155 /// \returns \c std::nullopt if the symbol has default availability attributes,
156 /// or an \c Array containing an object with the formatted availability
157 /// information.
158 std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
159   if (Avail.isDefault())
160     return std::nullopt;
161 
162   Object Availability;
163   Array AvailabilityArray;
164   Availability["domain"] = Avail.Domain;
165   serializeObject(Availability, "introduced",
166                   serializeSemanticVersion(Avail.Introduced));
167   serializeObject(Availability, "deprecated",
168                   serializeSemanticVersion(Avail.Deprecated));
169   serializeObject(Availability, "obsoleted",
170                   serializeSemanticVersion(Avail.Obsoleted));
171   if (Avail.isUnconditionallyDeprecated()) {
172     Object UnconditionallyDeprecated;
173     UnconditionallyDeprecated["domain"] = "*";
174     UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
175     AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
176   }
177   if (Avail.isUnconditionallyUnavailable()) {
178     Object UnconditionallyUnavailable;
179     UnconditionallyUnavailable["domain"] = "*";
180     UnconditionallyUnavailable["isUnconditionallyUnavailable"] = true;
181     AvailabilityArray.emplace_back(std::move(UnconditionallyUnavailable));
182   }
183   AvailabilityArray.emplace_back(std::move(Availability));
184   return AvailabilityArray;
185 }
186 
187 /// Get the language name string for interface language references.
188 StringRef getLanguageName(Language Lang) {
189   switch (Lang) {
190   case Language::C:
191     return "c";
192   case Language::ObjC:
193     return "objective-c";
194   case Language::CXX:
195     return "c++";
196   case Language::ObjCXX:
197     return "objective-c++";
198 
199   // Unsupported language currently
200   case Language::OpenCL:
201   case Language::OpenCLCXX:
202   case Language::CUDA:
203   case Language::RenderScript:
204   case Language::HIP:
205   case Language::HLSL:
206 
207   // Languages that the frontend cannot parse and compile
208   case Language::Unknown:
209   case Language::Asm:
210   case Language::LLVM_IR:
211   case Language::CIR:
212     llvm_unreachable("Unsupported language kind");
213   }
214 
215   llvm_unreachable("Unhandled language kind");
216 }
217 
218 /// Serialize the identifier object as specified by the Symbol Graph format.
219 ///
220 /// The identifier property of a symbol contains the USR for precise and unique
221 /// references, and the interface language name.
222 Object serializeIdentifier(const APIRecord &Record, Language Lang) {
223   Object Identifier;
224   Identifier["precise"] = Record.USR;
225   Identifier["interfaceLanguage"] = getLanguageName(Lang);
226 
227   return Identifier;
228 }
229 
230 /// Serialize the documentation comments attached to a symbol, as specified by
231 /// the Symbol Graph format.
232 ///
233 /// The Symbol Graph \c docComment object contains an array of lines. Each line
234 /// represents one line of striped documentation comment, with source range
235 /// information.
236 /// e.g.
237 /// \code
238 ///   /// This is a documentation comment
239 ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
240 ///   ///     with multiple lines.
241 ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
242 /// \endcode
243 ///
244 /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
245 /// the formatted lines.
246 std::optional<Object> serializeDocComment(const DocComment &Comment) {
247   if (Comment.empty())
248     return std::nullopt;
249 
250   Object DocComment;
251   Array LinesArray;
252   for (const auto &CommentLine : Comment) {
253     Object Line;
254     Line["text"] = CommentLine.Text;
255     serializeObject(Line, "range",
256                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
257     LinesArray.emplace_back(std::move(Line));
258   }
259   serializeArray(DocComment, "lines", LinesArray);
260 
261   return DocComment;
262 }
263 
264 /// Serialize the declaration fragments of a symbol.
265 ///
266 /// The Symbol Graph declaration fragments is an array of tagged important
267 /// parts of a symbol's declaration. The fragments sequence can be joined to
268 /// form spans of declaration text, with attached information useful for
269 /// purposes like syntax-highlighting etc. For example:
270 /// \code
271 ///   const int pi; -> "declarationFragments" : [
272 ///                      {
273 ///                        "kind" : "keyword",
274 ///                        "spelling" : "const"
275 ///                      },
276 ///                      {
277 ///                        "kind" : "text",
278 ///                        "spelling" : " "
279 ///                      },
280 ///                      {
281 ///                        "kind" : "typeIdentifier",
282 ///                        "preciseIdentifier" : "c:I",
283 ///                        "spelling" : "int"
284 ///                      },
285 ///                      {
286 ///                        "kind" : "text",
287 ///                        "spelling" : " "
288 ///                      },
289 ///                      {
290 ///                        "kind" : "identifier",
291 ///                        "spelling" : "pi"
292 ///                      }
293 ///                    ]
294 /// \endcode
295 ///
296 /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
297 /// formatted declaration fragments array.
298 std::optional<Array>
299 serializeDeclarationFragments(const DeclarationFragments &DF) {
300   if (DF.getFragments().empty())
301     return std::nullopt;
302 
303   Array Fragments;
304   for (const auto &F : DF.getFragments()) {
305     Object Fragment;
306     Fragment["spelling"] = F.Spelling;
307     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
308     if (!F.PreciseIdentifier.empty())
309       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
310     Fragments.emplace_back(std::move(Fragment));
311   }
312 
313   return Fragments;
314 }
315 
316 /// Serialize the \c names field of a symbol as specified by the Symbol Graph
317 /// format.
318 ///
319 /// The Symbol Graph names field contains multiple representations of a symbol
320 /// that can be used for different applications:
321 ///   - \c title : The simple declared name of the symbol;
322 ///   - \c subHeading : An array of declaration fragments that provides tags,
323 ///     and potentially more tokens (for example the \c +/- symbol for
324 ///     Objective-C methods). Can be used as sub-headings for documentation.
325 Object serializeNames(const APIRecord &Record) {
326   Object Names;
327   if (auto *CategoryRecord =
328           dyn_cast_or_null<const ObjCCategoryRecord>(&Record))
329     Names["title"] =
330         (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str();
331   else
332     Names["title"] = Record.Name;
333 
334   serializeArray(Names, "subHeading",
335                  serializeDeclarationFragments(Record.SubHeading));
336   DeclarationFragments NavigatorFragments;
337   NavigatorFragments.append(Record.Name,
338                             DeclarationFragments::FragmentKind::Identifier,
339                             /*PreciseIdentifier*/ "");
340   serializeArray(Names, "navigator",
341                  serializeDeclarationFragments(NavigatorFragments));
342 
343   return Names;
344 }
345 
346 Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
347   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
348     return (getLanguageName(Lang) + "." + S).str();
349   };
350 
351   Object Kind;
352   switch (RK) {
353   case APIRecord::RK_Unknown:
354     llvm_unreachable("Records should have an explicit kind");
355     break;
356   case APIRecord::RK_Namespace:
357     Kind["identifier"] = AddLangPrefix("namespace");
358     Kind["displayName"] = "Namespace";
359     break;
360   case APIRecord::RK_GlobalFunction:
361     Kind["identifier"] = AddLangPrefix("func");
362     Kind["displayName"] = "Function";
363     break;
364   case APIRecord::RK_GlobalFunctionTemplate:
365     Kind["identifier"] = AddLangPrefix("func");
366     Kind["displayName"] = "Function Template";
367     break;
368   case APIRecord::RK_GlobalFunctionTemplateSpecialization:
369     Kind["identifier"] = AddLangPrefix("func");
370     Kind["displayName"] = "Function Template Specialization";
371     break;
372   case APIRecord::RK_GlobalVariableTemplate:
373     Kind["identifier"] = AddLangPrefix("var");
374     Kind["displayName"] = "Global Variable Template";
375     break;
376   case APIRecord::RK_GlobalVariableTemplateSpecialization:
377     Kind["identifier"] = AddLangPrefix("var");
378     Kind["displayName"] = "Global Variable Template Specialization";
379     break;
380   case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
381     Kind["identifier"] = AddLangPrefix("var");
382     Kind["displayName"] = "Global Variable Template Partial Specialization";
383     break;
384   case APIRecord::RK_GlobalVariable:
385     Kind["identifier"] = AddLangPrefix("var");
386     Kind["displayName"] = "Global Variable";
387     break;
388   case APIRecord::RK_EnumConstant:
389     Kind["identifier"] = AddLangPrefix("enum.case");
390     Kind["displayName"] = "Enumeration Case";
391     break;
392   case APIRecord::RK_Enum:
393     Kind["identifier"] = AddLangPrefix("enum");
394     Kind["displayName"] = "Enumeration";
395     break;
396   case APIRecord::RK_StructField:
397     Kind["identifier"] = AddLangPrefix("property");
398     Kind["displayName"] = "Instance Property";
399     break;
400   case APIRecord::RK_Struct:
401     Kind["identifier"] = AddLangPrefix("struct");
402     Kind["displayName"] = "Structure";
403     break;
404   case APIRecord::RK_UnionField:
405     Kind["identifier"] = AddLangPrefix("property");
406     Kind["displayName"] = "Instance Property";
407     break;
408   case APIRecord::RK_Union:
409     Kind["identifier"] = AddLangPrefix("union");
410     Kind["displayName"] = "Union";
411     break;
412   case APIRecord::RK_CXXField:
413     Kind["identifier"] = AddLangPrefix("property");
414     Kind["displayName"] = "Instance Property";
415     break;
416   case APIRecord::RK_StaticField:
417     Kind["identifier"] = AddLangPrefix("type.property");
418     Kind["displayName"] = "Type Property";
419     break;
420   case APIRecord::RK_ClassTemplate:
421   case APIRecord::RK_ClassTemplateSpecialization:
422   case APIRecord::RK_ClassTemplatePartialSpecialization:
423   case APIRecord::RK_CXXClass:
424     Kind["identifier"] = AddLangPrefix("class");
425     Kind["displayName"] = "Class";
426     break;
427   case APIRecord::RK_CXXMethodTemplate:
428     Kind["identifier"] = AddLangPrefix("method");
429     Kind["displayName"] = "Method Template";
430     break;
431   case APIRecord::RK_CXXMethodTemplateSpecialization:
432     Kind["identifier"] = AddLangPrefix("method");
433     Kind["displayName"] = "Method Template Specialization";
434     break;
435   case APIRecord::RK_CXXFieldTemplate:
436     Kind["identifier"] = AddLangPrefix("property");
437     Kind["displayName"] = "Template Property";
438     break;
439   case APIRecord::RK_Concept:
440     Kind["identifier"] = AddLangPrefix("concept");
441     Kind["displayName"] = "Concept";
442     break;
443   case APIRecord::RK_CXXStaticMethod:
444     Kind["identifier"] = AddLangPrefix("type.method");
445     Kind["displayName"] = "Static Method";
446     break;
447   case APIRecord::RK_CXXInstanceMethod:
448     Kind["identifier"] = AddLangPrefix("method");
449     Kind["displayName"] = "Instance Method";
450     break;
451   case APIRecord::RK_CXXConstructorMethod:
452     Kind["identifier"] = AddLangPrefix("method");
453     Kind["displayName"] = "Constructor";
454     break;
455   case APIRecord::RK_CXXDestructorMethod:
456     Kind["identifier"] = AddLangPrefix("method");
457     Kind["displayName"] = "Destructor";
458     break;
459   case APIRecord::RK_ObjCIvar:
460     Kind["identifier"] = AddLangPrefix("ivar");
461     Kind["displayName"] = "Instance Variable";
462     break;
463   case APIRecord::RK_ObjCInstanceMethod:
464     Kind["identifier"] = AddLangPrefix("method");
465     Kind["displayName"] = "Instance Method";
466     break;
467   case APIRecord::RK_ObjCClassMethod:
468     Kind["identifier"] = AddLangPrefix("type.method");
469     Kind["displayName"] = "Type Method";
470     break;
471   case APIRecord::RK_ObjCInstanceProperty:
472     Kind["identifier"] = AddLangPrefix("property");
473     Kind["displayName"] = "Instance Property";
474     break;
475   case APIRecord::RK_ObjCClassProperty:
476     Kind["identifier"] = AddLangPrefix("type.property");
477     Kind["displayName"] = "Type Property";
478     break;
479   case APIRecord::RK_ObjCInterface:
480     Kind["identifier"] = AddLangPrefix("class");
481     Kind["displayName"] = "Class";
482     break;
483   case APIRecord::RK_ObjCCategory:
484     Kind["identifier"] = AddLangPrefix("class.extension");
485     Kind["displayName"] = "Class Extension";
486     break;
487   case APIRecord::RK_ObjCCategoryModule:
488     Kind["identifier"] = AddLangPrefix("module.extension");
489     Kind["displayName"] = "Module Extension";
490     break;
491   case APIRecord::RK_ObjCProtocol:
492     Kind["identifier"] = AddLangPrefix("protocol");
493     Kind["displayName"] = "Protocol";
494     break;
495   case APIRecord::RK_MacroDefinition:
496     Kind["identifier"] = AddLangPrefix("macro");
497     Kind["displayName"] = "Macro";
498     break;
499   case APIRecord::RK_Typedef:
500     Kind["identifier"] = AddLangPrefix("typealias");
501     Kind["displayName"] = "Type Alias";
502     break;
503   }
504 
505   return Kind;
506 }
507 
508 /// Serialize the symbol kind information.
509 ///
510 /// The Symbol Graph symbol kind property contains a shorthand \c identifier
511 /// which is prefixed by the source language name, useful for tooling to parse
512 /// the kind, and a \c displayName for rendering human-readable names.
513 Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
514   return serializeSymbolKind(Record.getKind(), Lang);
515 }
516 
517 template <typename RecordTy>
518 std::optional<Object>
519 serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
520   const auto &FS = Record.Signature;
521   if (FS.empty())
522     return std::nullopt;
523 
524   Object Signature;
525   serializeArray(Signature, "returns",
526                  serializeDeclarationFragments(FS.getReturnType()));
527 
528   Array Parameters;
529   for (const auto &P : FS.getParameters()) {
530     Object Parameter;
531     Parameter["name"] = P.Name;
532     serializeArray(Parameter, "declarationFragments",
533                    serializeDeclarationFragments(P.Fragments));
534     Parameters.emplace_back(std::move(Parameter));
535   }
536 
537   if (!Parameters.empty())
538     Signature["parameters"] = std::move(Parameters);
539 
540   return Signature;
541 }
542 
543 template <typename RecordTy>
544 std::optional<Object>
545 serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
546   return std::nullopt;
547 }
548 
549 /// Serialize the function signature field, as specified by the
550 /// Symbol Graph format.
551 ///
552 /// The Symbol Graph function signature property contains two arrays.
553 ///   - The \c returns array is the declaration fragments of the return type;
554 ///   - The \c parameters array contains names and declaration fragments of the
555 ///     parameters.
556 ///
557 /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
558 /// formatted function signature.
559 template <typename RecordTy>
560 void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
561   serializeObject(Paren, "functionSignature",
562                   serializeFunctionSignatureMixinImpl(
563                       Record, has_function_signature<RecordTy>()));
564 }
565 
566 template <typename RecordTy>
567 std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
568                                                     std::true_type) {
569   const auto &AccessControl = Record.Access;
570   std::string Access;
571   if (AccessControl.empty())
572     return std::nullopt;
573   Access = AccessControl.getAccess();
574   return Access;
575 }
576 
577 template <typename RecordTy>
578 std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
579                                                     std::false_type) {
580   return std::nullopt;
581 }
582 
583 template <typename RecordTy>
584 void serializeAccessMixin(Object &Paren, const RecordTy &Record) {
585   auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>());
586   if (!accessLevel.has_value())
587     accessLevel = "public";
588   serializeString(Paren, "accessLevel", accessLevel);
589 }
590 
591 template <typename RecordTy>
592 std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
593                                                  std::true_type) {
594   const auto &Template = Record.Templ;
595   if (Template.empty())
596     return std::nullopt;
597 
598   Object Generics;
599   Array GenericParameters;
600   for (const auto &Param : Template.getParameters()) {
601     Object Parameter;
602     Parameter["name"] = Param.Name;
603     Parameter["index"] = Param.Index;
604     Parameter["depth"] = Param.Depth;
605     GenericParameters.emplace_back(std::move(Parameter));
606   }
607   if (!GenericParameters.empty())
608     Generics["parameters"] = std::move(GenericParameters);
609 
610   Array GenericConstraints;
611   for (const auto &Constr : Template.getConstraints()) {
612     Object Constraint;
613     Constraint["kind"] = Constr.Kind;
614     Constraint["lhs"] = Constr.LHS;
615     Constraint["rhs"] = Constr.RHS;
616     GenericConstraints.emplace_back(std::move(Constraint));
617   }
618 
619   if (!GenericConstraints.empty())
620     Generics["constraints"] = std::move(GenericConstraints);
621 
622   return Generics;
623 }
624 
625 template <typename RecordTy>
626 std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
627                                                  std::false_type) {
628   return std::nullopt;
629 }
630 
631 template <typename RecordTy>
632 void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
633   serializeObject(Paren, "swiftGenerics",
634                   serializeTemplateMixinImpl(Record, has_template<RecordTy>()));
635 }
636 
637 struct PathComponent {
638   StringRef USR;
639   StringRef Name;
640   APIRecord::RecordKind Kind;
641 
642   PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
643       : USR(USR), Name(Name), Kind(Kind) {}
644 };
645 
646 template <typename RecordTy>
647 bool generatePathComponents(
648     const RecordTy &Record, const APISet &API,
649     function_ref<void(const PathComponent &)> ComponentTransformer) {
650   SmallVector<PathComponent, 4> ReverseComponenents;
651   ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
652   const auto *CurrentParent = &Record.ParentInformation;
653   bool FailedToFindParent = false;
654   while (CurrentParent && !CurrentParent->empty()) {
655     PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
656                                          CurrentParent->ParentName,
657                                          CurrentParent->ParentKind);
658 
659     auto *ParentRecord = CurrentParent->ParentRecord;
660     // Slow path if we don't have a direct reference to the ParentRecord
661     if (!ParentRecord)
662       ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
663 
664     // If the parent is a category extended from internal module then we need to
665     // pretend this belongs to the associated interface.
666     if (auto *CategoryRecord =
667             dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
668       if (!CategoryRecord->IsFromExternalModule) {
669         ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
670         CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
671                                                CategoryRecord->Interface.Name,
672                                                APIRecord::RK_ObjCInterface);
673       }
674     }
675 
676     // The parent record doesn't exist which means the symbol shouldn't be
677     // treated as part of the current product.
678     if (!ParentRecord) {
679       FailedToFindParent = true;
680       break;
681     }
682 
683     ReverseComponenents.push_back(std::move(CurrentParentComponent));
684     CurrentParent = &ParentRecord->ParentInformation;
685   }
686 
687   for (const auto &PC : reverse(ReverseComponenents))
688     ComponentTransformer(PC);
689 
690   return FailedToFindParent;
691 }
692 
693 Object serializeParentContext(const PathComponent &PC, Language Lang) {
694   Object ParentContextElem;
695   ParentContextElem["usr"] = PC.USR;
696   ParentContextElem["name"] = PC.Name;
697   ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
698   return ParentContextElem;
699 }
700 
701 template <typename RecordTy>
702 Array generateParentContexts(const RecordTy &Record, const APISet &API,
703                              Language Lang) {
704   Array ParentContexts;
705   generatePathComponents(
706       Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
707         ParentContexts.push_back(serializeParentContext(PC, Lang));
708       });
709 
710   return ParentContexts;
711 }
712 } // namespace
713 
714 /// Defines the format version emitted by SymbolGraphSerializer.
715 const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
716 
717 Object SymbolGraphSerializer::serializeMetadata() const {
718   Object Metadata;
719   serializeObject(Metadata, "formatVersion",
720                   serializeSemanticVersion(FormatVersion));
721   Metadata["generator"] = clang::getClangFullVersion();
722   return Metadata;
723 }
724 
725 Object SymbolGraphSerializer::serializeModule() const {
726   Object Module;
727   // The user is expected to always pass `--product-name=` on the command line
728   // to populate this field.
729   Module["name"] = API.ProductName;
730   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
731   return Module;
732 }
733 
734 bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
735   // Skip explicitly ignored symbols.
736   if (IgnoresList.shouldIgnore(Record.Name))
737     return true;
738 
739   // Skip unconditionally unavailable symbols
740   if (Record.Availability.isUnconditionallyUnavailable())
741     return true;
742 
743   // Filter out symbols prefixed with an underscored as they are understood to
744   // be symbols clients should not use.
745   if (Record.Name.starts_with("_"))
746     return true;
747 
748   return false;
749 }
750 
751 template <typename RecordTy>
752 std::optional<Object>
753 SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
754   if (shouldSkip(Record))
755     return std::nullopt;
756 
757   Object Obj;
758   serializeObject(Obj, "identifier",
759                   serializeIdentifier(Record, API.getLanguage()));
760   serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
761   serializeObject(Obj, "names", serializeNames(Record));
762   serializeObject(
763       Obj, "location",
764       serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
765   serializeArray(Obj, "availability",
766                  serializeAvailability(Record.Availability));
767   serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
768   serializeArray(Obj, "declarationFragments",
769                  serializeDeclarationFragments(Record.Declaration));
770   SmallVector<StringRef, 4> PathComponentsNames;
771   // If this returns true it indicates that we couldn't find a symbol in the
772   // hierarchy.
773   if (generatePathComponents(Record, API,
774                              [&PathComponentsNames](const PathComponent &PC) {
775                                PathComponentsNames.push_back(PC.Name);
776                              }))
777     return {};
778 
779   serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
780 
781   serializeFunctionSignatureMixin(Obj, Record);
782   serializeAccessMixin(Obj, Record);
783   serializeTemplateMixin(Obj, Record);
784 
785   return Obj;
786 }
787 
788 template <typename MemberTy>
789 void SymbolGraphSerializer::serializeMembers(
790     const APIRecord &Record,
791     const SmallVector<std::unique_ptr<MemberTy>> &Members) {
792   // Members should not be serialized if we aren't recursing.
793   if (!ShouldRecurse)
794     return;
795   for (const auto &Member : Members) {
796     auto MemberRecord = serializeAPIRecord(*Member);
797     if (!MemberRecord)
798       continue;
799 
800     Symbols.emplace_back(std::move(*MemberRecord));
801     serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
802   }
803 }
804 
805 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
806   switch (Kind) {
807   case RelationshipKind::MemberOf:
808     return "memberOf";
809   case RelationshipKind::InheritsFrom:
810     return "inheritsFrom";
811   case RelationshipKind::ConformsTo:
812     return "conformsTo";
813   case RelationshipKind::ExtensionTo:
814     return "extensionTo";
815   }
816   llvm_unreachable("Unhandled relationship kind");
817 }
818 
819 StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
820   switch (Kind) {
821   case ConstraintKind::Conformance:
822     return "conformance";
823   case ConstraintKind::ConditionalConformance:
824     return "conditionalConformance";
825   }
826   llvm_unreachable("Unhandled constraint kind");
827 }
828 
829 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
830                                                   SymbolReference Source,
831                                                   SymbolReference Target) {
832   Object Relationship;
833   Relationship["source"] = Source.USR;
834   Relationship["target"] = Target.USR;
835   Relationship["targetFallback"] = Target.Name;
836   Relationship["kind"] = getRelationshipString(Kind);
837 
838   Relationships.emplace_back(std::move(Relationship));
839 }
840 
841 void SymbolGraphSerializer::visitNamespaceRecord(
842     const NamespaceRecord &Record) {
843   auto Namespace = serializeAPIRecord(Record);
844   if (!Namespace)
845     return;
846   Symbols.emplace_back(std::move(*Namespace));
847   if (!Record.ParentInformation.empty())
848     serializeRelationship(RelationshipKind::MemberOf, Record,
849                           Record.ParentInformation.ParentRecord);
850 }
851 
852 void SymbolGraphSerializer::visitGlobalFunctionRecord(
853     const GlobalFunctionRecord &Record) {
854   auto Obj = serializeAPIRecord(Record);
855   if (!Obj)
856     return;
857 
858   Symbols.emplace_back(std::move(*Obj));
859 }
860 
861 void SymbolGraphSerializer::visitGlobalVariableRecord(
862     const GlobalVariableRecord &Record) {
863   auto Obj = serializeAPIRecord(Record);
864   if (!Obj)
865     return;
866 
867   Symbols.emplace_back(std::move(*Obj));
868 }
869 
870 void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) {
871   auto Enum = serializeAPIRecord(Record);
872   if (!Enum)
873     return;
874 
875   Symbols.emplace_back(std::move(*Enum));
876   serializeMembers(Record, Record.Constants);
877 }
878 
879 void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) {
880   auto SerializedRecord = serializeAPIRecord(Record);
881   if (!SerializedRecord)
882     return;
883 
884   Symbols.emplace_back(std::move(*SerializedRecord));
885   serializeMembers(Record, Record.Fields);
886 }
887 
888 void SymbolGraphSerializer::visitStaticFieldRecord(
889     const StaticFieldRecord &Record) {
890   auto StaticField = serializeAPIRecord(Record);
891   if (!StaticField)
892     return;
893   Symbols.emplace_back(std::move(*StaticField));
894   serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context);
895 }
896 
897 void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) {
898   auto Class = serializeAPIRecord(Record);
899   if (!Class)
900     return;
901 
902   Symbols.emplace_back(std::move(*Class));
903   for (const auto &Base : Record.Bases)
904     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
905   if (!Record.ParentInformation.empty())
906     serializeRelationship(RelationshipKind::MemberOf, Record,
907                           Record.ParentInformation.ParentRecord);
908 }
909 
910 void SymbolGraphSerializer::visitClassTemplateRecord(
911     const ClassTemplateRecord &Record) {
912   auto Class = serializeAPIRecord(Record);
913   if (!Class)
914     return;
915 
916   Symbols.emplace_back(std::move(*Class));
917   for (const auto &Base : Record.Bases)
918     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
919   if (!Record.ParentInformation.empty())
920     serializeRelationship(RelationshipKind::MemberOf, Record,
921                           Record.ParentInformation.ParentRecord);
922 }
923 
924 void SymbolGraphSerializer::visitClassTemplateSpecializationRecord(
925     const ClassTemplateSpecializationRecord &Record) {
926   auto Class = serializeAPIRecord(Record);
927   if (!Class)
928     return;
929 
930   Symbols.emplace_back(std::move(*Class));
931 
932   for (const auto &Base : Record.Bases)
933     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
934   if (!Record.ParentInformation.empty())
935     serializeRelationship(RelationshipKind::MemberOf, Record,
936                           Record.ParentInformation.ParentRecord);
937 }
938 
939 void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
940     const ClassTemplatePartialSpecializationRecord &Record) {
941   auto Class = serializeAPIRecord(Record);
942   if (!Class)
943     return;
944 
945   Symbols.emplace_back(std::move(*Class));
946 
947   for (const auto &Base : Record.Bases)
948     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
949   if (!Record.ParentInformation.empty())
950     serializeRelationship(RelationshipKind::MemberOf, Record,
951                           Record.ParentInformation.ParentRecord);
952 }
953 
954 void SymbolGraphSerializer::visitCXXInstanceMethodRecord(
955     const CXXInstanceMethodRecord &Record) {
956   auto InstanceMethod = serializeAPIRecord(Record);
957   if (!InstanceMethod)
958     return;
959 
960   Symbols.emplace_back(std::move(*InstanceMethod));
961   serializeRelationship(RelationshipKind::MemberOf, Record,
962                         Record.ParentInformation.ParentRecord);
963 }
964 
965 void SymbolGraphSerializer::visitCXXStaticMethodRecord(
966     const CXXStaticMethodRecord &Record) {
967   auto StaticMethod = serializeAPIRecord(Record);
968   if (!StaticMethod)
969     return;
970 
971   Symbols.emplace_back(std::move(*StaticMethod));
972   serializeRelationship(RelationshipKind::MemberOf, Record,
973                         Record.ParentInformation.ParentRecord);
974 }
975 
976 void SymbolGraphSerializer::visitMethodTemplateRecord(
977     const CXXMethodTemplateRecord &Record) {
978   if (!ShouldRecurse)
979     // Ignore child symbols
980     return;
981   auto MethodTemplate = serializeAPIRecord(Record);
982   if (!MethodTemplate)
983     return;
984   Symbols.emplace_back(std::move(*MethodTemplate));
985   serializeRelationship(RelationshipKind::MemberOf, Record,
986                         Record.ParentInformation.ParentRecord);
987 }
988 
989 void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord(
990     const CXXMethodTemplateSpecializationRecord &Record) {
991   if (!ShouldRecurse)
992     // Ignore child symbols
993     return;
994   auto MethodTemplateSpecialization = serializeAPIRecord(Record);
995   if (!MethodTemplateSpecialization)
996     return;
997   Symbols.emplace_back(std::move(*MethodTemplateSpecialization));
998   serializeRelationship(RelationshipKind::MemberOf, Record,
999                         Record.ParentInformation.ParentRecord);
1000 }
1001 
1002 void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) {
1003   if (!ShouldRecurse)
1004     return;
1005   auto CXXField = serializeAPIRecord(Record);
1006   if (!CXXField)
1007     return;
1008   Symbols.emplace_back(std::move(*CXXField));
1009   serializeRelationship(RelationshipKind::MemberOf, Record,
1010                         Record.ParentInformation.ParentRecord);
1011 }
1012 
1013 void SymbolGraphSerializer::visitCXXFieldTemplateRecord(
1014     const CXXFieldTemplateRecord &Record) {
1015   if (!ShouldRecurse)
1016     // Ignore child symbols
1017     return;
1018   auto CXXFieldTemplate = serializeAPIRecord(Record);
1019   if (!CXXFieldTemplate)
1020     return;
1021   Symbols.emplace_back(std::move(*CXXFieldTemplate));
1022   serializeRelationship(RelationshipKind::MemberOf, Record,
1023                         Record.ParentInformation.ParentRecord);
1024 }
1025 
1026 void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) {
1027   auto Concept = serializeAPIRecord(Record);
1028   if (!Concept)
1029     return;
1030 
1031   Symbols.emplace_back(std::move(*Concept));
1032 }
1033 
1034 void SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
1035     const GlobalVariableTemplateRecord &Record) {
1036   auto GlobalVariableTemplate = serializeAPIRecord(Record);
1037   if (!GlobalVariableTemplate)
1038     return;
1039   Symbols.emplace_back(std::move(*GlobalVariableTemplate));
1040 }
1041 
1042 void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord(
1043     const GlobalVariableTemplateSpecializationRecord &Record) {
1044   auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record);
1045   if (!GlobalVariableTemplateSpecialization)
1046     return;
1047   Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization));
1048 }
1049 
1050 void SymbolGraphSerializer::
1051     visitGlobalVariableTemplatePartialSpecializationRecord(
1052         const GlobalVariableTemplatePartialSpecializationRecord &Record) {
1053   auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record);
1054   if (!GlobalVariableTemplatePartialSpecialization)
1055     return;
1056   Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization));
1057 }
1058 
1059 void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
1060     const GlobalFunctionTemplateRecord &Record) {
1061   auto GlobalFunctionTemplate = serializeAPIRecord(Record);
1062   if (!GlobalFunctionTemplate)
1063     return;
1064   Symbols.emplace_back(std::move(*GlobalFunctionTemplate));
1065 }
1066 
1067 void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord(
1068     const GlobalFunctionTemplateSpecializationRecord &Record) {
1069   auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record);
1070   if (!GlobalFunctionTemplateSpecialization)
1071     return;
1072   Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization));
1073 }
1074 
1075 void SymbolGraphSerializer::visitObjCContainerRecord(
1076     const ObjCContainerRecord &Record) {
1077   auto ObjCContainer = serializeAPIRecord(Record);
1078   if (!ObjCContainer)
1079     return;
1080 
1081   Symbols.emplace_back(std::move(*ObjCContainer));
1082 
1083   serializeMembers(Record, Record.Ivars);
1084   serializeMembers(Record, Record.Methods);
1085   serializeMembers(Record, Record.Properties);
1086 
1087   for (const auto &Protocol : Record.Protocols)
1088     // Record that Record conforms to Protocol.
1089     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1090 
1091   if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
1092     if (!ObjCInterface->SuperClass.empty())
1093       // If Record is an Objective-C interface record and it has a super class,
1094       // record that Record is inherited from SuperClass.
1095       serializeRelationship(RelationshipKind::InheritsFrom, Record,
1096                             ObjCInterface->SuperClass);
1097 
1098     // Members of categories extending an interface are serialized as members of
1099     // the interface.
1100     for (const auto *Category : ObjCInterface->Categories) {
1101       serializeMembers(Record, Category->Ivars);
1102       serializeMembers(Record, Category->Methods);
1103       serializeMembers(Record, Category->Properties);
1104 
1105       // Surface the protocols of the category to the interface.
1106       for (const auto &Protocol : Category->Protocols)
1107         serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1108     }
1109   }
1110 }
1111 
1112 void SymbolGraphSerializer::visitObjCCategoryRecord(
1113     const ObjCCategoryRecord &Record) {
1114   if (!Record.IsFromExternalModule)
1115     return;
1116 
1117   // Check if the current Category' parent has been visited before, if so skip.
1118   if (!visitedCategories.contains(Record.Interface.Name)) {
1119     visitedCategories.insert(Record.Interface.Name);
1120     Object Obj;
1121     serializeObject(Obj, "identifier",
1122                     serializeIdentifier(Record, API.getLanguage()));
1123     serializeObject(Obj, "kind",
1124                     serializeSymbolKind(APIRecord::RK_ObjCCategoryModule,
1125                                         API.getLanguage()));
1126     Obj["accessLevel"] = "public";
1127     Symbols.emplace_back(std::move(Obj));
1128   }
1129 
1130   Object Relationship;
1131   Relationship["source"] = Record.USR;
1132   Relationship["target"] = Record.Interface.USR;
1133   Relationship["targetFallback"] = Record.Interface.Name;
1134   Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo);
1135   Relationships.emplace_back(std::move(Relationship));
1136 
1137   auto ObjCCategory = serializeAPIRecord(Record);
1138 
1139   if (!ObjCCategory)
1140     return;
1141 
1142   Symbols.emplace_back(std::move(*ObjCCategory));
1143   serializeMembers(Record, Record.Methods);
1144   serializeMembers(Record, Record.Properties);
1145 
1146   // Surface the protocols of the category to the interface.
1147   for (const auto &Protocol : Record.Protocols)
1148     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1149 }
1150 
1151 void SymbolGraphSerializer::visitMacroDefinitionRecord(
1152     const MacroDefinitionRecord &Record) {
1153   auto Macro = serializeAPIRecord(Record);
1154 
1155   if (!Macro)
1156     return;
1157 
1158   Symbols.emplace_back(std::move(*Macro));
1159 }
1160 
1161 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1162   switch (Record->getKind()) {
1163   case APIRecord::RK_Unknown:
1164     llvm_unreachable("Records should have a known kind!");
1165   case APIRecord::RK_GlobalFunction:
1166     visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
1167     break;
1168   case APIRecord::RK_GlobalVariable:
1169     visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
1170     break;
1171   case APIRecord::RK_Enum:
1172     visitEnumRecord(*cast<EnumRecord>(Record));
1173     break;
1174   case APIRecord::RK_Struct:
1175     LLVM_FALLTHROUGH;
1176   case APIRecord::RK_Union:
1177     visitRecordRecord(*cast<RecordRecord>(Record));
1178     break;
1179   case APIRecord::RK_StaticField:
1180     visitStaticFieldRecord(*cast<StaticFieldRecord>(Record));
1181     break;
1182   case APIRecord::RK_CXXClass:
1183     visitCXXClassRecord(*cast<CXXClassRecord>(Record));
1184     break;
1185   case APIRecord::RK_ObjCInterface:
1186     visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
1187     break;
1188   case APIRecord::RK_ObjCProtocol:
1189     visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
1190     break;
1191   case APIRecord::RK_ObjCCategory:
1192     visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record));
1193     break;
1194   case APIRecord::RK_MacroDefinition:
1195     visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
1196     break;
1197   case APIRecord::RK_Typedef:
1198     visitTypedefRecord(*cast<TypedefRecord>(Record));
1199     break;
1200   default:
1201     if (auto Obj = serializeAPIRecord(*Record)) {
1202       Symbols.emplace_back(std::move(*Obj));
1203       auto &ParentInformation = Record->ParentInformation;
1204       if (!ParentInformation.empty())
1205         serializeRelationship(RelationshipKind::MemberOf, *Record,
1206                               *ParentInformation.ParentRecord);
1207     }
1208     break;
1209   }
1210 }
1211 
1212 void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) {
1213   // Typedefs of anonymous types have their entries unified with the underlying
1214   // type.
1215   bool ShouldDrop = Record.UnderlyingType.Name.empty();
1216   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
1217   // the same name
1218   ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
1219   if (ShouldDrop)
1220     return;
1221 
1222   auto Typedef = serializeAPIRecord(Record);
1223   if (!Typedef)
1224     return;
1225 
1226   (*Typedef)["type"] = Record.UnderlyingType.USR;
1227 
1228   Symbols.emplace_back(std::move(*Typedef));
1229 }
1230 
1231 Object SymbolGraphSerializer::serialize() {
1232   traverseAPISet();
1233   return serializeCurrentGraph();
1234 }
1235 
1236 Object SymbolGraphSerializer::serializeCurrentGraph() {
1237   Object Root;
1238   serializeObject(Root, "metadata", serializeMetadata());
1239   serializeObject(Root, "module", serializeModule());
1240 
1241   Root["symbols"] = std::move(Symbols);
1242   Root["relationships"] = std::move(Relationships);
1243 
1244   return Root;
1245 }
1246 
1247 void SymbolGraphSerializer::serialize(raw_ostream &os) {
1248   Object root = serialize();
1249   if (Options.Compact)
1250     os << formatv("{0}", Value(std::move(root))) << "\n";
1251   else
1252     os << formatv("{0:2}", Value(std::move(root))) << "\n";
1253 }
1254 
1255 std::optional<Object>
1256 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1257                                                 const APISet &API) {
1258   APIRecord *Record = API.findRecordForUSR(USR);
1259   if (!Record)
1260     return {};
1261 
1262   Object Root;
1263   APIIgnoresList EmptyIgnores;
1264   SymbolGraphSerializer Serializer(API, EmptyIgnores,
1265                                    /*Options.Compact*/ {true},
1266                                    /*ShouldRecurse*/ false);
1267   Serializer.serializeSingleRecord(Record);
1268   serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
1269 
1270   Language Lang = API.getLanguage();
1271   serializeArray(Root, "parentContexts",
1272                  generateParentContexts(*Record, API, Lang));
1273 
1274   Array RelatedSymbols;
1275 
1276   for (const auto &Fragment : Record->Declaration.getFragments()) {
1277     // If we don't have a USR there isn't much we can do.
1278     if (Fragment.PreciseIdentifier.empty())
1279       continue;
1280 
1281     APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1282 
1283     // If we can't find the record let's skip.
1284     if (!RelatedRecord)
1285       continue;
1286 
1287     Object RelatedSymbol;
1288     RelatedSymbol["usr"] = RelatedRecord->USR;
1289     RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1290     // TODO: once we record this properly let's serialize it right.
1291     RelatedSymbol["accessLevel"] = "public";
1292     RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1293     RelatedSymbol["moduleName"] = API.ProductName;
1294     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1295 
1296     serializeArray(RelatedSymbol, "parentContexts",
1297                    generateParentContexts(*RelatedRecord, API, Lang));
1298     RelatedSymbols.push_back(std::move(RelatedSymbol));
1299   }
1300 
1301   serializeArray(Root, "relatedSymbols", RelatedSymbols);
1302   return Root;
1303 }
1304