xref: /llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision b18b4547f1bfaf6da37b29440a96176e807c2e6c)
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 without a name as we can generate correct symbol graphs
677   // for them. In practice these are anonymous record types that aren't attached
678   // to a declaration.
679   if (auto *Tag = dyn_cast<TagRecord>(Record)) {
680     if (Tag->IsEmbeddedInVarDeclarator)
681       return true;
682   }
683 
684   // Filter out symbols prefixed with an underscored as they are understood to
685   // be symbols clients should not use.
686   if (Record->Name.starts_with("_"))
687     return true;
688 
689   // Skip explicitly ignored symbols.
690   if (IgnoresList.shouldIgnore(Record->Name))
691     return true;
692 
693   return false;
694 }
695 
696 ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {
697   if (!ForceEmitToMainModule && ModuleForCurrentSymbol)
698     return *ModuleForCurrentSymbol;
699 
700   return MainModule;
701 }
702 
703 Array SymbolGraphSerializer::serializePathComponents(
704     const APIRecord *Record) const {
705   return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));
706 }
707 
708 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
709   switch (Kind) {
710   case RelationshipKind::MemberOf:
711     return "memberOf";
712   case RelationshipKind::InheritsFrom:
713     return "inheritsFrom";
714   case RelationshipKind::ConformsTo:
715     return "conformsTo";
716   case RelationshipKind::ExtensionTo:
717     return "extensionTo";
718   }
719   llvm_unreachable("Unhandled relationship kind");
720 }
721 
722 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
723                                                   const SymbolReference &Source,
724                                                   const SymbolReference &Target,
725                                                   ExtendedModule &Into) {
726   Object Relationship;
727   SmallString<64> TestRelLabel;
728   if (EmitSymbolLabelsForTesting) {
729     llvm::raw_svector_ostream OS(TestRelLabel);
730     OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ "
731        << Source.USR << " $ ";
732     if (Target.USR.empty())
733       OS << Target.Name;
734     else
735       OS << Target.USR;
736     Relationship["!testRelLabel"] = TestRelLabel;
737   }
738   Relationship["source"] = Source.USR;
739   Relationship["target"] = Target.USR;
740   Relationship["targetFallback"] = Target.Name;
741   Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind);
742 
743   if (ForceEmitToMainModule)
744     MainModule.addRelationship(std::move(Relationship));
745   else
746     Into.addRelationship(std::move(Relationship));
747 }
748 
749 StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
750   switch (Kind) {
751   case ConstraintKind::Conformance:
752     return "conformance";
753   case ConstraintKind::ConditionalConformance:
754     return "conditionalConformance";
755   }
756   llvm_unreachable("Unhandled constraint kind");
757 }
758 
759 void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) {
760   Object Obj;
761 
762   // If we need symbol labels for testing emit the USR as the value and the key
763   // starts with '!'' to ensure it ends up at the top of the object.
764   if (EmitSymbolLabelsForTesting)
765     Obj["!testLabel"] = Record->USR;
766 
767   serializeObject(Obj, "identifier",
768                   serializeIdentifier(*Record, API.getLanguage()));
769   serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage()));
770   serializeObject(Obj, "names", serializeNames(Record));
771   serializeObject(
772       Obj, "location",
773       serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true));
774   serializeArray(Obj, "availability",
775                  serializeAvailability(Record->Availability));
776   serializeObject(Obj, "docComment", serializeDocComment(Record->Comment));
777   serializeArray(Obj, "declarationFragments",
778                  serializeDeclarationFragments(Record->Declaration));
779 
780   Obj["pathComponents"] = serializePathComponents(Record);
781   Obj["accessLevel"] = Record->Access.getAccess();
782 
783   ExtendedModule &Module = getModuleForCurrentSymbol();
784   // If the hierarchy has at least one parent and child.
785   if (Hierarchy.size() >= 2)
786     serializeRelationship(MemberOf, Hierarchy.back(),
787                           Hierarchy[Hierarchy.size() - 2], Module);
788 
789   CurrentSymbol = Module.addSymbol(std::move(Obj));
790 }
791 
792 bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) {
793   if (!Record)
794     return true;
795   if (shouldSkip(Record))
796     return true;
797   Hierarchy.push_back(getHierarchyReference(Record, API));
798   // Defer traversal mechanics to APISetVisitor base implementation
799   auto RetVal = Base::traverseAPIRecord(Record);
800   Hierarchy.pop_back();
801   return RetVal;
802 }
803 
804 bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) {
805   serializeAPIRecord(Record);
806   return true;
807 }
808 
809 bool SymbolGraphSerializer::visitGlobalFunctionRecord(
810     const GlobalFunctionRecord *Record) {
811   if (!CurrentSymbol)
812     return true;
813 
814   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
815   return true;
816 }
817 
818 bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) {
819   if (!CurrentSymbol)
820     return true;
821 
822   for (const auto &Base : Record->Bases)
823     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base,
824                           getModuleForCurrentSymbol());
825   return true;
826 }
827 
828 bool SymbolGraphSerializer::visitClassTemplateRecord(
829     const ClassTemplateRecord *Record) {
830   if (!CurrentSymbol)
831     return true;
832 
833   serializeTemplateMixin(*CurrentSymbol, *Record);
834   return true;
835 }
836 
837 bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
838     const ClassTemplatePartialSpecializationRecord *Record) {
839   if (!CurrentSymbol)
840     return true;
841 
842   serializeTemplateMixin(*CurrentSymbol, *Record);
843   return true;
844 }
845 
846 bool SymbolGraphSerializer::visitCXXMethodRecord(
847     const CXXMethodRecord *Record) {
848   if (!CurrentSymbol)
849     return true;
850 
851   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
852   return true;
853 }
854 
855 bool SymbolGraphSerializer::visitCXXMethodTemplateRecord(
856     const CXXMethodTemplateRecord *Record) {
857   if (!CurrentSymbol)
858     return true;
859 
860   serializeTemplateMixin(*CurrentSymbol, *Record);
861   return true;
862 }
863 
864 bool SymbolGraphSerializer::visitCXXFieldTemplateRecord(
865     const CXXFieldTemplateRecord *Record) {
866   if (!CurrentSymbol)
867     return true;
868 
869   serializeTemplateMixin(*CurrentSymbol, *Record);
870   return true;
871 }
872 
873 bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) {
874   if (!CurrentSymbol)
875     return true;
876 
877   serializeTemplateMixin(*CurrentSymbol, *Record);
878   return true;
879 }
880 
881 bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
882     const GlobalVariableTemplateRecord *Record) {
883   if (!CurrentSymbol)
884     return true;
885 
886   serializeTemplateMixin(*CurrentSymbol, *Record);
887   return true;
888 }
889 
890 bool SymbolGraphSerializer::
891     visitGlobalVariableTemplatePartialSpecializationRecord(
892         const GlobalVariableTemplatePartialSpecializationRecord *Record) {
893   if (!CurrentSymbol)
894     return true;
895 
896   serializeTemplateMixin(*CurrentSymbol, *Record);
897   return true;
898 }
899 
900 bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
901     const GlobalFunctionTemplateRecord *Record) {
902   if (!CurrentSymbol)
903     return true;
904 
905   serializeTemplateMixin(*CurrentSymbol, *Record);
906   return true;
907 }
908 
909 bool SymbolGraphSerializer::visitObjCContainerRecord(
910     const ObjCContainerRecord *Record) {
911   if (!CurrentSymbol)
912     return true;
913 
914   for (const auto &Protocol : Record->Protocols)
915     serializeRelationship(ConformsTo, Record, Protocol,
916                           getModuleForCurrentSymbol());
917 
918   return true;
919 }
920 
921 bool SymbolGraphSerializer::visitObjCInterfaceRecord(
922     const ObjCInterfaceRecord *Record) {
923   if (!CurrentSymbol)
924     return true;
925 
926   if (!Record->SuperClass.empty())
927     serializeRelationship(InheritsFrom, Record, Record->SuperClass,
928                           getModuleForCurrentSymbol());
929   return true;
930 }
931 
932 bool SymbolGraphSerializer::traverseObjCCategoryRecord(
933     const ObjCCategoryRecord *Record) {
934   if (SkipSymbolsInCategoriesToExternalTypes &&
935       !API.findRecordForUSR(Record->Interface.USR))
936     return true;
937 
938   auto *CurrentModule = ModuleForCurrentSymbol;
939   if (Record->isExtendingExternalModule())
940     ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source];
941 
942   if (!walkUpFromObjCCategoryRecord(Record))
943     return false;
944 
945   bool RetVal = traverseRecordContext(Record);
946   ModuleForCurrentSymbol = CurrentModule;
947   return RetVal;
948 }
949 
950 bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord(
951     const ObjCCategoryRecord *Record) {
952   return visitObjCCategoryRecord(Record);
953 }
954 
955 bool SymbolGraphSerializer::visitObjCCategoryRecord(
956     const ObjCCategoryRecord *Record) {
957   // If we need to create a record for the category in the future do so here,
958   // otherwise everything is set up to pretend that the category is in fact the
959   // interface it extends.
960   for (const auto &Protocol : Record->Protocols)
961     serializeRelationship(ConformsTo, Record->Interface, Protocol,
962                           getModuleForCurrentSymbol());
963 
964   return true;
965 }
966 
967 bool SymbolGraphSerializer::visitObjCMethodRecord(
968     const ObjCMethodRecord *Record) {
969   if (!CurrentSymbol)
970     return true;
971 
972   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
973   return true;
974 }
975 
976 bool SymbolGraphSerializer::visitObjCInstanceVariableRecord(
977     const ObjCInstanceVariableRecord *Record) {
978   // FIXME: serialize ivar access control here.
979   return true;
980 }
981 
982 bool SymbolGraphSerializer::walkUpFromTypedefRecord(
983     const TypedefRecord *Record) {
984   // Short-circuit walking up the class hierarchy and handle creating typedef
985   // symbol objects manually as there are additional symbol dropping rules to
986   // respect.
987   return visitTypedefRecord(Record);
988 }
989 
990 bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) {
991   // Typedefs of anonymous types have their entries unified with the underlying
992   // type.
993   bool ShouldDrop = Record->UnderlyingType.Name.empty();
994   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
995   // the same name
996   ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
997   if (ShouldDrop)
998     return true;
999 
1000   // Create the symbol record if the other symbol droppping rules permit it.
1001   serializeAPIRecord(Record);
1002   if (!CurrentSymbol)
1003     return true;
1004 
1005   (*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
1006 
1007   return true;
1008 }
1009 
1010 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1011   switch (Record->getKind()) {
1012     // dispatch to the relevant walkUpFromMethod
1013 #define CONCRETE_RECORD(CLASS, BASE, KIND)                                     \
1014   case APIRecord::KIND: {                                                      \
1015     walkUpFrom##CLASS(static_cast<const CLASS *>(Record));                     \
1016     break;                                                                     \
1017   }
1018 #include "clang/ExtractAPI/APIRecords.inc"
1019   // otherwise fallback on the only behavior we can implement safely.
1020   case APIRecord::RK_Unknown:
1021     visitAPIRecord(Record);
1022     break;
1023   default:
1024     llvm_unreachable("API Record with uninstantiable kind");
1025   }
1026 }
1027 
1028 Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1029                                              ExtendedModule &&EM) {
1030   Object Root;
1031   serializeObject(Root, "metadata", serializeMetadata());
1032   serializeObject(Root, "module", serializeModuleObject(ModuleName));
1033 
1034   Root["symbols"] = std::move(EM.Symbols);
1035   Root["relationships"] = std::move(EM.Relationships);
1036 
1037   return Root;
1038 }
1039 
1040 void SymbolGraphSerializer::serializeGraphToStream(
1041     raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1042     ExtendedModule &&EM) {
1043   Object Root = serializeGraph(ModuleName, std::move(EM));
1044   if (Options.Compact)
1045     OS << formatv("{0}", json::Value(std::move(Root))) << "\n";
1046   else
1047     OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n";
1048 }
1049 
1050 void SymbolGraphSerializer::serializeMainSymbolGraph(
1051     raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1052     SymbolGraphSerializerOption Options) {
1053   SymbolGraphSerializer Serializer(
1054       API, IgnoresList, Options.EmitSymbolLabelsForTesting,
1055       /*ForceEmitToMainModule=*/true,
1056       /*SkipSymbolsInCategoriesToExternalTypes=*/true);
1057 
1058   Serializer.traverseAPISet();
1059   Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1060                                     std::move(Serializer.MainModule));
1061   // FIXME: TODO handle extended modules here
1062 }
1063 
1064 void SymbolGraphSerializer::serializeWithExtensionGraphs(
1065     raw_ostream &MainOutput, const APISet &API,
1066     const APIIgnoresList &IgnoresList,
1067     llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1068         CreateOutputStream,
1069     SymbolGraphSerializerOption Options) {
1070   SymbolGraphSerializer Serializer(API, IgnoresList,
1071                                    Options.EmitSymbolLabelsForTesting);
1072   Serializer.traverseAPISet();
1073 
1074   Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1075                                     std::move(Serializer.MainModule));
1076 
1077   for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1078     if (auto ExtensionOS =
1079             CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName))
1080       Serializer.serializeGraphToStream(*ExtensionOS, Options,
1081                                         ExtensionSGF.getKey(),
1082                                         std::move(ExtensionSGF.getValue()));
1083   }
1084 }
1085 
1086 std::optional<Object>
1087 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1088                                                 const APISet &API) {
1089   APIRecord *Record = API.findRecordForUSR(USR);
1090   if (!Record)
1091     return {};
1092 
1093   Object Root;
1094   APIIgnoresList EmptyIgnores;
1095   SymbolGraphSerializer Serializer(API, EmptyIgnores,
1096                                    /*EmitSymbolLabelsForTesting*/ false,
1097                                    /*ForceEmitToMainModule*/ true);
1098 
1099   // Set up serializer parent chain
1100   Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1101 
1102   Serializer.serializeSingleRecord(Record);
1103   serializeObject(Root, "symbolGraph",
1104                   Serializer.serializeGraph(API.ProductName,
1105                                             std::move(Serializer.MainModule)));
1106 
1107   Language Lang = API.getLanguage();
1108   serializeArray(Root, "parentContexts",
1109                  generateParentContexts(Serializer.Hierarchy, Lang));
1110 
1111   Array RelatedSymbols;
1112 
1113   for (const auto &Fragment : Record->Declaration.getFragments()) {
1114     // If we don't have a USR there isn't much we can do.
1115     if (Fragment.PreciseIdentifier.empty())
1116       continue;
1117 
1118     APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1119 
1120     // If we can't find the record let's skip.
1121     if (!RelatedRecord)
1122       continue;
1123 
1124     Object RelatedSymbol;
1125     RelatedSymbol["usr"] = RelatedRecord->USR;
1126     RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1127     RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
1128     RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1129     RelatedSymbol["moduleName"] = API.ProductName;
1130     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1131 
1132     serializeArray(RelatedSymbol, "parentContexts",
1133                    generateParentContexts(
1134                        generateHierarchyFromRecord(RelatedRecord), Lang));
1135 
1136     RelatedSymbols.push_back(std::move(RelatedSymbol));
1137   }
1138 
1139   serializeArray(Root, "relatedSymbols", RelatedSymbols);
1140   return Root;
1141 }
1142