xref: /freebsd-src/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision 7a6dacaca14b62ca4b74406814becb87a3fefac0)
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 
415f757f3fSDimitry Andric /// Helper function to inject a StringRef \p String into an object \p Paren at
425f757f3fSDimitry Andric /// position \p Key
435f757f3fSDimitry Andric void serializeString(Object &Paren, StringRef Key,
445f757f3fSDimitry Andric                      std::optional<std::string> String) {
455f757f3fSDimitry Andric   if (String)
465f757f3fSDimitry Andric     Paren[Key] = std::move(*String);
475f757f3fSDimitry Andric }
485f757f3fSDimitry 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;
1125f757f3fSDimitry Andric   SourcePosition["line"] = Loc.getLine() - 1;
1135f757f3fSDimitry 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
150*7a6dacacSDimitry Andric /// versions of the symbol as semantic versions, if not default.
151*7a6dacacSDimitry Andric /// Availability information also contains flags to indicate if the symbol is
152*7a6dacacSDimitry Andric /// unconditionally unavailable or deprecated,
153*7a6dacacSDimitry Andric /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
15481ad6265SDimitry Andric ///
155bdd1243dSDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes,
156*7a6dacacSDimitry Andric /// or an \c Array containing an object with the formatted availability
157*7a6dacacSDimitry Andric /// information.
158*7a6dacacSDimitry Andric std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
159*7a6dacacSDimitry Andric   if (Avail.isDefault())
160bdd1243dSDimitry Andric     return std::nullopt;
16181ad6265SDimitry Andric 
162*7a6dacacSDimitry Andric   Object Availability;
163bdd1243dSDimitry Andric   Array AvailabilityArray;
164*7a6dacacSDimitry Andric   Availability["domain"] = Avail.Domain;
165*7a6dacacSDimitry Andric   serializeObject(Availability, "introduced",
166*7a6dacacSDimitry Andric                   serializeSemanticVersion(Avail.Introduced));
167*7a6dacacSDimitry Andric   serializeObject(Availability, "deprecated",
168*7a6dacacSDimitry Andric                   serializeSemanticVersion(Avail.Deprecated));
169*7a6dacacSDimitry Andric   serializeObject(Availability, "obsoleted",
170*7a6dacacSDimitry Andric                   serializeSemanticVersion(Avail.Obsoleted));
171*7a6dacacSDimitry Andric   if (Avail.isUnconditionallyDeprecated()) {
172bdd1243dSDimitry Andric     Object UnconditionallyDeprecated;
173bdd1243dSDimitry Andric     UnconditionallyDeprecated["domain"] = "*";
174bdd1243dSDimitry Andric     UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
175bdd1243dSDimitry Andric     AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
176bdd1243dSDimitry Andric   }
177*7a6dacacSDimitry Andric   if (Avail.isUnconditionallyUnavailable()) {
178*7a6dacacSDimitry Andric     Object UnconditionallyUnavailable;
179*7a6dacacSDimitry Andric     UnconditionallyUnavailable["domain"] = "*";
180*7a6dacacSDimitry Andric     UnconditionallyUnavailable["isUnconditionallyUnavailable"] = true;
181*7a6dacacSDimitry Andric     AvailabilityArray.emplace_back(std::move(UnconditionallyUnavailable));
18206c3fb27SDimitry Andric   }
183bdd1243dSDimitry Andric   AvailabilityArray.emplace_back(std::move(Availability));
184bdd1243dSDimitry Andric   return AvailabilityArray;
18581ad6265SDimitry Andric }
18681ad6265SDimitry Andric 
18781ad6265SDimitry Andric /// Get the language name string for interface language references.
18881ad6265SDimitry Andric StringRef getLanguageName(Language Lang) {
18981ad6265SDimitry Andric   switch (Lang) {
19081ad6265SDimitry Andric   case Language::C:
19181ad6265SDimitry Andric     return "c";
19281ad6265SDimitry Andric   case Language::ObjC:
19381ad6265SDimitry Andric     return "objective-c";
1945f757f3fSDimitry Andric   case Language::CXX:
1955f757f3fSDimitry Andric     return "c++";
1965f757f3fSDimitry Andric   case Language::ObjCXX:
1975f757f3fSDimitry Andric     return "objective-c++";
19881ad6265SDimitry Andric 
19981ad6265SDimitry Andric   // Unsupported language currently
20081ad6265SDimitry Andric   case Language::OpenCL:
20181ad6265SDimitry Andric   case Language::OpenCLCXX:
20281ad6265SDimitry Andric   case Language::CUDA:
20381ad6265SDimitry Andric   case Language::RenderScript:
20481ad6265SDimitry Andric   case Language::HIP:
20581ad6265SDimitry Andric   case Language::HLSL:
20681ad6265SDimitry Andric 
20781ad6265SDimitry Andric   // Languages that the frontend cannot parse and compile
20881ad6265SDimitry Andric   case Language::Unknown:
20981ad6265SDimitry Andric   case Language::Asm:
21081ad6265SDimitry Andric   case Language::LLVM_IR:
21181ad6265SDimitry Andric     llvm_unreachable("Unsupported language kind");
21281ad6265SDimitry Andric   }
21381ad6265SDimitry Andric 
21481ad6265SDimitry Andric   llvm_unreachable("Unhandled language kind");
21581ad6265SDimitry Andric }
21681ad6265SDimitry Andric 
21781ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format.
21881ad6265SDimitry Andric ///
21981ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique
22081ad6265SDimitry Andric /// references, and the interface language name.
22181ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) {
22281ad6265SDimitry Andric   Object Identifier;
22381ad6265SDimitry Andric   Identifier["precise"] = Record.USR;
22481ad6265SDimitry Andric   Identifier["interfaceLanguage"] = getLanguageName(Lang);
22581ad6265SDimitry Andric 
22681ad6265SDimitry Andric   return Identifier;
22781ad6265SDimitry Andric }
22881ad6265SDimitry Andric 
22981ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by
23081ad6265SDimitry Andric /// the Symbol Graph format.
23181ad6265SDimitry Andric ///
23281ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line
23381ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range
23481ad6265SDimitry Andric /// information.
23581ad6265SDimitry Andric /// e.g.
23681ad6265SDimitry Andric /// \code
23781ad6265SDimitry Andric ///   /// This is a documentation comment
23881ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
23981ad6265SDimitry Andric ///   ///     with multiple lines.
24081ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
24181ad6265SDimitry Andric /// \endcode
24281ad6265SDimitry Andric ///
243bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
244bdd1243dSDimitry Andric /// the formatted lines.
245bdd1243dSDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) {
24681ad6265SDimitry Andric   if (Comment.empty())
247bdd1243dSDimitry Andric     return std::nullopt;
24881ad6265SDimitry Andric 
24981ad6265SDimitry Andric   Object DocComment;
25081ad6265SDimitry Andric   Array LinesArray;
25181ad6265SDimitry Andric   for (const auto &CommentLine : Comment) {
25281ad6265SDimitry Andric     Object Line;
25381ad6265SDimitry Andric     Line["text"] = CommentLine.Text;
25481ad6265SDimitry Andric     serializeObject(Line, "range",
25581ad6265SDimitry Andric                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
25681ad6265SDimitry Andric     LinesArray.emplace_back(std::move(Line));
25781ad6265SDimitry Andric   }
25881ad6265SDimitry Andric   serializeArray(DocComment, "lines", LinesArray);
25981ad6265SDimitry Andric 
26081ad6265SDimitry Andric   return DocComment;
26181ad6265SDimitry Andric }
26281ad6265SDimitry Andric 
26381ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol.
26481ad6265SDimitry Andric ///
26581ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important
26681ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to
26781ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for
26881ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example:
26981ad6265SDimitry Andric /// \code
27081ad6265SDimitry Andric ///   const int pi; -> "declarationFragments" : [
27181ad6265SDimitry Andric ///                      {
27281ad6265SDimitry Andric ///                        "kind" : "keyword",
27381ad6265SDimitry Andric ///                        "spelling" : "const"
27481ad6265SDimitry Andric ///                      },
27581ad6265SDimitry Andric ///                      {
27681ad6265SDimitry Andric ///                        "kind" : "text",
27781ad6265SDimitry Andric ///                        "spelling" : " "
27881ad6265SDimitry Andric ///                      },
27981ad6265SDimitry Andric ///                      {
28081ad6265SDimitry Andric ///                        "kind" : "typeIdentifier",
28181ad6265SDimitry Andric ///                        "preciseIdentifier" : "c:I",
28281ad6265SDimitry Andric ///                        "spelling" : "int"
28381ad6265SDimitry Andric ///                      },
28481ad6265SDimitry Andric ///                      {
28581ad6265SDimitry Andric ///                        "kind" : "text",
28681ad6265SDimitry Andric ///                        "spelling" : " "
28781ad6265SDimitry Andric ///                      },
28881ad6265SDimitry Andric ///                      {
28981ad6265SDimitry Andric ///                        "kind" : "identifier",
29081ad6265SDimitry Andric ///                        "spelling" : "pi"
29181ad6265SDimitry Andric ///                      }
29281ad6265SDimitry Andric ///                    ]
29381ad6265SDimitry Andric /// \endcode
29481ad6265SDimitry Andric ///
295bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
296bdd1243dSDimitry Andric /// formatted declaration fragments array.
297bdd1243dSDimitry Andric std::optional<Array>
298bdd1243dSDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) {
29981ad6265SDimitry Andric   if (DF.getFragments().empty())
300bdd1243dSDimitry Andric     return std::nullopt;
30181ad6265SDimitry Andric 
30281ad6265SDimitry Andric   Array Fragments;
30381ad6265SDimitry Andric   for (const auto &F : DF.getFragments()) {
30481ad6265SDimitry Andric     Object Fragment;
30581ad6265SDimitry Andric     Fragment["spelling"] = F.Spelling;
30681ad6265SDimitry Andric     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
30781ad6265SDimitry Andric     if (!F.PreciseIdentifier.empty())
30881ad6265SDimitry Andric       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
30981ad6265SDimitry Andric     Fragments.emplace_back(std::move(Fragment));
31081ad6265SDimitry Andric   }
31181ad6265SDimitry Andric 
31281ad6265SDimitry Andric   return Fragments;
31381ad6265SDimitry Andric }
31481ad6265SDimitry Andric 
31581ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph
31681ad6265SDimitry Andric /// format.
31781ad6265SDimitry Andric ///
31881ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol
31981ad6265SDimitry Andric /// that can be used for different applications:
32081ad6265SDimitry Andric ///   - \c title : The simple declared name of the symbol;
32181ad6265SDimitry Andric ///   - \c subHeading : An array of declaration fragments that provides tags,
32281ad6265SDimitry Andric ///     and potentially more tokens (for example the \c +/- symbol for
32381ad6265SDimitry Andric ///     Objective-C methods). Can be used as sub-headings for documentation.
32481ad6265SDimitry Andric Object serializeNames(const APIRecord &Record) {
32581ad6265SDimitry Andric   Object Names;
3265f757f3fSDimitry Andric   if (auto *CategoryRecord =
3275f757f3fSDimitry Andric           dyn_cast_or_null<const ObjCCategoryRecord>(&Record))
3285f757f3fSDimitry Andric     Names["title"] =
3295f757f3fSDimitry Andric         (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str();
3305f757f3fSDimitry Andric   else
33181ad6265SDimitry Andric     Names["title"] = Record.Name;
3325f757f3fSDimitry Andric 
33381ad6265SDimitry Andric   serializeArray(Names, "subHeading",
33481ad6265SDimitry Andric                  serializeDeclarationFragments(Record.SubHeading));
33581ad6265SDimitry Andric   DeclarationFragments NavigatorFragments;
33681ad6265SDimitry Andric   NavigatorFragments.append(Record.Name,
33781ad6265SDimitry Andric                             DeclarationFragments::FragmentKind::Identifier,
33881ad6265SDimitry Andric                             /*PreciseIdentifier*/ "");
33981ad6265SDimitry Andric   serializeArray(Names, "navigator",
34081ad6265SDimitry Andric                  serializeDeclarationFragments(NavigatorFragments));
34181ad6265SDimitry Andric 
34281ad6265SDimitry Andric   return Names;
34381ad6265SDimitry Andric }
34481ad6265SDimitry Andric 
345bdd1243dSDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
34681ad6265SDimitry Andric   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
34781ad6265SDimitry Andric     return (getLanguageName(Lang) + "." + S).str();
34881ad6265SDimitry Andric   };
34981ad6265SDimitry Andric 
35081ad6265SDimitry Andric   Object Kind;
351bdd1243dSDimitry Andric   switch (RK) {
352bdd1243dSDimitry Andric   case APIRecord::RK_Unknown:
353bdd1243dSDimitry Andric     llvm_unreachable("Records should have an explicit kind");
354bdd1243dSDimitry Andric     break;
3555f757f3fSDimitry Andric   case APIRecord::RK_Namespace:
3565f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("namespace");
3575f757f3fSDimitry Andric     Kind["displayName"] = "Namespace";
3585f757f3fSDimitry Andric     break;
35981ad6265SDimitry Andric   case APIRecord::RK_GlobalFunction:
36081ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
36181ad6265SDimitry Andric     Kind["displayName"] = "Function";
36281ad6265SDimitry Andric     break;
3635f757f3fSDimitry Andric   case APIRecord::RK_GlobalFunctionTemplate:
3645f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
3655f757f3fSDimitry Andric     Kind["displayName"] = "Function Template";
3665f757f3fSDimitry Andric     break;
3675f757f3fSDimitry Andric   case APIRecord::RK_GlobalFunctionTemplateSpecialization:
3685f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
3695f757f3fSDimitry Andric     Kind["displayName"] = "Function Template Specialization";
3705f757f3fSDimitry Andric     break;
3715f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplate:
3725f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
3735f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template";
3745f757f3fSDimitry Andric     break;
3755f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplateSpecialization:
3765f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
3775f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template Specialization";
3785f757f3fSDimitry Andric     break;
3795f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
3805f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
3815f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template Partial Specialization";
3825f757f3fSDimitry Andric     break;
38381ad6265SDimitry Andric   case APIRecord::RK_GlobalVariable:
38481ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
38581ad6265SDimitry Andric     Kind["displayName"] = "Global Variable";
38681ad6265SDimitry Andric     break;
38781ad6265SDimitry Andric   case APIRecord::RK_EnumConstant:
38881ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum.case");
38981ad6265SDimitry Andric     Kind["displayName"] = "Enumeration Case";
39081ad6265SDimitry Andric     break;
39181ad6265SDimitry Andric   case APIRecord::RK_Enum:
39281ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum");
39381ad6265SDimitry Andric     Kind["displayName"] = "Enumeration";
39481ad6265SDimitry Andric     break;
39581ad6265SDimitry Andric   case APIRecord::RK_StructField:
39681ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
39781ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
39881ad6265SDimitry Andric     break;
39981ad6265SDimitry Andric   case APIRecord::RK_Struct:
40081ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("struct");
40181ad6265SDimitry Andric     Kind["displayName"] = "Structure";
40281ad6265SDimitry Andric     break;
403*7a6dacacSDimitry Andric   case APIRecord::RK_UnionField:
4045f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
4055f757f3fSDimitry Andric     Kind["displayName"] = "Instance Property";
4065f757f3fSDimitry Andric     break;
4075f757f3fSDimitry Andric   case APIRecord::RK_Union:
4085f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("union");
4095f757f3fSDimitry Andric     Kind["displayName"] = "Union";
4105f757f3fSDimitry Andric     break;
411*7a6dacacSDimitry Andric   case APIRecord::RK_CXXField:
412*7a6dacacSDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
413*7a6dacacSDimitry Andric     Kind["displayName"] = "Instance Property";
414*7a6dacacSDimitry Andric     break;
4155f757f3fSDimitry Andric   case APIRecord::RK_StaticField:
4165f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.property");
4175f757f3fSDimitry Andric     Kind["displayName"] = "Type Property";
4185f757f3fSDimitry Andric     break;
4195f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplate:
4205f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplateSpecialization:
4215f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplatePartialSpecialization:
4225f757f3fSDimitry Andric   case APIRecord::RK_CXXClass:
4235f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("class");
4245f757f3fSDimitry Andric     Kind["displayName"] = "Class";
4255f757f3fSDimitry Andric     break;
4265f757f3fSDimitry Andric   case APIRecord::RK_CXXMethodTemplate:
4275f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4285f757f3fSDimitry Andric     Kind["displayName"] = "Method Template";
4295f757f3fSDimitry Andric     break;
4305f757f3fSDimitry Andric   case APIRecord::RK_CXXMethodTemplateSpecialization:
4315f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4325f757f3fSDimitry Andric     Kind["displayName"] = "Method Template Specialization";
4335f757f3fSDimitry Andric     break;
4345f757f3fSDimitry Andric   case APIRecord::RK_CXXFieldTemplate:
4355f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
4365f757f3fSDimitry Andric     Kind["displayName"] = "Template Property";
4375f757f3fSDimitry Andric     break;
4385f757f3fSDimitry Andric   case APIRecord::RK_Concept:
4395f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("concept");
4405f757f3fSDimitry Andric     Kind["displayName"] = "Concept";
4415f757f3fSDimitry Andric     break;
4425f757f3fSDimitry Andric   case APIRecord::RK_CXXStaticMethod:
4435f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.method");
4445f757f3fSDimitry Andric     Kind["displayName"] = "Static Method";
4455f757f3fSDimitry Andric     break;
4465f757f3fSDimitry Andric   case APIRecord::RK_CXXInstanceMethod:
4475f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4485f757f3fSDimitry Andric     Kind["displayName"] = "Instance Method";
4495f757f3fSDimitry Andric     break;
4505f757f3fSDimitry Andric   case APIRecord::RK_CXXConstructorMethod:
4515f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4525f757f3fSDimitry Andric     Kind["displayName"] = "Constructor";
4535f757f3fSDimitry Andric     break;
4545f757f3fSDimitry Andric   case APIRecord::RK_CXXDestructorMethod:
4555f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4565f757f3fSDimitry Andric     Kind["displayName"] = "Destructor";
4575f757f3fSDimitry Andric     break;
45881ad6265SDimitry Andric   case APIRecord::RK_ObjCIvar:
45981ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("ivar");
46081ad6265SDimitry Andric     Kind["displayName"] = "Instance Variable";
46181ad6265SDimitry Andric     break;
462bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInstanceMethod:
46381ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
46481ad6265SDimitry Andric     Kind["displayName"] = "Instance Method";
465bdd1243dSDimitry Andric     break;
466bdd1243dSDimitry Andric   case APIRecord::RK_ObjCClassMethod:
46781ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("type.method");
46881ad6265SDimitry Andric     Kind["displayName"] = "Type Method";
46981ad6265SDimitry Andric     break;
470bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInstanceProperty:
47181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
47281ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
47381ad6265SDimitry Andric     break;
474bdd1243dSDimitry Andric   case APIRecord::RK_ObjCClassProperty:
475bdd1243dSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.property");
476bdd1243dSDimitry Andric     Kind["displayName"] = "Type Property";
477bdd1243dSDimitry Andric     break;
47881ad6265SDimitry Andric   case APIRecord::RK_ObjCInterface:
47981ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("class");
48081ad6265SDimitry Andric     Kind["displayName"] = "Class";
48181ad6265SDimitry Andric     break;
48281ad6265SDimitry Andric   case APIRecord::RK_ObjCCategory:
4835f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("class.extension");
4845f757f3fSDimitry Andric     Kind["displayName"] = "Class Extension";
4855f757f3fSDimitry Andric     break;
4865f757f3fSDimitry Andric   case APIRecord::RK_ObjCCategoryModule:
4875f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("module.extension");
4885f757f3fSDimitry Andric     Kind["displayName"] = "Module Extension";
48981ad6265SDimitry Andric     break;
49081ad6265SDimitry Andric   case APIRecord::RK_ObjCProtocol:
49181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("protocol");
49281ad6265SDimitry Andric     Kind["displayName"] = "Protocol";
49381ad6265SDimitry Andric     break;
49481ad6265SDimitry Andric   case APIRecord::RK_MacroDefinition:
49581ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("macro");
49681ad6265SDimitry Andric     Kind["displayName"] = "Macro";
49781ad6265SDimitry Andric     break;
49881ad6265SDimitry Andric   case APIRecord::RK_Typedef:
49981ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("typealias");
50081ad6265SDimitry Andric     Kind["displayName"] = "Type Alias";
50181ad6265SDimitry Andric     break;
50281ad6265SDimitry Andric   }
50381ad6265SDimitry Andric 
50481ad6265SDimitry Andric   return Kind;
50581ad6265SDimitry Andric }
50681ad6265SDimitry Andric 
507bdd1243dSDimitry Andric /// Serialize the symbol kind information.
508bdd1243dSDimitry Andric ///
509bdd1243dSDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier
510bdd1243dSDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse
511bdd1243dSDimitry Andric /// the kind, and a \c displayName for rendering human-readable names.
512bdd1243dSDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
513bdd1243dSDimitry Andric   return serializeSymbolKind(Record.getKind(), Lang);
514bdd1243dSDimitry Andric }
515bdd1243dSDimitry Andric 
51681ad6265SDimitry Andric template <typename RecordTy>
517bdd1243dSDimitry Andric std::optional<Object>
518bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
51981ad6265SDimitry Andric   const auto &FS = Record.Signature;
52081ad6265SDimitry Andric   if (FS.empty())
521bdd1243dSDimitry Andric     return std::nullopt;
52281ad6265SDimitry Andric 
52381ad6265SDimitry Andric   Object Signature;
52481ad6265SDimitry Andric   serializeArray(Signature, "returns",
52581ad6265SDimitry Andric                  serializeDeclarationFragments(FS.getReturnType()));
52681ad6265SDimitry Andric 
52781ad6265SDimitry Andric   Array Parameters;
52881ad6265SDimitry Andric   for (const auto &P : FS.getParameters()) {
52981ad6265SDimitry Andric     Object Parameter;
53081ad6265SDimitry Andric     Parameter["name"] = P.Name;
53181ad6265SDimitry Andric     serializeArray(Parameter, "declarationFragments",
53281ad6265SDimitry Andric                    serializeDeclarationFragments(P.Fragments));
53381ad6265SDimitry Andric     Parameters.emplace_back(std::move(Parameter));
53481ad6265SDimitry Andric   }
53581ad6265SDimitry Andric 
53681ad6265SDimitry Andric   if (!Parameters.empty())
53781ad6265SDimitry Andric     Signature["parameters"] = std::move(Parameters);
53881ad6265SDimitry Andric 
53981ad6265SDimitry Andric   return Signature;
54081ad6265SDimitry Andric }
54181ad6265SDimitry Andric 
54281ad6265SDimitry Andric template <typename RecordTy>
543bdd1243dSDimitry Andric std::optional<Object>
544bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
545bdd1243dSDimitry Andric   return std::nullopt;
54681ad6265SDimitry Andric }
54781ad6265SDimitry Andric 
54881ad6265SDimitry Andric /// Serialize the function signature field, as specified by the
54981ad6265SDimitry Andric /// Symbol Graph format.
55081ad6265SDimitry Andric ///
55181ad6265SDimitry Andric /// The Symbol Graph function signature property contains two arrays.
55281ad6265SDimitry Andric ///   - The \c returns array is the declaration fragments of the return type;
55381ad6265SDimitry Andric ///   - The \c parameters array contains names and declaration fragments of the
55481ad6265SDimitry Andric ///     parameters.
55581ad6265SDimitry Andric ///
556bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
55781ad6265SDimitry Andric /// formatted function signature.
55881ad6265SDimitry Andric template <typename RecordTy>
55981ad6265SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
56081ad6265SDimitry Andric   serializeObject(Paren, "functionSignature",
56181ad6265SDimitry Andric                   serializeFunctionSignatureMixinImpl(
56281ad6265SDimitry Andric                       Record, has_function_signature<RecordTy>()));
56381ad6265SDimitry Andric }
56481ad6265SDimitry Andric 
5655f757f3fSDimitry Andric template <typename RecordTy>
5665f757f3fSDimitry Andric std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
5675f757f3fSDimitry Andric                                                     std::true_type) {
5685f757f3fSDimitry Andric   const auto &AccessControl = Record.Access;
5695f757f3fSDimitry Andric   std::string Access;
5705f757f3fSDimitry Andric   if (AccessControl.empty())
5715f757f3fSDimitry Andric     return std::nullopt;
5725f757f3fSDimitry Andric   Access = AccessControl.getAccess();
5735f757f3fSDimitry Andric   return Access;
5745f757f3fSDimitry Andric }
5755f757f3fSDimitry Andric 
5765f757f3fSDimitry Andric template <typename RecordTy>
5775f757f3fSDimitry Andric std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
5785f757f3fSDimitry Andric                                                     std::false_type) {
5795f757f3fSDimitry Andric   return std::nullopt;
5805f757f3fSDimitry Andric }
5815f757f3fSDimitry Andric 
5825f757f3fSDimitry Andric template <typename RecordTy>
5835f757f3fSDimitry Andric void serializeAccessMixin(Object &Paren, const RecordTy &Record) {
5845f757f3fSDimitry Andric   auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>());
5855f757f3fSDimitry Andric   if (!accessLevel.has_value())
5865f757f3fSDimitry Andric     accessLevel = "public";
5875f757f3fSDimitry Andric   serializeString(Paren, "accessLevel", accessLevel);
5885f757f3fSDimitry Andric }
5895f757f3fSDimitry Andric 
5905f757f3fSDimitry Andric template <typename RecordTy>
5915f757f3fSDimitry Andric std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
5925f757f3fSDimitry Andric                                                  std::true_type) {
5935f757f3fSDimitry Andric   const auto &Template = Record.Templ;
5945f757f3fSDimitry Andric   if (Template.empty())
5955f757f3fSDimitry Andric     return std::nullopt;
5965f757f3fSDimitry Andric 
5975f757f3fSDimitry Andric   Object Generics;
5985f757f3fSDimitry Andric   Array GenericParameters;
5995f757f3fSDimitry Andric   for (const auto &Param : Template.getParameters()) {
6005f757f3fSDimitry Andric     Object Parameter;
6015f757f3fSDimitry Andric     Parameter["name"] = Param.Name;
6025f757f3fSDimitry Andric     Parameter["index"] = Param.Index;
6035f757f3fSDimitry Andric     Parameter["depth"] = Param.Depth;
6045f757f3fSDimitry Andric     GenericParameters.emplace_back(std::move(Parameter));
6055f757f3fSDimitry Andric   }
6065f757f3fSDimitry Andric   if (!GenericParameters.empty())
6075f757f3fSDimitry Andric     Generics["parameters"] = std::move(GenericParameters);
6085f757f3fSDimitry Andric 
6095f757f3fSDimitry Andric   Array GenericConstraints;
6105f757f3fSDimitry Andric   for (const auto &Constr : Template.getConstraints()) {
6115f757f3fSDimitry Andric     Object Constraint;
6125f757f3fSDimitry Andric     Constraint["kind"] = Constr.Kind;
6135f757f3fSDimitry Andric     Constraint["lhs"] = Constr.LHS;
6145f757f3fSDimitry Andric     Constraint["rhs"] = Constr.RHS;
6155f757f3fSDimitry Andric     GenericConstraints.emplace_back(std::move(Constraint));
6165f757f3fSDimitry Andric   }
6175f757f3fSDimitry Andric 
6185f757f3fSDimitry Andric   if (!GenericConstraints.empty())
6195f757f3fSDimitry Andric     Generics["constraints"] = std::move(GenericConstraints);
6205f757f3fSDimitry Andric 
6215f757f3fSDimitry Andric   return Generics;
6225f757f3fSDimitry Andric }
6235f757f3fSDimitry Andric 
6245f757f3fSDimitry Andric template <typename RecordTy>
6255f757f3fSDimitry Andric std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
6265f757f3fSDimitry Andric                                                  std::false_type) {
6275f757f3fSDimitry Andric   return std::nullopt;
6285f757f3fSDimitry Andric }
6295f757f3fSDimitry Andric 
6305f757f3fSDimitry Andric template <typename RecordTy>
6315f757f3fSDimitry Andric void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
6325f757f3fSDimitry Andric   serializeObject(Paren, "swiftGenerics",
6335f757f3fSDimitry Andric                   serializeTemplateMixinImpl(Record, has_template<RecordTy>()));
6345f757f3fSDimitry Andric }
6355f757f3fSDimitry Andric 
636bdd1243dSDimitry Andric struct PathComponent {
637bdd1243dSDimitry Andric   StringRef USR;
638bdd1243dSDimitry Andric   StringRef Name;
639bdd1243dSDimitry Andric   APIRecord::RecordKind Kind;
640bdd1243dSDimitry Andric 
641bdd1243dSDimitry Andric   PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
642bdd1243dSDimitry Andric       : USR(USR), Name(Name), Kind(Kind) {}
643bdd1243dSDimitry Andric };
644bdd1243dSDimitry Andric 
645bdd1243dSDimitry Andric template <typename RecordTy>
646bdd1243dSDimitry Andric bool generatePathComponents(
647bdd1243dSDimitry Andric     const RecordTy &Record, const APISet &API,
648bdd1243dSDimitry Andric     function_ref<void(const PathComponent &)> ComponentTransformer) {
649bdd1243dSDimitry Andric   SmallVector<PathComponent, 4> ReverseComponenents;
650bdd1243dSDimitry Andric   ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
651bdd1243dSDimitry Andric   const auto *CurrentParent = &Record.ParentInformation;
65206c3fb27SDimitry Andric   bool FailedToFindParent = false;
653bdd1243dSDimitry Andric   while (CurrentParent && !CurrentParent->empty()) {
654bdd1243dSDimitry Andric     PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
655bdd1243dSDimitry Andric                                          CurrentParent->ParentName,
656bdd1243dSDimitry Andric                                          CurrentParent->ParentKind);
657bdd1243dSDimitry Andric 
658bdd1243dSDimitry Andric     auto *ParentRecord = CurrentParent->ParentRecord;
659bdd1243dSDimitry Andric     // Slow path if we don't have a direct reference to the ParentRecord
660bdd1243dSDimitry Andric     if (!ParentRecord)
661bdd1243dSDimitry Andric       ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
662bdd1243dSDimitry Andric 
6635f757f3fSDimitry Andric     // If the parent is a category extended from internal module then we need to
6645f757f3fSDimitry Andric     // pretend this belongs to the associated interface.
665bdd1243dSDimitry Andric     if (auto *CategoryRecord =
666bdd1243dSDimitry Andric             dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
6675f757f3fSDimitry Andric       if (!CategoryRecord->IsFromExternalModule) {
668bdd1243dSDimitry Andric         ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
669bdd1243dSDimitry Andric         CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
670bdd1243dSDimitry Andric                                                CategoryRecord->Interface.Name,
671bdd1243dSDimitry Andric                                                APIRecord::RK_ObjCInterface);
672bdd1243dSDimitry Andric       }
6735f757f3fSDimitry Andric     }
674bdd1243dSDimitry Andric 
675bdd1243dSDimitry Andric     // The parent record doesn't exist which means the symbol shouldn't be
676bdd1243dSDimitry Andric     // treated as part of the current product.
67706c3fb27SDimitry Andric     if (!ParentRecord) {
67806c3fb27SDimitry Andric       FailedToFindParent = true;
67906c3fb27SDimitry Andric       break;
68006c3fb27SDimitry Andric     }
681bdd1243dSDimitry Andric 
682bdd1243dSDimitry Andric     ReverseComponenents.push_back(std::move(CurrentParentComponent));
683bdd1243dSDimitry Andric     CurrentParent = &ParentRecord->ParentInformation;
684bdd1243dSDimitry Andric   }
685bdd1243dSDimitry Andric 
686bdd1243dSDimitry Andric   for (const auto &PC : reverse(ReverseComponenents))
687bdd1243dSDimitry Andric     ComponentTransformer(PC);
688bdd1243dSDimitry Andric 
68906c3fb27SDimitry Andric   return FailedToFindParent;
690bdd1243dSDimitry Andric }
69106c3fb27SDimitry Andric 
692bdd1243dSDimitry Andric Object serializeParentContext(const PathComponent &PC, Language Lang) {
693bdd1243dSDimitry Andric   Object ParentContextElem;
694bdd1243dSDimitry Andric   ParentContextElem["usr"] = PC.USR;
695bdd1243dSDimitry Andric   ParentContextElem["name"] = PC.Name;
696bdd1243dSDimitry Andric   ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
697bdd1243dSDimitry Andric   return ParentContextElem;
698bdd1243dSDimitry Andric }
699bdd1243dSDimitry Andric 
700bdd1243dSDimitry Andric template <typename RecordTy>
701bdd1243dSDimitry Andric Array generateParentContexts(const RecordTy &Record, const APISet &API,
702bdd1243dSDimitry Andric                              Language Lang) {
703bdd1243dSDimitry Andric   Array ParentContexts;
70406c3fb27SDimitry Andric   generatePathComponents(
705bdd1243dSDimitry Andric       Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
706bdd1243dSDimitry Andric         ParentContexts.push_back(serializeParentContext(PC, Lang));
70706c3fb27SDimitry Andric       });
708bdd1243dSDimitry Andric 
709bdd1243dSDimitry Andric   return ParentContexts;
710bdd1243dSDimitry Andric }
71181ad6265SDimitry Andric } // namespace
71281ad6265SDimitry Andric 
71381ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer.
71481ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
71581ad6265SDimitry Andric 
71681ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const {
71781ad6265SDimitry Andric   Object Metadata;
71881ad6265SDimitry Andric   serializeObject(Metadata, "formatVersion",
71981ad6265SDimitry Andric                   serializeSemanticVersion(FormatVersion));
72081ad6265SDimitry Andric   Metadata["generator"] = clang::getClangFullVersion();
72181ad6265SDimitry Andric   return Metadata;
72281ad6265SDimitry Andric }
72381ad6265SDimitry Andric 
72481ad6265SDimitry Andric Object SymbolGraphSerializer::serializeModule() const {
72581ad6265SDimitry Andric   Object Module;
72681ad6265SDimitry Andric   // The user is expected to always pass `--product-name=` on the command line
72781ad6265SDimitry Andric   // to populate this field.
728bdd1243dSDimitry Andric   Module["name"] = API.ProductName;
72981ad6265SDimitry Andric   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
73081ad6265SDimitry Andric   return Module;
73181ad6265SDimitry Andric }
73281ad6265SDimitry Andric 
73381ad6265SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
734bdd1243dSDimitry Andric   // Skip explicitly ignored symbols.
735bdd1243dSDimitry Andric   if (IgnoresList.shouldIgnore(Record.Name))
736bdd1243dSDimitry Andric     return true;
737bdd1243dSDimitry Andric 
73881ad6265SDimitry Andric   // Skip unconditionally unavailable symbols
739*7a6dacacSDimitry Andric   if (Record.Availability.isUnconditionallyUnavailable())
74081ad6265SDimitry Andric     return true;
74181ad6265SDimitry Andric 
74281ad6265SDimitry Andric   // Filter out symbols prefixed with an underscored as they are understood to
74381ad6265SDimitry Andric   // be symbols clients should not use.
7445f757f3fSDimitry Andric   if (Record.Name.starts_with("_"))
74581ad6265SDimitry Andric     return true;
74681ad6265SDimitry Andric 
74781ad6265SDimitry Andric   return false;
74881ad6265SDimitry Andric }
74981ad6265SDimitry Andric 
75081ad6265SDimitry Andric template <typename RecordTy>
751bdd1243dSDimitry Andric std::optional<Object>
75281ad6265SDimitry Andric SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
75381ad6265SDimitry Andric   if (shouldSkip(Record))
754bdd1243dSDimitry Andric     return std::nullopt;
75581ad6265SDimitry Andric 
75681ad6265SDimitry Andric   Object Obj;
75781ad6265SDimitry Andric   serializeObject(Obj, "identifier",
75881ad6265SDimitry Andric                   serializeIdentifier(Record, API.getLanguage()));
75981ad6265SDimitry Andric   serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
76081ad6265SDimitry Andric   serializeObject(Obj, "names", serializeNames(Record));
76181ad6265SDimitry Andric   serializeObject(
76281ad6265SDimitry Andric       Obj, "location",
76381ad6265SDimitry Andric       serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
764bdd1243dSDimitry Andric   serializeArray(Obj, "availability",
765*7a6dacacSDimitry Andric                  serializeAvailability(Record.Availability));
76681ad6265SDimitry Andric   serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
76781ad6265SDimitry Andric   serializeArray(Obj, "declarationFragments",
76881ad6265SDimitry Andric                  serializeDeclarationFragments(Record.Declaration));
769bdd1243dSDimitry Andric   SmallVector<StringRef, 4> PathComponentsNames;
770bdd1243dSDimitry Andric   // If this returns true it indicates that we couldn't find a symbol in the
771bdd1243dSDimitry Andric   // hierarchy.
772bdd1243dSDimitry Andric   if (generatePathComponents(Record, API,
773bdd1243dSDimitry Andric                              [&PathComponentsNames](const PathComponent &PC) {
774bdd1243dSDimitry Andric                                PathComponentsNames.push_back(PC.Name);
775bdd1243dSDimitry Andric                              }))
776bdd1243dSDimitry Andric     return {};
777bdd1243dSDimitry Andric 
778bdd1243dSDimitry Andric   serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
77981ad6265SDimitry Andric 
78081ad6265SDimitry Andric   serializeFunctionSignatureMixin(Obj, Record);
7815f757f3fSDimitry Andric   serializeAccessMixin(Obj, Record);
7825f757f3fSDimitry Andric   serializeTemplateMixin(Obj, Record);
78381ad6265SDimitry Andric 
78481ad6265SDimitry Andric   return Obj;
78581ad6265SDimitry Andric }
78681ad6265SDimitry Andric 
78781ad6265SDimitry Andric template <typename MemberTy>
78881ad6265SDimitry Andric void SymbolGraphSerializer::serializeMembers(
78981ad6265SDimitry Andric     const APIRecord &Record,
79081ad6265SDimitry Andric     const SmallVector<std::unique_ptr<MemberTy>> &Members) {
791bdd1243dSDimitry Andric   // Members should not be serialized if we aren't recursing.
792bdd1243dSDimitry Andric   if (!ShouldRecurse)
793bdd1243dSDimitry Andric     return;
79481ad6265SDimitry Andric   for (const auto &Member : Members) {
79581ad6265SDimitry Andric     auto MemberRecord = serializeAPIRecord(*Member);
79681ad6265SDimitry Andric     if (!MemberRecord)
79781ad6265SDimitry Andric       continue;
79881ad6265SDimitry Andric 
79981ad6265SDimitry Andric     Symbols.emplace_back(std::move(*MemberRecord));
80081ad6265SDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
80181ad6265SDimitry Andric   }
80281ad6265SDimitry Andric }
80381ad6265SDimitry Andric 
80481ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
80581ad6265SDimitry Andric   switch (Kind) {
80681ad6265SDimitry Andric   case RelationshipKind::MemberOf:
80781ad6265SDimitry Andric     return "memberOf";
80881ad6265SDimitry Andric   case RelationshipKind::InheritsFrom:
80981ad6265SDimitry Andric     return "inheritsFrom";
81081ad6265SDimitry Andric   case RelationshipKind::ConformsTo:
81181ad6265SDimitry Andric     return "conformsTo";
8125f757f3fSDimitry Andric   case RelationshipKind::ExtensionTo:
8135f757f3fSDimitry Andric     return "extensionTo";
81481ad6265SDimitry Andric   }
81581ad6265SDimitry Andric   llvm_unreachable("Unhandled relationship kind");
81681ad6265SDimitry Andric }
81781ad6265SDimitry Andric 
8185f757f3fSDimitry Andric StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
8195f757f3fSDimitry Andric   switch (Kind) {
8205f757f3fSDimitry Andric   case ConstraintKind::Conformance:
8215f757f3fSDimitry Andric     return "conformance";
8225f757f3fSDimitry Andric   case ConstraintKind::ConditionalConformance:
8235f757f3fSDimitry Andric     return "conditionalConformance";
8245f757f3fSDimitry Andric   }
8255f757f3fSDimitry Andric   llvm_unreachable("Unhandled constraint kind");
8265f757f3fSDimitry Andric }
8275f757f3fSDimitry Andric 
82881ad6265SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
82981ad6265SDimitry Andric                                                   SymbolReference Source,
83081ad6265SDimitry Andric                                                   SymbolReference Target) {
83181ad6265SDimitry Andric   Object Relationship;
83281ad6265SDimitry Andric   Relationship["source"] = Source.USR;
83381ad6265SDimitry Andric   Relationship["target"] = Target.USR;
834bdd1243dSDimitry Andric   Relationship["targetFallback"] = Target.Name;
83581ad6265SDimitry Andric   Relationship["kind"] = getRelationshipString(Kind);
83681ad6265SDimitry Andric 
83781ad6265SDimitry Andric   Relationships.emplace_back(std::move(Relationship));
83881ad6265SDimitry Andric }
83981ad6265SDimitry Andric 
8405f757f3fSDimitry Andric void SymbolGraphSerializer::visitNamespaceRecord(
8415f757f3fSDimitry Andric     const NamespaceRecord &Record) {
8425f757f3fSDimitry Andric   auto Namespace = serializeAPIRecord(Record);
8435f757f3fSDimitry Andric   if (!Namespace)
8445f757f3fSDimitry Andric     return;
8455f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Namespace));
8465f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
8475f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
8485f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
8495f757f3fSDimitry Andric }
8505f757f3fSDimitry Andric 
85106c3fb27SDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionRecord(
85281ad6265SDimitry Andric     const GlobalFunctionRecord &Record) {
85381ad6265SDimitry Andric   auto Obj = serializeAPIRecord(Record);
85481ad6265SDimitry Andric   if (!Obj)
85581ad6265SDimitry Andric     return;
85681ad6265SDimitry Andric 
85781ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Obj));
85881ad6265SDimitry Andric }
85981ad6265SDimitry Andric 
86006c3fb27SDimitry Andric void SymbolGraphSerializer::visitGlobalVariableRecord(
86181ad6265SDimitry Andric     const GlobalVariableRecord &Record) {
86281ad6265SDimitry Andric   auto Obj = serializeAPIRecord(Record);
86381ad6265SDimitry Andric   if (!Obj)
86481ad6265SDimitry Andric     return;
86581ad6265SDimitry Andric 
86681ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Obj));
86781ad6265SDimitry Andric }
86881ad6265SDimitry Andric 
86906c3fb27SDimitry Andric void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) {
87081ad6265SDimitry Andric   auto Enum = serializeAPIRecord(Record);
87181ad6265SDimitry Andric   if (!Enum)
87281ad6265SDimitry Andric     return;
87381ad6265SDimitry Andric 
87481ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Enum));
87581ad6265SDimitry Andric   serializeMembers(Record, Record.Constants);
87681ad6265SDimitry Andric }
87781ad6265SDimitry Andric 
878*7a6dacacSDimitry Andric void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) {
879*7a6dacacSDimitry Andric   auto SerializedRecord = serializeAPIRecord(Record);
880*7a6dacacSDimitry Andric   if (!SerializedRecord)
88181ad6265SDimitry Andric     return;
88281ad6265SDimitry Andric 
883*7a6dacacSDimitry Andric   Symbols.emplace_back(std::move(*SerializedRecord));
88481ad6265SDimitry Andric   serializeMembers(Record, Record.Fields);
88581ad6265SDimitry Andric }
88681ad6265SDimitry Andric 
8875f757f3fSDimitry Andric void SymbolGraphSerializer::visitStaticFieldRecord(
8885f757f3fSDimitry Andric     const StaticFieldRecord &Record) {
8895f757f3fSDimitry Andric   auto StaticField = serializeAPIRecord(Record);
8905f757f3fSDimitry Andric   if (!StaticField)
8915f757f3fSDimitry Andric     return;
8925f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*StaticField));
8935f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context);
8945f757f3fSDimitry Andric }
8955f757f3fSDimitry Andric 
8965f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) {
8975f757f3fSDimitry Andric   auto Class = serializeAPIRecord(Record);
8985f757f3fSDimitry Andric   if (!Class)
8995f757f3fSDimitry Andric     return;
9005f757f3fSDimitry Andric 
9015f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Class));
9025f757f3fSDimitry Andric   for (const auto &Base : Record.Bases)
9035f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
9045f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
9055f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
9065f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
9075f757f3fSDimitry Andric }
9085f757f3fSDimitry Andric 
9095f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplateRecord(
9105f757f3fSDimitry Andric     const ClassTemplateRecord &Record) {
9115f757f3fSDimitry Andric   auto Class = serializeAPIRecord(Record);
9125f757f3fSDimitry Andric   if (!Class)
9135f757f3fSDimitry Andric     return;
9145f757f3fSDimitry Andric 
9155f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Class));
9165f757f3fSDimitry Andric   for (const auto &Base : Record.Bases)
9175f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
9185f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
9195f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
9205f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
9215f757f3fSDimitry Andric }
9225f757f3fSDimitry Andric 
9235f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplateSpecializationRecord(
9245f757f3fSDimitry Andric     const ClassTemplateSpecializationRecord &Record) {
9255f757f3fSDimitry Andric   auto Class = serializeAPIRecord(Record);
9265f757f3fSDimitry Andric   if (!Class)
9275f757f3fSDimitry Andric     return;
9285f757f3fSDimitry Andric 
9295f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Class));
9305f757f3fSDimitry Andric 
9315f757f3fSDimitry Andric   for (const auto &Base : Record.Bases)
9325f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
9335f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
9345f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
9355f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
9365f757f3fSDimitry Andric }
9375f757f3fSDimitry Andric 
9385f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
9395f757f3fSDimitry Andric     const ClassTemplatePartialSpecializationRecord &Record) {
9405f757f3fSDimitry Andric   auto Class = serializeAPIRecord(Record);
9415f757f3fSDimitry Andric   if (!Class)
9425f757f3fSDimitry Andric     return;
9435f757f3fSDimitry Andric 
9445f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Class));
9455f757f3fSDimitry Andric 
9465f757f3fSDimitry Andric   for (const auto &Base : Record.Bases)
9475f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
9485f757f3fSDimitry Andric   if (!Record.ParentInformation.empty())
9495f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, Record,
9505f757f3fSDimitry Andric                           Record.ParentInformation.ParentRecord);
9515f757f3fSDimitry Andric }
9525f757f3fSDimitry Andric 
9535f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXInstanceMethodRecord(
9545f757f3fSDimitry Andric     const CXXInstanceMethodRecord &Record) {
9555f757f3fSDimitry Andric   auto InstanceMethod = serializeAPIRecord(Record);
9565f757f3fSDimitry Andric   if (!InstanceMethod)
9575f757f3fSDimitry Andric     return;
9585f757f3fSDimitry Andric 
9595f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*InstanceMethod));
9605f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
9615f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
9625f757f3fSDimitry Andric }
9635f757f3fSDimitry Andric 
9645f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXStaticMethodRecord(
9655f757f3fSDimitry Andric     const CXXStaticMethodRecord &Record) {
9665f757f3fSDimitry Andric   auto StaticMethod = serializeAPIRecord(Record);
9675f757f3fSDimitry Andric   if (!StaticMethod)
9685f757f3fSDimitry Andric     return;
9695f757f3fSDimitry Andric 
9705f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*StaticMethod));
9715f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
9725f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
9735f757f3fSDimitry Andric }
9745f757f3fSDimitry Andric 
9755f757f3fSDimitry Andric void SymbolGraphSerializer::visitMethodTemplateRecord(
9765f757f3fSDimitry Andric     const CXXMethodTemplateRecord &Record) {
9775f757f3fSDimitry Andric   if (!ShouldRecurse)
9785f757f3fSDimitry Andric     // Ignore child symbols
9795f757f3fSDimitry Andric     return;
9805f757f3fSDimitry Andric   auto MethodTemplate = serializeAPIRecord(Record);
9815f757f3fSDimitry Andric   if (!MethodTemplate)
9825f757f3fSDimitry Andric     return;
9835f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*MethodTemplate));
9845f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
9855f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
9865f757f3fSDimitry Andric }
9875f757f3fSDimitry Andric 
9885f757f3fSDimitry Andric void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord(
9895f757f3fSDimitry Andric     const CXXMethodTemplateSpecializationRecord &Record) {
9905f757f3fSDimitry Andric   if (!ShouldRecurse)
9915f757f3fSDimitry Andric     // Ignore child symbols
9925f757f3fSDimitry Andric     return;
9935f757f3fSDimitry Andric   auto MethodTemplateSpecialization = serializeAPIRecord(Record);
9945f757f3fSDimitry Andric   if (!MethodTemplateSpecialization)
9955f757f3fSDimitry Andric     return;
9965f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*MethodTemplateSpecialization));
9975f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
9985f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
9995f757f3fSDimitry Andric }
10005f757f3fSDimitry Andric 
10015f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) {
10025f757f3fSDimitry Andric   if (!ShouldRecurse)
10035f757f3fSDimitry Andric     return;
10045f757f3fSDimitry Andric   auto CXXField = serializeAPIRecord(Record);
10055f757f3fSDimitry Andric   if (!CXXField)
10065f757f3fSDimitry Andric     return;
10075f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*CXXField));
10085f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
10095f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
10105f757f3fSDimitry Andric }
10115f757f3fSDimitry Andric 
10125f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXFieldTemplateRecord(
10135f757f3fSDimitry Andric     const CXXFieldTemplateRecord &Record) {
10145f757f3fSDimitry Andric   if (!ShouldRecurse)
10155f757f3fSDimitry Andric     // Ignore child symbols
10165f757f3fSDimitry Andric     return;
10175f757f3fSDimitry Andric   auto CXXFieldTemplate = serializeAPIRecord(Record);
10185f757f3fSDimitry Andric   if (!CXXFieldTemplate)
10195f757f3fSDimitry Andric     return;
10205f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*CXXFieldTemplate));
10215f757f3fSDimitry Andric   serializeRelationship(RelationshipKind::MemberOf, Record,
10225f757f3fSDimitry Andric                         Record.ParentInformation.ParentRecord);
10235f757f3fSDimitry Andric }
10245f757f3fSDimitry Andric 
10255f757f3fSDimitry Andric void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) {
10265f757f3fSDimitry Andric   auto Concept = serializeAPIRecord(Record);
10275f757f3fSDimitry Andric   if (!Concept)
10285f757f3fSDimitry Andric     return;
10295f757f3fSDimitry Andric 
10305f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*Concept));
10315f757f3fSDimitry Andric }
10325f757f3fSDimitry Andric 
10335f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
10345f757f3fSDimitry Andric     const GlobalVariableTemplateRecord &Record) {
10355f757f3fSDimitry Andric   auto GlobalVariableTemplate = serializeAPIRecord(Record);
10365f757f3fSDimitry Andric   if (!GlobalVariableTemplate)
10375f757f3fSDimitry Andric     return;
10385f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalVariableTemplate));
10395f757f3fSDimitry Andric }
10405f757f3fSDimitry Andric 
10415f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord(
10425f757f3fSDimitry Andric     const GlobalVariableTemplateSpecializationRecord &Record) {
10435f757f3fSDimitry Andric   auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record);
10445f757f3fSDimitry Andric   if (!GlobalVariableTemplateSpecialization)
10455f757f3fSDimitry Andric     return;
10465f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization));
10475f757f3fSDimitry Andric }
10485f757f3fSDimitry Andric 
10495f757f3fSDimitry Andric void SymbolGraphSerializer::
10505f757f3fSDimitry Andric     visitGlobalVariableTemplatePartialSpecializationRecord(
10515f757f3fSDimitry Andric         const GlobalVariableTemplatePartialSpecializationRecord &Record) {
10525f757f3fSDimitry Andric   auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record);
10535f757f3fSDimitry Andric   if (!GlobalVariableTemplatePartialSpecialization)
10545f757f3fSDimitry Andric     return;
10555f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization));
10565f757f3fSDimitry Andric }
10575f757f3fSDimitry Andric 
10585f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
10595f757f3fSDimitry Andric     const GlobalFunctionTemplateRecord &Record) {
10605f757f3fSDimitry Andric   auto GlobalFunctionTemplate = serializeAPIRecord(Record);
10615f757f3fSDimitry Andric   if (!GlobalFunctionTemplate)
10625f757f3fSDimitry Andric     return;
10635f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalFunctionTemplate));
10645f757f3fSDimitry Andric }
10655f757f3fSDimitry Andric 
10665f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord(
10675f757f3fSDimitry Andric     const GlobalFunctionTemplateSpecializationRecord &Record) {
10685f757f3fSDimitry Andric   auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record);
10695f757f3fSDimitry Andric   if (!GlobalFunctionTemplateSpecialization)
10705f757f3fSDimitry Andric     return;
10715f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization));
10725f757f3fSDimitry Andric }
10735f757f3fSDimitry Andric 
107406c3fb27SDimitry Andric void SymbolGraphSerializer::visitObjCContainerRecord(
107581ad6265SDimitry Andric     const ObjCContainerRecord &Record) {
107681ad6265SDimitry Andric   auto ObjCContainer = serializeAPIRecord(Record);
107781ad6265SDimitry Andric   if (!ObjCContainer)
107881ad6265SDimitry Andric     return;
107981ad6265SDimitry Andric 
108081ad6265SDimitry Andric   Symbols.emplace_back(std::move(*ObjCContainer));
108181ad6265SDimitry Andric 
108281ad6265SDimitry Andric   serializeMembers(Record, Record.Ivars);
108381ad6265SDimitry Andric   serializeMembers(Record, Record.Methods);
108481ad6265SDimitry Andric   serializeMembers(Record, Record.Properties);
108581ad6265SDimitry Andric 
108681ad6265SDimitry Andric   for (const auto &Protocol : Record.Protocols)
108781ad6265SDimitry Andric     // Record that Record conforms to Protocol.
108881ad6265SDimitry Andric     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
108981ad6265SDimitry Andric 
109081ad6265SDimitry Andric   if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
109181ad6265SDimitry Andric     if (!ObjCInterface->SuperClass.empty())
109281ad6265SDimitry Andric       // If Record is an Objective-C interface record and it has a super class,
109381ad6265SDimitry Andric       // record that Record is inherited from SuperClass.
109481ad6265SDimitry Andric       serializeRelationship(RelationshipKind::InheritsFrom, Record,
109581ad6265SDimitry Andric                             ObjCInterface->SuperClass);
109681ad6265SDimitry Andric 
109781ad6265SDimitry Andric     // Members of categories extending an interface are serialized as members of
109881ad6265SDimitry Andric     // the interface.
109981ad6265SDimitry Andric     for (const auto *Category : ObjCInterface->Categories) {
110081ad6265SDimitry Andric       serializeMembers(Record, Category->Ivars);
110181ad6265SDimitry Andric       serializeMembers(Record, Category->Methods);
110281ad6265SDimitry Andric       serializeMembers(Record, Category->Properties);
110381ad6265SDimitry Andric 
1104bdd1243dSDimitry Andric       // Surface the protocols of the category to the interface.
110581ad6265SDimitry Andric       for (const auto &Protocol : Category->Protocols)
110681ad6265SDimitry Andric         serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
110781ad6265SDimitry Andric     }
110881ad6265SDimitry Andric   }
110981ad6265SDimitry Andric }
111081ad6265SDimitry Andric 
11115f757f3fSDimitry Andric void SymbolGraphSerializer::visitObjCCategoryRecord(
11125f757f3fSDimitry Andric     const ObjCCategoryRecord &Record) {
11135f757f3fSDimitry Andric   if (!Record.IsFromExternalModule)
11145f757f3fSDimitry Andric     return;
11155f757f3fSDimitry Andric 
11165f757f3fSDimitry Andric   // Check if the current Category' parent has been visited before, if so skip.
11175f757f3fSDimitry Andric   if (!visitedCategories.contains(Record.Interface.Name)) {
11185f757f3fSDimitry Andric     visitedCategories.insert(Record.Interface.Name);
11195f757f3fSDimitry Andric     Object Obj;
11205f757f3fSDimitry Andric     serializeObject(Obj, "identifier",
11215f757f3fSDimitry Andric                     serializeIdentifier(Record, API.getLanguage()));
11225f757f3fSDimitry Andric     serializeObject(Obj, "kind",
11235f757f3fSDimitry Andric                     serializeSymbolKind(APIRecord::RK_ObjCCategoryModule,
11245f757f3fSDimitry Andric                                         API.getLanguage()));
11255f757f3fSDimitry Andric     Obj["accessLevel"] = "public";
11265f757f3fSDimitry Andric     Symbols.emplace_back(std::move(Obj));
11275f757f3fSDimitry Andric   }
11285f757f3fSDimitry Andric 
11295f757f3fSDimitry Andric   Object Relationship;
11305f757f3fSDimitry Andric   Relationship["source"] = Record.USR;
11315f757f3fSDimitry Andric   Relationship["target"] = Record.Interface.USR;
11325f757f3fSDimitry Andric   Relationship["targetFallback"] = Record.Interface.Name;
11335f757f3fSDimitry Andric   Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo);
11345f757f3fSDimitry Andric   Relationships.emplace_back(std::move(Relationship));
11355f757f3fSDimitry Andric 
11365f757f3fSDimitry Andric   auto ObjCCategory = serializeAPIRecord(Record);
11375f757f3fSDimitry Andric 
11385f757f3fSDimitry Andric   if (!ObjCCategory)
11395f757f3fSDimitry Andric     return;
11405f757f3fSDimitry Andric 
11415f757f3fSDimitry Andric   Symbols.emplace_back(std::move(*ObjCCategory));
11425f757f3fSDimitry Andric   serializeMembers(Record, Record.Methods);
11435f757f3fSDimitry Andric   serializeMembers(Record, Record.Properties);
11445f757f3fSDimitry Andric 
11455f757f3fSDimitry Andric   // Surface the protocols of the category to the interface.
11465f757f3fSDimitry Andric   for (const auto &Protocol : Record.Protocols)
11475f757f3fSDimitry Andric     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
11485f757f3fSDimitry Andric }
11495f757f3fSDimitry Andric 
115006c3fb27SDimitry Andric void SymbolGraphSerializer::visitMacroDefinitionRecord(
115181ad6265SDimitry Andric     const MacroDefinitionRecord &Record) {
115281ad6265SDimitry Andric   auto Macro = serializeAPIRecord(Record);
115381ad6265SDimitry Andric 
115481ad6265SDimitry Andric   if (!Macro)
115581ad6265SDimitry Andric     return;
115681ad6265SDimitry Andric 
115781ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Macro));
115881ad6265SDimitry Andric }
115981ad6265SDimitry Andric 
1160bdd1243dSDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1161bdd1243dSDimitry Andric   switch (Record->getKind()) {
1162bdd1243dSDimitry Andric   case APIRecord::RK_Unknown:
1163bdd1243dSDimitry Andric     llvm_unreachable("Records should have a known kind!");
1164bdd1243dSDimitry Andric   case APIRecord::RK_GlobalFunction:
116506c3fb27SDimitry Andric     visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
1166bdd1243dSDimitry Andric     break;
1167bdd1243dSDimitry Andric   case APIRecord::RK_GlobalVariable:
116806c3fb27SDimitry Andric     visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
1169bdd1243dSDimitry Andric     break;
1170bdd1243dSDimitry Andric   case APIRecord::RK_Enum:
117106c3fb27SDimitry Andric     visitEnumRecord(*cast<EnumRecord>(Record));
1172bdd1243dSDimitry Andric     break;
1173bdd1243dSDimitry Andric   case APIRecord::RK_Struct:
1174*7a6dacacSDimitry Andric     LLVM_FALLTHROUGH;
1175*7a6dacacSDimitry Andric   case APIRecord::RK_Union:
1176*7a6dacacSDimitry Andric     visitRecordRecord(*cast<RecordRecord>(Record));
1177bdd1243dSDimitry Andric     break;
11785f757f3fSDimitry Andric   case APIRecord::RK_StaticField:
11795f757f3fSDimitry Andric     visitStaticFieldRecord(*cast<StaticFieldRecord>(Record));
11805f757f3fSDimitry Andric     break;
11815f757f3fSDimitry Andric   case APIRecord::RK_CXXClass:
11825f757f3fSDimitry Andric     visitCXXClassRecord(*cast<CXXClassRecord>(Record));
11835f757f3fSDimitry 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;
11905f757f3fSDimitry Andric   case APIRecord::RK_ObjCCategory:
11915f757f3fSDimitry Andric     visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record));
11925f757f3fSDimitry 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