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