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