xref: /freebsd-src/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
181ad6265SDimitry Andric //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric ///
981ad6265SDimitry Andric /// \file
1081ad6265SDimitry Andric /// This file implements the SymbolGraphSerializer.
1181ad6265SDimitry Andric ///
1281ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1381ad6265SDimitry Andric 
1481ad6265SDimitry Andric #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
15bdd1243dSDimitry Andric #include "clang/Basic/SourceLocation.h"
1681ad6265SDimitry Andric #include "clang/Basic/Version.h"
1781ad6265SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h"
18bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h"
19bdd1243dSDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h"
20bdd1243dSDimitry Andric #include "llvm/Support/Casting.h"
21bdd1243dSDimitry Andric #include "llvm/Support/Compiler.h"
2281ad6265SDimitry Andric #include "llvm/Support/Path.h"
2381ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h"
24bdd1243dSDimitry Andric #include <optional>
2581ad6265SDimitry Andric #include <type_traits>
2681ad6265SDimitry Andric 
2781ad6265SDimitry Andric using namespace clang;
2881ad6265SDimitry Andric using namespace clang::extractapi;
2981ad6265SDimitry Andric using namespace llvm;
3081ad6265SDimitry Andric using namespace llvm::json;
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric namespace {
3381ad6265SDimitry Andric 
3481ad6265SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren
3581ad6265SDimitry Andric /// at position \p Key.
36bdd1243dSDimitry Andric void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
3781ad6265SDimitry Andric   if (Obj)
38bdd1243dSDimitry Andric     Paren[Key] = std::move(*Obj);
3981ad6265SDimitry Andric }
4081ad6265SDimitry Andric 
41*5f757f3fSDimitry Andric /// Helper function to inject a StringRef \p String into an object \p Paren at
42*5f757f3fSDimitry Andric /// position \p Key
43*5f757f3fSDimitry Andric void serializeString(Object &Paren, StringRef Key,
44*5f757f3fSDimitry Andric                      std::optional<std::string> String) {
45*5f757f3fSDimitry Andric   if (String)
46*5f757f3fSDimitry Andric     Paren[Key] = std::move(*String);
47*5f757f3fSDimitry Andric }
48*5f757f3fSDimitry Andric 
4981ad6265SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at
5081ad6265SDimitry Andric /// position \p Key.
51bdd1243dSDimitry Andric void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
5281ad6265SDimitry Andric   if (Array)
53bdd1243dSDimitry Andric     Paren[Key] = std::move(*Array);
5481ad6265SDimitry Andric }
5581ad6265SDimitry Andric 
5681ad6265SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
5781ad6265SDimitry Andric /// format.
5881ad6265SDimitry Andric ///
5981ad6265SDimitry Andric /// A semantic version object contains three numeric fields, representing the
6081ad6265SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple.
6181ad6265SDimitry Andric /// For example version tuple 1.0.3 is serialized as:
6281ad6265SDimitry Andric /// \code
6381ad6265SDimitry Andric ///   {
6481ad6265SDimitry Andric ///     "major" : 1,
6581ad6265SDimitry Andric ///     "minor" : 0,
6681ad6265SDimitry Andric ///     "patch" : 3
6781ad6265SDimitry Andric ///   }
6881ad6265SDimitry Andric /// \endcode
6981ad6265SDimitry Andric ///
70bdd1243dSDimitry Andric /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
71bdd1243dSDimitry Andric /// containing the semantic version representation of \p V.
72bdd1243dSDimitry Andric std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
7381ad6265SDimitry Andric   if (V.empty())
74bdd1243dSDimitry Andric     return std::nullopt;
7581ad6265SDimitry Andric 
7681ad6265SDimitry Andric   Object Version;
7781ad6265SDimitry Andric   Version["major"] = V.getMajor();
7881ad6265SDimitry Andric   Version["minor"] = V.getMinor().value_or(0);
7981ad6265SDimitry Andric   Version["patch"] = V.getSubminor().value_or(0);
8081ad6265SDimitry Andric   return Version;
8181ad6265SDimitry Andric }
8281ad6265SDimitry Andric 
8381ad6265SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property.
8481ad6265SDimitry Andric ///
8581ad6265SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an
8681ad6265SDimitry Andric /// optional \c minimumVersion semantic version field.
8781ad6265SDimitry Andric Object serializeOperatingSystem(const Triple &T) {
8881ad6265SDimitry Andric   Object OS;
8981ad6265SDimitry Andric   OS["name"] = T.getOSTypeName(T.getOS());
9081ad6265SDimitry Andric   serializeObject(OS, "minimumVersion",
9181ad6265SDimitry Andric                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
9281ad6265SDimitry Andric   return OS;
9381ad6265SDimitry Andric }
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric /// Serialize the platform information in the Symbol Graph module section.
9681ad6265SDimitry Andric ///
9781ad6265SDimitry Andric /// The platform object describes a target platform triple in corresponding
9881ad6265SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem.
9981ad6265SDimitry Andric Object serializePlatform(const Triple &T) {
10081ad6265SDimitry Andric   Object Platform;
10181ad6265SDimitry Andric   Platform["architecture"] = T.getArchName();
10281ad6265SDimitry Andric   Platform["vendor"] = T.getVendorName();
10381ad6265SDimitry Andric   Platform["operatingSystem"] = serializeOperatingSystem(T);
10481ad6265SDimitry Andric   return Platform;
10581ad6265SDimitry Andric }
10681ad6265SDimitry Andric 
10781ad6265SDimitry Andric /// Serialize a source position.
10881ad6265SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) {
10981ad6265SDimitry Andric   assert(Loc.isValid() && "invalid source position");
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric   Object SourcePosition;
112*5f757f3fSDimitry Andric   SourcePosition["line"] = Loc.getLine() - 1;
113*5f757f3fSDimitry Andric   SourcePosition["character"] = Loc.getColumn() - 1;
11481ad6265SDimitry Andric 
11581ad6265SDimitry Andric   return SourcePosition;
11681ad6265SDimitry Andric }
11781ad6265SDimitry Andric 
11881ad6265SDimitry Andric /// Serialize a source location in file.
11981ad6265SDimitry Andric ///
12081ad6265SDimitry Andric /// \param Loc The presumed location to serialize.
12181ad6265SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
12281ad6265SDimitry Andric /// Defaults to false.
12381ad6265SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc,
12481ad6265SDimitry Andric                                bool IncludeFileURI = false) {
12581ad6265SDimitry Andric   Object SourceLocation;
12681ad6265SDimitry Andric   serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
12781ad6265SDimitry Andric 
12881ad6265SDimitry Andric   if (IncludeFileURI) {
12981ad6265SDimitry Andric     std::string FileURI = "file://";
13081ad6265SDimitry Andric     // Normalize file path to use forward slashes for the URI.
13181ad6265SDimitry Andric     FileURI += sys::path::convert_to_slash(Loc.getFilename());
13281ad6265SDimitry Andric     SourceLocation["uri"] = FileURI;
13381ad6265SDimitry Andric   }
13481ad6265SDimitry Andric 
13581ad6265SDimitry Andric   return SourceLocation;
13681ad6265SDimitry Andric }
13781ad6265SDimitry Andric 
13881ad6265SDimitry Andric /// Serialize a source range with begin and end locations.
13981ad6265SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc,
14081ad6265SDimitry Andric                             const PresumedLoc &EndLoc) {
14181ad6265SDimitry Andric   Object SourceRange;
14281ad6265SDimitry Andric   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
14381ad6265SDimitry Andric   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
14481ad6265SDimitry Andric   return SourceRange;
14581ad6265SDimitry Andric }
14681ad6265SDimitry Andric 
14781ad6265SDimitry Andric /// Serialize the availability attributes of a symbol.
14881ad6265SDimitry Andric ///
14981ad6265SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted
150bdd1243dSDimitry Andric /// versions of the symbol for a given domain (roughly corresponds to a
151bdd1243dSDimitry Andric /// platform) as semantic versions, if not default.  Availability information
152bdd1243dSDimitry Andric /// also contains flags to indicate if the symbol is unconditionally unavailable
153bdd1243dSDimitry Andric /// or deprecated, i.e. \c __attribute__((unavailable)) and \c
154bdd1243dSDimitry Andric /// __attribute__((deprecated)).
15581ad6265SDimitry Andric ///
156bdd1243dSDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes,
157bdd1243dSDimitry Andric /// or an \c Array containing the formatted availability information.
158bdd1243dSDimitry Andric std::optional<Array>
159bdd1243dSDimitry Andric serializeAvailability(const AvailabilitySet &Availabilities) {
160bdd1243dSDimitry Andric   if (Availabilities.isDefault())
161bdd1243dSDimitry Andric     return std::nullopt;
16281ad6265SDimitry Andric 
163bdd1243dSDimitry Andric   Array AvailabilityArray;
16481ad6265SDimitry Andric 
165bdd1243dSDimitry Andric   if (Availabilities.isUnconditionallyDeprecated()) {
166bdd1243dSDimitry Andric     Object UnconditionallyDeprecated;
167bdd1243dSDimitry Andric     UnconditionallyDeprecated["domain"] = "*";
168bdd1243dSDimitry Andric     UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
169bdd1243dSDimitry Andric     AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
170bdd1243dSDimitry Andric   }
171bdd1243dSDimitry Andric 
172bdd1243dSDimitry Andric   // Note unconditionally unavailable records are skipped.
173bdd1243dSDimitry Andric 
174bdd1243dSDimitry Andric   for (const auto &AvailInfo : Availabilities) {
175bdd1243dSDimitry Andric     Object Availability;
176bdd1243dSDimitry Andric     Availability["domain"] = AvailInfo.Domain;
17706c3fb27SDimitry Andric     if (AvailInfo.Unavailable)
17806c3fb27SDimitry Andric       Availability["isUnconditionallyUnavailable"] = true;
17906c3fb27SDimitry Andric     else {
180*5f757f3fSDimitry Andric       serializeObject(Availability, "introduced",
181bdd1243dSDimitry Andric                       serializeSemanticVersion(AvailInfo.Introduced));
182*5f757f3fSDimitry Andric       serializeObject(Availability, "deprecated",
183bdd1243dSDimitry Andric                       serializeSemanticVersion(AvailInfo.Deprecated));
184*5f757f3fSDimitry Andric       serializeObject(Availability, "obsoleted",
185bdd1243dSDimitry Andric                       serializeSemanticVersion(AvailInfo.Obsoleted));
18606c3fb27SDimitry Andric     }
187bdd1243dSDimitry Andric     AvailabilityArray.emplace_back(std::move(Availability));
188bdd1243dSDimitry Andric   }
189bdd1243dSDimitry Andric 
190bdd1243dSDimitry Andric   return AvailabilityArray;
19181ad6265SDimitry Andric }
19281ad6265SDimitry Andric 
19381ad6265SDimitry Andric /// Get the language name string for interface language references.
19481ad6265SDimitry Andric StringRef getLanguageName(Language Lang) {
19581ad6265SDimitry Andric   switch (Lang) {
19681ad6265SDimitry Andric   case Language::C:
19781ad6265SDimitry Andric     return "c";
19881ad6265SDimitry Andric   case Language::ObjC:
19981ad6265SDimitry Andric     return "objective-c";
200*5f757f3fSDimitry Andric   case Language::CXX:
201*5f757f3fSDimitry Andric     return "c++";
202*5f757f3fSDimitry Andric   case Language::ObjCXX:
203*5f757f3fSDimitry Andric     return "objective-c++";
20481ad6265SDimitry Andric 
20581ad6265SDimitry Andric   // Unsupported language currently
20681ad6265SDimitry Andric   case Language::OpenCL:
20781ad6265SDimitry Andric   case Language::OpenCLCXX:
20881ad6265SDimitry Andric   case Language::CUDA:
20981ad6265SDimitry Andric   case Language::RenderScript:
21081ad6265SDimitry Andric   case Language::HIP:
21181ad6265SDimitry Andric   case Language::HLSL:
21281ad6265SDimitry Andric 
21381ad6265SDimitry Andric   // Languages that the frontend cannot parse and compile
21481ad6265SDimitry Andric   case Language::Unknown:
21581ad6265SDimitry Andric   case Language::Asm:
21681ad6265SDimitry Andric   case Language::LLVM_IR:
21781ad6265SDimitry Andric     llvm_unreachable("Unsupported language kind");
21881ad6265SDimitry Andric   }
21981ad6265SDimitry Andric 
22081ad6265SDimitry Andric   llvm_unreachable("Unhandled language kind");
22181ad6265SDimitry Andric }
22281ad6265SDimitry Andric 
22381ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format.
22481ad6265SDimitry Andric ///
22581ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique
22681ad6265SDimitry Andric /// references, and the interface language name.
22781ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) {
22881ad6265SDimitry Andric   Object Identifier;
22981ad6265SDimitry Andric   Identifier["precise"] = Record.USR;
23081ad6265SDimitry Andric   Identifier["interfaceLanguage"] = getLanguageName(Lang);
23181ad6265SDimitry Andric 
23281ad6265SDimitry Andric   return Identifier;
23381ad6265SDimitry Andric }
23481ad6265SDimitry Andric 
23581ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by
23681ad6265SDimitry Andric /// the Symbol Graph format.
23781ad6265SDimitry Andric ///
23881ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line
23981ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range
24081ad6265SDimitry Andric /// information.
24181ad6265SDimitry Andric /// e.g.
24281ad6265SDimitry Andric /// \code
24381ad6265SDimitry Andric ///   /// This is a documentation comment
24481ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
24581ad6265SDimitry Andric ///   ///     with multiple lines.
24681ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
24781ad6265SDimitry Andric /// \endcode
24881ad6265SDimitry Andric ///
249bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
250bdd1243dSDimitry Andric /// the formatted lines.
251bdd1243dSDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) {
25281ad6265SDimitry Andric   if (Comment.empty())
253bdd1243dSDimitry Andric     return std::nullopt;
25481ad6265SDimitry Andric 
25581ad6265SDimitry Andric   Object DocComment;
25681ad6265SDimitry Andric   Array LinesArray;
25781ad6265SDimitry Andric   for (const auto &CommentLine : Comment) {
25881ad6265SDimitry Andric     Object Line;
25981ad6265SDimitry Andric     Line["text"] = CommentLine.Text;
26081ad6265SDimitry Andric     serializeObject(Line, "range",
26181ad6265SDimitry Andric                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
26281ad6265SDimitry Andric     LinesArray.emplace_back(std::move(Line));
26381ad6265SDimitry Andric   }
26481ad6265SDimitry Andric   serializeArray(DocComment, "lines", LinesArray);
26581ad6265SDimitry Andric 
26681ad6265SDimitry Andric   return DocComment;
26781ad6265SDimitry Andric }
26881ad6265SDimitry Andric 
26981ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol.
27081ad6265SDimitry Andric ///
27181ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important
27281ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to
27381ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for
27481ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example:
27581ad6265SDimitry Andric /// \code
27681ad6265SDimitry Andric ///   const int pi; -> "declarationFragments" : [
27781ad6265SDimitry Andric ///                      {
27881ad6265SDimitry Andric ///                        "kind" : "keyword",
27981ad6265SDimitry Andric ///                        "spelling" : "const"
28081ad6265SDimitry Andric ///                      },
28181ad6265SDimitry Andric ///                      {
28281ad6265SDimitry Andric ///                        "kind" : "text",
28381ad6265SDimitry Andric ///                        "spelling" : " "
28481ad6265SDimitry Andric ///                      },
28581ad6265SDimitry Andric ///                      {
28681ad6265SDimitry Andric ///                        "kind" : "typeIdentifier",
28781ad6265SDimitry Andric ///                        "preciseIdentifier" : "c:I",
28881ad6265SDimitry Andric ///                        "spelling" : "int"
28981ad6265SDimitry Andric ///                      },
29081ad6265SDimitry Andric ///                      {
29181ad6265SDimitry Andric ///                        "kind" : "text",
29281ad6265SDimitry Andric ///                        "spelling" : " "
29381ad6265SDimitry Andric ///                      },
29481ad6265SDimitry Andric ///                      {
29581ad6265SDimitry Andric ///                        "kind" : "identifier",
29681ad6265SDimitry Andric ///                        "spelling" : "pi"
29781ad6265SDimitry Andric ///                      }
29881ad6265SDimitry Andric ///                    ]
29981ad6265SDimitry Andric /// \endcode
30081ad6265SDimitry Andric ///
301bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
302bdd1243dSDimitry Andric /// formatted declaration fragments array.
303bdd1243dSDimitry Andric std::optional<Array>
304bdd1243dSDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) {
30581ad6265SDimitry Andric   if (DF.getFragments().empty())
306bdd1243dSDimitry Andric     return std::nullopt;
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric   Array Fragments;
30981ad6265SDimitry Andric   for (const auto &F : DF.getFragments()) {
31081ad6265SDimitry Andric     Object Fragment;
31181ad6265SDimitry Andric     Fragment["spelling"] = F.Spelling;
31281ad6265SDimitry Andric     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
31381ad6265SDimitry Andric     if (!F.PreciseIdentifier.empty())
31481ad6265SDimitry Andric       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
31581ad6265SDimitry Andric     Fragments.emplace_back(std::move(Fragment));
31681ad6265SDimitry Andric   }
31781ad6265SDimitry Andric 
31881ad6265SDimitry Andric   return Fragments;
31981ad6265SDimitry Andric }
32081ad6265SDimitry Andric 
32181ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph
32281ad6265SDimitry Andric /// format.
32381ad6265SDimitry Andric ///
32481ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol
32581ad6265SDimitry Andric /// that can be used for different applications:
32681ad6265SDimitry Andric ///   - \c title : The simple declared name of the symbol;
32781ad6265SDimitry Andric ///   - \c subHeading : An array of declaration fragments that provides tags,
32881ad6265SDimitry Andric ///     and potentially more tokens (for example the \c +/- symbol for
32981ad6265SDimitry Andric ///     Objective-C methods). Can be used as sub-headings for documentation.
33081ad6265SDimitry Andric Object serializeNames(const APIRecord &Record) {
33181ad6265SDimitry Andric   Object Names;
332*5f757f3fSDimitry Andric   if (auto *CategoryRecord =
333*5f757f3fSDimitry Andric           dyn_cast_or_null<const ObjCCategoryRecord>(&Record))
334*5f757f3fSDimitry Andric     Names["title"] =
335*5f757f3fSDimitry Andric         (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str();
336*5f757f3fSDimitry Andric   else
33781ad6265SDimitry Andric     Names["title"] = Record.Name;
338*5f757f3fSDimitry Andric 
33981ad6265SDimitry Andric   serializeArray(Names, "subHeading",
34081ad6265SDimitry Andric                  serializeDeclarationFragments(Record.SubHeading));
34181ad6265SDimitry Andric   DeclarationFragments NavigatorFragments;
34281ad6265SDimitry Andric   NavigatorFragments.append(Record.Name,
34381ad6265SDimitry Andric                             DeclarationFragments::FragmentKind::Identifier,
34481ad6265SDimitry Andric                             /*PreciseIdentifier*/ "");
34581ad6265SDimitry Andric   serializeArray(Names, "navigator",
34681ad6265SDimitry Andric                  serializeDeclarationFragments(NavigatorFragments));
34781ad6265SDimitry Andric 
34881ad6265SDimitry Andric   return Names;
34981ad6265SDimitry Andric }
35081ad6265SDimitry Andric 
351bdd1243dSDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
35281ad6265SDimitry Andric   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
35381ad6265SDimitry Andric     return (getLanguageName(Lang) + "." + S).str();
35481ad6265SDimitry Andric   };
35581ad6265SDimitry Andric 
35681ad6265SDimitry Andric   Object Kind;
357bdd1243dSDimitry Andric   switch (RK) {
358bdd1243dSDimitry Andric   case APIRecord::RK_Unknown:
359bdd1243dSDimitry Andric     llvm_unreachable("Records should have an explicit kind");
360bdd1243dSDimitry Andric     break;
361*5f757f3fSDimitry Andric   case APIRecord::RK_Namespace:
362*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("namespace");
363*5f757f3fSDimitry Andric     Kind["displayName"] = "Namespace";
364*5f757f3fSDimitry Andric     break;
36581ad6265SDimitry Andric   case APIRecord::RK_GlobalFunction:
36681ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
36781ad6265SDimitry Andric     Kind["displayName"] = "Function";
36881ad6265SDimitry Andric     break;
369*5f757f3fSDimitry Andric   case APIRecord::RK_GlobalFunctionTemplate:
370*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
371*5f757f3fSDimitry Andric     Kind["displayName"] = "Function Template";
372*5f757f3fSDimitry Andric     break;
373*5f757f3fSDimitry Andric   case APIRecord::RK_GlobalFunctionTemplateSpecialization:
374*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
375*5f757f3fSDimitry Andric     Kind["displayName"] = "Function Template Specialization";
376*5f757f3fSDimitry Andric     break;
377*5f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplate:
378*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
379*5f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template";
380*5f757f3fSDimitry Andric     break;
381*5f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplateSpecialization:
382*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
383*5f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template Specialization";
384*5f757f3fSDimitry Andric     break;
385*5f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
386*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
387*5f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template Partial Specialization";
388*5f757f3fSDimitry Andric     break;
38981ad6265SDimitry Andric   case APIRecord::RK_GlobalVariable:
39081ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
39181ad6265SDimitry Andric     Kind["displayName"] = "Global Variable";
39281ad6265SDimitry Andric     break;
39381ad6265SDimitry Andric   case APIRecord::RK_EnumConstant:
39481ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum.case");
39581ad6265SDimitry Andric     Kind["displayName"] = "Enumeration Case";
39681ad6265SDimitry Andric     break;
39781ad6265SDimitry Andric   case APIRecord::RK_Enum:
39881ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum");
39981ad6265SDimitry Andric     Kind["displayName"] = "Enumeration";
40081ad6265SDimitry Andric     break;
40181ad6265SDimitry Andric   case APIRecord::RK_StructField:
40281ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
40381ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
40481ad6265SDimitry Andric     break;
40581ad6265SDimitry Andric   case APIRecord::RK_Struct:
40681ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("struct");
40781ad6265SDimitry Andric     Kind["displayName"] = "Structure";
40881ad6265SDimitry Andric     break;
409*5f757f3fSDimitry Andric   case APIRecord::RK_CXXField:
410*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
411*5f757f3fSDimitry Andric     Kind["displayName"] = "Instance Property";
412*5f757f3fSDimitry Andric     break;
413*5f757f3fSDimitry Andric   case APIRecord::RK_Union:
414*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("union");
415*5f757f3fSDimitry Andric     Kind["displayName"] = "Union";
416*5f757f3fSDimitry Andric     break;
417*5f757f3fSDimitry Andric   case APIRecord::RK_StaticField:
418*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.property");
419*5f757f3fSDimitry Andric     Kind["displayName"] = "Type Property";
420*5f757f3fSDimitry Andric     break;
421*5f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplate:
422*5f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplateSpecialization:
423*5f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplatePartialSpecialization:
424*5f757f3fSDimitry Andric   case APIRecord::RK_CXXClass:
425*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("class");
426*5f757f3fSDimitry Andric     Kind["displayName"] = "Class";
427*5f757f3fSDimitry Andric     break;
428*5f757f3fSDimitry Andric   case APIRecord::RK_CXXMethodTemplate:
429*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
430*5f757f3fSDimitry Andric     Kind["displayName"] = "Method Template";
431*5f757f3fSDimitry Andric     break;
432*5f757f3fSDimitry Andric   case APIRecord::RK_CXXMethodTemplateSpecialization:
433*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
434*5f757f3fSDimitry Andric     Kind["displayName"] = "Method Template Specialization";
435*5f757f3fSDimitry Andric     break;
436*5f757f3fSDimitry Andric   case APIRecord::RK_CXXFieldTemplate:
437*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
438*5f757f3fSDimitry Andric     Kind["displayName"] = "Template Property";
439*5f757f3fSDimitry Andric     break;
440*5f757f3fSDimitry Andric   case APIRecord::RK_Concept:
441*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("concept");
442*5f757f3fSDimitry Andric     Kind["displayName"] = "Concept";
443*5f757f3fSDimitry Andric     break;
444*5f757f3fSDimitry Andric   case APIRecord::RK_CXXStaticMethod:
445*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.method");
446*5f757f3fSDimitry Andric     Kind["displayName"] = "Static Method";
447*5f757f3fSDimitry Andric     break;
448*5f757f3fSDimitry Andric   case APIRecord::RK_CXXInstanceMethod:
449*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
450*5f757f3fSDimitry Andric     Kind["displayName"] = "Instance Method";
451*5f757f3fSDimitry Andric     break;
452*5f757f3fSDimitry Andric   case APIRecord::RK_CXXConstructorMethod:
453*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
454*5f757f3fSDimitry Andric     Kind["displayName"] = "Constructor";
455*5f757f3fSDimitry Andric     break;
456*5f757f3fSDimitry Andric   case APIRecord::RK_CXXDestructorMethod:
457*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
458*5f757f3fSDimitry Andric     Kind["displayName"] = "Destructor";
459*5f757f3fSDimitry Andric     break;
46081ad6265SDimitry Andric   case APIRecord::RK_ObjCIvar:
46181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("ivar");
46281ad6265SDimitry Andric     Kind["displayName"] = "Instance Variable";
46381ad6265SDimitry Andric     break;
464bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInstanceMethod:
46581ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
46681ad6265SDimitry Andric     Kind["displayName"] = "Instance Method";
467bdd1243dSDimitry Andric     break;
468bdd1243dSDimitry Andric   case APIRecord::RK_ObjCClassMethod:
46981ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("type.method");
47081ad6265SDimitry Andric     Kind["displayName"] = "Type Method";
47181ad6265SDimitry Andric     break;
472bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInstanceProperty:
47381ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
47481ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
47581ad6265SDimitry Andric     break;
476bdd1243dSDimitry Andric   case APIRecord::RK_ObjCClassProperty:
477bdd1243dSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.property");
478bdd1243dSDimitry Andric     Kind["displayName"] = "Type Property";
479bdd1243dSDimitry Andric     break;
48081ad6265SDimitry Andric   case APIRecord::RK_ObjCInterface:
48181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("class");
48281ad6265SDimitry Andric     Kind["displayName"] = "Class";
48381ad6265SDimitry Andric     break;
48481ad6265SDimitry Andric   case APIRecord::RK_ObjCCategory:
485*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("class.extension");
486*5f757f3fSDimitry Andric     Kind["displayName"] = "Class Extension";
487*5f757f3fSDimitry Andric     break;
488*5f757f3fSDimitry Andric   case APIRecord::RK_ObjCCategoryModule:
489*5f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("module.extension");
490*5f757f3fSDimitry Andric     Kind["displayName"] = "Module Extension";
49181ad6265SDimitry Andric     break;
49281ad6265SDimitry Andric   case APIRecord::RK_ObjCProtocol:
49381ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("protocol");
49481ad6265SDimitry Andric     Kind["displayName"] = "Protocol";
49581ad6265SDimitry Andric     break;
49681ad6265SDimitry Andric   case APIRecord::RK_MacroDefinition:
49781ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("macro");
49881ad6265SDimitry Andric     Kind["displayName"] = "Macro";
49981ad6265SDimitry Andric     break;
50081ad6265SDimitry Andric   case APIRecord::RK_Typedef:
50181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("typealias");
50281ad6265SDimitry Andric     Kind["displayName"] = "Type Alias";
50381ad6265SDimitry Andric     break;
50481ad6265SDimitry Andric   }
50581ad6265SDimitry Andric 
50681ad6265SDimitry Andric   return Kind;
50781ad6265SDimitry Andric }
50881ad6265SDimitry Andric 
509bdd1243dSDimitry Andric /// Serialize the symbol kind information.
510bdd1243dSDimitry Andric ///
511bdd1243dSDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier
512bdd1243dSDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse
513bdd1243dSDimitry Andric /// the kind, and a \c displayName for rendering human-readable names.
514bdd1243dSDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
515bdd1243dSDimitry Andric   return serializeSymbolKind(Record.getKind(), Lang);
516bdd1243dSDimitry Andric }
517bdd1243dSDimitry Andric 
51881ad6265SDimitry Andric template <typename RecordTy>
519bdd1243dSDimitry Andric std::optional<Object>
520bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
52181ad6265SDimitry Andric   const auto &FS = Record.Signature;
52281ad6265SDimitry Andric   if (FS.empty())
523bdd1243dSDimitry Andric     return std::nullopt;
52481ad6265SDimitry Andric 
52581ad6265SDimitry Andric   Object Signature;
52681ad6265SDimitry Andric   serializeArray(Signature, "returns",
52781ad6265SDimitry Andric                  serializeDeclarationFragments(FS.getReturnType()));
52881ad6265SDimitry Andric 
52981ad6265SDimitry Andric   Array Parameters;
53081ad6265SDimitry Andric   for (const auto &P : FS.getParameters()) {
53181ad6265SDimitry Andric     Object Parameter;
53281ad6265SDimitry Andric     Parameter["name"] = P.Name;
53381ad6265SDimitry Andric     serializeArray(Parameter, "declarationFragments",
53481ad6265SDimitry Andric                    serializeDeclarationFragments(P.Fragments));
53581ad6265SDimitry Andric     Parameters.emplace_back(std::move(Parameter));
53681ad6265SDimitry Andric   }
53781ad6265SDimitry Andric 
53881ad6265SDimitry Andric   if (!Parameters.empty())
53981ad6265SDimitry Andric     Signature["parameters"] = std::move(Parameters);
54081ad6265SDimitry Andric 
54181ad6265SDimitry Andric   return Signature;
54281ad6265SDimitry Andric }
54381ad6265SDimitry Andric 
54481ad6265SDimitry Andric template <typename RecordTy>
545bdd1243dSDimitry Andric std::optional<Object>
546bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
547bdd1243dSDimitry Andric   return std::nullopt;
54881ad6265SDimitry Andric }
54981ad6265SDimitry Andric 
55081ad6265SDimitry Andric /// Serialize the function signature field, as specified by the
55181ad6265SDimitry Andric /// Symbol Graph format.
55281ad6265SDimitry Andric ///
55381ad6265SDimitry Andric /// The Symbol Graph function signature property contains two arrays.
55481ad6265SDimitry Andric ///   - The \c returns array is the declaration fragments of the return type;
55581ad6265SDimitry Andric ///   - The \c parameters array contains names and declaration fragments of the
55681ad6265SDimitry Andric ///     parameters.
55781ad6265SDimitry Andric ///
558bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
55981ad6265SDimitry Andric /// formatted function signature.
56081ad6265SDimitry Andric template <typename RecordTy>
56181ad6265SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
56281ad6265SDimitry Andric   serializeObject(Paren, "functionSignature",
56381ad6265SDimitry Andric                   serializeFunctionSignatureMixinImpl(
56481ad6265SDimitry Andric                       Record, has_function_signature<RecordTy>()));
56581ad6265SDimitry Andric }
56681ad6265SDimitry Andric 
567*5f757f3fSDimitry Andric template <typename RecordTy>
568*5f757f3fSDimitry Andric std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
569*5f757f3fSDimitry Andric                                                     std::true_type) {
570*5f757f3fSDimitry Andric   const auto &AccessControl = Record.Access;
571*5f757f3fSDimitry Andric   std::string Access;
572*5f757f3fSDimitry Andric   if (AccessControl.empty())
573*5f757f3fSDimitry Andric     return std::nullopt;
574*5f757f3fSDimitry Andric   Access = AccessControl.getAccess();
575*5f757f3fSDimitry Andric   return Access;
576*5f757f3fSDimitry Andric }
577*5f757f3fSDimitry Andric 
578*5f757f3fSDimitry Andric template <typename RecordTy>
579*5f757f3fSDimitry Andric std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
580*5f757f3fSDimitry Andric                                                     std::false_type) {
581*5f757f3fSDimitry Andric   return std::nullopt;
582*5f757f3fSDimitry Andric }
583*5f757f3fSDimitry Andric 
584*5f757f3fSDimitry Andric template <typename RecordTy>
585*5f757f3fSDimitry Andric void serializeAccessMixin(Object &Paren, const RecordTy &Record) {
586*5f757f3fSDimitry Andric   auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>());
587*5f757f3fSDimitry Andric   if (!accessLevel.has_value())
588*5f757f3fSDimitry Andric     accessLevel = "public";
589*5f757f3fSDimitry Andric   serializeString(Paren, "accessLevel", accessLevel);
590*5f757f3fSDimitry Andric }
591*5f757f3fSDimitry Andric 
592*5f757f3fSDimitry Andric template <typename RecordTy>
593*5f757f3fSDimitry Andric std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
594*5f757f3fSDimitry Andric                                                  std::true_type) {
595*5f757f3fSDimitry Andric   const auto &Template = Record.Templ;
596*5f757f3fSDimitry Andric   if (Template.empty())
597*5f757f3fSDimitry Andric     return std::nullopt;
598*5f757f3fSDimitry Andric 
599*5f757f3fSDimitry Andric   Object Generics;
600*5f757f3fSDimitry Andric   Array GenericParameters;
601*5f757f3fSDimitry Andric   for (const auto &Param : Template.getParameters()) {
602*5f757f3fSDimitry Andric     Object Parameter;
603*5f757f3fSDimitry Andric     Parameter["name"] = Param.Name;
604*5f757f3fSDimitry Andric     Parameter["index"] = Param.Index;
605*5f757f3fSDimitry Andric     Parameter["depth"] = Param.Depth;
606*5f757f3fSDimitry Andric     GenericParameters.emplace_back(std::move(Parameter));
607*5f757f3fSDimitry Andric   }
608*5f757f3fSDimitry Andric   if (!GenericParameters.empty())
609*5f757f3fSDimitry Andric     Generics["parameters"] = std::move(GenericParameters);
610*5f757f3fSDimitry Andric 
611*5f757f3fSDimitry Andric   Array GenericConstraints;
612*5f757f3fSDimitry Andric   for (const auto &Constr : Template.getConstraints()) {
613*5f757f3fSDimitry Andric     Object Constraint;
614*5f757f3fSDimitry Andric     Constraint["kind"] = Constr.Kind;
615*5f757f3fSDimitry Andric     Constraint["lhs"] = Constr.LHS;
616*5f757f3fSDimitry Andric     Constraint["rhs"] = Constr.RHS;
617*5f757f3fSDimitry Andric     GenericConstraints.emplace_back(std::move(Constraint));
618*5f757f3fSDimitry Andric   }
619*5f757f3fSDimitry Andric 
620*5f757f3fSDimitry Andric   if (!GenericConstraints.empty())
621*5f757f3fSDimitry Andric     Generics["constraints"] = std::move(GenericConstraints);
622*5f757f3fSDimitry Andric 
623*5f757f3fSDimitry Andric   return Generics;
624*5f757f3fSDimitry Andric }
625*5f757f3fSDimitry Andric 
626*5f757f3fSDimitry Andric template <typename RecordTy>
627*5f757f3fSDimitry Andric std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
628*5f757f3fSDimitry Andric                                                  std::false_type) {
629*5f757f3fSDimitry Andric   return std::nullopt;
630*5f757f3fSDimitry Andric }
631*5f757f3fSDimitry Andric 
632*5f757f3fSDimitry Andric template <typename RecordTy>
633*5f757f3fSDimitry Andric void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
634*5f757f3fSDimitry Andric   serializeObject(Paren, "swiftGenerics",
635*5f757f3fSDimitry Andric                   serializeTemplateMixinImpl(Record, has_template<RecordTy>()));
636*5f757f3fSDimitry Andric }
637*5f757f3fSDimitry Andric 
638bdd1243dSDimitry Andric struct PathComponent {
639bdd1243dSDimitry Andric   StringRef USR;
640bdd1243dSDimitry Andric   StringRef Name;
641bdd1243dSDimitry Andric   APIRecord::RecordKind Kind;
642bdd1243dSDimitry Andric 
643bdd1243dSDimitry Andric   PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
644bdd1243dSDimitry Andric       : USR(USR), Name(Name), Kind(Kind) {}
645bdd1243dSDimitry Andric };
646bdd1243dSDimitry Andric 
647bdd1243dSDimitry Andric template <typename RecordTy>
648bdd1243dSDimitry Andric bool generatePathComponents(
649bdd1243dSDimitry Andric     const RecordTy &Record, const APISet &API,
650bdd1243dSDimitry Andric     function_ref<void(const PathComponent &)> ComponentTransformer) {
651bdd1243dSDimitry Andric   SmallVector<PathComponent, 4> ReverseComponenents;
652bdd1243dSDimitry Andric   ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
653bdd1243dSDimitry Andric   const auto *CurrentParent = &Record.ParentInformation;
65406c3fb27SDimitry Andric   bool FailedToFindParent = false;
655bdd1243dSDimitry Andric   while (CurrentParent && !CurrentParent->empty()) {
656bdd1243dSDimitry Andric     PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
657bdd1243dSDimitry Andric                                          CurrentParent->ParentName,
658bdd1243dSDimitry Andric                                          CurrentParent->ParentKind);
659bdd1243dSDimitry Andric 
660bdd1243dSDimitry Andric     auto *ParentRecord = CurrentParent->ParentRecord;
661bdd1243dSDimitry Andric     // Slow path if we don't have a direct reference to the ParentRecord
662bdd1243dSDimitry Andric     if (!ParentRecord)
663bdd1243dSDimitry Andric       ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
664bdd1243dSDimitry Andric 
665*5f757f3fSDimitry Andric     // If the parent is a category extended from internal module then we need to
666*5f757f3fSDimitry Andric     // pretend this belongs to the associated interface.
667bdd1243dSDimitry Andric     if (auto *CategoryRecord =
668bdd1243dSDimitry Andric             dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
669*5f757f3fSDimitry Andric       if (!CategoryRecord->IsFromExternalModule) {
670bdd1243dSDimitry Andric         ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
671bdd1243dSDimitry Andric         CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
672bdd1243dSDimitry Andric                                                CategoryRecord->Interface.Name,
673bdd1243dSDimitry Andric                                                APIRecord::RK_ObjCInterface);
674bdd1243dSDimitry Andric       }
675*5f757f3fSDimitry Andric     }
676bdd1243dSDimitry Andric 
677bdd1243dSDimitry Andric     // The parent record doesn't exist which means the symbol shouldn't be
678bdd1243dSDimitry Andric     // treated as part of the current product.
67906c3fb27SDimitry Andric     if (!ParentRecord) {
68006c3fb27SDimitry Andric       FailedToFindParent = true;
68106c3fb27SDimitry Andric       break;
68206c3fb27SDimitry Andric     }
683bdd1243dSDimitry Andric 
684bdd1243dSDimitry Andric     ReverseComponenents.push_back(std::move(CurrentParentComponent));
685bdd1243dSDimitry Andric     CurrentParent = &ParentRecord->ParentInformation;
686bdd1243dSDimitry Andric   }
687bdd1243dSDimitry Andric 
688bdd1243dSDimitry Andric   for (const auto &PC : reverse(ReverseComponenents))
689bdd1243dSDimitry Andric     ComponentTransformer(PC);
690bdd1243dSDimitry Andric 
69106c3fb27SDimitry Andric   return FailedToFindParent;
692bdd1243dSDimitry Andric }
69306c3fb27SDimitry Andric 
694bdd1243dSDimitry Andric Object serializeParentContext(const PathComponent &PC, Language Lang) {
695bdd1243dSDimitry Andric   Object ParentContextElem;
696bdd1243dSDimitry Andric   ParentContextElem["usr"] = PC.USR;
697bdd1243dSDimitry Andric   ParentContextElem["name"] = PC.Name;
698bdd1243dSDimitry Andric   ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
699bdd1243dSDimitry Andric   return ParentContextElem;
700bdd1243dSDimitry Andric }
701bdd1243dSDimitry Andric 
702bdd1243dSDimitry Andric template <typename RecordTy>
703bdd1243dSDimitry Andric Array generateParentContexts(const RecordTy &Record, const APISet &API,
704bdd1243dSDimitry Andric                              Language Lang) {
705bdd1243dSDimitry Andric   Array ParentContexts;
70606c3fb27SDimitry Andric   generatePathComponents(
707bdd1243dSDimitry Andric       Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
708bdd1243dSDimitry Andric         ParentContexts.push_back(serializeParentContext(PC, Lang));
70906c3fb27SDimitry Andric       });
710bdd1243dSDimitry Andric 
711bdd1243dSDimitry Andric   return ParentContexts;
712bdd1243dSDimitry Andric }
71381ad6265SDimitry Andric } // namespace
71481ad6265SDimitry Andric 
71581ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer.
71681ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
71781ad6265SDimitry Andric 
71881ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const {
71981ad6265SDimitry Andric   Object Metadata;
72081ad6265SDimitry Andric   serializeObject(Metadata, "formatVersion",
72181ad6265SDimitry Andric                   serializeSemanticVersion(FormatVersion));
72281ad6265SDimitry Andric   Metadata["generator"] = clang::getClangFullVersion();
72381ad6265SDimitry Andric   return Metadata;
72481ad6265SDimitry Andric }
72581ad6265SDimitry Andric 
72681ad6265SDimitry Andric Object SymbolGraphSerializer::serializeModule() const {
72781ad6265SDimitry Andric   Object Module;
72881ad6265SDimitry Andric   // The user is expected to always pass `--product-name=` on the command line
72981ad6265SDimitry Andric   // to populate this field.
730bdd1243dSDimitry Andric   Module["name"] = API.ProductName;
73181ad6265SDimitry Andric   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
73281ad6265SDimitry Andric   return Module;
73381ad6265SDimitry Andric }
73481ad6265SDimitry Andric 
73581ad6265SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
736bdd1243dSDimitry Andric   // Skip explicitly ignored symbols.
737bdd1243dSDimitry Andric   if (IgnoresList.shouldIgnore(Record.Name))
738bdd1243dSDimitry Andric     return true;
739bdd1243dSDimitry Andric 
74081ad6265SDimitry Andric   // Skip unconditionally unavailable symbols
741bdd1243dSDimitry Andric   if (Record.Availabilities.isUnconditionallyUnavailable())
74281ad6265SDimitry Andric     return true;
74381ad6265SDimitry Andric 
74481ad6265SDimitry Andric   // Filter out symbols prefixed with an underscored as they are understood to
74581ad6265SDimitry Andric   // be symbols clients should not use.
746*5f757f3fSDimitry Andric   if (Record.Name.starts_with("_"))
74781ad6265SDimitry Andric     return true;
74881ad6265SDimitry Andric 
74981ad6265SDimitry Andric   return false;
75081ad6265SDimitry Andric }
75181ad6265SDimitry Andric 
75281ad6265SDimitry Andric template <typename RecordTy>
753bdd1243dSDimitry Andric std::optional<Object>
75481ad6265SDimitry Andric SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
75581ad6265SDimitry Andric   if (shouldSkip(Record))
756bdd1243dSDimitry Andric     return std::nullopt;
75781ad6265SDimitry Andric 
75881ad6265SDimitry Andric   Object Obj;
75981ad6265SDimitry Andric   serializeObject(Obj, "identifier",
76081ad6265SDimitry Andric                   serializeIdentifier(Record, API.getLanguage()));
76181ad6265SDimitry Andric   serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
76281ad6265SDimitry Andric   serializeObject(Obj, "names", serializeNames(Record));
76381ad6265SDimitry Andric   serializeObject(
76481ad6265SDimitry Andric       Obj, "location",
76581ad6265SDimitry Andric       serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
766bdd1243dSDimitry Andric   serializeArray(Obj, "availability",
767bdd1243dSDimitry Andric                  serializeAvailability(Record.Availabilities));
76881ad6265SDimitry Andric   serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
76981ad6265SDimitry Andric   serializeArray(Obj, "declarationFragments",
77081ad6265SDimitry Andric                  serializeDeclarationFragments(Record.Declaration));
771bdd1243dSDimitry Andric   SmallVector<StringRef, 4> PathComponentsNames;
772bdd1243dSDimitry Andric   // If this returns true it indicates that we couldn't find a symbol in the
773bdd1243dSDimitry Andric   // hierarchy.
774bdd1243dSDimitry Andric   if (generatePathComponents(Record, API,
775bdd1243dSDimitry Andric                              [&PathComponentsNames](const PathComponent &PC) {
776bdd1243dSDimitry Andric                                PathComponentsNames.push_back(PC.Name);
777bdd1243dSDimitry Andric                              }))
778bdd1243dSDimitry Andric     return {};
779bdd1243dSDimitry Andric 
780bdd1243dSDimitry Andric   serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
78181ad6265SDimitry Andric 
78281ad6265SDimitry Andric   serializeFunctionSignatureMixin(Obj, Record);
783*5f757f3fSDimitry Andric   serializeAccessMixin(Obj, Record);
784*5f757f3fSDimitry Andric   serializeTemplateMixin(Obj, Record);
78581ad6265SDimitry Andric 
78681ad6265SDimitry Andric   return Obj;
78781ad6265SDimitry Andric }
78881ad6265SDimitry Andric 
78981ad6265SDimitry Andric template <typename MemberTy>
79081ad6265SDimitry Andric void SymbolGraphSerializer::serializeMembers(
79181ad6265SDimitry Andric     const APIRecord &Record,
79281ad6265SDimitry Andric     const SmallVector<std::unique_ptr<MemberTy>> &Members) {
793bdd1243dSDimitry Andric   // Members should not be serialized if we aren't recursing.
794bdd1243dSDimitry Andric   if (!ShouldRecurse)
795bdd1243dSDimitry Andric     return;
79681ad6265SDimitry Andric   for (const auto &Member : Members) {
79781ad6265SDimitry Andric     auto MemberRecord = serializeAPIRecord(*Member);
79881ad6265SDimitry Andric     if (!MemberRecord)
79981ad6265SDimitry Andric       continue;
80081ad6265SDimitry Andric 
80181ad6265SDimitry Andric     Symbols.emplace_back(std::move(*MemberRecord));
80281ad6265SDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
80381ad6265SDimitry Andric   }
80481ad6265SDimitry Andric }
80581ad6265SDimitry Andric 
80681ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
80781ad6265SDimitry Andric   switch (Kind) {
80881ad6265SDimitry Andric   case RelationshipKind::MemberOf:
80981ad6265SDimitry Andric     return "memberOf";
81081ad6265SDimitry Andric   case RelationshipKind::InheritsFrom:
81181ad6265SDimitry Andric     return "inheritsFrom";
81281ad6265SDimitry Andric   case RelationshipKind::ConformsTo:
81381ad6265SDimitry Andric     return "conformsTo";
814*5f757f3fSDimitry Andric   case RelationshipKind::ExtensionTo:
815*5f757f3fSDimitry Andric     return "extensionTo";
81681ad6265SDimitry Andric   }
81781ad6265SDimitry Andric   llvm_unreachable("Unhandled relationship kind");
81881ad6265SDimitry Andric }
81981ad6265SDimitry Andric 
820*5f757f3fSDimitry Andric StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
821*5f757f3fSDimitry Andric   switch (Kind) {
822*5f757f3fSDimitry Andric   case ConstraintKind::Conformance:
823*5f757f3fSDimitry Andric     return "conformance";
824*5f757f3fSDimitry Andric   case ConstraintKind::ConditionalConformance:
825*5f757f3fSDimitry Andric     return "conditionalConformance";
826*5f757f3fSDimitry Andric   }
827*5f757f3fSDimitry Andric   llvm_unreachable("Unhandled constraint kind");
828*5f757f3fSDimitry Andric }
829*5f757f3fSDimitry Andric 
83081ad6265SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
83181ad6265SDimitry Andric                                                   SymbolReference Source,
83281ad6265SDimitry Andric                                                   SymbolReference Target) {
83381ad6265SDimitry Andric   Object Relationship;
83481ad6265SDimitry Andric   Relationship["source"] = Source.USR;
83581ad6265SDimitry Andric   Relationship["target"] = Target.USR;
836bdd1243dSDimitry Andric   Relationship["targetFallback"] = Target.Name;
83781ad6265SDimitry Andric   Relationship["kind"] = getRelationshipString(Kind);
83881ad6265SDimitry Andric 
83981ad6265SDimitry Andric   Relationships.emplace_back(std::move(Relationship));
84081ad6265SDimitry Andric }
84181ad6265SDimitry Andric 
842*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitNamespaceRecord(
843*5f757f3fSDimitry Andric     const NamespaceRecord &Record) {
844*5f757f3fSDimitry Andric   auto Namespace = serializeAPIRecord(Record);
845*5f757f3fSDimitry Andric   if (!Namespace)
846*5f757f3fSDimitry Andric     return;
847*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Namespace));
848*5f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
849*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
850*5f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
851*5f757f3fSDimitry Andric }
852*5f757f3fSDimitry Andric 
85306c3fb27SDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionRecord(
85481ad6265SDimitry Andric     const GlobalFunctionRecord &Record) {
85581ad6265SDimitry Andric   auto Obj = serializeAPIRecord(Record);
85681ad6265SDimitry Andric   if (!Obj)
85781ad6265SDimitry Andric     return;
85881ad6265SDimitry Andric 
85981ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Obj));
86081ad6265SDimitry Andric }
86181ad6265SDimitry Andric 
86206c3fb27SDimitry Andric void SymbolGraphSerializer::visitGlobalVariableRecord(
86381ad6265SDimitry Andric     const GlobalVariableRecord &Record) {
86481ad6265SDimitry Andric   auto Obj = serializeAPIRecord(Record);
86581ad6265SDimitry Andric   if (!Obj)
86681ad6265SDimitry Andric     return;
86781ad6265SDimitry Andric 
86881ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Obj));
86981ad6265SDimitry Andric }
87081ad6265SDimitry Andric 
87106c3fb27SDimitry Andric void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) {
87281ad6265SDimitry Andric   auto Enum = serializeAPIRecord(Record);
87381ad6265SDimitry Andric   if (!Enum)
87481ad6265SDimitry Andric     return;
87581ad6265SDimitry Andric 
87681ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Enum));
87781ad6265SDimitry Andric   serializeMembers(Record, Record.Constants);
87881ad6265SDimitry Andric }
87981ad6265SDimitry Andric 
88006c3fb27SDimitry Andric void SymbolGraphSerializer::visitStructRecord(const StructRecord &Record) {
88181ad6265SDimitry Andric   auto Struct = serializeAPIRecord(Record);
88281ad6265SDimitry Andric   if (!Struct)
88381ad6265SDimitry Andric     return;
88481ad6265SDimitry Andric 
88581ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Struct));
88681ad6265SDimitry Andric   serializeMembers(Record, Record.Fields);
88781ad6265SDimitry Andric }
88881ad6265SDimitry Andric 
889*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitStaticFieldRecord(
890*5f757f3fSDimitry Andric     const StaticFieldRecord &Record) {
891*5f757f3fSDimitry Andric   auto StaticField = serializeAPIRecord(Record);
892*5f757f3fSDimitry Andric   if (!StaticField)
893*5f757f3fSDimitry Andric     return;
894*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*StaticField));
895*5f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context);
896*5f757f3fSDimitry Andric }
897*5f757f3fSDimitry Andric 
898*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) {
899*5f757f3fSDimitry Andric   auto Class = serializeAPIRecord(Record);
900*5f757f3fSDimitry Andric   if (!Class)
901*5f757f3fSDimitry Andric     return;
902*5f757f3fSDimitry Andric 
903*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Class));
904*5f757f3fSDimitry Andric   for (const auto &Base : Record.Bases)
905*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
906*5f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
907*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
908*5f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
909*5f757f3fSDimitry Andric }
910*5f757f3fSDimitry Andric 
911*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplateRecord(
912*5f757f3fSDimitry Andric     const ClassTemplateRecord &Record) {
913*5f757f3fSDimitry Andric   auto Class = serializeAPIRecord(Record);
914*5f757f3fSDimitry Andric   if (!Class)
915*5f757f3fSDimitry Andric     return;
916*5f757f3fSDimitry Andric 
917*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Class));
918*5f757f3fSDimitry Andric   for (const auto &Base : Record.Bases)
919*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
920*5f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
921*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
922*5f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
923*5f757f3fSDimitry Andric }
924*5f757f3fSDimitry Andric 
925*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplateSpecializationRecord(
926*5f757f3fSDimitry Andric     const ClassTemplateSpecializationRecord &Record) {
927*5f757f3fSDimitry Andric   auto Class = serializeAPIRecord(Record);
928*5f757f3fSDimitry Andric   if (!Class)
929*5f757f3fSDimitry Andric     return;
930*5f757f3fSDimitry Andric 
931*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Class));
932*5f757f3fSDimitry Andric 
933*5f757f3fSDimitry Andric   for (const auto &Base : Record.Bases)
934*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
935*5f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
936*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
937*5f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
938*5f757f3fSDimitry Andric }
939*5f757f3fSDimitry Andric 
940*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
941*5f757f3fSDimitry Andric     const ClassTemplatePartialSpecializationRecord &Record) {
942*5f757f3fSDimitry Andric   auto Class = serializeAPIRecord(Record);
943*5f757f3fSDimitry Andric   if (!Class)
944*5f757f3fSDimitry Andric     return;
945*5f757f3fSDimitry Andric 
946*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Class));
947*5f757f3fSDimitry Andric 
948*5f757f3fSDimitry Andric   for (const auto &Base : Record.Bases)
949*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
950*5f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
951*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
952*5f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
953*5f757f3fSDimitry Andric }
954*5f757f3fSDimitry Andric 
955*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXInstanceMethodRecord(
956*5f757f3fSDimitry Andric     const CXXInstanceMethodRecord &Record) {
957*5f757f3fSDimitry Andric   auto InstanceMethod = serializeAPIRecord(Record);
958*5f757f3fSDimitry Andric   if (!InstanceMethod)
959*5f757f3fSDimitry Andric     return;
960*5f757f3fSDimitry Andric 
961*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*InstanceMethod));
962*5f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
963*5f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
964*5f757f3fSDimitry Andric }
965*5f757f3fSDimitry Andric 
966*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXStaticMethodRecord(
967*5f757f3fSDimitry Andric     const CXXStaticMethodRecord &Record) {
968*5f757f3fSDimitry Andric   auto StaticMethod = serializeAPIRecord(Record);
969*5f757f3fSDimitry Andric   if (!StaticMethod)
970*5f757f3fSDimitry Andric     return;
971*5f757f3fSDimitry Andric 
972*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*StaticMethod));
973*5f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
974*5f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
975*5f757f3fSDimitry Andric }
976*5f757f3fSDimitry Andric 
977*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitMethodTemplateRecord(
978*5f757f3fSDimitry Andric     const CXXMethodTemplateRecord &Record) {
979*5f757f3fSDimitry Andric   if (!ShouldRecurse)
980*5f757f3fSDimitry Andric     // Ignore child symbols
981*5f757f3fSDimitry Andric     return;
982*5f757f3fSDimitry Andric   auto MethodTemplate = serializeAPIRecord(Record);
983*5f757f3fSDimitry Andric   if (!MethodTemplate)
984*5f757f3fSDimitry Andric     return;
985*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*MethodTemplate));
986*5f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
987*5f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
988*5f757f3fSDimitry Andric }
989*5f757f3fSDimitry Andric 
990*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord(
991*5f757f3fSDimitry Andric     const CXXMethodTemplateSpecializationRecord &Record) {
992*5f757f3fSDimitry Andric   if (!ShouldRecurse)
993*5f757f3fSDimitry Andric     // Ignore child symbols
994*5f757f3fSDimitry Andric     return;
995*5f757f3fSDimitry Andric   auto MethodTemplateSpecialization = serializeAPIRecord(Record);
996*5f757f3fSDimitry Andric   if (!MethodTemplateSpecialization)
997*5f757f3fSDimitry Andric     return;
998*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*MethodTemplateSpecialization));
999*5f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
1000*5f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
1001*5f757f3fSDimitry Andric }
1002*5f757f3fSDimitry Andric 
1003*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) {
1004*5f757f3fSDimitry Andric   if (!ShouldRecurse)
1005*5f757f3fSDimitry Andric     return;
1006*5f757f3fSDimitry Andric   auto CXXField = serializeAPIRecord(Record);
1007*5f757f3fSDimitry Andric   if (!CXXField)
1008*5f757f3fSDimitry Andric     return;
1009*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*CXXField));
1010*5f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
1011*5f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
1012*5f757f3fSDimitry Andric }
1013*5f757f3fSDimitry Andric 
1014*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXFieldTemplateRecord(
1015*5f757f3fSDimitry Andric     const CXXFieldTemplateRecord &Record) {
1016*5f757f3fSDimitry Andric   if (!ShouldRecurse)
1017*5f757f3fSDimitry Andric     // Ignore child symbols
1018*5f757f3fSDimitry Andric     return;
1019*5f757f3fSDimitry Andric   auto CXXFieldTemplate = serializeAPIRecord(Record);
1020*5f757f3fSDimitry Andric   if (!CXXFieldTemplate)
1021*5f757f3fSDimitry Andric     return;
1022*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*CXXFieldTemplate));
1023*5f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
1024*5f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
1025*5f757f3fSDimitry Andric }
1026*5f757f3fSDimitry Andric 
1027*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) {
1028*5f757f3fSDimitry Andric   auto Concept = serializeAPIRecord(Record);
1029*5f757f3fSDimitry Andric   if (!Concept)
1030*5f757f3fSDimitry Andric     return;
1031*5f757f3fSDimitry Andric 
1032*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Concept));
1033*5f757f3fSDimitry Andric }
1034*5f757f3fSDimitry Andric 
1035*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
1036*5f757f3fSDimitry Andric     const GlobalVariableTemplateRecord &Record) {
1037*5f757f3fSDimitry Andric   auto GlobalVariableTemplate = serializeAPIRecord(Record);
1038*5f757f3fSDimitry Andric   if (!GlobalVariableTemplate)
1039*5f757f3fSDimitry Andric     return;
1040*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalVariableTemplate));
1041*5f757f3fSDimitry Andric }
1042*5f757f3fSDimitry Andric 
1043*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord(
1044*5f757f3fSDimitry Andric     const GlobalVariableTemplateSpecializationRecord &Record) {
1045*5f757f3fSDimitry Andric   auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record);
1046*5f757f3fSDimitry Andric   if (!GlobalVariableTemplateSpecialization)
1047*5f757f3fSDimitry Andric     return;
1048*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization));
1049*5f757f3fSDimitry Andric }
1050*5f757f3fSDimitry Andric 
1051*5f757f3fSDimitry Andric void SymbolGraphSerializer::
1052*5f757f3fSDimitry Andric     visitGlobalVariableTemplatePartialSpecializationRecord(
1053*5f757f3fSDimitry Andric         const GlobalVariableTemplatePartialSpecializationRecord &Record) {
1054*5f757f3fSDimitry Andric   auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record);
1055*5f757f3fSDimitry Andric   if (!GlobalVariableTemplatePartialSpecialization)
1056*5f757f3fSDimitry Andric     return;
1057*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization));
1058*5f757f3fSDimitry Andric }
1059*5f757f3fSDimitry Andric 
1060*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
1061*5f757f3fSDimitry Andric     const GlobalFunctionTemplateRecord &Record) {
1062*5f757f3fSDimitry Andric   auto GlobalFunctionTemplate = serializeAPIRecord(Record);
1063*5f757f3fSDimitry Andric   if (!GlobalFunctionTemplate)
1064*5f757f3fSDimitry Andric     return;
1065*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalFunctionTemplate));
1066*5f757f3fSDimitry Andric }
1067*5f757f3fSDimitry Andric 
1068*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord(
1069*5f757f3fSDimitry Andric     const GlobalFunctionTemplateSpecializationRecord &Record) {
1070*5f757f3fSDimitry Andric   auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record);
1071*5f757f3fSDimitry Andric   if (!GlobalFunctionTemplateSpecialization)
1072*5f757f3fSDimitry Andric     return;
1073*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization));
1074*5f757f3fSDimitry Andric }
1075*5f757f3fSDimitry Andric 
107606c3fb27SDimitry Andric void SymbolGraphSerializer::visitObjCContainerRecord(
107781ad6265SDimitry Andric     const ObjCContainerRecord &Record) {
107881ad6265SDimitry Andric   auto ObjCContainer = serializeAPIRecord(Record);
107981ad6265SDimitry Andric   if (!ObjCContainer)
108081ad6265SDimitry Andric     return;
108181ad6265SDimitry Andric 
108281ad6265SDimitry Andric   Symbols.emplace_back(std::move(*ObjCContainer));
108381ad6265SDimitry Andric 
108481ad6265SDimitry Andric   serializeMembers(Record, Record.Ivars);
108581ad6265SDimitry Andric   serializeMembers(Record, Record.Methods);
108681ad6265SDimitry Andric   serializeMembers(Record, Record.Properties);
108781ad6265SDimitry Andric 
108881ad6265SDimitry Andric   for (const auto &Protocol : Record.Protocols)
108981ad6265SDimitry Andric     // Record that Record conforms to Protocol.
109081ad6265SDimitry Andric     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
109181ad6265SDimitry Andric 
109281ad6265SDimitry Andric   if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
109381ad6265SDimitry Andric     if (!ObjCInterface->SuperClass.empty())
109481ad6265SDimitry Andric       // If Record is an Objective-C interface record and it has a super class,
109581ad6265SDimitry Andric       // record that Record is inherited from SuperClass.
109681ad6265SDimitry Andric       serializeRelationship(RelationshipKind::InheritsFrom, Record,
109781ad6265SDimitry Andric                             ObjCInterface->SuperClass);
109881ad6265SDimitry Andric 
109981ad6265SDimitry Andric     // Members of categories extending an interface are serialized as members of
110081ad6265SDimitry Andric     // the interface.
110181ad6265SDimitry Andric     for (const auto *Category : ObjCInterface->Categories) {
110281ad6265SDimitry Andric       serializeMembers(Record, Category->Ivars);
110381ad6265SDimitry Andric       serializeMembers(Record, Category->Methods);
110481ad6265SDimitry Andric       serializeMembers(Record, Category->Properties);
110581ad6265SDimitry Andric 
1106bdd1243dSDimitry Andric       // Surface the protocols of the category to the interface.
110781ad6265SDimitry Andric       for (const auto &Protocol : Category->Protocols)
110881ad6265SDimitry Andric         serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
110981ad6265SDimitry Andric     }
111081ad6265SDimitry Andric   }
111181ad6265SDimitry Andric }
111281ad6265SDimitry Andric 
1113*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitObjCCategoryRecord(
1114*5f757f3fSDimitry Andric     const ObjCCategoryRecord &Record) {
1115*5f757f3fSDimitry Andric   if (!Record.IsFromExternalModule)
1116*5f757f3fSDimitry Andric     return;
1117*5f757f3fSDimitry Andric 
1118*5f757f3fSDimitry Andric   // Check if the current Category' parent has been visited before, if so skip.
1119*5f757f3fSDimitry Andric   if (!visitedCategories.contains(Record.Interface.Name)) {
1120*5f757f3fSDimitry Andric     visitedCategories.insert(Record.Interface.Name);
1121*5f757f3fSDimitry Andric     Object Obj;
1122*5f757f3fSDimitry Andric     serializeObject(Obj, "identifier",
1123*5f757f3fSDimitry Andric                     serializeIdentifier(Record, API.getLanguage()));
1124*5f757f3fSDimitry Andric     serializeObject(Obj, "kind",
1125*5f757f3fSDimitry Andric                     serializeSymbolKind(APIRecord::RK_ObjCCategoryModule,
1126*5f757f3fSDimitry Andric                                         API.getLanguage()));
1127*5f757f3fSDimitry Andric     Obj["accessLevel"] = "public";
1128*5f757f3fSDimitry Andric     Symbols.emplace_back(std::move(Obj));
1129*5f757f3fSDimitry Andric   }
1130*5f757f3fSDimitry Andric 
1131*5f757f3fSDimitry Andric   Object Relationship;
1132*5f757f3fSDimitry Andric   Relationship["source"] = Record.USR;
1133*5f757f3fSDimitry Andric   Relationship["target"] = Record.Interface.USR;
1134*5f757f3fSDimitry Andric   Relationship["targetFallback"] = Record.Interface.Name;
1135*5f757f3fSDimitry Andric   Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo);
1136*5f757f3fSDimitry Andric   Relationships.emplace_back(std::move(Relationship));
1137*5f757f3fSDimitry Andric 
1138*5f757f3fSDimitry Andric   auto ObjCCategory = serializeAPIRecord(Record);
1139*5f757f3fSDimitry Andric 
1140*5f757f3fSDimitry Andric   if (!ObjCCategory)
1141*5f757f3fSDimitry Andric     return;
1142*5f757f3fSDimitry Andric 
1143*5f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*ObjCCategory));
1144*5f757f3fSDimitry Andric   serializeMembers(Record, Record.Methods);
1145*5f757f3fSDimitry Andric   serializeMembers(Record, Record.Properties);
1146*5f757f3fSDimitry Andric 
1147*5f757f3fSDimitry Andric   // Surface the protocols of the category to the interface.
1148*5f757f3fSDimitry Andric   for (const auto &Protocol : Record.Protocols)
1149*5f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1150*5f757f3fSDimitry Andric }
1151*5f757f3fSDimitry Andric 
115206c3fb27SDimitry Andric void SymbolGraphSerializer::visitMacroDefinitionRecord(
115381ad6265SDimitry Andric     const MacroDefinitionRecord &Record) {
115481ad6265SDimitry Andric   auto Macro = serializeAPIRecord(Record);
115581ad6265SDimitry Andric 
115681ad6265SDimitry Andric   if (!Macro)
115781ad6265SDimitry Andric     return;
115881ad6265SDimitry Andric 
115981ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Macro));
116081ad6265SDimitry Andric }
116181ad6265SDimitry Andric 
1162bdd1243dSDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1163bdd1243dSDimitry Andric   switch (Record->getKind()) {
1164bdd1243dSDimitry Andric   case APIRecord::RK_Unknown:
1165bdd1243dSDimitry Andric     llvm_unreachable("Records should have a known kind!");
1166bdd1243dSDimitry Andric   case APIRecord::RK_GlobalFunction:
116706c3fb27SDimitry Andric     visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
1168bdd1243dSDimitry Andric     break;
1169bdd1243dSDimitry Andric   case APIRecord::RK_GlobalVariable:
117006c3fb27SDimitry Andric     visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
1171bdd1243dSDimitry Andric     break;
1172bdd1243dSDimitry Andric   case APIRecord::RK_Enum:
117306c3fb27SDimitry Andric     visitEnumRecord(*cast<EnumRecord>(Record));
1174bdd1243dSDimitry Andric     break;
1175bdd1243dSDimitry Andric   case APIRecord::RK_Struct:
117606c3fb27SDimitry Andric     visitStructRecord(*cast<StructRecord>(Record));
1177bdd1243dSDimitry Andric     break;
1178*5f757f3fSDimitry Andric   case APIRecord::RK_StaticField:
1179*5f757f3fSDimitry Andric     visitStaticFieldRecord(*cast<StaticFieldRecord>(Record));
1180*5f757f3fSDimitry Andric     break;
1181*5f757f3fSDimitry Andric   case APIRecord::RK_CXXClass:
1182*5f757f3fSDimitry Andric     visitCXXClassRecord(*cast<CXXClassRecord>(Record));
1183*5f757f3fSDimitry Andric     break;
1184bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInterface:
118506c3fb27SDimitry Andric     visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
1186bdd1243dSDimitry Andric     break;
1187bdd1243dSDimitry Andric   case APIRecord::RK_ObjCProtocol:
118806c3fb27SDimitry Andric     visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
1189bdd1243dSDimitry Andric     break;
1190*5f757f3fSDimitry Andric   case APIRecord::RK_ObjCCategory:
1191*5f757f3fSDimitry Andric     visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record));
1192*5f757f3fSDimitry Andric     break;
1193bdd1243dSDimitry Andric   case APIRecord::RK_MacroDefinition:
119406c3fb27SDimitry Andric     visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
1195bdd1243dSDimitry Andric     break;
1196bdd1243dSDimitry Andric   case APIRecord::RK_Typedef:
119706c3fb27SDimitry Andric     visitTypedefRecord(*cast<TypedefRecord>(Record));
1198bdd1243dSDimitry Andric     break;
1199bdd1243dSDimitry Andric   default:
1200bdd1243dSDimitry Andric     if (auto Obj = serializeAPIRecord(*Record)) {
1201bdd1243dSDimitry Andric       Symbols.emplace_back(std::move(*Obj));
1202bdd1243dSDimitry Andric       auto &ParentInformation = Record->ParentInformation;
1203bdd1243dSDimitry Andric       if (!ParentInformation.empty())
1204bdd1243dSDimitry Andric         serializeRelationship(RelationshipKind::MemberOf, *Record,
1205bdd1243dSDimitry Andric                               *ParentInformation.ParentRecord);
1206bdd1243dSDimitry Andric     }
1207bdd1243dSDimitry Andric     break;
1208bdd1243dSDimitry Andric   }
1209bdd1243dSDimitry Andric }
1210bdd1243dSDimitry Andric 
121106c3fb27SDimitry Andric void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) {
121281ad6265SDimitry Andric   // Typedefs of anonymous types have their entries unified with the underlying
121381ad6265SDimitry Andric   // type.
121481ad6265SDimitry Andric   bool ShouldDrop = Record.UnderlyingType.Name.empty();
121581ad6265SDimitry Andric   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
121681ad6265SDimitry Andric   // the same name
121781ad6265SDimitry Andric   ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
121881ad6265SDimitry Andric   if (ShouldDrop)
121981ad6265SDimitry Andric     return;
122081ad6265SDimitry Andric 
122181ad6265SDimitry Andric   auto Typedef = serializeAPIRecord(Record);
122281ad6265SDimitry Andric   if (!Typedef)
122381ad6265SDimitry Andric     return;
122481ad6265SDimitry Andric 
122581ad6265SDimitry Andric   (*Typedef)["type"] = Record.UnderlyingType.USR;
122681ad6265SDimitry Andric 
122781ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Typedef));
122881ad6265SDimitry Andric }
122981ad6265SDimitry Andric 
123081ad6265SDimitry Andric Object SymbolGraphSerializer::serialize() {
123106c3fb27SDimitry Andric   traverseAPISet();
1232bdd1243dSDimitry Andric   return serializeCurrentGraph();
1233bdd1243dSDimitry Andric }
1234bdd1243dSDimitry Andric 
1235bdd1243dSDimitry Andric Object SymbolGraphSerializer::serializeCurrentGraph() {
1236bdd1243dSDimitry Andric   Object Root;
1237bdd1243dSDimitry Andric   serializeObject(Root, "metadata", serializeMetadata());
1238bdd1243dSDimitry Andric   serializeObject(Root, "module", serializeModule());
1239bdd1243dSDimitry Andric 
124081ad6265SDimitry Andric   Root["symbols"] = std::move(Symbols);
124181ad6265SDimitry Andric   Root["relationships"] = std::move(Relationships);
124281ad6265SDimitry Andric 
124381ad6265SDimitry Andric   return Root;
124481ad6265SDimitry Andric }
124581ad6265SDimitry Andric 
124681ad6265SDimitry Andric void SymbolGraphSerializer::serialize(raw_ostream &os) {
124781ad6265SDimitry Andric   Object root = serialize();
124881ad6265SDimitry Andric   if (Options.Compact)
124981ad6265SDimitry Andric     os << formatv("{0}", Value(std::move(root))) << "\n";
125081ad6265SDimitry Andric   else
125181ad6265SDimitry Andric     os << formatv("{0:2}", Value(std::move(root))) << "\n";
125281ad6265SDimitry Andric }
1253bdd1243dSDimitry Andric 
1254bdd1243dSDimitry Andric std::optional<Object>
1255bdd1243dSDimitry Andric SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1256bdd1243dSDimitry Andric                                                 const APISet &API) {
1257bdd1243dSDimitry Andric   APIRecord *Record = API.findRecordForUSR(USR);
1258bdd1243dSDimitry Andric   if (!Record)
1259bdd1243dSDimitry Andric     return {};
1260bdd1243dSDimitry Andric 
1261bdd1243dSDimitry Andric   Object Root;
1262bdd1243dSDimitry Andric   APIIgnoresList EmptyIgnores;
1263bdd1243dSDimitry Andric   SymbolGraphSerializer Serializer(API, EmptyIgnores,
1264bdd1243dSDimitry Andric                                    /*Options.Compact*/ {true},
1265bdd1243dSDimitry Andric                                    /*ShouldRecurse*/ false);
1266bdd1243dSDimitry Andric   Serializer.serializeSingleRecord(Record);
1267bdd1243dSDimitry Andric   serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
1268bdd1243dSDimitry Andric 
1269bdd1243dSDimitry Andric   Language Lang = API.getLanguage();
1270bdd1243dSDimitry Andric   serializeArray(Root, "parentContexts",
1271bdd1243dSDimitry Andric                  generateParentContexts(*Record, API, Lang));
1272bdd1243dSDimitry Andric 
1273bdd1243dSDimitry Andric   Array RelatedSymbols;
1274bdd1243dSDimitry Andric 
1275bdd1243dSDimitry Andric   for (const auto &Fragment : Record->Declaration.getFragments()) {
1276bdd1243dSDimitry Andric     // If we don't have a USR there isn't much we can do.
1277bdd1243dSDimitry Andric     if (Fragment.PreciseIdentifier.empty())
1278bdd1243dSDimitry Andric       continue;
1279bdd1243dSDimitry Andric 
1280bdd1243dSDimitry Andric     APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1281bdd1243dSDimitry Andric 
1282bdd1243dSDimitry Andric     // If we can't find the record let's skip.
1283bdd1243dSDimitry Andric     if (!RelatedRecord)
1284bdd1243dSDimitry Andric       continue;
1285bdd1243dSDimitry Andric 
1286bdd1243dSDimitry Andric     Object RelatedSymbol;
1287bdd1243dSDimitry Andric     RelatedSymbol["usr"] = RelatedRecord->USR;
1288bdd1243dSDimitry Andric     RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1289bdd1243dSDimitry Andric     // TODO: once we record this properly let's serialize it right.
1290bdd1243dSDimitry Andric     RelatedSymbol["accessLevel"] = "public";
1291bdd1243dSDimitry Andric     RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1292bdd1243dSDimitry Andric     RelatedSymbol["moduleName"] = API.ProductName;
1293bdd1243dSDimitry Andric     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1294bdd1243dSDimitry Andric 
1295bdd1243dSDimitry Andric     serializeArray(RelatedSymbol, "parentContexts",
1296bdd1243dSDimitry Andric                    generateParentContexts(*RelatedRecord, API, Lang));
1297bdd1243dSDimitry Andric     RelatedSymbols.push_back(std::move(RelatedSymbol));
1298bdd1243dSDimitry Andric   }
1299bdd1243dSDimitry Andric 
1300bdd1243dSDimitry Andric   serializeArray(Root, "relatedSymbols", RelatedSymbols);
1301bdd1243dSDimitry Andric   return Root;
1302bdd1243dSDimitry Andric }
1303