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