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