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