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