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