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