xref: /llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision 1be4a67454b02dae4df2368af31b5f655736d829)
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/DeclarationFragments.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/STLFunctionalExtras.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/Support/Casting.h"
23 #include "llvm/Support/Compiler.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/VersionTuple.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <iterator>
28 #include <optional>
29 #include <type_traits>
30 
31 using namespace clang;
32 using namespace clang::extractapi;
33 using namespace llvm;
34 
35 namespace {
36 
37 /// Helper function to inject a JSON object \p Obj into another object \p Paren
38 /// at position \p Key.
39 void serializeObject(Object &Paren, StringRef Key,
40                      std::optional<Object> &&Obj) {
41   if (Obj)
42     Paren[Key] = std::move(*Obj);
43 }
44 
45 /// Helper function to inject a JSON array \p Array into object \p Paren at
46 /// position \p Key.
47 void serializeArray(Object &Paren, StringRef Key,
48                     std::optional<Array> &&Array) {
49   if (Array)
50     Paren[Key] = std::move(*Array);
51 }
52 
53 /// Helper function to inject a JSON array composed of the values in \p C into
54 /// object \p Paren at position \p Key.
55 template <typename ContainerTy>
56 void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) {
57   Paren[Key] = Array(C);
58 }
59 
60 /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
61 /// format.
62 ///
63 /// A semantic version object contains three numeric fields, representing the
64 /// \c major, \c minor, and \c patch parts of the version tuple.
65 /// For example version tuple 1.0.3 is serialized as:
66 /// \code
67 ///   {
68 ///     "major" : 1,
69 ///     "minor" : 0,
70 ///     "patch" : 3
71 ///   }
72 /// \endcode
73 ///
74 /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
75 /// containing the semantic version representation of \p V.
76 std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
77   if (V.empty())
78     return std::nullopt;
79 
80   Object Version;
81   Version["major"] = V.getMajor();
82   Version["minor"] = V.getMinor().value_or(0);
83   Version["patch"] = V.getSubminor().value_or(0);
84   return Version;
85 }
86 
87 /// Serialize the OS information in the Symbol Graph platform property.
88 ///
89 /// The OS information in Symbol Graph contains the \c name of the OS, and an
90 /// optional \c minimumVersion semantic version field.
91 Object serializeOperatingSystem(const Triple &T) {
92   Object OS;
93   OS["name"] = T.getOSTypeName(T.getOS());
94   serializeObject(OS, "minimumVersion",
95                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
96   return OS;
97 }
98 
99 /// Serialize the platform information in the Symbol Graph module section.
100 ///
101 /// The platform object describes a target platform triple in corresponding
102 /// three fields: \c architecture, \c vendor, and \c operatingSystem.
103 Object serializePlatform(const Triple &T) {
104   Object Platform;
105   Platform["architecture"] = T.getArchName();
106   Platform["vendor"] = T.getVendorName();
107 
108   if (!T.getEnvironmentName().empty())
109     Platform["environment"] = T.getEnvironmentName();
110 
111   Platform["operatingSystem"] = serializeOperatingSystem(T);
112   return Platform;
113 }
114 
115 /// Serialize a source position.
116 Object serializeSourcePosition(const PresumedLoc &Loc) {
117   assert(Loc.isValid() && "invalid source position");
118 
119   Object SourcePosition;
120   SourcePosition["line"] = Loc.getLine() - 1;
121   SourcePosition["character"] = Loc.getColumn() - 1;
122 
123   return SourcePosition;
124 }
125 
126 /// Serialize a source location in file.
127 ///
128 /// \param Loc The presumed location to serialize.
129 /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
130 /// Defaults to false.
131 Object serializeSourceLocation(const PresumedLoc &Loc,
132                                bool IncludeFileURI = false) {
133   Object SourceLocation;
134   serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
135 
136   if (IncludeFileURI) {
137     std::string FileURI = "file://";
138     // Normalize file path to use forward slashes for the URI.
139     FileURI += sys::path::convert_to_slash(Loc.getFilename());
140     SourceLocation["uri"] = FileURI;
141   }
142 
143   return SourceLocation;
144 }
145 
146 /// Serialize a source range with begin and end locations.
147 Object serializeSourceRange(const PresumedLoc &BeginLoc,
148                             const PresumedLoc &EndLoc) {
149   Object SourceRange;
150   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
151   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
152   return SourceRange;
153 }
154 
155 /// Serialize the availability attributes of a symbol.
156 ///
157 /// Availability information contains the introduced, deprecated, and obsoleted
158 /// versions of the symbol as semantic versions, if not default.
159 /// Availability information also contains flags to indicate if the symbol is
160 /// unconditionally unavailable or deprecated,
161 /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
162 ///
163 /// \returns \c std::nullopt if the symbol has default availability attributes,
164 /// or an \c Array containing an object with the formatted availability
165 /// information.
166 std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
167   if (Avail.isDefault())
168     return std::nullopt;
169 
170   Array AvailabilityArray;
171 
172   if (Avail.isUnconditionallyDeprecated()) {
173     Object UnconditionallyDeprecated;
174     UnconditionallyDeprecated["domain"] = "*";
175     UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
176     AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
177   }
178 
179   if (Avail.Domain.str() != "") {
180     Object Availability;
181     Availability["domain"] = Avail.Domain;
182 
183     if (Avail.isUnavailable()) {
184       Availability["isUnconditionallyUnavailable"] = true;
185     } else {
186       serializeObject(Availability, "introduced",
187                       serializeSemanticVersion(Avail.Introduced));
188       serializeObject(Availability, "deprecated",
189                       serializeSemanticVersion(Avail.Deprecated));
190       serializeObject(Availability, "obsoleted",
191                       serializeSemanticVersion(Avail.Obsoleted));
192     }
193 
194     AvailabilityArray.emplace_back(std::move(Availability));
195   }
196 
197   return AvailabilityArray;
198 }
199 
200 /// Get the language name string for interface language references.
201 StringRef getLanguageName(Language Lang) {
202   switch (Lang) {
203   case Language::C:
204     return "c";
205   case Language::ObjC:
206     return "objective-c";
207   case Language::CXX:
208     return "c++";
209   case Language::ObjCXX:
210     return "objective-c++";
211 
212   // Unsupported language currently
213   case Language::OpenCL:
214   case Language::OpenCLCXX:
215   case Language::CUDA:
216   case Language::HIP:
217   case Language::HLSL:
218 
219   // Languages that the frontend cannot parse and compile
220   case Language::Unknown:
221   case Language::Asm:
222   case Language::LLVM_IR:
223   case Language::CIR:
224     llvm_unreachable("Unsupported language kind");
225   }
226 
227   llvm_unreachable("Unhandled language kind");
228 }
229 
230 /// Serialize the identifier object as specified by the Symbol Graph format.
231 ///
232 /// The identifier property of a symbol contains the USR for precise and unique
233 /// references, and the interface language name.
234 Object serializeIdentifier(const APIRecord &Record, Language Lang) {
235   Object Identifier;
236   Identifier["precise"] = Record.USR;
237   Identifier["interfaceLanguage"] = getLanguageName(Lang);
238 
239   return Identifier;
240 }
241 
242 /// Serialize the documentation comments attached to a symbol, as specified by
243 /// the Symbol Graph format.
244 ///
245 /// The Symbol Graph \c docComment object contains an array of lines. Each line
246 /// represents one line of striped documentation comment, with source range
247 /// information.
248 /// e.g.
249 /// \code
250 ///   /// This is a documentation comment
251 ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
252 ///   ///     with multiple lines.
253 ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
254 /// \endcode
255 ///
256 /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
257 /// the formatted lines.
258 std::optional<Object> serializeDocComment(const DocComment &Comment) {
259   if (Comment.empty())
260     return std::nullopt;
261 
262   Object DocComment;
263 
264   Array LinesArray;
265   for (const auto &CommentLine : Comment) {
266     Object Line;
267     Line["text"] = CommentLine.Text;
268     serializeObject(Line, "range",
269                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
270     LinesArray.emplace_back(std::move(Line));
271   }
272 
273   serializeArray(DocComment, "lines", std::move(LinesArray));
274 
275   return DocComment;
276 }
277 
278 /// Serialize the declaration fragments of a symbol.
279 ///
280 /// The Symbol Graph declaration fragments is an array of tagged important
281 /// parts of a symbol's declaration. The fragments sequence can be joined to
282 /// form spans of declaration text, with attached information useful for
283 /// purposes like syntax-highlighting etc. For example:
284 /// \code
285 ///   const int pi; -> "declarationFragments" : [
286 ///                      {
287 ///                        "kind" : "keyword",
288 ///                        "spelling" : "const"
289 ///                      },
290 ///                      {
291 ///                        "kind" : "text",
292 ///                        "spelling" : " "
293 ///                      },
294 ///                      {
295 ///                        "kind" : "typeIdentifier",
296 ///                        "preciseIdentifier" : "c:I",
297 ///                        "spelling" : "int"
298 ///                      },
299 ///                      {
300 ///                        "kind" : "text",
301 ///                        "spelling" : " "
302 ///                      },
303 ///                      {
304 ///                        "kind" : "identifier",
305 ///                        "spelling" : "pi"
306 ///                      }
307 ///                    ]
308 /// \endcode
309 ///
310 /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
311 /// formatted declaration fragments array.
312 std::optional<Array>
313 serializeDeclarationFragments(const DeclarationFragments &DF) {
314   if (DF.getFragments().empty())
315     return std::nullopt;
316 
317   Array Fragments;
318   for (const auto &F : DF.getFragments()) {
319     Object Fragment;
320     Fragment["spelling"] = F.Spelling;
321     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
322     if (!F.PreciseIdentifier.empty())
323       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
324     Fragments.emplace_back(std::move(Fragment));
325   }
326 
327   return Fragments;
328 }
329 
330 /// Serialize the \c names field of a symbol as specified by the Symbol Graph
331 /// format.
332 ///
333 /// The Symbol Graph names field contains multiple representations of a symbol
334 /// that can be used for different applications:
335 ///   - \c title : The simple declared name of the symbol;
336 ///   - \c subHeading : An array of declaration fragments that provides tags,
337 ///     and potentially more tokens (for example the \c +/- symbol for
338 ///     Objective-C methods). Can be used as sub-headings for documentation.
339 Object serializeNames(const APIRecord *Record) {
340   Object Names;
341   Names["title"] = Record->Name;
342 
343   serializeArray(Names, "subHeading",
344                  serializeDeclarationFragments(Record->SubHeading));
345   DeclarationFragments NavigatorFragments;
346   NavigatorFragments.append(Record->Name,
347                             DeclarationFragments::FragmentKind::Identifier,
348                             /*PreciseIdentifier*/ "");
349   serializeArray(Names, "navigator",
350                  serializeDeclarationFragments(NavigatorFragments));
351 
352   return Names;
353 }
354 
355 Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
356   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
357     return (getLanguageName(Lang) + "." + S).str();
358   };
359 
360   Object Kind;
361   switch (RK) {
362   case APIRecord::RK_Unknown:
363     Kind["identifier"] = AddLangPrefix("unknown");
364     Kind["displayName"] = "Unknown";
365     break;
366   case APIRecord::RK_Namespace:
367     Kind["identifier"] = AddLangPrefix("namespace");
368     Kind["displayName"] = "Namespace";
369     break;
370   case APIRecord::RK_GlobalFunction:
371     Kind["identifier"] = AddLangPrefix("func");
372     Kind["displayName"] = "Function";
373     break;
374   case APIRecord::RK_GlobalFunctionTemplate:
375     Kind["identifier"] = AddLangPrefix("func");
376     Kind["displayName"] = "Function Template";
377     break;
378   case APIRecord::RK_GlobalFunctionTemplateSpecialization:
379     Kind["identifier"] = AddLangPrefix("func");
380     Kind["displayName"] = "Function Template Specialization";
381     break;
382   case APIRecord::RK_GlobalVariableTemplate:
383     Kind["identifier"] = AddLangPrefix("var");
384     Kind["displayName"] = "Global Variable Template";
385     break;
386   case APIRecord::RK_GlobalVariableTemplateSpecialization:
387     Kind["identifier"] = AddLangPrefix("var");
388     Kind["displayName"] = "Global Variable Template Specialization";
389     break;
390   case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
391     Kind["identifier"] = AddLangPrefix("var");
392     Kind["displayName"] = "Global Variable Template Partial Specialization";
393     break;
394   case APIRecord::RK_GlobalVariable:
395     Kind["identifier"] = AddLangPrefix("var");
396     Kind["displayName"] = "Global Variable";
397     break;
398   case APIRecord::RK_EnumConstant:
399     Kind["identifier"] = AddLangPrefix("enum.case");
400     Kind["displayName"] = "Enumeration Case";
401     break;
402   case APIRecord::RK_Enum:
403     Kind["identifier"] = AddLangPrefix("enum");
404     Kind["displayName"] = "Enumeration";
405     break;
406   case APIRecord::RK_StructField:
407     Kind["identifier"] = AddLangPrefix("property");
408     Kind["displayName"] = "Instance Property";
409     break;
410   case APIRecord::RK_Struct:
411     Kind["identifier"] = AddLangPrefix("struct");
412     Kind["displayName"] = "Structure";
413     break;
414   case APIRecord::RK_UnionField:
415     Kind["identifier"] = AddLangPrefix("property");
416     Kind["displayName"] = "Instance Property";
417     break;
418   case APIRecord::RK_Union:
419     Kind["identifier"] = AddLangPrefix("union");
420     Kind["displayName"] = "Union";
421     break;
422   case APIRecord::RK_CXXField:
423     Kind["identifier"] = AddLangPrefix("property");
424     Kind["displayName"] = "Instance Property";
425     break;
426   case APIRecord::RK_StaticField:
427     Kind["identifier"] = AddLangPrefix("type.property");
428     Kind["displayName"] = "Type Property";
429     break;
430   case APIRecord::RK_ClassTemplate:
431   case APIRecord::RK_ClassTemplateSpecialization:
432   case APIRecord::RK_ClassTemplatePartialSpecialization:
433   case APIRecord::RK_CXXClass:
434     Kind["identifier"] = AddLangPrefix("class");
435     Kind["displayName"] = "Class";
436     break;
437   case APIRecord::RK_CXXMethodTemplate:
438     Kind["identifier"] = AddLangPrefix("method");
439     Kind["displayName"] = "Method Template";
440     break;
441   case APIRecord::RK_CXXMethodTemplateSpecialization:
442     Kind["identifier"] = AddLangPrefix("method");
443     Kind["displayName"] = "Method Template Specialization";
444     break;
445   case APIRecord::RK_CXXFieldTemplate:
446     Kind["identifier"] = AddLangPrefix("property");
447     Kind["displayName"] = "Template Property";
448     break;
449   case APIRecord::RK_Concept:
450     Kind["identifier"] = AddLangPrefix("concept");
451     Kind["displayName"] = "Concept";
452     break;
453   case APIRecord::RK_CXXStaticMethod:
454     Kind["identifier"] = AddLangPrefix("type.method");
455     Kind["displayName"] = "Static Method";
456     break;
457   case APIRecord::RK_CXXInstanceMethod:
458     Kind["identifier"] = AddLangPrefix("method");
459     Kind["displayName"] = "Instance Method";
460     break;
461   case APIRecord::RK_CXXConstructorMethod:
462     Kind["identifier"] = AddLangPrefix("method");
463     Kind["displayName"] = "Constructor";
464     break;
465   case APIRecord::RK_CXXDestructorMethod:
466     Kind["identifier"] = AddLangPrefix("method");
467     Kind["displayName"] = "Destructor";
468     break;
469   case APIRecord::RK_ObjCIvar:
470     Kind["identifier"] = AddLangPrefix("ivar");
471     Kind["displayName"] = "Instance Variable";
472     break;
473   case APIRecord::RK_ObjCInstanceMethod:
474     Kind["identifier"] = AddLangPrefix("method");
475     Kind["displayName"] = "Instance Method";
476     break;
477   case APIRecord::RK_ObjCClassMethod:
478     Kind["identifier"] = AddLangPrefix("type.method");
479     Kind["displayName"] = "Type Method";
480     break;
481   case APIRecord::RK_ObjCInstanceProperty:
482     Kind["identifier"] = AddLangPrefix("property");
483     Kind["displayName"] = "Instance Property";
484     break;
485   case APIRecord::RK_ObjCClassProperty:
486     Kind["identifier"] = AddLangPrefix("type.property");
487     Kind["displayName"] = "Type Property";
488     break;
489   case APIRecord::RK_ObjCInterface:
490     Kind["identifier"] = AddLangPrefix("class");
491     Kind["displayName"] = "Class";
492     break;
493   case APIRecord::RK_ObjCCategory:
494     Kind["identifier"] = AddLangPrefix("class.extension");
495     Kind["displayName"] = "Class Extension";
496     break;
497   case APIRecord::RK_ObjCProtocol:
498     Kind["identifier"] = AddLangPrefix("protocol");
499     Kind["displayName"] = "Protocol";
500     break;
501   case APIRecord::RK_MacroDefinition:
502     Kind["identifier"] = AddLangPrefix("macro");
503     Kind["displayName"] = "Macro";
504     break;
505   case APIRecord::RK_Typedef:
506     Kind["identifier"] = AddLangPrefix("typealias");
507     Kind["displayName"] = "Type Alias";
508     break;
509   default:
510     llvm_unreachable("API Record with uninstantiable kind");
511   }
512 
513   return Kind;
514 }
515 
516 /// Serialize the symbol kind information.
517 ///
518 /// The Symbol Graph symbol kind property contains a shorthand \c identifier
519 /// which is prefixed by the source language name, useful for tooling to parse
520 /// the kind, and a \c displayName for rendering human-readable names.
521 Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
522   return serializeSymbolKind(Record.KindForDisplay, Lang);
523 }
524 
525 /// Serialize the function signature field, as specified by the
526 /// Symbol Graph format.
527 ///
528 /// The Symbol Graph function signature property contains two arrays.
529 ///   - The \c returns array is the declaration fragments of the return type;
530 ///   - The \c parameters array contains names and declaration fragments of the
531 ///     parameters.
532 template <typename RecordTy>
533 void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
534   const auto &FS = Record.Signature;
535   if (FS.empty())
536     return;
537 
538   Object Signature;
539   serializeArray(Signature, "returns",
540                  serializeDeclarationFragments(FS.getReturnType()));
541 
542   Array Parameters;
543   for (const auto &P : FS.getParameters()) {
544     Object Parameter;
545     Parameter["name"] = P.Name;
546     serializeArray(Parameter, "declarationFragments",
547                    serializeDeclarationFragments(P.Fragments));
548     Parameters.emplace_back(std::move(Parameter));
549   }
550 
551   if (!Parameters.empty())
552     Signature["parameters"] = std::move(Parameters);
553 
554   serializeObject(Paren, "functionSignature", std::move(Signature));
555 }
556 
557 template <typename RecordTy>
558 void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
559   const auto &Template = Record.Templ;
560   if (Template.empty())
561     return;
562 
563   Object Generics;
564   Array GenericParameters;
565   for (const auto &Param : Template.getParameters()) {
566     Object Parameter;
567     Parameter["name"] = Param.Name;
568     Parameter["index"] = Param.Index;
569     Parameter["depth"] = Param.Depth;
570     GenericParameters.emplace_back(std::move(Parameter));
571   }
572   if (!GenericParameters.empty())
573     Generics["parameters"] = std::move(GenericParameters);
574 
575   Array GenericConstraints;
576   for (const auto &Constr : Template.getConstraints()) {
577     Object Constraint;
578     Constraint["kind"] = Constr.Kind;
579     Constraint["lhs"] = Constr.LHS;
580     Constraint["rhs"] = Constr.RHS;
581     GenericConstraints.emplace_back(std::move(Constraint));
582   }
583 
584   if (!GenericConstraints.empty())
585     Generics["constraints"] = std::move(GenericConstraints);
586 
587   serializeObject(Paren, "swiftGenerics", Generics);
588 }
589 
590 Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents,
591                              Language Lang) {
592   Array ParentContexts;
593 
594   for (const auto &Parent : Parents) {
595     Object Elem;
596     Elem["usr"] = Parent.USR;
597     Elem["name"] = Parent.Name;
598     if (Parent.Record)
599       Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay,
600                                          Lang)["identifier"];
601     else
602       Elem["kind"] =
603           serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"];
604     ParentContexts.emplace_back(std::move(Elem));
605   }
606 
607   return ParentContexts;
608 }
609 
610 /// Walk the records parent information in reverse to generate a hierarchy
611 /// suitable for serialization.
612 SmallVector<SymbolReference, 8>
613 generateHierarchyFromRecord(const APIRecord *Record) {
614   SmallVector<SymbolReference, 8> ReverseHierarchy;
615   for (const auto *Current = Record; Current != nullptr;
616        Current = Current->Parent.Record)
617     ReverseHierarchy.emplace_back(Current);
618 
619   return SmallVector<SymbolReference, 8>(
620       std::make_move_iterator(ReverseHierarchy.rbegin()),
621       std::make_move_iterator(ReverseHierarchy.rend()));
622 }
623 
624 SymbolReference getHierarchyReference(const APIRecord *Record,
625                                       const APISet &API) {
626   // If the parent is a category extended from internal module then we need to
627   // pretend this belongs to the associated interface.
628   if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) {
629     return CategoryRecord->Interface;
630     // FIXME: TODO generate path components correctly for categories extending
631     // an external module.
632   }
633 
634   return SymbolReference(Record);
635 }
636 
637 } // namespace
638 
639 Object *ExtendedModule::addSymbol(Object &&Symbol) {
640   Symbols.emplace_back(std::move(Symbol));
641   return Symbols.back().getAsObject();
642 }
643 
644 void ExtendedModule::addRelationship(Object &&Relationship) {
645   Relationships.emplace_back(std::move(Relationship));
646 }
647 
648 /// Defines the format version emitted by SymbolGraphSerializer.
649 const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
650 
651 Object SymbolGraphSerializer::serializeMetadata() const {
652   Object Metadata;
653   serializeObject(Metadata, "formatVersion",
654                   serializeSemanticVersion(FormatVersion));
655   Metadata["generator"] = clang::getClangFullVersion();
656   return Metadata;
657 }
658 
659 Object
660 SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const {
661   Object Module;
662   Module["name"] = ModuleName;
663   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
664   return Module;
665 }
666 
667 bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {
668   if (!Record)
669     return true;
670 
671   // Skip unconditionally unavailable symbols
672   if (Record->Availability.isUnconditionallyUnavailable())
673     return true;
674 
675   // Filter out symbols prefixed with an underscored as they are understood to
676   // be symbols clients should not use.
677   if (Record->Name.starts_with("_"))
678     return true;
679 
680   // Skip explicitly ignored symbols.
681   if (IgnoresList.shouldIgnore(Record->Name))
682     return true;
683 
684   return false;
685 }
686 
687 ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {
688   if (!ForceEmitToMainModule && ModuleForCurrentSymbol)
689     return *ModuleForCurrentSymbol;
690 
691   return MainModule;
692 }
693 
694 Array SymbolGraphSerializer::serializePathComponents(
695     const APIRecord *Record) const {
696   return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));
697 }
698 
699 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
700   switch (Kind) {
701   case RelationshipKind::MemberOf:
702     return "memberOf";
703   case RelationshipKind::InheritsFrom:
704     return "inheritsFrom";
705   case RelationshipKind::ConformsTo:
706     return "conformsTo";
707   case RelationshipKind::ExtensionTo:
708     return "extensionTo";
709   }
710   llvm_unreachable("Unhandled relationship kind");
711 }
712 
713 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
714                                                   const SymbolReference &Source,
715                                                   const SymbolReference &Target,
716                                                   ExtendedModule &Into) {
717   Object Relationship;
718   SmallString<64> TestRelLabel;
719   if (EmitSymbolLabelsForTesting) {
720     llvm::raw_svector_ostream OS(TestRelLabel);
721     OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ "
722        << Source.USR << " $ ";
723     if (Target.USR.empty())
724       OS << Target.Name;
725     else
726       OS << Target.USR;
727     Relationship["!testRelLabel"] = TestRelLabel;
728   }
729   Relationship["source"] = Source.USR;
730   Relationship["target"] = Target.USR;
731   Relationship["targetFallback"] = Target.Name;
732   Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind);
733 
734   if (ForceEmitToMainModule)
735     MainModule.addRelationship(std::move(Relationship));
736   else
737     Into.addRelationship(std::move(Relationship));
738 }
739 
740 StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
741   switch (Kind) {
742   case ConstraintKind::Conformance:
743     return "conformance";
744   case ConstraintKind::ConditionalConformance:
745     return "conditionalConformance";
746   }
747   llvm_unreachable("Unhandled constraint kind");
748 }
749 
750 void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) {
751   Object Obj;
752 
753   // If we need symbol labels for testing emit the USR as the value and the key
754   // starts with '!'' to ensure it ends up at the top of the object.
755   if (EmitSymbolLabelsForTesting)
756     Obj["!testLabel"] = Record->USR;
757 
758   serializeObject(Obj, "identifier",
759                   serializeIdentifier(*Record, API.getLanguage()));
760   serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage()));
761   serializeObject(Obj, "names", serializeNames(Record));
762   serializeObject(
763       Obj, "location",
764       serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true));
765   serializeArray(Obj, "availability",
766                  serializeAvailability(Record->Availability));
767   serializeObject(Obj, "docComment", serializeDocComment(Record->Comment));
768   serializeArray(Obj, "declarationFragments",
769                  serializeDeclarationFragments(Record->Declaration));
770 
771   Obj["pathComponents"] = serializePathComponents(Record);
772   Obj["accessLevel"] = Record->Access.getAccess();
773 
774   ExtendedModule &Module = getModuleForCurrentSymbol();
775   // If the hierarchy has at least one parent and child.
776   if (Hierarchy.size() >= 2)
777     serializeRelationship(MemberOf, Hierarchy.back(),
778                           Hierarchy[Hierarchy.size() - 2], Module);
779 
780   CurrentSymbol = Module.addSymbol(std::move(Obj));
781 }
782 
783 bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) {
784   if (!Record)
785     return true;
786   if (shouldSkip(Record))
787     return true;
788   Hierarchy.push_back(getHierarchyReference(Record, API));
789   // Defer traversal mechanics to APISetVisitor base implementation
790   auto RetVal = Base::traverseAPIRecord(Record);
791   Hierarchy.pop_back();
792   return RetVal;
793 }
794 
795 bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) {
796   serializeAPIRecord(Record);
797   return true;
798 }
799 
800 bool SymbolGraphSerializer::visitGlobalFunctionRecord(
801     const GlobalFunctionRecord *Record) {
802   if (!CurrentSymbol)
803     return true;
804 
805   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
806   return true;
807 }
808 
809 bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) {
810   if (!CurrentSymbol)
811     return true;
812 
813   for (const auto &Base : Record->Bases)
814     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base,
815                           getModuleForCurrentSymbol());
816   return true;
817 }
818 
819 bool SymbolGraphSerializer::visitClassTemplateRecord(
820     const ClassTemplateRecord *Record) {
821   if (!CurrentSymbol)
822     return true;
823 
824   serializeTemplateMixin(*CurrentSymbol, *Record);
825   return true;
826 }
827 
828 bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
829     const ClassTemplatePartialSpecializationRecord *Record) {
830   if (!CurrentSymbol)
831     return true;
832 
833   serializeTemplateMixin(*CurrentSymbol, *Record);
834   return true;
835 }
836 
837 bool SymbolGraphSerializer::visitCXXMethodRecord(
838     const CXXMethodRecord *Record) {
839   if (!CurrentSymbol)
840     return true;
841 
842   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
843   return true;
844 }
845 
846 bool SymbolGraphSerializer::visitCXXMethodTemplateRecord(
847     const CXXMethodTemplateRecord *Record) {
848   if (!CurrentSymbol)
849     return true;
850 
851   serializeTemplateMixin(*CurrentSymbol, *Record);
852   return true;
853 }
854 
855 bool SymbolGraphSerializer::visitCXXFieldTemplateRecord(
856     const CXXFieldTemplateRecord *Record) {
857   if (!CurrentSymbol)
858     return true;
859 
860   serializeTemplateMixin(*CurrentSymbol, *Record);
861   return true;
862 }
863 
864 bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) {
865   if (!CurrentSymbol)
866     return true;
867 
868   serializeTemplateMixin(*CurrentSymbol, *Record);
869   return true;
870 }
871 
872 bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
873     const GlobalVariableTemplateRecord *Record) {
874   if (!CurrentSymbol)
875     return true;
876 
877   serializeTemplateMixin(*CurrentSymbol, *Record);
878   return true;
879 }
880 
881 bool SymbolGraphSerializer::
882     visitGlobalVariableTemplatePartialSpecializationRecord(
883         const GlobalVariableTemplatePartialSpecializationRecord *Record) {
884   if (!CurrentSymbol)
885     return true;
886 
887   serializeTemplateMixin(*CurrentSymbol, *Record);
888   return true;
889 }
890 
891 bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
892     const GlobalFunctionTemplateRecord *Record) {
893   if (!CurrentSymbol)
894     return true;
895 
896   serializeTemplateMixin(*CurrentSymbol, *Record);
897   return true;
898 }
899 
900 bool SymbolGraphSerializer::visitObjCContainerRecord(
901     const ObjCContainerRecord *Record) {
902   if (!CurrentSymbol)
903     return true;
904 
905   for (const auto &Protocol : Record->Protocols)
906     serializeRelationship(ConformsTo, Record, Protocol,
907                           getModuleForCurrentSymbol());
908 
909   return true;
910 }
911 
912 bool SymbolGraphSerializer::visitObjCInterfaceRecord(
913     const ObjCInterfaceRecord *Record) {
914   if (!CurrentSymbol)
915     return true;
916 
917   if (!Record->SuperClass.empty())
918     serializeRelationship(InheritsFrom, Record, Record->SuperClass,
919                           getModuleForCurrentSymbol());
920   return true;
921 }
922 
923 bool SymbolGraphSerializer::traverseObjCCategoryRecord(
924     const ObjCCategoryRecord *Record) {
925   if (SkipSymbolsInCategoriesToExternalTypes &&
926       !API.findRecordForUSR(Record->Interface.USR))
927     return true;
928 
929   auto *CurrentModule = ModuleForCurrentSymbol;
930   if (auto ModuleExtendedByRecord = Record->getExtendedExternalModule())
931     ModuleForCurrentSymbol = &ExtendedModules[*ModuleExtendedByRecord];
932 
933   if (!walkUpFromObjCCategoryRecord(Record))
934     return false;
935 
936   bool RetVal = traverseRecordContext(Record);
937   ModuleForCurrentSymbol = CurrentModule;
938   return RetVal;
939 }
940 
941 bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord(
942     const ObjCCategoryRecord *Record) {
943   return visitObjCCategoryRecord(Record);
944 }
945 
946 bool SymbolGraphSerializer::visitObjCCategoryRecord(
947     const ObjCCategoryRecord *Record) {
948   // If we need to create a record for the category in the future do so here,
949   // otherwise everything is set up to pretend that the category is in fact the
950   // interface it extends.
951   for (const auto &Protocol : Record->Protocols)
952     serializeRelationship(ConformsTo, Record->Interface, Protocol,
953                           getModuleForCurrentSymbol());
954 
955   return true;
956 }
957 
958 bool SymbolGraphSerializer::visitObjCMethodRecord(
959     const ObjCMethodRecord *Record) {
960   if (!CurrentSymbol)
961     return true;
962 
963   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
964   return true;
965 }
966 
967 bool SymbolGraphSerializer::visitObjCInstanceVariableRecord(
968     const ObjCInstanceVariableRecord *Record) {
969   // FIXME: serialize ivar access control here.
970   return true;
971 }
972 
973 bool SymbolGraphSerializer::walkUpFromTypedefRecord(
974     const TypedefRecord *Record) {
975   // Short-circuit walking up the class hierarchy and handle creating typedef
976   // symbol objects manually as there are additional symbol dropping rules to
977   // respect.
978   return visitTypedefRecord(Record);
979 }
980 
981 bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) {
982   // Typedefs of anonymous types have their entries unified with the underlying
983   // type.
984   bool ShouldDrop = Record->UnderlyingType.Name.empty();
985   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
986   // the same name
987   ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
988   if (ShouldDrop)
989     return true;
990 
991   // Create the symbol record if the other symbol droppping rules permit it.
992   serializeAPIRecord(Record);
993   if (!CurrentSymbol)
994     return true;
995 
996   (*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
997 
998   return true;
999 }
1000 
1001 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1002   switch (Record->getKind()) {
1003     // dispatch to the relevant walkUpFromMethod
1004 #define CONCRETE_RECORD(CLASS, BASE, KIND)                                     \
1005   case APIRecord::KIND: {                                                      \
1006     walkUpFrom##CLASS(static_cast<const CLASS *>(Record));                     \
1007     break;                                                                     \
1008   }
1009 #include "clang/ExtractAPI/APIRecords.inc"
1010   // otherwise fallback on the only behavior we can implement safely.
1011   case APIRecord::RK_Unknown:
1012     visitAPIRecord(Record);
1013     break;
1014   default:
1015     llvm_unreachable("API Record with uninstantiable kind");
1016   }
1017 }
1018 
1019 Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1020                                              ExtendedModule &&EM) {
1021   Object Root;
1022   serializeObject(Root, "metadata", serializeMetadata());
1023   serializeObject(Root, "module", serializeModuleObject(ModuleName));
1024 
1025   Root["symbols"] = std::move(EM.Symbols);
1026   Root["relationships"] = std::move(EM.Relationships);
1027 
1028   return Root;
1029 }
1030 
1031 void SymbolGraphSerializer::serializeGraphToStream(
1032     raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1033     ExtendedModule &&EM) {
1034   Object Root = serializeGraph(ModuleName, std::move(EM));
1035   if (Options.Compact)
1036     OS << formatv("{0}", json::Value(std::move(Root))) << "\n";
1037   else
1038     OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n";
1039 }
1040 
1041 void SymbolGraphSerializer::serializeMainSymbolGraph(
1042     raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1043     SymbolGraphSerializerOption Options) {
1044   SymbolGraphSerializer Serializer(
1045       API, IgnoresList, Options.EmitSymbolLabelsForTesting,
1046       /*ForceEmitToMainModule=*/true,
1047       /*SkipSymbolsInCategoriesToExternalTypes=*/true);
1048 
1049   Serializer.traverseAPISet();
1050   Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1051                                     std::move(Serializer.MainModule));
1052   // FIXME: TODO handle extended modules here
1053 }
1054 
1055 void SymbolGraphSerializer::serializeWithExtensionGraphs(
1056     raw_ostream &MainOutput, const APISet &API,
1057     const APIIgnoresList &IgnoresList,
1058     llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1059         CreateOutputStream,
1060     SymbolGraphSerializerOption Options) {
1061   SymbolGraphSerializer Serializer(API, IgnoresList,
1062                                    Options.EmitSymbolLabelsForTesting);
1063   Serializer.traverseAPISet();
1064 
1065   Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1066                                     std::move(Serializer.MainModule));
1067 
1068   for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1069     if (auto ExtensionOS =
1070             CreateOutputStream(API.ProductName + "@" + ExtensionSGF.getKey()))
1071       Serializer.serializeGraphToStream(*ExtensionOS, Options, API.ProductName,
1072                                         std::move(ExtensionSGF.getValue()));
1073   }
1074 }
1075 
1076 std::optional<Object>
1077 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1078                                                 const APISet &API) {
1079   APIRecord *Record = API.findRecordForUSR(USR);
1080   if (!Record)
1081     return {};
1082 
1083   Object Root;
1084   APIIgnoresList EmptyIgnores;
1085   SymbolGraphSerializer Serializer(API, EmptyIgnores,
1086                                    /*EmitSymbolLabelsForTesting*/ false,
1087                                    /*ForceEmitToMainModule*/ true);
1088 
1089   // Set up serializer parent chain
1090   Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1091 
1092   Serializer.serializeSingleRecord(Record);
1093   serializeObject(Root, "symbolGraph",
1094                   Serializer.serializeGraph(API.ProductName,
1095                                             std::move(Serializer.MainModule)));
1096 
1097   Language Lang = API.getLanguage();
1098   serializeArray(Root, "parentContexts",
1099                  generateParentContexts(Serializer.Hierarchy, Lang));
1100 
1101   Array RelatedSymbols;
1102 
1103   for (const auto &Fragment : Record->Declaration.getFragments()) {
1104     // If we don't have a USR there isn't much we can do.
1105     if (Fragment.PreciseIdentifier.empty())
1106       continue;
1107 
1108     APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1109 
1110     // If we can't find the record let's skip.
1111     if (!RelatedRecord)
1112       continue;
1113 
1114     Object RelatedSymbol;
1115     RelatedSymbol["usr"] = RelatedRecord->USR;
1116     RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1117     RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
1118     RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1119     RelatedSymbol["moduleName"] = API.ProductName;
1120     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1121 
1122     serializeArray(RelatedSymbol, "parentContexts",
1123                    generateParentContexts(
1124                        generateHierarchyFromRecord(RelatedRecord), Lang));
1125 
1126     RelatedSymbols.push_back(std::move(RelatedSymbol));
1127   }
1128 
1129   serializeArray(Root, "relatedSymbols", RelatedSymbols);
1130   return Root;
1131 }
1132