xref: /freebsd-src/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
17*0fca6ea1SDimitry Andric #include "clang/ExtractAPI/API.h"
1881ad6265SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h"
19bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h"
20bdd1243dSDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h"
21*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h"
22bdd1243dSDimitry Andric #include "llvm/Support/Casting.h"
23bdd1243dSDimitry Andric #include "llvm/Support/Compiler.h"
2481ad6265SDimitry Andric #include "llvm/Support/Path.h"
2581ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h"
26*0fca6ea1SDimitry Andric #include "llvm/Support/raw_ostream.h"
27*0fca6ea1SDimitry Andric #include <iterator>
28bdd1243dSDimitry Andric #include <optional>
2981ad6265SDimitry Andric #include <type_traits>
3081ad6265SDimitry Andric 
3181ad6265SDimitry Andric using namespace clang;
3281ad6265SDimitry Andric using namespace clang::extractapi;
3381ad6265SDimitry Andric using namespace llvm;
3481ad6265SDimitry Andric 
3581ad6265SDimitry Andric namespace {
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren
3881ad6265SDimitry Andric /// at position \p Key.
39*0fca6ea1SDimitry Andric void serializeObject(Object &Paren, StringRef Key,
40*0fca6ea1SDimitry Andric                      std::optional<Object> &&Obj) {
4181ad6265SDimitry Andric   if (Obj)
42bdd1243dSDimitry Andric     Paren[Key] = std::move(*Obj);
4381ad6265SDimitry Andric }
4481ad6265SDimitry Andric 
4581ad6265SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at
4681ad6265SDimitry Andric /// position \p Key.
47*0fca6ea1SDimitry Andric void serializeArray(Object &Paren, StringRef Key,
48*0fca6ea1SDimitry Andric                     std::optional<Array> &&Array) {
4981ad6265SDimitry Andric   if (Array)
50bdd1243dSDimitry Andric     Paren[Key] = std::move(*Array);
5181ad6265SDimitry Andric }
5281ad6265SDimitry Andric 
53*0fca6ea1SDimitry Andric /// Helper function to inject a JSON array composed of the values in \p C into
54*0fca6ea1SDimitry Andric /// object \p Paren at position \p Key.
55*0fca6ea1SDimitry Andric template <typename ContainerTy>
56*0fca6ea1SDimitry Andric void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) {
57*0fca6ea1SDimitry Andric   Paren[Key] = Array(C);
58*0fca6ea1SDimitry Andric }
59*0fca6ea1SDimitry Andric 
6081ad6265SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
6181ad6265SDimitry Andric /// format.
6281ad6265SDimitry Andric ///
6381ad6265SDimitry Andric /// A semantic version object contains three numeric fields, representing the
6481ad6265SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple.
6581ad6265SDimitry Andric /// For example version tuple 1.0.3 is serialized as:
6681ad6265SDimitry Andric /// \code
6781ad6265SDimitry Andric ///   {
6881ad6265SDimitry Andric ///     "major" : 1,
6981ad6265SDimitry Andric ///     "minor" : 0,
7081ad6265SDimitry Andric ///     "patch" : 3
7181ad6265SDimitry Andric ///   }
7281ad6265SDimitry Andric /// \endcode
7381ad6265SDimitry Andric ///
74bdd1243dSDimitry Andric /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
75bdd1243dSDimitry Andric /// containing the semantic version representation of \p V.
76bdd1243dSDimitry Andric std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
7781ad6265SDimitry Andric   if (V.empty())
78bdd1243dSDimitry Andric     return std::nullopt;
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric   Object Version;
8181ad6265SDimitry Andric   Version["major"] = V.getMajor();
8281ad6265SDimitry Andric   Version["minor"] = V.getMinor().value_or(0);
8381ad6265SDimitry Andric   Version["patch"] = V.getSubminor().value_or(0);
8481ad6265SDimitry Andric   return Version;
8581ad6265SDimitry Andric }
8681ad6265SDimitry Andric 
8781ad6265SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property.
8881ad6265SDimitry Andric ///
8981ad6265SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an
9081ad6265SDimitry Andric /// optional \c minimumVersion semantic version field.
9181ad6265SDimitry Andric Object serializeOperatingSystem(const Triple &T) {
9281ad6265SDimitry Andric   Object OS;
9381ad6265SDimitry Andric   OS["name"] = T.getOSTypeName(T.getOS());
9481ad6265SDimitry Andric   serializeObject(OS, "minimumVersion",
9581ad6265SDimitry Andric                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
9681ad6265SDimitry Andric   return OS;
9781ad6265SDimitry Andric }
9881ad6265SDimitry Andric 
9981ad6265SDimitry Andric /// Serialize the platform information in the Symbol Graph module section.
10081ad6265SDimitry Andric ///
10181ad6265SDimitry Andric /// The platform object describes a target platform triple in corresponding
10281ad6265SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem.
10381ad6265SDimitry Andric Object serializePlatform(const Triple &T) {
10481ad6265SDimitry Andric   Object Platform;
10581ad6265SDimitry Andric   Platform["architecture"] = T.getArchName();
10681ad6265SDimitry Andric   Platform["vendor"] = T.getVendorName();
10781ad6265SDimitry Andric   Platform["operatingSystem"] = serializeOperatingSystem(T);
10881ad6265SDimitry Andric   return Platform;
10981ad6265SDimitry Andric }
11081ad6265SDimitry Andric 
11181ad6265SDimitry Andric /// Serialize a source position.
11281ad6265SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) {
11381ad6265SDimitry Andric   assert(Loc.isValid() && "invalid source position");
11481ad6265SDimitry Andric 
11581ad6265SDimitry Andric   Object SourcePosition;
1165f757f3fSDimitry Andric   SourcePosition["line"] = Loc.getLine() - 1;
1175f757f3fSDimitry Andric   SourcePosition["character"] = Loc.getColumn() - 1;
11881ad6265SDimitry Andric 
11981ad6265SDimitry Andric   return SourcePosition;
12081ad6265SDimitry Andric }
12181ad6265SDimitry Andric 
12281ad6265SDimitry Andric /// Serialize a source location in file.
12381ad6265SDimitry Andric ///
12481ad6265SDimitry Andric /// \param Loc The presumed location to serialize.
12581ad6265SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
12681ad6265SDimitry Andric /// Defaults to false.
12781ad6265SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc,
12881ad6265SDimitry Andric                                bool IncludeFileURI = false) {
12981ad6265SDimitry Andric   Object SourceLocation;
13081ad6265SDimitry Andric   serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric   if (IncludeFileURI) {
13381ad6265SDimitry Andric     std::string FileURI = "file://";
13481ad6265SDimitry Andric     // Normalize file path to use forward slashes for the URI.
13581ad6265SDimitry Andric     FileURI += sys::path::convert_to_slash(Loc.getFilename());
13681ad6265SDimitry Andric     SourceLocation["uri"] = FileURI;
13781ad6265SDimitry Andric   }
13881ad6265SDimitry Andric 
13981ad6265SDimitry Andric   return SourceLocation;
14081ad6265SDimitry Andric }
14181ad6265SDimitry Andric 
14281ad6265SDimitry Andric /// Serialize a source range with begin and end locations.
14381ad6265SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc,
14481ad6265SDimitry Andric                             const PresumedLoc &EndLoc) {
14581ad6265SDimitry Andric   Object SourceRange;
14681ad6265SDimitry Andric   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
14781ad6265SDimitry Andric   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
14881ad6265SDimitry Andric   return SourceRange;
14981ad6265SDimitry Andric }
15081ad6265SDimitry Andric 
15181ad6265SDimitry Andric /// Serialize the availability attributes of a symbol.
15281ad6265SDimitry Andric ///
15381ad6265SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted
1547a6dacacSDimitry Andric /// versions of the symbol as semantic versions, if not default.
1557a6dacacSDimitry Andric /// Availability information also contains flags to indicate if the symbol is
1567a6dacacSDimitry Andric /// unconditionally unavailable or deprecated,
1577a6dacacSDimitry Andric /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
15881ad6265SDimitry Andric ///
159bdd1243dSDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes,
1607a6dacacSDimitry Andric /// or an \c Array containing an object with the formatted availability
1617a6dacacSDimitry Andric /// information.
1627a6dacacSDimitry Andric std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
1637a6dacacSDimitry Andric   if (Avail.isDefault())
164bdd1243dSDimitry Andric     return std::nullopt;
16581ad6265SDimitry Andric 
166bdd1243dSDimitry Andric   Array AvailabilityArray;
167*0fca6ea1SDimitry Andric 
1687a6dacacSDimitry Andric   if (Avail.isUnconditionallyDeprecated()) {
169bdd1243dSDimitry Andric     Object UnconditionallyDeprecated;
170bdd1243dSDimitry Andric     UnconditionallyDeprecated["domain"] = "*";
171bdd1243dSDimitry Andric     UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
172bdd1243dSDimitry Andric     AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
173bdd1243dSDimitry Andric   }
174*0fca6ea1SDimitry Andric   Object Availability;
175*0fca6ea1SDimitry Andric 
176*0fca6ea1SDimitry Andric   Availability["domain"] = Avail.Domain;
177*0fca6ea1SDimitry Andric 
178*0fca6ea1SDimitry Andric   if (Avail.isUnavailable()) {
179*0fca6ea1SDimitry Andric     Availability["isUnconditionallyUnavailable"] = true;
180*0fca6ea1SDimitry Andric   } else {
181*0fca6ea1SDimitry Andric     serializeObject(Availability, "introduced",
182*0fca6ea1SDimitry Andric                     serializeSemanticVersion(Avail.Introduced));
183*0fca6ea1SDimitry Andric     serializeObject(Availability, "deprecated",
184*0fca6ea1SDimitry Andric                     serializeSemanticVersion(Avail.Deprecated));
185*0fca6ea1SDimitry Andric     serializeObject(Availability, "obsoleted",
186*0fca6ea1SDimitry Andric                     serializeSemanticVersion(Avail.Obsoleted));
18706c3fb27SDimitry Andric   }
188*0fca6ea1SDimitry Andric 
189bdd1243dSDimitry Andric   AvailabilityArray.emplace_back(std::move(Availability));
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";
2005f757f3fSDimitry Andric   case Language::CXX:
2015f757f3fSDimitry Andric     return "c++";
2025f757f3fSDimitry Andric   case Language::ObjCXX:
2035f757f3fSDimitry 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:
217*0fca6ea1SDimitry Andric   case Language::CIR:
21881ad6265SDimitry Andric     llvm_unreachable("Unsupported language kind");
21981ad6265SDimitry Andric   }
22081ad6265SDimitry Andric 
22181ad6265SDimitry Andric   llvm_unreachable("Unhandled language kind");
22281ad6265SDimitry Andric }
22381ad6265SDimitry Andric 
22481ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format.
22581ad6265SDimitry Andric ///
22681ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique
22781ad6265SDimitry Andric /// references, and the interface language name.
22881ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) {
22981ad6265SDimitry Andric   Object Identifier;
23081ad6265SDimitry Andric   Identifier["precise"] = Record.USR;
23181ad6265SDimitry Andric   Identifier["interfaceLanguage"] = getLanguageName(Lang);
23281ad6265SDimitry Andric 
23381ad6265SDimitry Andric   return Identifier;
23481ad6265SDimitry Andric }
23581ad6265SDimitry Andric 
23681ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by
23781ad6265SDimitry Andric /// the Symbol Graph format.
23881ad6265SDimitry Andric ///
23981ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line
24081ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range
24181ad6265SDimitry Andric /// information.
24281ad6265SDimitry Andric /// e.g.
24381ad6265SDimitry Andric /// \code
24481ad6265SDimitry Andric ///   /// This is a documentation comment
24581ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
24681ad6265SDimitry Andric ///   ///     with multiple lines.
24781ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
24881ad6265SDimitry Andric /// \endcode
24981ad6265SDimitry Andric ///
250bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
251bdd1243dSDimitry Andric /// the formatted lines.
252bdd1243dSDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) {
25381ad6265SDimitry Andric   if (Comment.empty())
254bdd1243dSDimitry Andric     return std::nullopt;
25581ad6265SDimitry Andric 
25681ad6265SDimitry Andric   Object DocComment;
257*0fca6ea1SDimitry Andric 
25881ad6265SDimitry Andric   Array LinesArray;
25981ad6265SDimitry Andric   for (const auto &CommentLine : Comment) {
26081ad6265SDimitry Andric     Object Line;
26181ad6265SDimitry Andric     Line["text"] = CommentLine.Text;
26281ad6265SDimitry Andric     serializeObject(Line, "range",
26381ad6265SDimitry Andric                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
26481ad6265SDimitry Andric     LinesArray.emplace_back(std::move(Line));
26581ad6265SDimitry Andric   }
266*0fca6ea1SDimitry Andric 
267*0fca6ea1SDimitry Andric   serializeArray(DocComment, "lines", std::move(LinesArray));
26881ad6265SDimitry Andric 
26981ad6265SDimitry Andric   return DocComment;
27081ad6265SDimitry Andric }
27181ad6265SDimitry Andric 
27281ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol.
27381ad6265SDimitry Andric ///
27481ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important
27581ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to
27681ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for
27781ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example:
27881ad6265SDimitry Andric /// \code
27981ad6265SDimitry Andric ///   const int pi; -> "declarationFragments" : [
28081ad6265SDimitry Andric ///                      {
28181ad6265SDimitry Andric ///                        "kind" : "keyword",
28281ad6265SDimitry Andric ///                        "spelling" : "const"
28381ad6265SDimitry Andric ///                      },
28481ad6265SDimitry Andric ///                      {
28581ad6265SDimitry Andric ///                        "kind" : "text",
28681ad6265SDimitry Andric ///                        "spelling" : " "
28781ad6265SDimitry Andric ///                      },
28881ad6265SDimitry Andric ///                      {
28981ad6265SDimitry Andric ///                        "kind" : "typeIdentifier",
29081ad6265SDimitry Andric ///                        "preciseIdentifier" : "c:I",
29181ad6265SDimitry Andric ///                        "spelling" : "int"
29281ad6265SDimitry Andric ///                      },
29381ad6265SDimitry Andric ///                      {
29481ad6265SDimitry Andric ///                        "kind" : "text",
29581ad6265SDimitry Andric ///                        "spelling" : " "
29681ad6265SDimitry Andric ///                      },
29781ad6265SDimitry Andric ///                      {
29881ad6265SDimitry Andric ///                        "kind" : "identifier",
29981ad6265SDimitry Andric ///                        "spelling" : "pi"
30081ad6265SDimitry Andric ///                      }
30181ad6265SDimitry Andric ///                    ]
30281ad6265SDimitry Andric /// \endcode
30381ad6265SDimitry Andric ///
304bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
305bdd1243dSDimitry Andric /// formatted declaration fragments array.
306bdd1243dSDimitry Andric std::optional<Array>
307bdd1243dSDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) {
30881ad6265SDimitry Andric   if (DF.getFragments().empty())
309bdd1243dSDimitry Andric     return std::nullopt;
31081ad6265SDimitry Andric 
31181ad6265SDimitry Andric   Array Fragments;
31281ad6265SDimitry Andric   for (const auto &F : DF.getFragments()) {
31381ad6265SDimitry Andric     Object Fragment;
31481ad6265SDimitry Andric     Fragment["spelling"] = F.Spelling;
31581ad6265SDimitry Andric     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
31681ad6265SDimitry Andric     if (!F.PreciseIdentifier.empty())
31781ad6265SDimitry Andric       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
31881ad6265SDimitry Andric     Fragments.emplace_back(std::move(Fragment));
31981ad6265SDimitry Andric   }
32081ad6265SDimitry Andric 
32181ad6265SDimitry Andric   return Fragments;
32281ad6265SDimitry Andric }
32381ad6265SDimitry Andric 
32481ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph
32581ad6265SDimitry Andric /// format.
32681ad6265SDimitry Andric ///
32781ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol
32881ad6265SDimitry Andric /// that can be used for different applications:
32981ad6265SDimitry Andric ///   - \c title : The simple declared name of the symbol;
33081ad6265SDimitry Andric ///   - \c subHeading : An array of declaration fragments that provides tags,
33181ad6265SDimitry Andric ///     and potentially more tokens (for example the \c +/- symbol for
33281ad6265SDimitry Andric ///     Objective-C methods). Can be used as sub-headings for documentation.
333*0fca6ea1SDimitry Andric Object serializeNames(const APIRecord *Record) {
33481ad6265SDimitry Andric   Object Names;
335*0fca6ea1SDimitry Andric   Names["title"] = Record->Name;
3365f757f3fSDimitry Andric 
33781ad6265SDimitry Andric   serializeArray(Names, "subHeading",
338*0fca6ea1SDimitry Andric                  serializeDeclarationFragments(Record->SubHeading));
33981ad6265SDimitry Andric   DeclarationFragments NavigatorFragments;
340*0fca6ea1SDimitry Andric   NavigatorFragments.append(Record->Name,
34181ad6265SDimitry Andric                             DeclarationFragments::FragmentKind::Identifier,
34281ad6265SDimitry Andric                             /*PreciseIdentifier*/ "");
34381ad6265SDimitry Andric   serializeArray(Names, "navigator",
34481ad6265SDimitry Andric                  serializeDeclarationFragments(NavigatorFragments));
34581ad6265SDimitry Andric 
34681ad6265SDimitry Andric   return Names;
34781ad6265SDimitry Andric }
34881ad6265SDimitry Andric 
349bdd1243dSDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
35081ad6265SDimitry Andric   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
35181ad6265SDimitry Andric     return (getLanguageName(Lang) + "." + S).str();
35281ad6265SDimitry Andric   };
35381ad6265SDimitry Andric 
35481ad6265SDimitry Andric   Object Kind;
355bdd1243dSDimitry Andric   switch (RK) {
356bdd1243dSDimitry Andric   case APIRecord::RK_Unknown:
357*0fca6ea1SDimitry Andric     Kind["identifier"] = AddLangPrefix("unknown");
358*0fca6ea1SDimitry Andric     Kind["displayName"] = "Unknown";
359bdd1243dSDimitry Andric     break;
3605f757f3fSDimitry Andric   case APIRecord::RK_Namespace:
3615f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("namespace");
3625f757f3fSDimitry Andric     Kind["displayName"] = "Namespace";
3635f757f3fSDimitry Andric     break;
36481ad6265SDimitry Andric   case APIRecord::RK_GlobalFunction:
36581ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
36681ad6265SDimitry Andric     Kind["displayName"] = "Function";
36781ad6265SDimitry Andric     break;
3685f757f3fSDimitry Andric   case APIRecord::RK_GlobalFunctionTemplate:
3695f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
3705f757f3fSDimitry Andric     Kind["displayName"] = "Function Template";
3715f757f3fSDimitry Andric     break;
3725f757f3fSDimitry Andric   case APIRecord::RK_GlobalFunctionTemplateSpecialization:
3735f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
3745f757f3fSDimitry Andric     Kind["displayName"] = "Function Template Specialization";
3755f757f3fSDimitry Andric     break;
3765f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplate:
3775f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
3785f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template";
3795f757f3fSDimitry Andric     break;
3805f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplateSpecialization:
3815f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
3825f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template Specialization";
3835f757f3fSDimitry Andric     break;
3845f757f3fSDimitry Andric   case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
3855f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
3865f757f3fSDimitry Andric     Kind["displayName"] = "Global Variable Template Partial Specialization";
3875f757f3fSDimitry Andric     break;
38881ad6265SDimitry Andric   case APIRecord::RK_GlobalVariable:
38981ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
39081ad6265SDimitry Andric     Kind["displayName"] = "Global Variable";
39181ad6265SDimitry Andric     break;
39281ad6265SDimitry Andric   case APIRecord::RK_EnumConstant:
39381ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum.case");
39481ad6265SDimitry Andric     Kind["displayName"] = "Enumeration Case";
39581ad6265SDimitry Andric     break;
39681ad6265SDimitry Andric   case APIRecord::RK_Enum:
39781ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum");
39881ad6265SDimitry Andric     Kind["displayName"] = "Enumeration";
39981ad6265SDimitry Andric     break;
40081ad6265SDimitry Andric   case APIRecord::RK_StructField:
40181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
40281ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
40381ad6265SDimitry Andric     break;
40481ad6265SDimitry Andric   case APIRecord::RK_Struct:
40581ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("struct");
40681ad6265SDimitry Andric     Kind["displayName"] = "Structure";
40781ad6265SDimitry Andric     break;
4087a6dacacSDimitry Andric   case APIRecord::RK_UnionField:
4095f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
4105f757f3fSDimitry Andric     Kind["displayName"] = "Instance Property";
4115f757f3fSDimitry Andric     break;
4125f757f3fSDimitry Andric   case APIRecord::RK_Union:
4135f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("union");
4145f757f3fSDimitry Andric     Kind["displayName"] = "Union";
4155f757f3fSDimitry Andric     break;
4167a6dacacSDimitry Andric   case APIRecord::RK_CXXField:
4177a6dacacSDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
4187a6dacacSDimitry Andric     Kind["displayName"] = "Instance Property";
4197a6dacacSDimitry Andric     break;
4205f757f3fSDimitry Andric   case APIRecord::RK_StaticField:
4215f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.property");
4225f757f3fSDimitry Andric     Kind["displayName"] = "Type Property";
4235f757f3fSDimitry Andric     break;
4245f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplate:
4255f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplateSpecialization:
4265f757f3fSDimitry Andric   case APIRecord::RK_ClassTemplatePartialSpecialization:
4275f757f3fSDimitry Andric   case APIRecord::RK_CXXClass:
4285f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("class");
4295f757f3fSDimitry Andric     Kind["displayName"] = "Class";
4305f757f3fSDimitry Andric     break;
4315f757f3fSDimitry Andric   case APIRecord::RK_CXXMethodTemplate:
4325f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4335f757f3fSDimitry Andric     Kind["displayName"] = "Method Template";
4345f757f3fSDimitry Andric     break;
4355f757f3fSDimitry Andric   case APIRecord::RK_CXXMethodTemplateSpecialization:
4365f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4375f757f3fSDimitry Andric     Kind["displayName"] = "Method Template Specialization";
4385f757f3fSDimitry Andric     break;
4395f757f3fSDimitry Andric   case APIRecord::RK_CXXFieldTemplate:
4405f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
4415f757f3fSDimitry Andric     Kind["displayName"] = "Template Property";
4425f757f3fSDimitry Andric     break;
4435f757f3fSDimitry Andric   case APIRecord::RK_Concept:
4445f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("concept");
4455f757f3fSDimitry Andric     Kind["displayName"] = "Concept";
4465f757f3fSDimitry Andric     break;
4475f757f3fSDimitry Andric   case APIRecord::RK_CXXStaticMethod:
4485f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.method");
4495f757f3fSDimitry Andric     Kind["displayName"] = "Static Method";
4505f757f3fSDimitry Andric     break;
4515f757f3fSDimitry Andric   case APIRecord::RK_CXXInstanceMethod:
4525f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4535f757f3fSDimitry Andric     Kind["displayName"] = "Instance Method";
4545f757f3fSDimitry Andric     break;
4555f757f3fSDimitry Andric   case APIRecord::RK_CXXConstructorMethod:
4565f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4575f757f3fSDimitry Andric     Kind["displayName"] = "Constructor";
4585f757f3fSDimitry Andric     break;
4595f757f3fSDimitry Andric   case APIRecord::RK_CXXDestructorMethod:
4605f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
4615f757f3fSDimitry Andric     Kind["displayName"] = "Destructor";
4625f757f3fSDimitry Andric     break;
46381ad6265SDimitry Andric   case APIRecord::RK_ObjCIvar:
46481ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("ivar");
46581ad6265SDimitry Andric     Kind["displayName"] = "Instance Variable";
46681ad6265SDimitry Andric     break;
467bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInstanceMethod:
46881ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
46981ad6265SDimitry Andric     Kind["displayName"] = "Instance Method";
470bdd1243dSDimitry Andric     break;
471bdd1243dSDimitry Andric   case APIRecord::RK_ObjCClassMethod:
47281ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("type.method");
47381ad6265SDimitry Andric     Kind["displayName"] = "Type Method";
47481ad6265SDimitry Andric     break;
475bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInstanceProperty:
47681ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
47781ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
47881ad6265SDimitry Andric     break;
479bdd1243dSDimitry Andric   case APIRecord::RK_ObjCClassProperty:
480bdd1243dSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.property");
481bdd1243dSDimitry Andric     Kind["displayName"] = "Type Property";
482bdd1243dSDimitry Andric     break;
48381ad6265SDimitry Andric   case APIRecord::RK_ObjCInterface:
48481ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("class");
48581ad6265SDimitry Andric     Kind["displayName"] = "Class";
48681ad6265SDimitry Andric     break;
48781ad6265SDimitry Andric   case APIRecord::RK_ObjCCategory:
4885f757f3fSDimitry Andric     Kind["identifier"] = AddLangPrefix("class.extension");
4895f757f3fSDimitry Andric     Kind["displayName"] = "Class Extension";
4905f757f3fSDimitry Andric     break;
49181ad6265SDimitry Andric   case APIRecord::RK_ObjCProtocol:
49281ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("protocol");
49381ad6265SDimitry Andric     Kind["displayName"] = "Protocol";
49481ad6265SDimitry Andric     break;
49581ad6265SDimitry Andric   case APIRecord::RK_MacroDefinition:
49681ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("macro");
49781ad6265SDimitry Andric     Kind["displayName"] = "Macro";
49881ad6265SDimitry Andric     break;
49981ad6265SDimitry Andric   case APIRecord::RK_Typedef:
50081ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("typealias");
50181ad6265SDimitry Andric     Kind["displayName"] = "Type Alias";
50281ad6265SDimitry Andric     break;
503*0fca6ea1SDimitry Andric   default:
504*0fca6ea1SDimitry Andric     llvm_unreachable("API Record with uninstantiable kind");
50581ad6265SDimitry Andric   }
50681ad6265SDimitry Andric 
50781ad6265SDimitry Andric   return Kind;
50881ad6265SDimitry Andric }
50981ad6265SDimitry Andric 
510bdd1243dSDimitry Andric /// Serialize the symbol kind information.
511bdd1243dSDimitry Andric ///
512bdd1243dSDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier
513bdd1243dSDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse
514bdd1243dSDimitry Andric /// the kind, and a \c displayName for rendering human-readable names.
515bdd1243dSDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
516*0fca6ea1SDimitry Andric   return serializeSymbolKind(Record.KindForDisplay, Lang);
517bdd1243dSDimitry Andric }
518bdd1243dSDimitry Andric 
519*0fca6ea1SDimitry Andric /// Serialize the function signature field, as specified by the
520*0fca6ea1SDimitry Andric /// Symbol Graph format.
521*0fca6ea1SDimitry Andric ///
522*0fca6ea1SDimitry Andric /// The Symbol Graph function signature property contains two arrays.
523*0fca6ea1SDimitry Andric ///   - The \c returns array is the declaration fragments of the return type;
524*0fca6ea1SDimitry Andric ///   - The \c parameters array contains names and declaration fragments of the
525*0fca6ea1SDimitry Andric ///     parameters.
52681ad6265SDimitry Andric template <typename RecordTy>
527*0fca6ea1SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
52881ad6265SDimitry Andric   const auto &FS = Record.Signature;
52981ad6265SDimitry Andric   if (FS.empty())
530*0fca6ea1SDimitry Andric     return;
53181ad6265SDimitry Andric 
53281ad6265SDimitry Andric   Object Signature;
53381ad6265SDimitry Andric   serializeArray(Signature, "returns",
53481ad6265SDimitry Andric                  serializeDeclarationFragments(FS.getReturnType()));
53581ad6265SDimitry Andric 
53681ad6265SDimitry Andric   Array Parameters;
53781ad6265SDimitry Andric   for (const auto &P : FS.getParameters()) {
53881ad6265SDimitry Andric     Object Parameter;
53981ad6265SDimitry Andric     Parameter["name"] = P.Name;
54081ad6265SDimitry Andric     serializeArray(Parameter, "declarationFragments",
54181ad6265SDimitry Andric                    serializeDeclarationFragments(P.Fragments));
54281ad6265SDimitry Andric     Parameters.emplace_back(std::move(Parameter));
54381ad6265SDimitry Andric   }
54481ad6265SDimitry Andric 
54581ad6265SDimitry Andric   if (!Parameters.empty())
54681ad6265SDimitry Andric     Signature["parameters"] = std::move(Parameters);
54781ad6265SDimitry Andric 
548*0fca6ea1SDimitry Andric   serializeObject(Paren, "functionSignature", std::move(Signature));
54981ad6265SDimitry Andric }
55081ad6265SDimitry Andric 
55181ad6265SDimitry Andric template <typename RecordTy>
552*0fca6ea1SDimitry Andric void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
5535f757f3fSDimitry Andric   const auto &Template = Record.Templ;
5545f757f3fSDimitry Andric   if (Template.empty())
555*0fca6ea1SDimitry Andric     return;
5565f757f3fSDimitry Andric 
5575f757f3fSDimitry Andric   Object Generics;
5585f757f3fSDimitry Andric   Array GenericParameters;
5595f757f3fSDimitry Andric   for (const auto &Param : Template.getParameters()) {
5605f757f3fSDimitry Andric     Object Parameter;
5615f757f3fSDimitry Andric     Parameter["name"] = Param.Name;
5625f757f3fSDimitry Andric     Parameter["index"] = Param.Index;
5635f757f3fSDimitry Andric     Parameter["depth"] = Param.Depth;
5645f757f3fSDimitry Andric     GenericParameters.emplace_back(std::move(Parameter));
5655f757f3fSDimitry Andric   }
5665f757f3fSDimitry Andric   if (!GenericParameters.empty())
5675f757f3fSDimitry Andric     Generics["parameters"] = std::move(GenericParameters);
5685f757f3fSDimitry Andric 
5695f757f3fSDimitry Andric   Array GenericConstraints;
5705f757f3fSDimitry Andric   for (const auto &Constr : Template.getConstraints()) {
5715f757f3fSDimitry Andric     Object Constraint;
5725f757f3fSDimitry Andric     Constraint["kind"] = Constr.Kind;
5735f757f3fSDimitry Andric     Constraint["lhs"] = Constr.LHS;
5745f757f3fSDimitry Andric     Constraint["rhs"] = Constr.RHS;
5755f757f3fSDimitry Andric     GenericConstraints.emplace_back(std::move(Constraint));
5765f757f3fSDimitry Andric   }
5775f757f3fSDimitry Andric 
5785f757f3fSDimitry Andric   if (!GenericConstraints.empty())
5795f757f3fSDimitry Andric     Generics["constraints"] = std::move(GenericConstraints);
5805f757f3fSDimitry Andric 
581*0fca6ea1SDimitry Andric   serializeObject(Paren, "swiftGenerics", Generics);
5825f757f3fSDimitry Andric }
5835f757f3fSDimitry Andric 
584*0fca6ea1SDimitry Andric Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents,
585bdd1243dSDimitry Andric                              Language Lang) {
586bdd1243dSDimitry Andric   Array ParentContexts;
587*0fca6ea1SDimitry Andric 
588*0fca6ea1SDimitry Andric   for (const auto &Parent : Parents) {
589*0fca6ea1SDimitry Andric     Object Elem;
590*0fca6ea1SDimitry Andric     Elem["usr"] = Parent.USR;
591*0fca6ea1SDimitry Andric     Elem["name"] = Parent.Name;
592*0fca6ea1SDimitry Andric     if (Parent.Record)
593*0fca6ea1SDimitry Andric       Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay,
594*0fca6ea1SDimitry Andric                                          Lang)["identifier"];
595*0fca6ea1SDimitry Andric     else
596*0fca6ea1SDimitry Andric       Elem["kind"] =
597*0fca6ea1SDimitry Andric           serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"];
598*0fca6ea1SDimitry Andric     ParentContexts.emplace_back(std::move(Elem));
599*0fca6ea1SDimitry Andric   }
600bdd1243dSDimitry Andric 
601bdd1243dSDimitry Andric   return ParentContexts;
602bdd1243dSDimitry Andric }
603*0fca6ea1SDimitry Andric 
604*0fca6ea1SDimitry Andric /// Walk the records parent information in reverse to generate a hierarchy
605*0fca6ea1SDimitry Andric /// suitable for serialization.
606*0fca6ea1SDimitry Andric SmallVector<SymbolReference, 8>
607*0fca6ea1SDimitry Andric generateHierarchyFromRecord(const APIRecord *Record) {
608*0fca6ea1SDimitry Andric   SmallVector<SymbolReference, 8> ReverseHierarchy;
609*0fca6ea1SDimitry Andric   for (const auto *Current = Record; Current != nullptr;
610*0fca6ea1SDimitry Andric        Current = Current->Parent.Record)
611*0fca6ea1SDimitry Andric     ReverseHierarchy.emplace_back(Current);
612*0fca6ea1SDimitry Andric 
613*0fca6ea1SDimitry Andric   return SmallVector<SymbolReference, 8>(
614*0fca6ea1SDimitry Andric       std::make_move_iterator(ReverseHierarchy.rbegin()),
615*0fca6ea1SDimitry Andric       std::make_move_iterator(ReverseHierarchy.rend()));
616*0fca6ea1SDimitry Andric }
617*0fca6ea1SDimitry Andric 
618*0fca6ea1SDimitry Andric SymbolReference getHierarchyReference(const APIRecord *Record,
619*0fca6ea1SDimitry Andric                                       const APISet &API) {
620*0fca6ea1SDimitry Andric   // If the parent is a category extended from internal module then we need to
621*0fca6ea1SDimitry Andric   // pretend this belongs to the associated interface.
622*0fca6ea1SDimitry Andric   if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) {
623*0fca6ea1SDimitry Andric     return CategoryRecord->Interface;
624*0fca6ea1SDimitry Andric     // FIXME: TODO generate path components correctly for categories extending
625*0fca6ea1SDimitry Andric     // an external module.
626*0fca6ea1SDimitry Andric   }
627*0fca6ea1SDimitry Andric 
628*0fca6ea1SDimitry Andric   return SymbolReference(Record);
629*0fca6ea1SDimitry Andric }
630*0fca6ea1SDimitry Andric 
63181ad6265SDimitry Andric } // namespace
63281ad6265SDimitry Andric 
633*0fca6ea1SDimitry Andric Object *ExtendedModule::addSymbol(Object &&Symbol) {
634*0fca6ea1SDimitry Andric   Symbols.emplace_back(std::move(Symbol));
635*0fca6ea1SDimitry Andric   return Symbols.back().getAsObject();
636*0fca6ea1SDimitry Andric }
637*0fca6ea1SDimitry Andric 
638*0fca6ea1SDimitry Andric void ExtendedModule::addRelationship(Object &&Relationship) {
639*0fca6ea1SDimitry Andric   Relationships.emplace_back(std::move(Relationship));
640*0fca6ea1SDimitry Andric }
641*0fca6ea1SDimitry Andric 
64281ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer.
64381ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
64481ad6265SDimitry Andric 
64581ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const {
64681ad6265SDimitry Andric   Object Metadata;
64781ad6265SDimitry Andric   serializeObject(Metadata, "formatVersion",
64881ad6265SDimitry Andric                   serializeSemanticVersion(FormatVersion));
64981ad6265SDimitry Andric   Metadata["generator"] = clang::getClangFullVersion();
65081ad6265SDimitry Andric   return Metadata;
65181ad6265SDimitry Andric }
65281ad6265SDimitry Andric 
653*0fca6ea1SDimitry Andric Object
654*0fca6ea1SDimitry Andric SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const {
65581ad6265SDimitry Andric   Object Module;
656*0fca6ea1SDimitry Andric   Module["name"] = ModuleName;
65781ad6265SDimitry Andric   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
65881ad6265SDimitry Andric   return Module;
65981ad6265SDimitry Andric }
66081ad6265SDimitry Andric 
661*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {
662*0fca6ea1SDimitry Andric   if (!Record)
663bdd1243dSDimitry Andric     return true;
664bdd1243dSDimitry Andric 
66581ad6265SDimitry Andric   // Skip unconditionally unavailable symbols
666*0fca6ea1SDimitry Andric   if (Record->Availability.isUnconditionallyUnavailable())
66781ad6265SDimitry Andric     return true;
66881ad6265SDimitry Andric 
669*0fca6ea1SDimitry Andric   // Filter out symbols without a name as we can generate correct symbol graphs
670*0fca6ea1SDimitry Andric   // for them. In practice these are anonymous record types that aren't attached
671*0fca6ea1SDimitry Andric   // to a declaration.
672*0fca6ea1SDimitry Andric   if (auto *Tag = dyn_cast<TagRecord>(Record)) {
673*0fca6ea1SDimitry Andric     if (Tag->IsEmbeddedInVarDeclarator)
674*0fca6ea1SDimitry Andric       return true;
675*0fca6ea1SDimitry Andric   }
676*0fca6ea1SDimitry Andric 
67781ad6265SDimitry Andric   // Filter out symbols prefixed with an underscored as they are understood to
67881ad6265SDimitry Andric   // be symbols clients should not use.
679*0fca6ea1SDimitry Andric   if (Record->Name.starts_with("_"))
680*0fca6ea1SDimitry Andric     return true;
681*0fca6ea1SDimitry Andric 
682*0fca6ea1SDimitry Andric   // Skip explicitly ignored symbols.
683*0fca6ea1SDimitry Andric   if (IgnoresList.shouldIgnore(Record->Name))
68481ad6265SDimitry Andric     return true;
68581ad6265SDimitry Andric 
68681ad6265SDimitry Andric   return false;
68781ad6265SDimitry Andric }
68881ad6265SDimitry Andric 
689*0fca6ea1SDimitry Andric ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {
690*0fca6ea1SDimitry Andric   if (!ForceEmitToMainModule && ModuleForCurrentSymbol)
691*0fca6ea1SDimitry Andric     return *ModuleForCurrentSymbol;
69281ad6265SDimitry Andric 
693*0fca6ea1SDimitry Andric   return MainModule;
69481ad6265SDimitry Andric }
69581ad6265SDimitry Andric 
696*0fca6ea1SDimitry Andric Array SymbolGraphSerializer::serializePathComponents(
697*0fca6ea1SDimitry Andric     const APIRecord *Record) const {
698*0fca6ea1SDimitry Andric   return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));
69981ad6265SDimitry Andric }
70081ad6265SDimitry Andric 
70181ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
70281ad6265SDimitry Andric   switch (Kind) {
70381ad6265SDimitry Andric   case RelationshipKind::MemberOf:
70481ad6265SDimitry Andric     return "memberOf";
70581ad6265SDimitry Andric   case RelationshipKind::InheritsFrom:
70681ad6265SDimitry Andric     return "inheritsFrom";
70781ad6265SDimitry Andric   case RelationshipKind::ConformsTo:
70881ad6265SDimitry Andric     return "conformsTo";
7095f757f3fSDimitry Andric   case RelationshipKind::ExtensionTo:
7105f757f3fSDimitry Andric     return "extensionTo";
71181ad6265SDimitry Andric   }
71281ad6265SDimitry Andric   llvm_unreachable("Unhandled relationship kind");
71381ad6265SDimitry Andric }
71481ad6265SDimitry Andric 
715*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
716*0fca6ea1SDimitry Andric                                                   const SymbolReference &Source,
717*0fca6ea1SDimitry Andric                                                   const SymbolReference &Target,
718*0fca6ea1SDimitry Andric                                                   ExtendedModule &Into) {
719*0fca6ea1SDimitry Andric   Object Relationship;
720*0fca6ea1SDimitry Andric   SmallString<64> TestRelLabel;
721*0fca6ea1SDimitry Andric   if (EmitSymbolLabelsForTesting) {
722*0fca6ea1SDimitry Andric     llvm::raw_svector_ostream OS(TestRelLabel);
723*0fca6ea1SDimitry Andric     OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ "
724*0fca6ea1SDimitry Andric        << Source.USR << " $ ";
725*0fca6ea1SDimitry Andric     if (Target.USR.empty())
726*0fca6ea1SDimitry Andric       OS << Target.Name;
727*0fca6ea1SDimitry Andric     else
728*0fca6ea1SDimitry Andric       OS << Target.USR;
729*0fca6ea1SDimitry Andric     Relationship["!testRelLabel"] = TestRelLabel;
730*0fca6ea1SDimitry Andric   }
731*0fca6ea1SDimitry Andric   Relationship["source"] = Source.USR;
732*0fca6ea1SDimitry Andric   Relationship["target"] = Target.USR;
733*0fca6ea1SDimitry Andric   Relationship["targetFallback"] = Target.Name;
734*0fca6ea1SDimitry Andric   Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind);
735*0fca6ea1SDimitry Andric 
736*0fca6ea1SDimitry Andric   if (ForceEmitToMainModule)
737*0fca6ea1SDimitry Andric     MainModule.addRelationship(std::move(Relationship));
738*0fca6ea1SDimitry Andric   else
739*0fca6ea1SDimitry Andric     Into.addRelationship(std::move(Relationship));
740*0fca6ea1SDimitry Andric }
741*0fca6ea1SDimitry Andric 
7425f757f3fSDimitry Andric StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
7435f757f3fSDimitry Andric   switch (Kind) {
7445f757f3fSDimitry Andric   case ConstraintKind::Conformance:
7455f757f3fSDimitry Andric     return "conformance";
7465f757f3fSDimitry Andric   case ConstraintKind::ConditionalConformance:
7475f757f3fSDimitry Andric     return "conditionalConformance";
7485f757f3fSDimitry Andric   }
7495f757f3fSDimitry Andric   llvm_unreachable("Unhandled constraint kind");
7505f757f3fSDimitry Andric }
7515f757f3fSDimitry Andric 
752*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) {
7535f757f3fSDimitry Andric   Object Obj;
754*0fca6ea1SDimitry Andric 
755*0fca6ea1SDimitry Andric   // If we need symbol labels for testing emit the USR as the value and the key
756*0fca6ea1SDimitry Andric   // starts with '!'' to ensure it ends up at the top of the object.
757*0fca6ea1SDimitry Andric   if (EmitSymbolLabelsForTesting)
758*0fca6ea1SDimitry Andric     Obj["!testLabel"] = Record->USR;
759*0fca6ea1SDimitry Andric 
7605f757f3fSDimitry Andric   serializeObject(Obj, "identifier",
761*0fca6ea1SDimitry Andric                   serializeIdentifier(*Record, API.getLanguage()));
762*0fca6ea1SDimitry Andric   serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage()));
763*0fca6ea1SDimitry Andric   serializeObject(Obj, "names", serializeNames(Record));
764*0fca6ea1SDimitry Andric   serializeObject(
765*0fca6ea1SDimitry Andric       Obj, "location",
766*0fca6ea1SDimitry Andric       serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true));
767*0fca6ea1SDimitry Andric   serializeArray(Obj, "availability",
768*0fca6ea1SDimitry Andric                  serializeAvailability(Record->Availability));
769*0fca6ea1SDimitry Andric   serializeObject(Obj, "docComment", serializeDocComment(Record->Comment));
770*0fca6ea1SDimitry Andric   serializeArray(Obj, "declarationFragments",
771*0fca6ea1SDimitry Andric                  serializeDeclarationFragments(Record->Declaration));
772*0fca6ea1SDimitry Andric 
773*0fca6ea1SDimitry Andric   Obj["pathComponents"] = serializePathComponents(Record);
774*0fca6ea1SDimitry Andric   Obj["accessLevel"] = Record->Access.getAccess();
775*0fca6ea1SDimitry Andric 
776*0fca6ea1SDimitry Andric   ExtendedModule &Module = getModuleForCurrentSymbol();
777*0fca6ea1SDimitry Andric   // If the hierarchy has at least one parent and child.
778*0fca6ea1SDimitry Andric   if (Hierarchy.size() >= 2)
779*0fca6ea1SDimitry Andric     serializeRelationship(MemberOf, Hierarchy.back(),
780*0fca6ea1SDimitry Andric                           Hierarchy[Hierarchy.size() - 2], Module);
781*0fca6ea1SDimitry Andric 
782*0fca6ea1SDimitry Andric   CurrentSymbol = Module.addSymbol(std::move(Obj));
7835f757f3fSDimitry Andric }
7845f757f3fSDimitry Andric 
785*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) {
786*0fca6ea1SDimitry Andric   if (!Record)
787*0fca6ea1SDimitry Andric     return true;
788*0fca6ea1SDimitry Andric   if (shouldSkip(Record))
789*0fca6ea1SDimitry Andric     return true;
790*0fca6ea1SDimitry Andric   Hierarchy.push_back(getHierarchyReference(Record, API));
791*0fca6ea1SDimitry Andric   // Defer traversal mechanics to APISetVisitor base implementation
792*0fca6ea1SDimitry Andric   auto RetVal = Base::traverseAPIRecord(Record);
793*0fca6ea1SDimitry Andric   Hierarchy.pop_back();
794*0fca6ea1SDimitry Andric   return RetVal;
7955f757f3fSDimitry Andric }
7965f757f3fSDimitry Andric 
797*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) {
798*0fca6ea1SDimitry Andric   serializeAPIRecord(Record);
799*0fca6ea1SDimitry Andric   return true;
800*0fca6ea1SDimitry Andric }
80181ad6265SDimitry Andric 
802*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitGlobalFunctionRecord(
803*0fca6ea1SDimitry Andric     const GlobalFunctionRecord *Record) {
804*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
805*0fca6ea1SDimitry Andric     return true;
80681ad6265SDimitry Andric 
807*0fca6ea1SDimitry Andric   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
808*0fca6ea1SDimitry Andric   return true;
809*0fca6ea1SDimitry Andric }
810*0fca6ea1SDimitry Andric 
811*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) {
812*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
813*0fca6ea1SDimitry Andric     return true;
814*0fca6ea1SDimitry Andric 
815*0fca6ea1SDimitry Andric   for (const auto &Base : Record->Bases)
816*0fca6ea1SDimitry Andric     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base,
817*0fca6ea1SDimitry Andric                           getModuleForCurrentSymbol());
818*0fca6ea1SDimitry Andric   return true;
819*0fca6ea1SDimitry Andric }
820*0fca6ea1SDimitry Andric 
821*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitClassTemplateRecord(
822*0fca6ea1SDimitry Andric     const ClassTemplateRecord *Record) {
823*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
824*0fca6ea1SDimitry Andric     return true;
825*0fca6ea1SDimitry Andric 
826*0fca6ea1SDimitry Andric   serializeTemplateMixin(*CurrentSymbol, *Record);
827*0fca6ea1SDimitry Andric   return true;
828*0fca6ea1SDimitry Andric }
829*0fca6ea1SDimitry Andric 
830*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
831*0fca6ea1SDimitry Andric     const ClassTemplatePartialSpecializationRecord *Record) {
832*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
833*0fca6ea1SDimitry Andric     return true;
834*0fca6ea1SDimitry Andric 
835*0fca6ea1SDimitry Andric   serializeTemplateMixin(*CurrentSymbol, *Record);
836*0fca6ea1SDimitry Andric   return true;
837*0fca6ea1SDimitry Andric }
838*0fca6ea1SDimitry Andric 
839*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitCXXMethodRecord(
840*0fca6ea1SDimitry Andric     const CXXMethodRecord *Record) {
841*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
842*0fca6ea1SDimitry Andric     return true;
843*0fca6ea1SDimitry Andric 
844*0fca6ea1SDimitry Andric   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
845*0fca6ea1SDimitry Andric   return true;
846*0fca6ea1SDimitry Andric }
847*0fca6ea1SDimitry Andric 
848*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitCXXMethodTemplateRecord(
849*0fca6ea1SDimitry Andric     const CXXMethodTemplateRecord *Record) {
850*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
851*0fca6ea1SDimitry Andric     return true;
852*0fca6ea1SDimitry Andric 
853*0fca6ea1SDimitry Andric   serializeTemplateMixin(*CurrentSymbol, *Record);
854*0fca6ea1SDimitry Andric   return true;
855*0fca6ea1SDimitry Andric }
856*0fca6ea1SDimitry Andric 
857*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitCXXFieldTemplateRecord(
858*0fca6ea1SDimitry Andric     const CXXFieldTemplateRecord *Record) {
859*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
860*0fca6ea1SDimitry Andric     return true;
861*0fca6ea1SDimitry Andric 
862*0fca6ea1SDimitry Andric   serializeTemplateMixin(*CurrentSymbol, *Record);
863*0fca6ea1SDimitry Andric   return true;
864*0fca6ea1SDimitry Andric }
865*0fca6ea1SDimitry Andric 
866*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) {
867*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
868*0fca6ea1SDimitry Andric     return true;
869*0fca6ea1SDimitry Andric 
870*0fca6ea1SDimitry Andric   serializeTemplateMixin(*CurrentSymbol, *Record);
871*0fca6ea1SDimitry Andric   return true;
872*0fca6ea1SDimitry Andric }
873*0fca6ea1SDimitry Andric 
874*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
875*0fca6ea1SDimitry Andric     const GlobalVariableTemplateRecord *Record) {
876*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
877*0fca6ea1SDimitry Andric     return true;
878*0fca6ea1SDimitry Andric 
879*0fca6ea1SDimitry Andric   serializeTemplateMixin(*CurrentSymbol, *Record);
880*0fca6ea1SDimitry Andric   return true;
881*0fca6ea1SDimitry Andric }
882*0fca6ea1SDimitry Andric 
883*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::
884*0fca6ea1SDimitry Andric     visitGlobalVariableTemplatePartialSpecializationRecord(
885*0fca6ea1SDimitry Andric         const GlobalVariableTemplatePartialSpecializationRecord *Record) {
886*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
887*0fca6ea1SDimitry Andric     return true;
888*0fca6ea1SDimitry Andric 
889*0fca6ea1SDimitry Andric   serializeTemplateMixin(*CurrentSymbol, *Record);
890*0fca6ea1SDimitry Andric   return true;
891*0fca6ea1SDimitry Andric }
892*0fca6ea1SDimitry Andric 
893*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
894*0fca6ea1SDimitry Andric     const GlobalFunctionTemplateRecord *Record) {
895*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
896*0fca6ea1SDimitry Andric     return true;
897*0fca6ea1SDimitry Andric 
898*0fca6ea1SDimitry Andric   serializeTemplateMixin(*CurrentSymbol, *Record);
899*0fca6ea1SDimitry Andric   return true;
900*0fca6ea1SDimitry Andric }
901*0fca6ea1SDimitry Andric 
902*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCContainerRecord(
903*0fca6ea1SDimitry Andric     const ObjCContainerRecord *Record) {
904*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
905*0fca6ea1SDimitry Andric     return true;
906*0fca6ea1SDimitry Andric 
907*0fca6ea1SDimitry Andric   for (const auto &Protocol : Record->Protocols)
908*0fca6ea1SDimitry Andric     serializeRelationship(ConformsTo, Record, Protocol,
909*0fca6ea1SDimitry Andric                           getModuleForCurrentSymbol());
910*0fca6ea1SDimitry Andric 
911*0fca6ea1SDimitry Andric   return true;
912*0fca6ea1SDimitry Andric }
913*0fca6ea1SDimitry Andric 
914*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCInterfaceRecord(
915*0fca6ea1SDimitry Andric     const ObjCInterfaceRecord *Record) {
916*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
917*0fca6ea1SDimitry Andric     return true;
918*0fca6ea1SDimitry Andric 
919*0fca6ea1SDimitry Andric   if (!Record->SuperClass.empty())
920*0fca6ea1SDimitry Andric     serializeRelationship(InheritsFrom, Record, Record->SuperClass,
921*0fca6ea1SDimitry Andric                           getModuleForCurrentSymbol());
922*0fca6ea1SDimitry Andric   return true;
923*0fca6ea1SDimitry Andric }
924*0fca6ea1SDimitry Andric 
925*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::traverseObjCCategoryRecord(
926*0fca6ea1SDimitry Andric     const ObjCCategoryRecord *Record) {
927*0fca6ea1SDimitry Andric   if (SkipSymbolsInCategoriesToExternalTypes &&
928*0fca6ea1SDimitry Andric       !API.findRecordForUSR(Record->Interface.USR))
929*0fca6ea1SDimitry Andric     return true;
930*0fca6ea1SDimitry Andric 
931*0fca6ea1SDimitry Andric   auto *CurrentModule = ModuleForCurrentSymbol;
932*0fca6ea1SDimitry Andric   if (Record->isExtendingExternalModule())
933*0fca6ea1SDimitry Andric     ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source];
934*0fca6ea1SDimitry Andric 
935*0fca6ea1SDimitry Andric   if (!walkUpFromObjCCategoryRecord(Record))
936*0fca6ea1SDimitry Andric     return false;
937*0fca6ea1SDimitry Andric 
938*0fca6ea1SDimitry Andric   bool RetVal = traverseRecordContext(Record);
939*0fca6ea1SDimitry Andric   ModuleForCurrentSymbol = CurrentModule;
940*0fca6ea1SDimitry Andric   return RetVal;
941*0fca6ea1SDimitry Andric }
942*0fca6ea1SDimitry Andric 
943*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord(
944*0fca6ea1SDimitry Andric     const ObjCCategoryRecord *Record) {
945*0fca6ea1SDimitry Andric   return visitObjCCategoryRecord(Record);
946*0fca6ea1SDimitry Andric }
947*0fca6ea1SDimitry Andric 
948*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCCategoryRecord(
949*0fca6ea1SDimitry Andric     const ObjCCategoryRecord *Record) {
950*0fca6ea1SDimitry Andric   // If we need to create a record for the category in the future do so here,
951*0fca6ea1SDimitry Andric   // otherwise everything is set up to pretend that the category is in fact the
952*0fca6ea1SDimitry Andric   // interface it extends.
953*0fca6ea1SDimitry Andric   for (const auto &Protocol : Record->Protocols)
954*0fca6ea1SDimitry Andric     serializeRelationship(ConformsTo, Record->Interface, Protocol,
955*0fca6ea1SDimitry Andric                           getModuleForCurrentSymbol());
956*0fca6ea1SDimitry Andric 
957*0fca6ea1SDimitry Andric   return true;
958*0fca6ea1SDimitry Andric }
959*0fca6ea1SDimitry Andric 
960*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCMethodRecord(
961*0fca6ea1SDimitry Andric     const ObjCMethodRecord *Record) {
962*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
963*0fca6ea1SDimitry Andric     return true;
964*0fca6ea1SDimitry Andric 
965*0fca6ea1SDimitry Andric   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
966*0fca6ea1SDimitry Andric   return true;
967*0fca6ea1SDimitry Andric }
968*0fca6ea1SDimitry Andric 
969*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCInstanceVariableRecord(
970*0fca6ea1SDimitry Andric     const ObjCInstanceVariableRecord *Record) {
971*0fca6ea1SDimitry Andric   // FIXME: serialize ivar access control here.
972*0fca6ea1SDimitry Andric   return true;
973*0fca6ea1SDimitry Andric }
974*0fca6ea1SDimitry Andric 
975*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::walkUpFromTypedefRecord(
976*0fca6ea1SDimitry Andric     const TypedefRecord *Record) {
977*0fca6ea1SDimitry Andric   // Short-circuit walking up the class hierarchy and handle creating typedef
978*0fca6ea1SDimitry Andric   // symbol objects manually as there are additional symbol dropping rules to
979*0fca6ea1SDimitry Andric   // respect.
980*0fca6ea1SDimitry Andric   return visitTypedefRecord(Record);
981*0fca6ea1SDimitry Andric }
982*0fca6ea1SDimitry Andric 
983*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) {
984*0fca6ea1SDimitry Andric   // Typedefs of anonymous types have their entries unified with the underlying
985*0fca6ea1SDimitry Andric   // type.
986*0fca6ea1SDimitry Andric   bool ShouldDrop = Record->UnderlyingType.Name.empty();
987*0fca6ea1SDimitry Andric   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
988*0fca6ea1SDimitry Andric   // the same name
989*0fca6ea1SDimitry Andric   ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
990*0fca6ea1SDimitry Andric   if (ShouldDrop)
991*0fca6ea1SDimitry Andric     return true;
992*0fca6ea1SDimitry Andric 
993*0fca6ea1SDimitry Andric   // Create the symbol record if the other symbol droppping rules permit it.
994*0fca6ea1SDimitry Andric   serializeAPIRecord(Record);
995*0fca6ea1SDimitry Andric   if (!CurrentSymbol)
996*0fca6ea1SDimitry Andric     return true;
997*0fca6ea1SDimitry Andric 
998*0fca6ea1SDimitry Andric   (*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
999*0fca6ea1SDimitry Andric 
1000*0fca6ea1SDimitry Andric   return true;
100181ad6265SDimitry Andric }
100281ad6265SDimitry Andric 
1003bdd1243dSDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1004bdd1243dSDimitry Andric   switch (Record->getKind()) {
1005*0fca6ea1SDimitry Andric     // dispatch to the relevant walkUpFromMethod
1006*0fca6ea1SDimitry Andric #define CONCRETE_RECORD(CLASS, BASE, KIND)                                     \
1007*0fca6ea1SDimitry Andric   case APIRecord::KIND: {                                                      \
1008*0fca6ea1SDimitry Andric     walkUpFrom##CLASS(static_cast<const CLASS *>(Record));                     \
1009*0fca6ea1SDimitry Andric     break;                                                                     \
1010*0fca6ea1SDimitry Andric   }
1011*0fca6ea1SDimitry Andric #include "clang/ExtractAPI/APIRecords.inc"
1012*0fca6ea1SDimitry Andric   // otherwise fallback on the only behavior we can implement safely.
1013bdd1243dSDimitry Andric   case APIRecord::RK_Unknown:
1014*0fca6ea1SDimitry Andric     visitAPIRecord(Record);
1015bdd1243dSDimitry Andric     break;
1016bdd1243dSDimitry Andric   default:
1017*0fca6ea1SDimitry Andric     llvm_unreachable("API Record with uninstantiable kind");
1018bdd1243dSDimitry Andric   }
1019bdd1243dSDimitry Andric }
1020bdd1243dSDimitry Andric 
1021*0fca6ea1SDimitry Andric Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1022*0fca6ea1SDimitry Andric                                              ExtendedModule &&EM) {
1023bdd1243dSDimitry Andric   Object Root;
1024bdd1243dSDimitry Andric   serializeObject(Root, "metadata", serializeMetadata());
1025*0fca6ea1SDimitry Andric   serializeObject(Root, "module", serializeModuleObject(ModuleName));
1026bdd1243dSDimitry Andric 
1027*0fca6ea1SDimitry Andric   Root["symbols"] = std::move(EM.Symbols);
1028*0fca6ea1SDimitry Andric   Root["relationships"] = std::move(EM.Relationships);
102981ad6265SDimitry Andric 
103081ad6265SDimitry Andric   return Root;
103181ad6265SDimitry Andric }
103281ad6265SDimitry Andric 
1033*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeGraphToStream(
1034*0fca6ea1SDimitry Andric     raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1035*0fca6ea1SDimitry Andric     ExtendedModule &&EM) {
1036*0fca6ea1SDimitry Andric   Object Root = serializeGraph(ModuleName, std::move(EM));
103781ad6265SDimitry Andric   if (Options.Compact)
1038*0fca6ea1SDimitry Andric     OS << formatv("{0}", json::Value(std::move(Root))) << "\n";
103981ad6265SDimitry Andric   else
1040*0fca6ea1SDimitry Andric     OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n";
1041*0fca6ea1SDimitry Andric }
1042*0fca6ea1SDimitry Andric 
1043*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeMainSymbolGraph(
1044*0fca6ea1SDimitry Andric     raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1045*0fca6ea1SDimitry Andric     SymbolGraphSerializerOption Options) {
1046*0fca6ea1SDimitry Andric   SymbolGraphSerializer Serializer(
1047*0fca6ea1SDimitry Andric       API, IgnoresList, Options.EmitSymbolLabelsForTesting,
1048*0fca6ea1SDimitry Andric       /*ForceEmitToMainModule=*/true,
1049*0fca6ea1SDimitry Andric       /*SkipSymbolsInCategoriesToExternalTypes=*/true);
1050*0fca6ea1SDimitry Andric 
1051*0fca6ea1SDimitry Andric   Serializer.traverseAPISet();
1052*0fca6ea1SDimitry Andric   Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1053*0fca6ea1SDimitry Andric                                     std::move(Serializer.MainModule));
1054*0fca6ea1SDimitry Andric   // FIXME: TODO handle extended modules here
1055*0fca6ea1SDimitry Andric }
1056*0fca6ea1SDimitry Andric 
1057*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeWithExtensionGraphs(
1058*0fca6ea1SDimitry Andric     raw_ostream &MainOutput, const APISet &API,
1059*0fca6ea1SDimitry Andric     const APIIgnoresList &IgnoresList,
1060*0fca6ea1SDimitry Andric     llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1061*0fca6ea1SDimitry Andric         CreateOutputStream,
1062*0fca6ea1SDimitry Andric     SymbolGraphSerializerOption Options) {
1063*0fca6ea1SDimitry Andric   SymbolGraphSerializer Serializer(API, IgnoresList,
1064*0fca6ea1SDimitry Andric                                    Options.EmitSymbolLabelsForTesting);
1065*0fca6ea1SDimitry Andric   Serializer.traverseAPISet();
1066*0fca6ea1SDimitry Andric 
1067*0fca6ea1SDimitry Andric   Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1068*0fca6ea1SDimitry Andric                                     std::move(Serializer.MainModule));
1069*0fca6ea1SDimitry Andric 
1070*0fca6ea1SDimitry Andric   for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1071*0fca6ea1SDimitry Andric     if (auto ExtensionOS =
1072*0fca6ea1SDimitry Andric             CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName))
1073*0fca6ea1SDimitry Andric       Serializer.serializeGraphToStream(*ExtensionOS, Options,
1074*0fca6ea1SDimitry Andric                                         ExtensionSGF.getKey(),
1075*0fca6ea1SDimitry Andric                                         std::move(ExtensionSGF.getValue()));
1076*0fca6ea1SDimitry Andric   }
107781ad6265SDimitry Andric }
1078bdd1243dSDimitry Andric 
1079bdd1243dSDimitry Andric std::optional<Object>
1080bdd1243dSDimitry Andric SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1081bdd1243dSDimitry Andric                                                 const APISet &API) {
1082bdd1243dSDimitry Andric   APIRecord *Record = API.findRecordForUSR(USR);
1083bdd1243dSDimitry Andric   if (!Record)
1084bdd1243dSDimitry Andric     return {};
1085bdd1243dSDimitry Andric 
1086bdd1243dSDimitry Andric   Object Root;
1087bdd1243dSDimitry Andric   APIIgnoresList EmptyIgnores;
1088bdd1243dSDimitry Andric   SymbolGraphSerializer Serializer(API, EmptyIgnores,
1089*0fca6ea1SDimitry Andric                                    /*EmitSymbolLabelsForTesting*/ false,
1090*0fca6ea1SDimitry Andric                                    /*ForceEmitToMainModule*/ true);
1091*0fca6ea1SDimitry Andric 
1092*0fca6ea1SDimitry Andric   // Set up serializer parent chain
1093*0fca6ea1SDimitry Andric   Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1094*0fca6ea1SDimitry Andric 
1095bdd1243dSDimitry Andric   Serializer.serializeSingleRecord(Record);
1096*0fca6ea1SDimitry Andric   serializeObject(Root, "symbolGraph",
1097*0fca6ea1SDimitry Andric                   Serializer.serializeGraph(API.ProductName,
1098*0fca6ea1SDimitry Andric                                             std::move(Serializer.MainModule)));
1099bdd1243dSDimitry Andric 
1100bdd1243dSDimitry Andric   Language Lang = API.getLanguage();
1101bdd1243dSDimitry Andric   serializeArray(Root, "parentContexts",
1102*0fca6ea1SDimitry Andric                  generateParentContexts(Serializer.Hierarchy, Lang));
1103bdd1243dSDimitry Andric 
1104bdd1243dSDimitry Andric   Array RelatedSymbols;
1105bdd1243dSDimitry Andric 
1106bdd1243dSDimitry Andric   for (const auto &Fragment : Record->Declaration.getFragments()) {
1107bdd1243dSDimitry Andric     // If we don't have a USR there isn't much we can do.
1108bdd1243dSDimitry Andric     if (Fragment.PreciseIdentifier.empty())
1109bdd1243dSDimitry Andric       continue;
1110bdd1243dSDimitry Andric 
1111bdd1243dSDimitry Andric     APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1112bdd1243dSDimitry Andric 
1113bdd1243dSDimitry Andric     // If we can't find the record let's skip.
1114bdd1243dSDimitry Andric     if (!RelatedRecord)
1115bdd1243dSDimitry Andric       continue;
1116bdd1243dSDimitry Andric 
1117bdd1243dSDimitry Andric     Object RelatedSymbol;
1118bdd1243dSDimitry Andric     RelatedSymbol["usr"] = RelatedRecord->USR;
1119bdd1243dSDimitry Andric     RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1120*0fca6ea1SDimitry Andric     RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
1121bdd1243dSDimitry Andric     RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1122bdd1243dSDimitry Andric     RelatedSymbol["moduleName"] = API.ProductName;
1123bdd1243dSDimitry Andric     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1124bdd1243dSDimitry Andric 
1125bdd1243dSDimitry Andric     serializeArray(RelatedSymbol, "parentContexts",
1126*0fca6ea1SDimitry Andric                    generateParentContexts(
1127*0fca6ea1SDimitry Andric                        generateHierarchyFromRecord(RelatedRecord), Lang));
1128*0fca6ea1SDimitry Andric 
1129bdd1243dSDimitry Andric     RelatedSymbols.push_back(std::move(RelatedSymbol));
1130bdd1243dSDimitry Andric   }
1131bdd1243dSDimitry Andric 
1132bdd1243dSDimitry Andric   serializeArray(Root, "relatedSymbols", RelatedSymbols);
1133bdd1243dSDimitry Andric   return Root;
1134bdd1243dSDimitry Andric }
1135