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