xref: /llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision 1be4a67454b02dae4df2368af31b5f655736d829)
189f6b26fSZixu Wang //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===//
289f6b26fSZixu Wang //
389f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
489f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information.
589f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
689f6b26fSZixu Wang //
789f6b26fSZixu Wang //===----------------------------------------------------------------------===//
889f6b26fSZixu Wang ///
989f6b26fSZixu Wang /// \file
1089f6b26fSZixu Wang /// This file implements the SymbolGraphSerializer.
1189f6b26fSZixu Wang ///
1289f6b26fSZixu Wang //===----------------------------------------------------------------------===//
1389f6b26fSZixu Wang 
1489f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
157a851921SDaniel Grumberg #include "clang/Basic/SourceLocation.h"
1689f6b26fSZixu Wang #include "clang/Basic/Version.h"
17e05c1b46SDaniel Grumberg #include "clang/ExtractAPI/API.h"
1880ae3665SDaniel Grumberg #include "clang/ExtractAPI/DeclarationFragments.h"
197a851921SDaniel Grumberg #include "llvm/ADT/STLExtras.h"
207a851921SDaniel Grumberg #include "llvm/ADT/STLFunctionalExtras.h"
21e05c1b46SDaniel Grumberg #include "llvm/ADT/SmallVector.h"
227a851921SDaniel Grumberg #include "llvm/Support/Casting.h"
237a851921SDaniel Grumberg #include "llvm/Support/Compiler.h"
2489f6b26fSZixu Wang #include "llvm/Support/Path.h"
2589f6b26fSZixu Wang #include "llvm/Support/VersionTuple.h"
26e05c1b46SDaniel Grumberg #include "llvm/Support/raw_ostream.h"
27e05c1b46SDaniel Grumberg #include <iterator>
28a1580d7bSKazu Hirata #include <optional>
29236b6a0eSDaniel Grumberg #include <type_traits>
3089f6b26fSZixu Wang 
3189f6b26fSZixu Wang using namespace clang;
3289f6b26fSZixu Wang using namespace clang::extractapi;
3389f6b26fSZixu Wang using namespace llvm;
3489f6b26fSZixu Wang 
3589f6b26fSZixu Wang namespace {
3689f6b26fSZixu Wang 
3789f6b26fSZixu Wang /// Helper function to inject a JSON object \p Obj into another object \p Paren
3889f6b26fSZixu Wang /// at position \p Key.
39e05c1b46SDaniel Grumberg void serializeObject(Object &Paren, StringRef Key,
40e05c1b46SDaniel Grumberg                      std::optional<Object> &&Obj) {
4189f6b26fSZixu Wang   if (Obj)
4253e5cd4dSFangrui Song     Paren[Key] = std::move(*Obj);
4389f6b26fSZixu Wang }
4489f6b26fSZixu Wang 
45209a1e8dSDaniel Grumberg /// Helper function to inject a JSON array \p Array into object \p Paren at
46209a1e8dSDaniel Grumberg /// position \p Key.
47e05c1b46SDaniel Grumberg void serializeArray(Object &Paren, StringRef Key,
48e05c1b46SDaniel Grumberg                     std::optional<Array> &&Array) {
49209a1e8dSDaniel Grumberg   if (Array)
50209a1e8dSDaniel Grumberg     Paren[Key] = std::move(*Array);
51b31414bfSDaniel Grumberg }
52b31414bfSDaniel Grumberg 
53e05c1b46SDaniel Grumberg /// Helper function to inject a JSON array composed of the values in \p C into
54e05c1b46SDaniel Grumberg /// object \p Paren at position \p Key.
55e05c1b46SDaniel Grumberg template <typename ContainerTy>
56e05c1b46SDaniel Grumberg void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) {
57e05c1b46SDaniel Grumberg   Paren[Key] = Array(C);
58e05c1b46SDaniel Grumberg }
59e05c1b46SDaniel Grumberg 
6089f6b26fSZixu Wang /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
6189f6b26fSZixu Wang /// format.
6289f6b26fSZixu Wang ///
6389f6b26fSZixu Wang /// A semantic version object contains three numeric fields, representing the
6489f6b26fSZixu Wang /// \c major, \c minor, and \c patch parts of the version tuple.
6589f6b26fSZixu Wang /// For example version tuple 1.0.3 is serialized as:
6689f6b26fSZixu Wang /// \code
6789f6b26fSZixu Wang ///   {
6889f6b26fSZixu Wang ///     "major" : 1,
6989f6b26fSZixu Wang ///     "minor" : 0,
7089f6b26fSZixu Wang ///     "patch" : 3
7189f6b26fSZixu Wang ///   }
7289f6b26fSZixu Wang /// \endcode
7389f6b26fSZixu Wang ///
7437a3e98cSKazu Hirata /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
7537a3e98cSKazu Hirata /// containing the semantic version representation of \p V.
766ad0788cSKazu Hirata std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
7789f6b26fSZixu Wang   if (V.empty())
785891420eSKazu Hirata     return std::nullopt;
7989f6b26fSZixu Wang 
8089f6b26fSZixu Wang   Object Version;
8189f6b26fSZixu Wang   Version["major"] = V.getMajor();
8206decd0bSKazu Hirata   Version["minor"] = V.getMinor().value_or(0);
8306decd0bSKazu Hirata   Version["patch"] = V.getSubminor().value_or(0);
8489f6b26fSZixu Wang   return Version;
8589f6b26fSZixu Wang }
8689f6b26fSZixu Wang 
8789f6b26fSZixu Wang /// Serialize the OS information in the Symbol Graph platform property.
8889f6b26fSZixu Wang ///
8989f6b26fSZixu Wang /// The OS information in Symbol Graph contains the \c name of the OS, and an
9089f6b26fSZixu Wang /// optional \c minimumVersion semantic version field.
9189f6b26fSZixu Wang Object serializeOperatingSystem(const Triple &T) {
9289f6b26fSZixu Wang   Object OS;
9389f6b26fSZixu Wang   OS["name"] = T.getOSTypeName(T.getOS());
9489f6b26fSZixu Wang   serializeObject(OS, "minimumVersion",
9589f6b26fSZixu Wang                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
9689f6b26fSZixu Wang   return OS;
9789f6b26fSZixu Wang }
9889f6b26fSZixu Wang 
9989f6b26fSZixu Wang /// Serialize the platform information in the Symbol Graph module section.
10089f6b26fSZixu Wang ///
10189f6b26fSZixu Wang /// The platform object describes a target platform triple in corresponding
10289f6b26fSZixu Wang /// three fields: \c architecture, \c vendor, and \c operatingSystem.
10389f6b26fSZixu Wang Object serializePlatform(const Triple &T) {
10489f6b26fSZixu Wang   Object Platform;
10589f6b26fSZixu Wang   Platform["architecture"] = T.getArchName();
10689f6b26fSZixu Wang   Platform["vendor"] = T.getVendorName();
10757abd4e4SDaniel Grumberg 
10857abd4e4SDaniel Grumberg   if (!T.getEnvironmentName().empty())
10957abd4e4SDaniel Grumberg     Platform["environment"] = T.getEnvironmentName();
11057abd4e4SDaniel Grumberg 
11189f6b26fSZixu Wang   Platform["operatingSystem"] = serializeOperatingSystem(T);
11289f6b26fSZixu Wang   return Platform;
11389f6b26fSZixu Wang }
11489f6b26fSZixu Wang 
11528d79314SDaniel Grumberg /// Serialize a source position.
11628d79314SDaniel Grumberg Object serializeSourcePosition(const PresumedLoc &Loc) {
11789f6b26fSZixu Wang   assert(Loc.isValid() && "invalid source position");
11889f6b26fSZixu Wang 
11989f6b26fSZixu Wang   Object SourcePosition;
12063537872SQuietMisdreavus   SourcePosition["line"] = Loc.getLine() - 1;
12163537872SQuietMisdreavus   SourcePosition["character"] = Loc.getColumn() - 1;
12289f6b26fSZixu Wang 
12328d79314SDaniel Grumberg   return SourcePosition;
12428d79314SDaniel Grumberg }
12528d79314SDaniel Grumberg 
12628d79314SDaniel Grumberg /// Serialize a source location in file.
12728d79314SDaniel Grumberg ///
12828d79314SDaniel Grumberg /// \param Loc The presumed location to serialize.
12928d79314SDaniel Grumberg /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
13028d79314SDaniel Grumberg /// Defaults to false.
13128d79314SDaniel Grumberg Object serializeSourceLocation(const PresumedLoc &Loc,
13228d79314SDaniel Grumberg                                bool IncludeFileURI = false) {
13328d79314SDaniel Grumberg   Object SourceLocation;
13428d79314SDaniel Grumberg   serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
13528d79314SDaniel Grumberg 
13689f6b26fSZixu Wang   if (IncludeFileURI) {
13789f6b26fSZixu Wang     std::string FileURI = "file://";
13889f6b26fSZixu Wang     // Normalize file path to use forward slashes for the URI.
13989f6b26fSZixu Wang     FileURI += sys::path::convert_to_slash(Loc.getFilename());
14028d79314SDaniel Grumberg     SourceLocation["uri"] = FileURI;
14189f6b26fSZixu Wang   }
14289f6b26fSZixu Wang 
14328d79314SDaniel Grumberg   return SourceLocation;
14489f6b26fSZixu Wang }
14589f6b26fSZixu Wang 
14689f6b26fSZixu Wang /// Serialize a source range with begin and end locations.
14789f6b26fSZixu Wang Object serializeSourceRange(const PresumedLoc &BeginLoc,
14889f6b26fSZixu Wang                             const PresumedLoc &EndLoc) {
14989f6b26fSZixu Wang   Object SourceRange;
15089f6b26fSZixu Wang   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
15189f6b26fSZixu Wang   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
15289f6b26fSZixu Wang   return SourceRange;
15389f6b26fSZixu Wang }
15489f6b26fSZixu Wang 
15589f6b26fSZixu Wang /// Serialize the availability attributes of a symbol.
15689f6b26fSZixu Wang ///
15789f6b26fSZixu Wang /// Availability information contains the introduced, deprecated, and obsoleted
1583d4128f7SSofía Rodríguez /// versions of the symbol as semantic versions, if not default.
1593d4128f7SSofía Rodríguez /// Availability information also contains flags to indicate if the symbol is
1603d4128f7SSofía Rodríguez /// unconditionally unavailable or deprecated,
1613d4128f7SSofía Rodríguez /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
16289f6b26fSZixu Wang ///
16337a3e98cSKazu Hirata /// \returns \c std::nullopt if the symbol has default availability attributes,
1643d4128f7SSofía Rodríguez /// or an \c Array containing an object with the formatted availability
1653d4128f7SSofía Rodríguez /// information.
1663d4128f7SSofía Rodríguez std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
1673d4128f7SSofía Rodríguez   if (Avail.isDefault())
1685891420eSKazu Hirata     return std::nullopt;
16989f6b26fSZixu Wang 
17057c9780dSDaniel Grumberg   Array AvailabilityArray;
17105c1447bSDaniel Grumberg 
1723d4128f7SSofía Rodríguez   if (Avail.isUnconditionallyDeprecated()) {
17357c9780dSDaniel Grumberg     Object UnconditionallyDeprecated;
17457c9780dSDaniel Grumberg     UnconditionallyDeprecated["domain"] = "*";
17557c9780dSDaniel Grumberg     UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
17657c9780dSDaniel Grumberg     AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
17757c9780dSDaniel Grumberg   }
17805c1447bSDaniel Grumberg 
179026d963cSDaniel Grumberg   if (Avail.Domain.str() != "") {
180026d963cSDaniel Grumberg     Object Availability;
18105c1447bSDaniel Grumberg     Availability["domain"] = Avail.Domain;
18205c1447bSDaniel Grumberg 
18305c1447bSDaniel Grumberg     if (Avail.isUnavailable()) {
18405c1447bSDaniel Grumberg       Availability["isUnconditionallyUnavailable"] = true;
18505c1447bSDaniel Grumberg     } else {
18605c1447bSDaniel Grumberg       serializeObject(Availability, "introduced",
18705c1447bSDaniel Grumberg                       serializeSemanticVersion(Avail.Introduced));
18805c1447bSDaniel Grumberg       serializeObject(Availability, "deprecated",
18905c1447bSDaniel Grumberg                       serializeSemanticVersion(Avail.Deprecated));
19005c1447bSDaniel Grumberg       serializeObject(Availability, "obsoleted",
19105c1447bSDaniel Grumberg                       serializeSemanticVersion(Avail.Obsoleted));
19265f7a84cSAnkur     }
19305c1447bSDaniel Grumberg 
19457c9780dSDaniel Grumberg     AvailabilityArray.emplace_back(std::move(Availability));
195026d963cSDaniel Grumberg   }
196026d963cSDaniel Grumberg 
19757c9780dSDaniel Grumberg   return AvailabilityArray;
19889f6b26fSZixu Wang }
19989f6b26fSZixu Wang 
20015bf0e56SZixu Wang /// Get the language name string for interface language references.
20115bf0e56SZixu Wang StringRef getLanguageName(Language Lang) {
20215bf0e56SZixu Wang   switch (Lang) {
20389f6b26fSZixu Wang   case Language::C:
20489f6b26fSZixu Wang     return "c";
20589f6b26fSZixu Wang   case Language::ObjC:
206b62d4021SZixu Wang     return "objective-c";
20775f55eb3SErick Velez   case Language::CXX:
20875f55eb3SErick Velez     return "c++";
209789a5bbbSDaniel Grumberg   case Language::ObjCXX:
210789a5bbbSDaniel Grumberg     return "objective-c++";
21189f6b26fSZixu Wang 
21289f6b26fSZixu Wang   // Unsupported language currently
21389f6b26fSZixu Wang   case Language::OpenCL:
21489f6b26fSZixu Wang   case Language::OpenCLCXX:
21589f6b26fSZixu Wang   case Language::CUDA:
21689f6b26fSZixu Wang   case Language::HIP:
217d394f9f8SChris Bieneman   case Language::HLSL:
21889f6b26fSZixu Wang 
21989f6b26fSZixu Wang   // Languages that the frontend cannot parse and compile
22089f6b26fSZixu Wang   case Language::Unknown:
22189f6b26fSZixu Wang   case Language::Asm:
22289f6b26fSZixu Wang   case Language::LLVM_IR:
223e66b670fSNathan Lanza   case Language::CIR:
22489f6b26fSZixu Wang     llvm_unreachable("Unsupported language kind");
22589f6b26fSZixu Wang   }
22689f6b26fSZixu Wang 
22789f6b26fSZixu Wang   llvm_unreachable("Unhandled language kind");
22889f6b26fSZixu Wang }
22989f6b26fSZixu Wang 
23089f6b26fSZixu Wang /// Serialize the identifier object as specified by the Symbol Graph format.
23189f6b26fSZixu Wang ///
23289f6b26fSZixu Wang /// The identifier property of a symbol contains the USR for precise and unique
23389f6b26fSZixu Wang /// references, and the interface language name.
23415bf0e56SZixu Wang Object serializeIdentifier(const APIRecord &Record, Language Lang) {
23589f6b26fSZixu Wang   Object Identifier;
23689f6b26fSZixu Wang   Identifier["precise"] = Record.USR;
23715bf0e56SZixu Wang   Identifier["interfaceLanguage"] = getLanguageName(Lang);
23889f6b26fSZixu Wang 
23989f6b26fSZixu Wang   return Identifier;
24089f6b26fSZixu Wang }
24189f6b26fSZixu Wang 
24289f6b26fSZixu Wang /// Serialize the documentation comments attached to a symbol, as specified by
24389f6b26fSZixu Wang /// the Symbol Graph format.
24489f6b26fSZixu Wang ///
24589f6b26fSZixu Wang /// The Symbol Graph \c docComment object contains an array of lines. Each line
24689f6b26fSZixu Wang /// represents one line of striped documentation comment, with source range
24789f6b26fSZixu Wang /// information.
24889f6b26fSZixu Wang /// e.g.
24989f6b26fSZixu Wang /// \code
25089f6b26fSZixu Wang ///   /// This is a documentation comment
25189f6b26fSZixu Wang ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
25289f6b26fSZixu Wang ///   ///     with multiple lines.
25389f6b26fSZixu Wang ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
25489f6b26fSZixu Wang /// \endcode
25589f6b26fSZixu Wang ///
25637a3e98cSKazu Hirata /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
25737a3e98cSKazu Hirata /// the formatted lines.
2586ad0788cSKazu Hirata std::optional<Object> serializeDocComment(const DocComment &Comment) {
25989f6b26fSZixu Wang   if (Comment.empty())
2605891420eSKazu Hirata     return std::nullopt;
26189f6b26fSZixu Wang 
26289f6b26fSZixu Wang   Object DocComment;
263e05c1b46SDaniel Grumberg 
26489f6b26fSZixu Wang   Array LinesArray;
26589f6b26fSZixu Wang   for (const auto &CommentLine : Comment) {
26689f6b26fSZixu Wang     Object Line;
26789f6b26fSZixu Wang     Line["text"] = CommentLine.Text;
26889f6b26fSZixu Wang     serializeObject(Line, "range",
26989f6b26fSZixu Wang                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
27089f6b26fSZixu Wang     LinesArray.emplace_back(std::move(Line));
27189f6b26fSZixu Wang   }
272e05c1b46SDaniel Grumberg 
273e05c1b46SDaniel Grumberg   serializeArray(DocComment, "lines", std::move(LinesArray));
27489f6b26fSZixu Wang 
27589f6b26fSZixu Wang   return DocComment;
27689f6b26fSZixu Wang }
27789f6b26fSZixu Wang 
27889f6b26fSZixu Wang /// Serialize the declaration fragments of a symbol.
27989f6b26fSZixu Wang ///
28089f6b26fSZixu Wang /// The Symbol Graph declaration fragments is an array of tagged important
28189f6b26fSZixu Wang /// parts of a symbol's declaration. The fragments sequence can be joined to
28289f6b26fSZixu Wang /// form spans of declaration text, with attached information useful for
28389f6b26fSZixu Wang /// purposes like syntax-highlighting etc. For example:
28489f6b26fSZixu Wang /// \code
28589f6b26fSZixu Wang ///   const int pi; -> "declarationFragments" : [
28689f6b26fSZixu Wang ///                      {
28789f6b26fSZixu Wang ///                        "kind" : "keyword",
28889f6b26fSZixu Wang ///                        "spelling" : "const"
28989f6b26fSZixu Wang ///                      },
29089f6b26fSZixu Wang ///                      {
29189f6b26fSZixu Wang ///                        "kind" : "text",
29289f6b26fSZixu Wang ///                        "spelling" : " "
29389f6b26fSZixu Wang ///                      },
29489f6b26fSZixu Wang ///                      {
29589f6b26fSZixu Wang ///                        "kind" : "typeIdentifier",
29689f6b26fSZixu Wang ///                        "preciseIdentifier" : "c:I",
29789f6b26fSZixu Wang ///                        "spelling" : "int"
29889f6b26fSZixu Wang ///                      },
29989f6b26fSZixu Wang ///                      {
30089f6b26fSZixu Wang ///                        "kind" : "text",
30189f6b26fSZixu Wang ///                        "spelling" : " "
30289f6b26fSZixu Wang ///                      },
30389f6b26fSZixu Wang ///                      {
30489f6b26fSZixu Wang ///                        "kind" : "identifier",
30589f6b26fSZixu Wang ///                        "spelling" : "pi"
30689f6b26fSZixu Wang ///                      }
30789f6b26fSZixu Wang ///                    ]
30889f6b26fSZixu Wang /// \endcode
30989f6b26fSZixu Wang ///
31037a3e98cSKazu Hirata /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
31137a3e98cSKazu Hirata /// formatted declaration fragments array.
3126ad0788cSKazu Hirata std::optional<Array>
3136ad0788cSKazu Hirata serializeDeclarationFragments(const DeclarationFragments &DF) {
31489f6b26fSZixu Wang   if (DF.getFragments().empty())
3155891420eSKazu Hirata     return std::nullopt;
31689f6b26fSZixu Wang 
31789f6b26fSZixu Wang   Array Fragments;
31889f6b26fSZixu Wang   for (const auto &F : DF.getFragments()) {
31989f6b26fSZixu Wang     Object Fragment;
32089f6b26fSZixu Wang     Fragment["spelling"] = F.Spelling;
32189f6b26fSZixu Wang     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
32289f6b26fSZixu Wang     if (!F.PreciseIdentifier.empty())
32389f6b26fSZixu Wang       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
32489f6b26fSZixu Wang     Fragments.emplace_back(std::move(Fragment));
32589f6b26fSZixu Wang   }
32689f6b26fSZixu Wang 
32789f6b26fSZixu Wang   return Fragments;
32889f6b26fSZixu Wang }
32989f6b26fSZixu Wang 
33089f6b26fSZixu Wang /// Serialize the \c names field of a symbol as specified by the Symbol Graph
33189f6b26fSZixu Wang /// format.
33289f6b26fSZixu Wang ///
33389f6b26fSZixu Wang /// The Symbol Graph names field contains multiple representations of a symbol
33489f6b26fSZixu Wang /// that can be used for different applications:
33589f6b26fSZixu Wang ///   - \c title : The simple declared name of the symbol;
33689f6b26fSZixu Wang ///   - \c subHeading : An array of declaration fragments that provides tags,
33789f6b26fSZixu Wang ///     and potentially more tokens (for example the \c +/- symbol for
33889f6b26fSZixu Wang ///     Objective-C methods). Can be used as sub-headings for documentation.
339e05c1b46SDaniel Grumberg Object serializeNames(const APIRecord *Record) {
34089f6b26fSZixu Wang   Object Names;
341e05c1b46SDaniel Grumberg   Names["title"] = Record->Name;
34218493185Sruturaj4 
34389f6b26fSZixu Wang   serializeArray(Names, "subHeading",
344e05c1b46SDaniel Grumberg                  serializeDeclarationFragments(Record->SubHeading));
34580ae3665SDaniel Grumberg   DeclarationFragments NavigatorFragments;
346e05c1b46SDaniel Grumberg   NavigatorFragments.append(Record->Name,
34780ae3665SDaniel Grumberg                             DeclarationFragments::FragmentKind::Identifier,
34880ae3665SDaniel Grumberg                             /*PreciseIdentifier*/ "");
34980ae3665SDaniel Grumberg   serializeArray(Names, "navigator",
35080ae3665SDaniel Grumberg                  serializeDeclarationFragments(NavigatorFragments));
35189f6b26fSZixu Wang 
35289f6b26fSZixu Wang   return Names;
35389f6b26fSZixu Wang }
35489f6b26fSZixu Wang 
3557a851921SDaniel Grumberg Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
35615bf0e56SZixu Wang   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
35715bf0e56SZixu Wang     return (getLanguageName(Lang) + "." + S).str();
35871b4c226SZixu Wang   };
35971b4c226SZixu Wang 
36089f6b26fSZixu Wang   Object Kind;
3617a851921SDaniel Grumberg   switch (RK) {
3627a851921SDaniel Grumberg   case APIRecord::RK_Unknown:
363e05c1b46SDaniel Grumberg     Kind["identifier"] = AddLangPrefix("unknown");
364e05c1b46SDaniel Grumberg     Kind["displayName"] = "Unknown";
3657a851921SDaniel Grumberg     break;
36608f034f9SErick Velez   case APIRecord::RK_Namespace:
36708f034f9SErick Velez     Kind["identifier"] = AddLangPrefix("namespace");
36808f034f9SErick Velez     Kind["displayName"] = "Namespace";
36908f034f9SErick Velez     break;
370236b6a0eSDaniel Grumberg   case APIRecord::RK_GlobalFunction:
37171b4c226SZixu Wang     Kind["identifier"] = AddLangPrefix("func");
37289f6b26fSZixu Wang     Kind["displayName"] = "Function";
37389f6b26fSZixu Wang     break;
37480b787e8SErick Velez   case APIRecord::RK_GlobalFunctionTemplate:
37580b787e8SErick Velez     Kind["identifier"] = AddLangPrefix("func");
37680b787e8SErick Velez     Kind["displayName"] = "Function Template";
37780b787e8SErick Velez     break;
37880b787e8SErick Velez   case APIRecord::RK_GlobalFunctionTemplateSpecialization:
37980b787e8SErick Velez     Kind["identifier"] = AddLangPrefix("func");
38080b787e8SErick Velez     Kind["displayName"] = "Function Template Specialization";
38180b787e8SErick Velez     break;
3828d8c8981SErick Velez   case APIRecord::RK_GlobalVariableTemplate:
3838d8c8981SErick Velez     Kind["identifier"] = AddLangPrefix("var");
3848d8c8981SErick Velez     Kind["displayName"] = "Global Variable Template";
3858d8c8981SErick Velez     break;
3868d8c8981SErick Velez   case APIRecord::RK_GlobalVariableTemplateSpecialization:
3878d8c8981SErick Velez     Kind["identifier"] = AddLangPrefix("var");
3888d8c8981SErick Velez     Kind["displayName"] = "Global Variable Template Specialization";
3898d8c8981SErick Velez     break;
3908d8c8981SErick Velez   case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
3918d8c8981SErick Velez     Kind["identifier"] = AddLangPrefix("var");
3928d8c8981SErick Velez     Kind["displayName"] = "Global Variable Template Partial Specialization";
3938d8c8981SErick Velez     break;
394236b6a0eSDaniel Grumberg   case APIRecord::RK_GlobalVariable:
39571b4c226SZixu Wang     Kind["identifier"] = AddLangPrefix("var");
39689f6b26fSZixu Wang     Kind["displayName"] = "Global Variable";
39789f6b26fSZixu Wang     break;
39871b4c226SZixu Wang   case APIRecord::RK_EnumConstant:
39971b4c226SZixu Wang     Kind["identifier"] = AddLangPrefix("enum.case");
40071b4c226SZixu Wang     Kind["displayName"] = "Enumeration Case";
40171b4c226SZixu Wang     break;
40271b4c226SZixu Wang   case APIRecord::RK_Enum:
40371b4c226SZixu Wang     Kind["identifier"] = AddLangPrefix("enum");
40471b4c226SZixu Wang     Kind["displayName"] = "Enumeration";
40571b4c226SZixu Wang     break;
4065bb5704cSZixu Wang   case APIRecord::RK_StructField:
4075bb5704cSZixu Wang     Kind["identifier"] = AddLangPrefix("property");
4085bb5704cSZixu Wang     Kind["displayName"] = "Instance Property";
4095bb5704cSZixu Wang     break;
4105bb5704cSZixu Wang   case APIRecord::RK_Struct:
4115bb5704cSZixu Wang     Kind["identifier"] = AddLangPrefix("struct");
4125bb5704cSZixu Wang     Kind["displayName"] = "Structure";
4135bb5704cSZixu Wang     break;
41469fedaf8SDaniel Grumberg   case APIRecord::RK_UnionField:
41575f55eb3SErick Velez     Kind["identifier"] = AddLangPrefix("property");
41675f55eb3SErick Velez     Kind["displayName"] = "Instance Property";
41775f55eb3SErick Velez     break;
41875f55eb3SErick Velez   case APIRecord::RK_Union:
41975f55eb3SErick Velez     Kind["identifier"] = AddLangPrefix("union");
42075f55eb3SErick Velez     Kind["displayName"] = "Union";
42175f55eb3SErick Velez     break;
42269fedaf8SDaniel Grumberg   case APIRecord::RK_CXXField:
42369fedaf8SDaniel Grumberg     Kind["identifier"] = AddLangPrefix("property");
42469fedaf8SDaniel Grumberg     Kind["displayName"] = "Instance Property";
42569fedaf8SDaniel Grumberg     break;
42675f55eb3SErick Velez   case APIRecord::RK_StaticField:
42775f55eb3SErick Velez     Kind["identifier"] = AddLangPrefix("type.property");
42875f55eb3SErick Velez     Kind["displayName"] = "Type Property";
42975f55eb3SErick Velez     break;
4307ba37f4eSErick Velez   case APIRecord::RK_ClassTemplate:
4317ba37f4eSErick Velez   case APIRecord::RK_ClassTemplateSpecialization:
4327ba37f4eSErick Velez   case APIRecord::RK_ClassTemplatePartialSpecialization:
43375f55eb3SErick Velez   case APIRecord::RK_CXXClass:
43475f55eb3SErick Velez     Kind["identifier"] = AddLangPrefix("class");
43575f55eb3SErick Velez     Kind["displayName"] = "Class";
43675f55eb3SErick Velez     break;
437d8e9c5d9SErick Velez   case APIRecord::RK_CXXMethodTemplate:
438d8e9c5d9SErick Velez     Kind["identifier"] = AddLangPrefix("method");
439d8e9c5d9SErick Velez     Kind["displayName"] = "Method Template";
440d8e9c5d9SErick Velez     break;
441d8e9c5d9SErick Velez   case APIRecord::RK_CXXMethodTemplateSpecialization:
442d8e9c5d9SErick Velez     Kind["identifier"] = AddLangPrefix("method");
443d8e9c5d9SErick Velez     Kind["displayName"] = "Method Template Specialization";
444d8e9c5d9SErick Velez     break;
445634b2fd2SErick Velez   case APIRecord::RK_CXXFieldTemplate:
446634b2fd2SErick Velez     Kind["identifier"] = AddLangPrefix("property");
447634b2fd2SErick Velez     Kind["displayName"] = "Template Property";
448634b2fd2SErick Velez     break;
4497ba37f4eSErick Velez   case APIRecord::RK_Concept:
4507ba37f4eSErick Velez     Kind["identifier"] = AddLangPrefix("concept");
4517ba37f4eSErick Velez     Kind["displayName"] = "Concept";
4527ba37f4eSErick Velez     break;
45375f55eb3SErick Velez   case APIRecord::RK_CXXStaticMethod:
45475f55eb3SErick Velez     Kind["identifier"] = AddLangPrefix("type.method");
45575f55eb3SErick Velez     Kind["displayName"] = "Static Method";
45675f55eb3SErick Velez     break;
45775f55eb3SErick Velez   case APIRecord::RK_CXXInstanceMethod:
45875f55eb3SErick Velez     Kind["identifier"] = AddLangPrefix("method");
45975f55eb3SErick Velez     Kind["displayName"] = "Instance Method";
46075f55eb3SErick Velez     break;
46175f55eb3SErick Velez   case APIRecord::RK_CXXConstructorMethod:
46275f55eb3SErick Velez     Kind["identifier"] = AddLangPrefix("method");
46375f55eb3SErick Velez     Kind["displayName"] = "Constructor";
46475f55eb3SErick Velez     break;
46575f55eb3SErick Velez   case APIRecord::RK_CXXDestructorMethod:
46675f55eb3SErick Velez     Kind["identifier"] = AddLangPrefix("method");
46775f55eb3SErick Velez     Kind["displayName"] = "Destructor";
46875f55eb3SErick Velez     break;
4699b36e126SZixu Wang   case APIRecord::RK_ObjCIvar:
4709b36e126SZixu Wang     Kind["identifier"] = AddLangPrefix("ivar");
4719b36e126SZixu Wang     Kind["displayName"] = "Instance Variable";
4729b36e126SZixu Wang     break;
4737a851921SDaniel Grumberg   case APIRecord::RK_ObjCInstanceMethod:
4749b36e126SZixu Wang     Kind["identifier"] = AddLangPrefix("method");
4759b36e126SZixu Wang     Kind["displayName"] = "Instance Method";
4767a851921SDaniel Grumberg     break;
4777a851921SDaniel Grumberg   case APIRecord::RK_ObjCClassMethod:
4789b36e126SZixu Wang     Kind["identifier"] = AddLangPrefix("type.method");
4799b36e126SZixu Wang     Kind["displayName"] = "Type Method";
4809b36e126SZixu Wang     break;
4817a851921SDaniel Grumberg   case APIRecord::RK_ObjCInstanceProperty:
4829b36e126SZixu Wang     Kind["identifier"] = AddLangPrefix("property");
4839b36e126SZixu Wang     Kind["displayName"] = "Instance Property";
4847a851921SDaniel Grumberg     break;
4857a851921SDaniel Grumberg   case APIRecord::RK_ObjCClassProperty:
4867a851921SDaniel Grumberg     Kind["identifier"] = AddLangPrefix("type.property");
4877a851921SDaniel Grumberg     Kind["displayName"] = "Type Property";
4889b36e126SZixu Wang     break;
4899b36e126SZixu Wang   case APIRecord::RK_ObjCInterface:
4909b36e126SZixu Wang     Kind["identifier"] = AddLangPrefix("class");
4919b36e126SZixu Wang     Kind["displayName"] = "Class";
4929b36e126SZixu Wang     break;
493178aad9bSZixu Wang   case APIRecord::RK_ObjCCategory:
49418493185Sruturaj4     Kind["identifier"] = AddLangPrefix("class.extension");
49518493185Sruturaj4     Kind["displayName"] = "Class Extension";
49618493185Sruturaj4     break;
497d1d34bafSZixu Wang   case APIRecord::RK_ObjCProtocol:
498d1d34bafSZixu Wang     Kind["identifier"] = AddLangPrefix("protocol");
499d1d34bafSZixu Wang     Kind["displayName"] = "Protocol";
500d1d34bafSZixu Wang     break;
501529a0570SDaniel Grumberg   case APIRecord::RK_MacroDefinition:
502529a0570SDaniel Grumberg     Kind["identifier"] = AddLangPrefix("macro");
503529a0570SDaniel Grumberg     Kind["displayName"] = "Macro";
5049fc45ca0SDaniel Grumberg     break;
5059fc45ca0SDaniel Grumberg   case APIRecord::RK_Typedef:
5069fc45ca0SDaniel Grumberg     Kind["identifier"] = AddLangPrefix("typealias");
5079fc45ca0SDaniel Grumberg     Kind["displayName"] = "Type Alias";
5089fc45ca0SDaniel Grumberg     break;
509e05c1b46SDaniel Grumberg   default:
510e05c1b46SDaniel Grumberg     llvm_unreachable("API Record with uninstantiable kind");
51171b4c226SZixu Wang   }
51289f6b26fSZixu Wang 
51389f6b26fSZixu Wang   return Kind;
51489f6b26fSZixu Wang }
51589f6b26fSZixu Wang 
5167a851921SDaniel Grumberg /// Serialize the symbol kind information.
5177a851921SDaniel Grumberg ///
5187a851921SDaniel Grumberg /// The Symbol Graph symbol kind property contains a shorthand \c identifier
5197a851921SDaniel Grumberg /// which is prefixed by the source language name, useful for tooling to parse
5207a851921SDaniel Grumberg /// the kind, and a \c displayName for rendering human-readable names.
5217a851921SDaniel Grumberg Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
52261d4ca87SDaniel Grumberg   return serializeSymbolKind(Record.KindForDisplay, Lang);
5237a851921SDaniel Grumberg }
5247a851921SDaniel Grumberg 
525e05c1b46SDaniel Grumberg /// Serialize the function signature field, as specified by the
526e05c1b46SDaniel Grumberg /// Symbol Graph format.
527e05c1b46SDaniel Grumberg ///
528e05c1b46SDaniel Grumberg /// The Symbol Graph function signature property contains two arrays.
529e05c1b46SDaniel Grumberg ///   - The \c returns array is the declaration fragments of the return type;
530e05c1b46SDaniel Grumberg ///   - The \c parameters array contains names and declaration fragments of the
531e05c1b46SDaniel Grumberg ///     parameters.
532236b6a0eSDaniel Grumberg template <typename RecordTy>
533e05c1b46SDaniel Grumberg void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
534236b6a0eSDaniel Grumberg   const auto &FS = Record.Signature;
535236b6a0eSDaniel Grumberg   if (FS.empty())
536e05c1b46SDaniel Grumberg     return;
537236b6a0eSDaniel Grumberg 
538236b6a0eSDaniel Grumberg   Object Signature;
539236b6a0eSDaniel Grumberg   serializeArray(Signature, "returns",
540236b6a0eSDaniel Grumberg                  serializeDeclarationFragments(FS.getReturnType()));
541236b6a0eSDaniel Grumberg 
542236b6a0eSDaniel Grumberg   Array Parameters;
543236b6a0eSDaniel Grumberg   for (const auto &P : FS.getParameters()) {
544236b6a0eSDaniel Grumberg     Object Parameter;
545236b6a0eSDaniel Grumberg     Parameter["name"] = P.Name;
546236b6a0eSDaniel Grumberg     serializeArray(Parameter, "declarationFragments",
547236b6a0eSDaniel Grumberg                    serializeDeclarationFragments(P.Fragments));
548236b6a0eSDaniel Grumberg     Parameters.emplace_back(std::move(Parameter));
549236b6a0eSDaniel Grumberg   }
550236b6a0eSDaniel Grumberg 
551236b6a0eSDaniel Grumberg   if (!Parameters.empty())
552236b6a0eSDaniel Grumberg     Signature["parameters"] = std::move(Parameters);
553236b6a0eSDaniel Grumberg 
554e05c1b46SDaniel Grumberg   serializeObject(Paren, "functionSignature", std::move(Signature));
555236b6a0eSDaniel Grumberg }
556236b6a0eSDaniel Grumberg 
557236b6a0eSDaniel Grumberg template <typename RecordTy>
558e05c1b46SDaniel Grumberg void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
5597ba37f4eSErick Velez   const auto &Template = Record.Templ;
5607ba37f4eSErick Velez   if (Template.empty())
561e05c1b46SDaniel Grumberg     return;
5627ba37f4eSErick Velez 
5637ba37f4eSErick Velez   Object Generics;
5647ba37f4eSErick Velez   Array GenericParameters;
565ffb8434fSAntonio Frighetto   for (const auto &Param : Template.getParameters()) {
5667ba37f4eSErick Velez     Object Parameter;
5677ba37f4eSErick Velez     Parameter["name"] = Param.Name;
5687ba37f4eSErick Velez     Parameter["index"] = Param.Index;
5697ba37f4eSErick Velez     Parameter["depth"] = Param.Depth;
5707ba37f4eSErick Velez     GenericParameters.emplace_back(std::move(Parameter));
5717ba37f4eSErick Velez   }
5727ba37f4eSErick Velez   if (!GenericParameters.empty())
5737ba37f4eSErick Velez     Generics["parameters"] = std::move(GenericParameters);
5747ba37f4eSErick Velez 
5757ba37f4eSErick Velez   Array GenericConstraints;
576ffb8434fSAntonio Frighetto   for (const auto &Constr : Template.getConstraints()) {
5777ba37f4eSErick Velez     Object Constraint;
5787ba37f4eSErick Velez     Constraint["kind"] = Constr.Kind;
5797ba37f4eSErick Velez     Constraint["lhs"] = Constr.LHS;
5807ba37f4eSErick Velez     Constraint["rhs"] = Constr.RHS;
5817ba37f4eSErick Velez     GenericConstraints.emplace_back(std::move(Constraint));
5827ba37f4eSErick Velez   }
5837ba37f4eSErick Velez 
5847ba37f4eSErick Velez   if (!GenericConstraints.empty())
5857ba37f4eSErick Velez     Generics["constraints"] = std::move(GenericConstraints);
5867ba37f4eSErick Velez 
587e05c1b46SDaniel Grumberg   serializeObject(Paren, "swiftGenerics", Generics);
5887ba37f4eSErick Velez }
5897ba37f4eSErick Velez 
590e05c1b46SDaniel Grumberg Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents,
5917a851921SDaniel Grumberg                              Language Lang) {
5927a851921SDaniel Grumberg   Array ParentContexts;
593e05c1b46SDaniel Grumberg 
594e05c1b46SDaniel Grumberg   for (const auto &Parent : Parents) {
595e05c1b46SDaniel Grumberg     Object Elem;
596e05c1b46SDaniel Grumberg     Elem["usr"] = Parent.USR;
597e05c1b46SDaniel Grumberg     Elem["name"] = Parent.Name;
598e05c1b46SDaniel Grumberg     if (Parent.Record)
59961d4ca87SDaniel Grumberg       Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay,
60061d4ca87SDaniel Grumberg                                          Lang)["identifier"];
601e05c1b46SDaniel Grumberg     else
602e05c1b46SDaniel Grumberg       Elem["kind"] =
603e05c1b46SDaniel Grumberg           serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"];
604e05c1b46SDaniel Grumberg     ParentContexts.emplace_back(std::move(Elem));
605e05c1b46SDaniel Grumberg   }
6067da2d644SDaniel Grumberg 
6077a851921SDaniel Grumberg   return ParentContexts;
6087a851921SDaniel Grumberg }
609e05c1b46SDaniel Grumberg 
610e05c1b46SDaniel Grumberg /// Walk the records parent information in reverse to generate a hierarchy
611e05c1b46SDaniel Grumberg /// suitable for serialization.
612e05c1b46SDaniel Grumberg SmallVector<SymbolReference, 8>
613e05c1b46SDaniel Grumberg generateHierarchyFromRecord(const APIRecord *Record) {
614e05c1b46SDaniel Grumberg   SmallVector<SymbolReference, 8> ReverseHierarchy;
615e05c1b46SDaniel Grumberg   for (const auto *Current = Record; Current != nullptr;
616e05c1b46SDaniel Grumberg        Current = Current->Parent.Record)
617e05c1b46SDaniel Grumberg     ReverseHierarchy.emplace_back(Current);
618e05c1b46SDaniel Grumberg 
619e05c1b46SDaniel Grumberg   return SmallVector<SymbolReference, 8>(
620e05c1b46SDaniel Grumberg       std::make_move_iterator(ReverseHierarchy.rbegin()),
621e05c1b46SDaniel Grumberg       std::make_move_iterator(ReverseHierarchy.rend()));
622e05c1b46SDaniel Grumberg }
623e05c1b46SDaniel Grumberg 
624e05c1b46SDaniel Grumberg SymbolReference getHierarchyReference(const APIRecord *Record,
625e05c1b46SDaniel Grumberg                                       const APISet &API) {
626e05c1b46SDaniel Grumberg   // If the parent is a category extended from internal module then we need to
627e05c1b46SDaniel Grumberg   // pretend this belongs to the associated interface.
628e05c1b46SDaniel Grumberg   if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) {
629e05c1b46SDaniel Grumberg     return CategoryRecord->Interface;
630e05c1b46SDaniel Grumberg     // FIXME: TODO generate path components correctly for categories extending
631e05c1b46SDaniel Grumberg     // an external module.
632e05c1b46SDaniel Grumberg   }
633e05c1b46SDaniel Grumberg 
634e05c1b46SDaniel Grumberg   return SymbolReference(Record);
635e05c1b46SDaniel Grumberg }
636e05c1b46SDaniel Grumberg 
63789f6b26fSZixu Wang } // namespace
63889f6b26fSZixu Wang 
639e05c1b46SDaniel Grumberg Object *ExtendedModule::addSymbol(Object &&Symbol) {
640e05c1b46SDaniel Grumberg   Symbols.emplace_back(std::move(Symbol));
641e05c1b46SDaniel Grumberg   return Symbols.back().getAsObject();
642e05c1b46SDaniel Grumberg }
643e05c1b46SDaniel Grumberg 
644e05c1b46SDaniel Grumberg void ExtendedModule::addRelationship(Object &&Relationship) {
645e05c1b46SDaniel Grumberg   Relationships.emplace_back(std::move(Relationship));
646e05c1b46SDaniel Grumberg }
647e05c1b46SDaniel Grumberg 
64889f6b26fSZixu Wang /// Defines the format version emitted by SymbolGraphSerializer.
64989f6b26fSZixu Wang const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
65089f6b26fSZixu Wang 
65189f6b26fSZixu Wang Object SymbolGraphSerializer::serializeMetadata() const {
65289f6b26fSZixu Wang   Object Metadata;
65389f6b26fSZixu Wang   serializeObject(Metadata, "formatVersion",
65489f6b26fSZixu Wang                   serializeSemanticVersion(FormatVersion));
65589f6b26fSZixu Wang   Metadata["generator"] = clang::getClangFullVersion();
65689f6b26fSZixu Wang   return Metadata;
65789f6b26fSZixu Wang }
65889f6b26fSZixu Wang 
659e05c1b46SDaniel Grumberg Object
660e05c1b46SDaniel Grumberg SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const {
66189f6b26fSZixu Wang   Object Module;
662e05c1b46SDaniel Grumberg   Module["name"] = ModuleName;
66389f6b26fSZixu Wang   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
66489f6b26fSZixu Wang   return Module;
66589f6b26fSZixu Wang }
66689f6b26fSZixu Wang 
667e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {
668e05c1b46SDaniel Grumberg   if (!Record)
669791fe26dSDaniel Grumberg     return true;
670791fe26dSDaniel Grumberg 
67189f6b26fSZixu Wang   // Skip unconditionally unavailable symbols
672e05c1b46SDaniel Grumberg   if (Record->Availability.isUnconditionallyUnavailable())
67389f6b26fSZixu Wang     return true;
67489f6b26fSZixu Wang 
675504736ceSDaniel Grumberg   // Filter out symbols prefixed with an underscored as they are understood to
676504736ceSDaniel Grumberg   // be symbols clients should not use.
677e05c1b46SDaniel Grumberg   if (Record->Name.starts_with("_"))
678e05c1b46SDaniel Grumberg     return true;
679e05c1b46SDaniel Grumberg 
680e05c1b46SDaniel Grumberg   // Skip explicitly ignored symbols.
681e05c1b46SDaniel Grumberg   if (IgnoresList.shouldIgnore(Record->Name))
682504736ceSDaniel Grumberg     return true;
683504736ceSDaniel Grumberg 
68489f6b26fSZixu Wang   return false;
68589f6b26fSZixu Wang }
68689f6b26fSZixu Wang 
687e05c1b46SDaniel Grumberg ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {
688e05c1b46SDaniel Grumberg   if (!ForceEmitToMainModule && ModuleForCurrentSymbol)
689e05c1b46SDaniel Grumberg     return *ModuleForCurrentSymbol;
69089f6b26fSZixu Wang 
691e05c1b46SDaniel Grumberg   return MainModule;
69289f6b26fSZixu Wang }
69389f6b26fSZixu Wang 
694e05c1b46SDaniel Grumberg Array SymbolGraphSerializer::serializePathComponents(
695e05c1b46SDaniel Grumberg     const APIRecord *Record) const {
696e05c1b46SDaniel Grumberg   return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));
697178aad9bSZixu Wang }
698178aad9bSZixu Wang 
69971b4c226SZixu Wang StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
70071b4c226SZixu Wang   switch (Kind) {
70171b4c226SZixu Wang   case RelationshipKind::MemberOf:
70271b4c226SZixu Wang     return "memberOf";
7039b36e126SZixu Wang   case RelationshipKind::InheritsFrom:
7049b36e126SZixu Wang     return "inheritsFrom";
7059b36e126SZixu Wang   case RelationshipKind::ConformsTo:
7069b36e126SZixu Wang     return "conformsTo";
70718493185Sruturaj4   case RelationshipKind::ExtensionTo:
70818493185Sruturaj4     return "extensionTo";
70971b4c226SZixu Wang   }
71071b4c226SZixu Wang   llvm_unreachable("Unhandled relationship kind");
71171b4c226SZixu Wang }
71271b4c226SZixu Wang 
713e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
714e05c1b46SDaniel Grumberg                                                   const SymbolReference &Source,
715e05c1b46SDaniel Grumberg                                                   const SymbolReference &Target,
716e05c1b46SDaniel Grumberg                                                   ExtendedModule &Into) {
717e05c1b46SDaniel Grumberg   Object Relationship;
718e05c1b46SDaniel Grumberg   SmallString<64> TestRelLabel;
719e05c1b46SDaniel Grumberg   if (EmitSymbolLabelsForTesting) {
720e05c1b46SDaniel Grumberg     llvm::raw_svector_ostream OS(TestRelLabel);
721e05c1b46SDaniel Grumberg     OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ "
722e05c1b46SDaniel Grumberg        << Source.USR << " $ ";
723e05c1b46SDaniel Grumberg     if (Target.USR.empty())
724e05c1b46SDaniel Grumberg       OS << Target.Name;
725e05c1b46SDaniel Grumberg     else
726e05c1b46SDaniel Grumberg       OS << Target.USR;
727e05c1b46SDaniel Grumberg     Relationship["!testRelLabel"] = TestRelLabel;
728e05c1b46SDaniel Grumberg   }
729e05c1b46SDaniel Grumberg   Relationship["source"] = Source.USR;
730e05c1b46SDaniel Grumberg   Relationship["target"] = Target.USR;
731e05c1b46SDaniel Grumberg   Relationship["targetFallback"] = Target.Name;
732e05c1b46SDaniel Grumberg   Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind);
733e05c1b46SDaniel Grumberg 
734e05c1b46SDaniel Grumberg   if (ForceEmitToMainModule)
735e05c1b46SDaniel Grumberg     MainModule.addRelationship(std::move(Relationship));
736e05c1b46SDaniel Grumberg   else
737e05c1b46SDaniel Grumberg     Into.addRelationship(std::move(Relationship));
738e05c1b46SDaniel Grumberg }
739e05c1b46SDaniel Grumberg 
7407ba37f4eSErick Velez StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
7417ba37f4eSErick Velez   switch (Kind) {
7427ba37f4eSErick Velez   case ConstraintKind::Conformance:
7437ba37f4eSErick Velez     return "conformance";
7447ba37f4eSErick Velez   case ConstraintKind::ConditionalConformance:
7457ba37f4eSErick Velez     return "conditionalConformance";
7467ba37f4eSErick Velez   }
7477ba37f4eSErick Velez   llvm_unreachable("Unhandled constraint kind");
7487ba37f4eSErick Velez }
7497ba37f4eSErick Velez 
750e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) {
751209a1e8dSDaniel Grumberg   Object Obj;
752e05c1b46SDaniel Grumberg 
753e05c1b46SDaniel Grumberg   // If we need symbol labels for testing emit the USR as the value and the key
754e05c1b46SDaniel Grumberg   // starts with '!'' to ensure it ends up at the top of the object.
755e05c1b46SDaniel Grumberg   if (EmitSymbolLabelsForTesting)
756e05c1b46SDaniel Grumberg     Obj["!testLabel"] = Record->USR;
757e05c1b46SDaniel Grumberg 
758209a1e8dSDaniel Grumberg   serializeObject(Obj, "identifier",
759e05c1b46SDaniel Grumberg                   serializeIdentifier(*Record, API.getLanguage()));
760e05c1b46SDaniel Grumberg   serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage()));
761e05c1b46SDaniel Grumberg   serializeObject(Obj, "names", serializeNames(Record));
762e05c1b46SDaniel Grumberg   serializeObject(
763e05c1b46SDaniel Grumberg       Obj, "location",
764e05c1b46SDaniel Grumberg       serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true));
765e05c1b46SDaniel Grumberg   serializeArray(Obj, "availability",
766e05c1b46SDaniel Grumberg                  serializeAvailability(Record->Availability));
767e05c1b46SDaniel Grumberg   serializeObject(Obj, "docComment", serializeDocComment(Record->Comment));
768e05c1b46SDaniel Grumberg   serializeArray(Obj, "declarationFragments",
769e05c1b46SDaniel Grumberg                  serializeDeclarationFragments(Record->Declaration));
770e05c1b46SDaniel Grumberg 
771e05c1b46SDaniel Grumberg   Obj["pathComponents"] = serializePathComponents(Record);
772e05c1b46SDaniel Grumberg   Obj["accessLevel"] = Record->Access.getAccess();
773e05c1b46SDaniel Grumberg 
774e05c1b46SDaniel Grumberg   ExtendedModule &Module = getModuleForCurrentSymbol();
775e05c1b46SDaniel Grumberg   // If the hierarchy has at least one parent and child.
776e05c1b46SDaniel Grumberg   if (Hierarchy.size() >= 2)
777e05c1b46SDaniel Grumberg     serializeRelationship(MemberOf, Hierarchy.back(),
778e05c1b46SDaniel Grumberg                           Hierarchy[Hierarchy.size() - 2], Module);
779e05c1b46SDaniel Grumberg 
780e05c1b46SDaniel Grumberg   CurrentSymbol = Module.addSymbol(std::move(Obj));
781b31414bfSDaniel Grumberg }
782b31414bfSDaniel Grumberg 
783e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) {
784e05c1b46SDaniel Grumberg   if (!Record)
785e05c1b46SDaniel Grumberg     return true;
786e05c1b46SDaniel Grumberg   if (shouldSkip(Record))
787e05c1b46SDaniel Grumberg     return true;
788e05c1b46SDaniel Grumberg   Hierarchy.push_back(getHierarchyReference(Record, API));
789e05c1b46SDaniel Grumberg   // Defer traversal mechanics to APISetVisitor base implementation
790e05c1b46SDaniel Grumberg   auto RetVal = Base::traverseAPIRecord(Record);
791e05c1b46SDaniel Grumberg   Hierarchy.pop_back();
792e05c1b46SDaniel Grumberg   return RetVal;
793b31414bfSDaniel Grumberg }
794b31414bfSDaniel Grumberg 
795e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) {
796e05c1b46SDaniel Grumberg   serializeAPIRecord(Record);
797e05c1b46SDaniel Grumberg   return true;
798e05c1b46SDaniel Grumberg }
799b31414bfSDaniel Grumberg 
800e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitGlobalFunctionRecord(
801e05c1b46SDaniel Grumberg     const GlobalFunctionRecord *Record) {
802e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
803e05c1b46SDaniel Grumberg     return true;
804b31414bfSDaniel Grumberg 
805e05c1b46SDaniel Grumberg   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
806e05c1b46SDaniel Grumberg   return true;
807e05c1b46SDaniel Grumberg }
808e05c1b46SDaniel Grumberg 
809e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) {
810e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
811e05c1b46SDaniel Grumberg     return true;
812e05c1b46SDaniel Grumberg 
813e05c1b46SDaniel Grumberg   for (const auto &Base : Record->Bases)
814e05c1b46SDaniel Grumberg     serializeRelationship(RelationshipKind::InheritsFrom, Record, Base,
815e05c1b46SDaniel Grumberg                           getModuleForCurrentSymbol());
816e05c1b46SDaniel Grumberg   return true;
817e05c1b46SDaniel Grumberg }
818e05c1b46SDaniel Grumberg 
819e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitClassTemplateRecord(
820e05c1b46SDaniel Grumberg     const ClassTemplateRecord *Record) {
821e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
822e05c1b46SDaniel Grumberg     return true;
823e05c1b46SDaniel Grumberg 
824e05c1b46SDaniel Grumberg   serializeTemplateMixin(*CurrentSymbol, *Record);
825e05c1b46SDaniel Grumberg   return true;
826e05c1b46SDaniel Grumberg }
827e05c1b46SDaniel Grumberg 
828e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
829e05c1b46SDaniel Grumberg     const ClassTemplatePartialSpecializationRecord *Record) {
830e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
831e05c1b46SDaniel Grumberg     return true;
832e05c1b46SDaniel Grumberg 
833e05c1b46SDaniel Grumberg   serializeTemplateMixin(*CurrentSymbol, *Record);
834e05c1b46SDaniel Grumberg   return true;
835e05c1b46SDaniel Grumberg }
836e05c1b46SDaniel Grumberg 
837e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitCXXMethodRecord(
838e05c1b46SDaniel Grumberg     const CXXMethodRecord *Record) {
839e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
840e05c1b46SDaniel Grumberg     return true;
841e05c1b46SDaniel Grumberg 
842e05c1b46SDaniel Grumberg   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
843e05c1b46SDaniel Grumberg   return true;
844e05c1b46SDaniel Grumberg }
845e05c1b46SDaniel Grumberg 
846e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitCXXMethodTemplateRecord(
847e05c1b46SDaniel Grumberg     const CXXMethodTemplateRecord *Record) {
848e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
849e05c1b46SDaniel Grumberg     return true;
850e05c1b46SDaniel Grumberg 
851e05c1b46SDaniel Grumberg   serializeTemplateMixin(*CurrentSymbol, *Record);
852e05c1b46SDaniel Grumberg   return true;
853e05c1b46SDaniel Grumberg }
854e05c1b46SDaniel Grumberg 
855e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitCXXFieldTemplateRecord(
856e05c1b46SDaniel Grumberg     const CXXFieldTemplateRecord *Record) {
857e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
858e05c1b46SDaniel Grumberg     return true;
859e05c1b46SDaniel Grumberg 
860e05c1b46SDaniel Grumberg   serializeTemplateMixin(*CurrentSymbol, *Record);
861e05c1b46SDaniel Grumberg   return true;
862e05c1b46SDaniel Grumberg }
863e05c1b46SDaniel Grumberg 
864e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) {
865e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
866e05c1b46SDaniel Grumberg     return true;
867e05c1b46SDaniel Grumberg 
868e05c1b46SDaniel Grumberg   serializeTemplateMixin(*CurrentSymbol, *Record);
869e05c1b46SDaniel Grumberg   return true;
870e05c1b46SDaniel Grumberg }
871e05c1b46SDaniel Grumberg 
872e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
873e05c1b46SDaniel Grumberg     const GlobalVariableTemplateRecord *Record) {
874e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
875e05c1b46SDaniel Grumberg     return true;
876e05c1b46SDaniel Grumberg 
877e05c1b46SDaniel Grumberg   serializeTemplateMixin(*CurrentSymbol, *Record);
878e05c1b46SDaniel Grumberg   return true;
879e05c1b46SDaniel Grumberg }
880e05c1b46SDaniel Grumberg 
881e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::
882e05c1b46SDaniel Grumberg     visitGlobalVariableTemplatePartialSpecializationRecord(
883e05c1b46SDaniel Grumberg         const GlobalVariableTemplatePartialSpecializationRecord *Record) {
884e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
885e05c1b46SDaniel Grumberg     return true;
886e05c1b46SDaniel Grumberg 
887e05c1b46SDaniel Grumberg   serializeTemplateMixin(*CurrentSymbol, *Record);
888e05c1b46SDaniel Grumberg   return true;
889e05c1b46SDaniel Grumberg }
890e05c1b46SDaniel Grumberg 
891e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
892e05c1b46SDaniel Grumberg     const GlobalFunctionTemplateRecord *Record) {
893e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
894e05c1b46SDaniel Grumberg     return true;
895e05c1b46SDaniel Grumberg 
896e05c1b46SDaniel Grumberg   serializeTemplateMixin(*CurrentSymbol, *Record);
897e05c1b46SDaniel Grumberg   return true;
898e05c1b46SDaniel Grumberg }
899e05c1b46SDaniel Grumberg 
900e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCContainerRecord(
901e05c1b46SDaniel Grumberg     const ObjCContainerRecord *Record) {
902e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
903e05c1b46SDaniel Grumberg     return true;
904e05c1b46SDaniel Grumberg 
905e05c1b46SDaniel Grumberg   for (const auto &Protocol : Record->Protocols)
906e05c1b46SDaniel Grumberg     serializeRelationship(ConformsTo, Record, Protocol,
907e05c1b46SDaniel Grumberg                           getModuleForCurrentSymbol());
908e05c1b46SDaniel Grumberg 
909e05c1b46SDaniel Grumberg   return true;
910e05c1b46SDaniel Grumberg }
911e05c1b46SDaniel Grumberg 
912e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCInterfaceRecord(
913e05c1b46SDaniel Grumberg     const ObjCInterfaceRecord *Record) {
914e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
915e05c1b46SDaniel Grumberg     return true;
916e05c1b46SDaniel Grumberg 
917e05c1b46SDaniel Grumberg   if (!Record->SuperClass.empty())
918e05c1b46SDaniel Grumberg     serializeRelationship(InheritsFrom, Record, Record->SuperClass,
919e05c1b46SDaniel Grumberg                           getModuleForCurrentSymbol());
920e05c1b46SDaniel Grumberg   return true;
921e05c1b46SDaniel Grumberg }
922e05c1b46SDaniel Grumberg 
923e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::traverseObjCCategoryRecord(
924e05c1b46SDaniel Grumberg     const ObjCCategoryRecord *Record) {
92550b2bd4aSDaniel Grumberg   if (SkipSymbolsInCategoriesToExternalTypes &&
92650b2bd4aSDaniel Grumberg       !API.findRecordForUSR(Record->Interface.USR))
92750b2bd4aSDaniel Grumberg     return true;
92850b2bd4aSDaniel Grumberg 
929e05c1b46SDaniel Grumberg   auto *CurrentModule = ModuleForCurrentSymbol;
930b1b24d75SDaniel Grumberg   if (auto ModuleExtendedByRecord = Record->getExtendedExternalModule())
931b1b24d75SDaniel Grumberg     ModuleForCurrentSymbol = &ExtendedModules[*ModuleExtendedByRecord];
932e05c1b46SDaniel Grumberg 
933e05c1b46SDaniel Grumberg   if (!walkUpFromObjCCategoryRecord(Record))
934e05c1b46SDaniel Grumberg     return false;
935e05c1b46SDaniel Grumberg 
936e05c1b46SDaniel Grumberg   bool RetVal = traverseRecordContext(Record);
937e05c1b46SDaniel Grumberg   ModuleForCurrentSymbol = CurrentModule;
938e05c1b46SDaniel Grumberg   return RetVal;
939e05c1b46SDaniel Grumberg }
940e05c1b46SDaniel Grumberg 
941e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord(
942e05c1b46SDaniel Grumberg     const ObjCCategoryRecord *Record) {
943e05c1b46SDaniel Grumberg   return visitObjCCategoryRecord(Record);
944e05c1b46SDaniel Grumberg }
945e05c1b46SDaniel Grumberg 
946e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCCategoryRecord(
947e05c1b46SDaniel Grumberg     const ObjCCategoryRecord *Record) {
948e05c1b46SDaniel Grumberg   // If we need to create a record for the category in the future do so here,
949e05c1b46SDaniel Grumberg   // otherwise everything is set up to pretend that the category is in fact the
950e05c1b46SDaniel Grumberg   // interface it extends.
951e05c1b46SDaniel Grumberg   for (const auto &Protocol : Record->Protocols)
952e05c1b46SDaniel Grumberg     serializeRelationship(ConformsTo, Record->Interface, Protocol,
953e05c1b46SDaniel Grumberg                           getModuleForCurrentSymbol());
954e05c1b46SDaniel Grumberg 
955e05c1b46SDaniel Grumberg   return true;
956e05c1b46SDaniel Grumberg }
957e05c1b46SDaniel Grumberg 
958e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCMethodRecord(
959e05c1b46SDaniel Grumberg     const ObjCMethodRecord *Record) {
960e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
961e05c1b46SDaniel Grumberg     return true;
962e05c1b46SDaniel Grumberg 
963e05c1b46SDaniel Grumberg   serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
964e05c1b46SDaniel Grumberg   return true;
965e05c1b46SDaniel Grumberg }
966e05c1b46SDaniel Grumberg 
967e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCInstanceVariableRecord(
968e05c1b46SDaniel Grumberg     const ObjCInstanceVariableRecord *Record) {
969e05c1b46SDaniel Grumberg   // FIXME: serialize ivar access control here.
970e05c1b46SDaniel Grumberg   return true;
971e05c1b46SDaniel Grumberg }
972e05c1b46SDaniel Grumberg 
973e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::walkUpFromTypedefRecord(
974e05c1b46SDaniel Grumberg     const TypedefRecord *Record) {
975e05c1b46SDaniel Grumberg   // Short-circuit walking up the class hierarchy and handle creating typedef
976e05c1b46SDaniel Grumberg   // symbol objects manually as there are additional symbol dropping rules to
977e05c1b46SDaniel Grumberg   // respect.
978e05c1b46SDaniel Grumberg   return visitTypedefRecord(Record);
979e05c1b46SDaniel Grumberg }
980e05c1b46SDaniel Grumberg 
981e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) {
982e05c1b46SDaniel Grumberg   // Typedefs of anonymous types have their entries unified with the underlying
983e05c1b46SDaniel Grumberg   // type.
984e05c1b46SDaniel Grumberg   bool ShouldDrop = Record->UnderlyingType.Name.empty();
985e05c1b46SDaniel Grumberg   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
986e05c1b46SDaniel Grumberg   // the same name
987e05c1b46SDaniel Grumberg   ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
988e05c1b46SDaniel Grumberg   if (ShouldDrop)
989e05c1b46SDaniel Grumberg     return true;
990e05c1b46SDaniel Grumberg 
991e05c1b46SDaniel Grumberg   // Create the symbol record if the other symbol droppping rules permit it.
992e05c1b46SDaniel Grumberg   serializeAPIRecord(Record);
993e05c1b46SDaniel Grumberg   if (!CurrentSymbol)
994e05c1b46SDaniel Grumberg     return true;
995e05c1b46SDaniel Grumberg 
996e05c1b46SDaniel Grumberg   (*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
997e05c1b46SDaniel Grumberg 
998e05c1b46SDaniel Grumberg   return true;
999529a0570SDaniel Grumberg }
1000529a0570SDaniel Grumberg 
10017a851921SDaniel Grumberg void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
10027a851921SDaniel Grumberg   switch (Record->getKind()) {
1003e05c1b46SDaniel Grumberg     // dispatch to the relevant walkUpFromMethod
1004e05c1b46SDaniel Grumberg #define CONCRETE_RECORD(CLASS, BASE, KIND)                                     \
1005e05c1b46SDaniel Grumberg   case APIRecord::KIND: {                                                      \
1006e05c1b46SDaniel Grumberg     walkUpFrom##CLASS(static_cast<const CLASS *>(Record));                     \
1007e05c1b46SDaniel Grumberg     break;                                                                     \
1008e05c1b46SDaniel Grumberg   }
1009e05c1b46SDaniel Grumberg #include "clang/ExtractAPI/APIRecords.inc"
1010e05c1b46SDaniel Grumberg   // otherwise fallback on the only behavior we can implement safely.
10117a851921SDaniel Grumberg   case APIRecord::RK_Unknown:
1012e05c1b46SDaniel Grumberg     visitAPIRecord(Record);
10137a851921SDaniel Grumberg     break;
10147a851921SDaniel Grumberg   default:
1015e05c1b46SDaniel Grumberg     llvm_unreachable("API Record with uninstantiable kind");
10167a851921SDaniel Grumberg   }
10177a851921SDaniel Grumberg }
10187a851921SDaniel Grumberg 
1019e05c1b46SDaniel Grumberg Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1020e05c1b46SDaniel Grumberg                                              ExtendedModule &&EM) {
10217a851921SDaniel Grumberg   Object Root;
10227a851921SDaniel Grumberg   serializeObject(Root, "metadata", serializeMetadata());
1023e05c1b46SDaniel Grumberg   serializeObject(Root, "module", serializeModuleObject(ModuleName));
10247a851921SDaniel Grumberg 
1025e05c1b46SDaniel Grumberg   Root["symbols"] = std::move(EM.Symbols);
1026e05c1b46SDaniel Grumberg   Root["relationships"] = std::move(EM.Relationships);
102789f6b26fSZixu Wang 
102889f6b26fSZixu Wang   return Root;
102989f6b26fSZixu Wang }
103089f6b26fSZixu Wang 
1031e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeGraphToStream(
1032e05c1b46SDaniel Grumberg     raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1033e05c1b46SDaniel Grumberg     ExtendedModule &&EM) {
1034e05c1b46SDaniel Grumberg   Object Root = serializeGraph(ModuleName, std::move(EM));
103589f6b26fSZixu Wang   if (Options.Compact)
1036f0785484SYuxuan Chen     OS << formatv("{0}", json::Value(std::move(Root))) << "\n";
103789f6b26fSZixu Wang   else
1038f0785484SYuxuan Chen     OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n";
1039e05c1b46SDaniel Grumberg }
1040e05c1b46SDaniel Grumberg 
1041e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeMainSymbolGraph(
1042e05c1b46SDaniel Grumberg     raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1043e05c1b46SDaniel Grumberg     SymbolGraphSerializerOption Options) {
104450b2bd4aSDaniel Grumberg   SymbolGraphSerializer Serializer(
104550b2bd4aSDaniel Grumberg       API, IgnoresList, Options.EmitSymbolLabelsForTesting,
104650b2bd4aSDaniel Grumberg       /*ForceEmitToMainModule=*/true,
104750b2bd4aSDaniel Grumberg       /*SkipSymbolsInCategoriesToExternalTypes=*/true);
104850b2bd4aSDaniel Grumberg 
1049e05c1b46SDaniel Grumberg   Serializer.traverseAPISet();
1050e05c1b46SDaniel Grumberg   Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1051e05c1b46SDaniel Grumberg                                     std::move(Serializer.MainModule));
1052e05c1b46SDaniel Grumberg   // FIXME: TODO handle extended modules here
1053e05c1b46SDaniel Grumberg }
1054e05c1b46SDaniel Grumberg 
1055e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeWithExtensionGraphs(
1056e05c1b46SDaniel Grumberg     raw_ostream &MainOutput, const APISet &API,
1057e05c1b46SDaniel Grumberg     const APIIgnoresList &IgnoresList,
1058e05c1b46SDaniel Grumberg     llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1059e05c1b46SDaniel Grumberg         CreateOutputStream,
1060e05c1b46SDaniel Grumberg     SymbolGraphSerializerOption Options) {
1061e05c1b46SDaniel Grumberg   SymbolGraphSerializer Serializer(API, IgnoresList,
1062e05c1b46SDaniel Grumberg                                    Options.EmitSymbolLabelsForTesting);
1063e05c1b46SDaniel Grumberg   Serializer.traverseAPISet();
1064e05c1b46SDaniel Grumberg 
1065e05c1b46SDaniel Grumberg   Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1066e05c1b46SDaniel Grumberg                                     std::move(Serializer.MainModule));
1067e05c1b46SDaniel Grumberg 
1068e05c1b46SDaniel Grumberg   for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1069e05c1b46SDaniel Grumberg     if (auto ExtensionOS =
1070*1be4a674SQuietMisdreavus             CreateOutputStream(API.ProductName + "@" + ExtensionSGF.getKey()))
1071*1be4a674SQuietMisdreavus       Serializer.serializeGraphToStream(*ExtensionOS, Options, API.ProductName,
1072e05c1b46SDaniel Grumberg                                         std::move(ExtensionSGF.getValue()));
1073e05c1b46SDaniel Grumberg   }
107489f6b26fSZixu Wang }
10757a851921SDaniel Grumberg 
10766ad0788cSKazu Hirata std::optional<Object>
10777a851921SDaniel Grumberg SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
10787a851921SDaniel Grumberg                                                 const APISet &API) {
10797a851921SDaniel Grumberg   APIRecord *Record = API.findRecordForUSR(USR);
10807a851921SDaniel Grumberg   if (!Record)
10817a851921SDaniel Grumberg     return {};
10827a851921SDaniel Grumberg 
10837a851921SDaniel Grumberg   Object Root;
10847a851921SDaniel Grumberg   APIIgnoresList EmptyIgnores;
10857a851921SDaniel Grumberg   SymbolGraphSerializer Serializer(API, EmptyIgnores,
1086e05c1b46SDaniel Grumberg                                    /*EmitSymbolLabelsForTesting*/ false,
1087e05c1b46SDaniel Grumberg                                    /*ForceEmitToMainModule*/ true);
1088e05c1b46SDaniel Grumberg 
1089e05c1b46SDaniel Grumberg   // Set up serializer parent chain
1090e05c1b46SDaniel Grumberg   Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1091e05c1b46SDaniel Grumberg 
10927a851921SDaniel Grumberg   Serializer.serializeSingleRecord(Record);
1093e05c1b46SDaniel Grumberg   serializeObject(Root, "symbolGraph",
1094e05c1b46SDaniel Grumberg                   Serializer.serializeGraph(API.ProductName,
1095e05c1b46SDaniel Grumberg                                             std::move(Serializer.MainModule)));
10967a851921SDaniel Grumberg 
10977a851921SDaniel Grumberg   Language Lang = API.getLanguage();
10987a851921SDaniel Grumberg   serializeArray(Root, "parentContexts",
1099e05c1b46SDaniel Grumberg                  generateParentContexts(Serializer.Hierarchy, Lang));
11007a851921SDaniel Grumberg 
11017a851921SDaniel Grumberg   Array RelatedSymbols;
11027a851921SDaniel Grumberg 
11037a851921SDaniel Grumberg   for (const auto &Fragment : Record->Declaration.getFragments()) {
11047a851921SDaniel Grumberg     // If we don't have a USR there isn't much we can do.
11057a851921SDaniel Grumberg     if (Fragment.PreciseIdentifier.empty())
11067a851921SDaniel Grumberg       continue;
11077a851921SDaniel Grumberg 
11087a851921SDaniel Grumberg     APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
11097a851921SDaniel Grumberg 
11107a851921SDaniel Grumberg     // If we can't find the record let's skip.
11117a851921SDaniel Grumberg     if (!RelatedRecord)
11127a851921SDaniel Grumberg       continue;
11137a851921SDaniel Grumberg 
11147a851921SDaniel Grumberg     Object RelatedSymbol;
11157a851921SDaniel Grumberg     RelatedSymbol["usr"] = RelatedRecord->USR;
11167a851921SDaniel Grumberg     RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1117e05c1b46SDaniel Grumberg     RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
11187a851921SDaniel Grumberg     RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
11197a851921SDaniel Grumberg     RelatedSymbol["moduleName"] = API.ProductName;
11207a851921SDaniel Grumberg     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
11217a851921SDaniel Grumberg 
11227a851921SDaniel Grumberg     serializeArray(RelatedSymbol, "parentContexts",
1123e05c1b46SDaniel Grumberg                    generateParentContexts(
1124e05c1b46SDaniel Grumberg                        generateHierarchyFromRecord(RelatedRecord), Lang));
1125e05c1b46SDaniel Grumberg 
11267a851921SDaniel Grumberg     RelatedSymbols.push_back(std::move(RelatedSymbol));
11277a851921SDaniel Grumberg   }
11287a851921SDaniel Grumberg 
11297a851921SDaniel Grumberg   serializeArray(Root, "relatedSymbols", RelatedSymbols);
11307a851921SDaniel Grumberg   return Root;
11317a851921SDaniel Grumberg }
1132