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