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