xref: /freebsd-src/contrib/llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
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"
15*bdd1243dSDimitry Andric #include "clang/Basic/SourceLocation.h"
1681ad6265SDimitry Andric #include "clang/Basic/Version.h"
1781ad6265SDimitry Andric #include "clang/ExtractAPI/API.h"
18*bdd1243dSDimitry Andric #include "clang/ExtractAPI/APIIgnoresList.h"
1981ad6265SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h"
20*bdd1243dSDimitry Andric #include "clang/ExtractAPI/Serialization/SerializerBase.h"
21*bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h"
22*bdd1243dSDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h"
23*bdd1243dSDimitry Andric #include "llvm/ADT/SmallVector.h"
24*bdd1243dSDimitry Andric #include "llvm/Support/Casting.h"
25*bdd1243dSDimitry Andric #include "llvm/Support/Compiler.h"
2681ad6265SDimitry Andric #include "llvm/Support/JSON.h"
2781ad6265SDimitry Andric #include "llvm/Support/Path.h"
2881ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h"
29*bdd1243dSDimitry Andric #include <optional>
3081ad6265SDimitry Andric #include <type_traits>
3181ad6265SDimitry Andric 
3281ad6265SDimitry Andric using namespace clang;
3381ad6265SDimitry Andric using namespace clang::extractapi;
3481ad6265SDimitry Andric using namespace llvm;
3581ad6265SDimitry Andric using namespace llvm::json;
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric namespace {
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren
4081ad6265SDimitry Andric /// at position \p Key.
41*bdd1243dSDimitry Andric void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
4281ad6265SDimitry Andric   if (Obj)
43*bdd1243dSDimitry Andric     Paren[Key] = std::move(*Obj);
4481ad6265SDimitry Andric }
4581ad6265SDimitry Andric 
4681ad6265SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at
4781ad6265SDimitry Andric /// position \p Key.
48*bdd1243dSDimitry Andric void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
4981ad6265SDimitry Andric   if (Array)
50*bdd1243dSDimitry Andric     Paren[Key] = std::move(*Array);
5181ad6265SDimitry Andric }
5281ad6265SDimitry Andric 
5381ad6265SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
5481ad6265SDimitry Andric /// format.
5581ad6265SDimitry Andric ///
5681ad6265SDimitry Andric /// A semantic version object contains three numeric fields, representing the
5781ad6265SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple.
5881ad6265SDimitry Andric /// For example version tuple 1.0.3 is serialized as:
5981ad6265SDimitry Andric /// \code
6081ad6265SDimitry Andric ///   {
6181ad6265SDimitry Andric ///     "major" : 1,
6281ad6265SDimitry Andric ///     "minor" : 0,
6381ad6265SDimitry Andric ///     "patch" : 3
6481ad6265SDimitry Andric ///   }
6581ad6265SDimitry Andric /// \endcode
6681ad6265SDimitry Andric ///
67*bdd1243dSDimitry Andric /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
68*bdd1243dSDimitry Andric /// containing the semantic version representation of \p V.
69*bdd1243dSDimitry Andric std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
7081ad6265SDimitry Andric   if (V.empty())
71*bdd1243dSDimitry Andric     return std::nullopt;
7281ad6265SDimitry Andric 
7381ad6265SDimitry Andric   Object Version;
7481ad6265SDimitry Andric   Version["major"] = V.getMajor();
7581ad6265SDimitry Andric   Version["minor"] = V.getMinor().value_or(0);
7681ad6265SDimitry Andric   Version["patch"] = V.getSubminor().value_or(0);
7781ad6265SDimitry Andric   return Version;
7881ad6265SDimitry Andric }
7981ad6265SDimitry Andric 
8081ad6265SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property.
8181ad6265SDimitry Andric ///
8281ad6265SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an
8381ad6265SDimitry Andric /// optional \c minimumVersion semantic version field.
8481ad6265SDimitry Andric Object serializeOperatingSystem(const Triple &T) {
8581ad6265SDimitry Andric   Object OS;
8681ad6265SDimitry Andric   OS["name"] = T.getOSTypeName(T.getOS());
8781ad6265SDimitry Andric   serializeObject(OS, "minimumVersion",
8881ad6265SDimitry Andric                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
8981ad6265SDimitry Andric   return OS;
9081ad6265SDimitry Andric }
9181ad6265SDimitry Andric 
9281ad6265SDimitry Andric /// Serialize the platform information in the Symbol Graph module section.
9381ad6265SDimitry Andric ///
9481ad6265SDimitry Andric /// The platform object describes a target platform triple in corresponding
9581ad6265SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem.
9681ad6265SDimitry Andric Object serializePlatform(const Triple &T) {
9781ad6265SDimitry Andric   Object Platform;
9881ad6265SDimitry Andric   Platform["architecture"] = T.getArchName();
9981ad6265SDimitry Andric   Platform["vendor"] = T.getVendorName();
10081ad6265SDimitry Andric   Platform["operatingSystem"] = serializeOperatingSystem(T);
10181ad6265SDimitry Andric   return Platform;
10281ad6265SDimitry Andric }
10381ad6265SDimitry Andric 
10481ad6265SDimitry Andric /// Serialize a source position.
10581ad6265SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) {
10681ad6265SDimitry Andric   assert(Loc.isValid() && "invalid source position");
10781ad6265SDimitry Andric 
10881ad6265SDimitry Andric   Object SourcePosition;
10981ad6265SDimitry Andric   SourcePosition["line"] = Loc.getLine();
11081ad6265SDimitry Andric   SourcePosition["character"] = Loc.getColumn();
11181ad6265SDimitry Andric 
11281ad6265SDimitry Andric   return SourcePosition;
11381ad6265SDimitry Andric }
11481ad6265SDimitry Andric 
11581ad6265SDimitry Andric /// Serialize a source location in file.
11681ad6265SDimitry Andric ///
11781ad6265SDimitry Andric /// \param Loc The presumed location to serialize.
11881ad6265SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
11981ad6265SDimitry Andric /// Defaults to false.
12081ad6265SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc,
12181ad6265SDimitry Andric                                bool IncludeFileURI = false) {
12281ad6265SDimitry Andric   Object SourceLocation;
12381ad6265SDimitry Andric   serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
12481ad6265SDimitry Andric 
12581ad6265SDimitry Andric   if (IncludeFileURI) {
12681ad6265SDimitry Andric     std::string FileURI = "file://";
12781ad6265SDimitry Andric     // Normalize file path to use forward slashes for the URI.
12881ad6265SDimitry Andric     FileURI += sys::path::convert_to_slash(Loc.getFilename());
12981ad6265SDimitry Andric     SourceLocation["uri"] = FileURI;
13081ad6265SDimitry Andric   }
13181ad6265SDimitry Andric 
13281ad6265SDimitry Andric   return SourceLocation;
13381ad6265SDimitry Andric }
13481ad6265SDimitry Andric 
13581ad6265SDimitry Andric /// Serialize a source range with begin and end locations.
13681ad6265SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc,
13781ad6265SDimitry Andric                             const PresumedLoc &EndLoc) {
13881ad6265SDimitry Andric   Object SourceRange;
13981ad6265SDimitry Andric   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
14081ad6265SDimitry Andric   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
14181ad6265SDimitry Andric   return SourceRange;
14281ad6265SDimitry Andric }
14381ad6265SDimitry Andric 
14481ad6265SDimitry Andric /// Serialize the availability attributes of a symbol.
14581ad6265SDimitry Andric ///
14681ad6265SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted
147*bdd1243dSDimitry Andric /// versions of the symbol for a given domain (roughly corresponds to a
148*bdd1243dSDimitry Andric /// platform) as semantic versions, if not default.  Availability information
149*bdd1243dSDimitry Andric /// also contains flags to indicate if the symbol is unconditionally unavailable
150*bdd1243dSDimitry Andric /// or deprecated, i.e. \c __attribute__((unavailable)) and \c
151*bdd1243dSDimitry Andric /// __attribute__((deprecated)).
15281ad6265SDimitry Andric ///
153*bdd1243dSDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes,
154*bdd1243dSDimitry Andric /// or an \c Array containing the formatted availability information.
155*bdd1243dSDimitry Andric std::optional<Array>
156*bdd1243dSDimitry Andric serializeAvailability(const AvailabilitySet &Availabilities) {
157*bdd1243dSDimitry Andric   if (Availabilities.isDefault())
158*bdd1243dSDimitry Andric     return std::nullopt;
15981ad6265SDimitry Andric 
160*bdd1243dSDimitry Andric   Array AvailabilityArray;
16181ad6265SDimitry Andric 
162*bdd1243dSDimitry Andric   if (Availabilities.isUnconditionallyDeprecated()) {
163*bdd1243dSDimitry Andric     Object UnconditionallyDeprecated;
164*bdd1243dSDimitry Andric     UnconditionallyDeprecated["domain"] = "*";
165*bdd1243dSDimitry Andric     UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
166*bdd1243dSDimitry Andric     AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
167*bdd1243dSDimitry Andric   }
168*bdd1243dSDimitry Andric 
169*bdd1243dSDimitry Andric   // Note unconditionally unavailable records are skipped.
170*bdd1243dSDimitry Andric 
171*bdd1243dSDimitry Andric   for (const auto &AvailInfo : Availabilities) {
172*bdd1243dSDimitry Andric     Object Availability;
173*bdd1243dSDimitry Andric     Availability["domain"] = AvailInfo.Domain;
174*bdd1243dSDimitry Andric     serializeObject(Availability, "introducedVersion",
175*bdd1243dSDimitry Andric                     serializeSemanticVersion(AvailInfo.Introduced));
176*bdd1243dSDimitry Andric     serializeObject(Availability, "deprecatedVersion",
177*bdd1243dSDimitry Andric                     serializeSemanticVersion(AvailInfo.Deprecated));
178*bdd1243dSDimitry Andric     serializeObject(Availability, "obsoletedVersion",
179*bdd1243dSDimitry Andric                     serializeSemanticVersion(AvailInfo.Obsoleted));
180*bdd1243dSDimitry Andric     AvailabilityArray.emplace_back(std::move(Availability));
181*bdd1243dSDimitry Andric   }
182*bdd1243dSDimitry Andric 
183*bdd1243dSDimitry Andric   return AvailabilityArray;
18481ad6265SDimitry Andric }
18581ad6265SDimitry Andric 
18681ad6265SDimitry Andric /// Get the language name string for interface language references.
18781ad6265SDimitry Andric StringRef getLanguageName(Language Lang) {
18881ad6265SDimitry Andric   switch (Lang) {
18981ad6265SDimitry Andric   case Language::C:
19081ad6265SDimitry Andric     return "c";
19181ad6265SDimitry Andric   case Language::ObjC:
19281ad6265SDimitry Andric     return "objective-c";
19381ad6265SDimitry Andric 
19481ad6265SDimitry Andric   // Unsupported language currently
19581ad6265SDimitry Andric   case Language::CXX:
19681ad6265SDimitry Andric   case Language::ObjCXX:
19781ad6265SDimitry Andric   case Language::OpenCL:
19881ad6265SDimitry Andric   case Language::OpenCLCXX:
19981ad6265SDimitry Andric   case Language::CUDA:
20081ad6265SDimitry Andric   case Language::RenderScript:
20181ad6265SDimitry Andric   case Language::HIP:
20281ad6265SDimitry Andric   case Language::HLSL:
20381ad6265SDimitry Andric 
20481ad6265SDimitry Andric   // Languages that the frontend cannot parse and compile
20581ad6265SDimitry Andric   case Language::Unknown:
20681ad6265SDimitry Andric   case Language::Asm:
20781ad6265SDimitry Andric   case Language::LLVM_IR:
20881ad6265SDimitry Andric     llvm_unreachable("Unsupported language kind");
20981ad6265SDimitry Andric   }
21081ad6265SDimitry Andric 
21181ad6265SDimitry Andric   llvm_unreachable("Unhandled language kind");
21281ad6265SDimitry Andric }
21381ad6265SDimitry Andric 
21481ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format.
21581ad6265SDimitry Andric ///
21681ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique
21781ad6265SDimitry Andric /// references, and the interface language name.
21881ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) {
21981ad6265SDimitry Andric   Object Identifier;
22081ad6265SDimitry Andric   Identifier["precise"] = Record.USR;
22181ad6265SDimitry Andric   Identifier["interfaceLanguage"] = getLanguageName(Lang);
22281ad6265SDimitry Andric 
22381ad6265SDimitry Andric   return Identifier;
22481ad6265SDimitry Andric }
22581ad6265SDimitry Andric 
22681ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by
22781ad6265SDimitry Andric /// the Symbol Graph format.
22881ad6265SDimitry Andric ///
22981ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line
23081ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range
23181ad6265SDimitry Andric /// information.
23281ad6265SDimitry Andric /// e.g.
23381ad6265SDimitry Andric /// \code
23481ad6265SDimitry Andric ///   /// This is a documentation comment
23581ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
23681ad6265SDimitry Andric ///   ///     with multiple lines.
23781ad6265SDimitry Andric ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
23881ad6265SDimitry Andric /// \endcode
23981ad6265SDimitry Andric ///
240*bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
241*bdd1243dSDimitry Andric /// the formatted lines.
242*bdd1243dSDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) {
24381ad6265SDimitry Andric   if (Comment.empty())
244*bdd1243dSDimitry Andric     return std::nullopt;
24581ad6265SDimitry Andric 
24681ad6265SDimitry Andric   Object DocComment;
24781ad6265SDimitry Andric   Array LinesArray;
24881ad6265SDimitry Andric   for (const auto &CommentLine : Comment) {
24981ad6265SDimitry Andric     Object Line;
25081ad6265SDimitry Andric     Line["text"] = CommentLine.Text;
25181ad6265SDimitry Andric     serializeObject(Line, "range",
25281ad6265SDimitry Andric                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
25381ad6265SDimitry Andric     LinesArray.emplace_back(std::move(Line));
25481ad6265SDimitry Andric   }
25581ad6265SDimitry Andric   serializeArray(DocComment, "lines", LinesArray);
25681ad6265SDimitry Andric 
25781ad6265SDimitry Andric   return DocComment;
25881ad6265SDimitry Andric }
25981ad6265SDimitry Andric 
26081ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol.
26181ad6265SDimitry Andric ///
26281ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important
26381ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to
26481ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for
26581ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example:
26681ad6265SDimitry Andric /// \code
26781ad6265SDimitry Andric ///   const int pi; -> "declarationFragments" : [
26881ad6265SDimitry Andric ///                      {
26981ad6265SDimitry Andric ///                        "kind" : "keyword",
27081ad6265SDimitry Andric ///                        "spelling" : "const"
27181ad6265SDimitry Andric ///                      },
27281ad6265SDimitry Andric ///                      {
27381ad6265SDimitry Andric ///                        "kind" : "text",
27481ad6265SDimitry Andric ///                        "spelling" : " "
27581ad6265SDimitry Andric ///                      },
27681ad6265SDimitry Andric ///                      {
27781ad6265SDimitry Andric ///                        "kind" : "typeIdentifier",
27881ad6265SDimitry Andric ///                        "preciseIdentifier" : "c:I",
27981ad6265SDimitry Andric ///                        "spelling" : "int"
28081ad6265SDimitry Andric ///                      },
28181ad6265SDimitry Andric ///                      {
28281ad6265SDimitry Andric ///                        "kind" : "text",
28381ad6265SDimitry Andric ///                        "spelling" : " "
28481ad6265SDimitry Andric ///                      },
28581ad6265SDimitry Andric ///                      {
28681ad6265SDimitry Andric ///                        "kind" : "identifier",
28781ad6265SDimitry Andric ///                        "spelling" : "pi"
28881ad6265SDimitry Andric ///                      }
28981ad6265SDimitry Andric ///                    ]
29081ad6265SDimitry Andric /// \endcode
29181ad6265SDimitry Andric ///
292*bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
293*bdd1243dSDimitry Andric /// formatted declaration fragments array.
294*bdd1243dSDimitry Andric std::optional<Array>
295*bdd1243dSDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) {
29681ad6265SDimitry Andric   if (DF.getFragments().empty())
297*bdd1243dSDimitry Andric     return std::nullopt;
29881ad6265SDimitry Andric 
29981ad6265SDimitry Andric   Array Fragments;
30081ad6265SDimitry Andric   for (const auto &F : DF.getFragments()) {
30181ad6265SDimitry Andric     Object Fragment;
30281ad6265SDimitry Andric     Fragment["spelling"] = F.Spelling;
30381ad6265SDimitry Andric     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
30481ad6265SDimitry Andric     if (!F.PreciseIdentifier.empty())
30581ad6265SDimitry Andric       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
30681ad6265SDimitry Andric     Fragments.emplace_back(std::move(Fragment));
30781ad6265SDimitry Andric   }
30881ad6265SDimitry Andric 
30981ad6265SDimitry Andric   return Fragments;
31081ad6265SDimitry Andric }
31181ad6265SDimitry Andric 
31281ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph
31381ad6265SDimitry Andric /// format.
31481ad6265SDimitry Andric ///
31581ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol
31681ad6265SDimitry Andric /// that can be used for different applications:
31781ad6265SDimitry Andric ///   - \c title : The simple declared name of the symbol;
31881ad6265SDimitry Andric ///   - \c subHeading : An array of declaration fragments that provides tags,
31981ad6265SDimitry Andric ///     and potentially more tokens (for example the \c +/- symbol for
32081ad6265SDimitry Andric ///     Objective-C methods). Can be used as sub-headings for documentation.
32181ad6265SDimitry Andric Object serializeNames(const APIRecord &Record) {
32281ad6265SDimitry Andric   Object Names;
32381ad6265SDimitry Andric   Names["title"] = Record.Name;
32481ad6265SDimitry Andric   serializeArray(Names, "subHeading",
32581ad6265SDimitry Andric                  serializeDeclarationFragments(Record.SubHeading));
32681ad6265SDimitry Andric   DeclarationFragments NavigatorFragments;
32781ad6265SDimitry Andric   NavigatorFragments.append(Record.Name,
32881ad6265SDimitry Andric                             DeclarationFragments::FragmentKind::Identifier,
32981ad6265SDimitry Andric                             /*PreciseIdentifier*/ "");
33081ad6265SDimitry Andric   serializeArray(Names, "navigator",
33181ad6265SDimitry Andric                  serializeDeclarationFragments(NavigatorFragments));
33281ad6265SDimitry Andric 
33381ad6265SDimitry Andric   return Names;
33481ad6265SDimitry Andric }
33581ad6265SDimitry Andric 
336*bdd1243dSDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
33781ad6265SDimitry Andric   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
33881ad6265SDimitry Andric     return (getLanguageName(Lang) + "." + S).str();
33981ad6265SDimitry Andric   };
34081ad6265SDimitry Andric 
34181ad6265SDimitry Andric   Object Kind;
342*bdd1243dSDimitry Andric   switch (RK) {
343*bdd1243dSDimitry Andric   case APIRecord::RK_Unknown:
344*bdd1243dSDimitry Andric     llvm_unreachable("Records should have an explicit kind");
345*bdd1243dSDimitry Andric     break;
34681ad6265SDimitry Andric   case APIRecord::RK_GlobalFunction:
34781ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("func");
34881ad6265SDimitry Andric     Kind["displayName"] = "Function";
34981ad6265SDimitry Andric     break;
35081ad6265SDimitry Andric   case APIRecord::RK_GlobalVariable:
35181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("var");
35281ad6265SDimitry Andric     Kind["displayName"] = "Global Variable";
35381ad6265SDimitry Andric     break;
35481ad6265SDimitry Andric   case APIRecord::RK_EnumConstant:
35581ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum.case");
35681ad6265SDimitry Andric     Kind["displayName"] = "Enumeration Case";
35781ad6265SDimitry Andric     break;
35881ad6265SDimitry Andric   case APIRecord::RK_Enum:
35981ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("enum");
36081ad6265SDimitry Andric     Kind["displayName"] = "Enumeration";
36181ad6265SDimitry Andric     break;
36281ad6265SDimitry Andric   case APIRecord::RK_StructField:
36381ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
36481ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
36581ad6265SDimitry Andric     break;
36681ad6265SDimitry Andric   case APIRecord::RK_Struct:
36781ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("struct");
36881ad6265SDimitry Andric     Kind["displayName"] = "Structure";
36981ad6265SDimitry Andric     break;
37081ad6265SDimitry Andric   case APIRecord::RK_ObjCIvar:
37181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("ivar");
37281ad6265SDimitry Andric     Kind["displayName"] = "Instance Variable";
37381ad6265SDimitry Andric     break;
374*bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInstanceMethod:
37581ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("method");
37681ad6265SDimitry Andric     Kind["displayName"] = "Instance Method";
377*bdd1243dSDimitry Andric     break;
378*bdd1243dSDimitry Andric   case APIRecord::RK_ObjCClassMethod:
37981ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("type.method");
38081ad6265SDimitry Andric     Kind["displayName"] = "Type Method";
38181ad6265SDimitry Andric     break;
382*bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInstanceProperty:
38381ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("property");
38481ad6265SDimitry Andric     Kind["displayName"] = "Instance Property";
38581ad6265SDimitry Andric     break;
386*bdd1243dSDimitry Andric   case APIRecord::RK_ObjCClassProperty:
387*bdd1243dSDimitry Andric     Kind["identifier"] = AddLangPrefix("type.property");
388*bdd1243dSDimitry Andric     Kind["displayName"] = "Type Property";
389*bdd1243dSDimitry Andric     break;
39081ad6265SDimitry Andric   case APIRecord::RK_ObjCInterface:
39181ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("class");
39281ad6265SDimitry Andric     Kind["displayName"] = "Class";
39381ad6265SDimitry Andric     break;
39481ad6265SDimitry Andric   case APIRecord::RK_ObjCCategory:
39581ad6265SDimitry Andric     // We don't serialize out standalone Objective-C category symbols yet.
39681ad6265SDimitry Andric     llvm_unreachable("Serializing standalone Objective-C category symbols is "
39781ad6265SDimitry Andric                      "not supported.");
39881ad6265SDimitry Andric     break;
39981ad6265SDimitry Andric   case APIRecord::RK_ObjCProtocol:
40081ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("protocol");
40181ad6265SDimitry Andric     Kind["displayName"] = "Protocol";
40281ad6265SDimitry Andric     break;
40381ad6265SDimitry Andric   case APIRecord::RK_MacroDefinition:
40481ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("macro");
40581ad6265SDimitry Andric     Kind["displayName"] = "Macro";
40681ad6265SDimitry Andric     break;
40781ad6265SDimitry Andric   case APIRecord::RK_Typedef:
40881ad6265SDimitry Andric     Kind["identifier"] = AddLangPrefix("typealias");
40981ad6265SDimitry Andric     Kind["displayName"] = "Type Alias";
41081ad6265SDimitry Andric     break;
41181ad6265SDimitry Andric   }
41281ad6265SDimitry Andric 
41381ad6265SDimitry Andric   return Kind;
41481ad6265SDimitry Andric }
41581ad6265SDimitry Andric 
416*bdd1243dSDimitry Andric /// Serialize the symbol kind information.
417*bdd1243dSDimitry Andric ///
418*bdd1243dSDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier
419*bdd1243dSDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse
420*bdd1243dSDimitry Andric /// the kind, and a \c displayName for rendering human-readable names.
421*bdd1243dSDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
422*bdd1243dSDimitry Andric   return serializeSymbolKind(Record.getKind(), Lang);
423*bdd1243dSDimitry Andric }
424*bdd1243dSDimitry Andric 
42581ad6265SDimitry Andric template <typename RecordTy>
426*bdd1243dSDimitry Andric std::optional<Object>
427*bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
42881ad6265SDimitry Andric   const auto &FS = Record.Signature;
42981ad6265SDimitry Andric   if (FS.empty())
430*bdd1243dSDimitry Andric     return std::nullopt;
43181ad6265SDimitry Andric 
43281ad6265SDimitry Andric   Object Signature;
43381ad6265SDimitry Andric   serializeArray(Signature, "returns",
43481ad6265SDimitry Andric                  serializeDeclarationFragments(FS.getReturnType()));
43581ad6265SDimitry Andric 
43681ad6265SDimitry Andric   Array Parameters;
43781ad6265SDimitry Andric   for (const auto &P : FS.getParameters()) {
43881ad6265SDimitry Andric     Object Parameter;
43981ad6265SDimitry Andric     Parameter["name"] = P.Name;
44081ad6265SDimitry Andric     serializeArray(Parameter, "declarationFragments",
44181ad6265SDimitry Andric                    serializeDeclarationFragments(P.Fragments));
44281ad6265SDimitry Andric     Parameters.emplace_back(std::move(Parameter));
44381ad6265SDimitry Andric   }
44481ad6265SDimitry Andric 
44581ad6265SDimitry Andric   if (!Parameters.empty())
44681ad6265SDimitry Andric     Signature["parameters"] = std::move(Parameters);
44781ad6265SDimitry Andric 
44881ad6265SDimitry Andric   return Signature;
44981ad6265SDimitry Andric }
45081ad6265SDimitry Andric 
45181ad6265SDimitry Andric template <typename RecordTy>
452*bdd1243dSDimitry Andric std::optional<Object>
453*bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
454*bdd1243dSDimitry Andric   return std::nullopt;
45581ad6265SDimitry Andric }
45681ad6265SDimitry Andric 
45781ad6265SDimitry Andric /// Serialize the function signature field, as specified by the
45881ad6265SDimitry Andric /// Symbol Graph format.
45981ad6265SDimitry Andric ///
46081ad6265SDimitry Andric /// The Symbol Graph function signature property contains two arrays.
46181ad6265SDimitry Andric ///   - The \c returns array is the declaration fragments of the return type;
46281ad6265SDimitry Andric ///   - The \c parameters array contains names and declaration fragments of the
46381ad6265SDimitry Andric ///     parameters.
46481ad6265SDimitry Andric ///
465*bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
46681ad6265SDimitry Andric /// formatted function signature.
46781ad6265SDimitry Andric template <typename RecordTy>
46881ad6265SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
46981ad6265SDimitry Andric   serializeObject(Paren, "functionSignature",
47081ad6265SDimitry Andric                   serializeFunctionSignatureMixinImpl(
47181ad6265SDimitry Andric                       Record, has_function_signature<RecordTy>()));
47281ad6265SDimitry Andric }
47381ad6265SDimitry Andric 
474*bdd1243dSDimitry Andric struct PathComponent {
475*bdd1243dSDimitry Andric   StringRef USR;
476*bdd1243dSDimitry Andric   StringRef Name;
477*bdd1243dSDimitry Andric   APIRecord::RecordKind Kind;
478*bdd1243dSDimitry Andric 
479*bdd1243dSDimitry Andric   PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
480*bdd1243dSDimitry Andric       : USR(USR), Name(Name), Kind(Kind) {}
481*bdd1243dSDimitry Andric };
482*bdd1243dSDimitry Andric 
483*bdd1243dSDimitry Andric template <typename RecordTy>
484*bdd1243dSDimitry Andric bool generatePathComponents(
485*bdd1243dSDimitry Andric     const RecordTy &Record, const APISet &API,
486*bdd1243dSDimitry Andric     function_ref<void(const PathComponent &)> ComponentTransformer) {
487*bdd1243dSDimitry Andric   SmallVector<PathComponent, 4> ReverseComponenents;
488*bdd1243dSDimitry Andric   ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
489*bdd1243dSDimitry Andric   const auto *CurrentParent = &Record.ParentInformation;
490*bdd1243dSDimitry Andric   while (CurrentParent && !CurrentParent->empty()) {
491*bdd1243dSDimitry Andric     PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
492*bdd1243dSDimitry Andric                                          CurrentParent->ParentName,
493*bdd1243dSDimitry Andric                                          CurrentParent->ParentKind);
494*bdd1243dSDimitry Andric 
495*bdd1243dSDimitry Andric     auto *ParentRecord = CurrentParent->ParentRecord;
496*bdd1243dSDimitry Andric     // Slow path if we don't have a direct reference to the ParentRecord
497*bdd1243dSDimitry Andric     if (!ParentRecord)
498*bdd1243dSDimitry Andric       ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
499*bdd1243dSDimitry Andric 
500*bdd1243dSDimitry Andric     // If the parent is a category then we need to pretend this belongs to the
501*bdd1243dSDimitry Andric     // associated interface.
502*bdd1243dSDimitry Andric     if (auto *CategoryRecord =
503*bdd1243dSDimitry Andric             dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
504*bdd1243dSDimitry Andric       ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
505*bdd1243dSDimitry Andric       CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
506*bdd1243dSDimitry Andric                                              CategoryRecord->Interface.Name,
507*bdd1243dSDimitry Andric                                              APIRecord::RK_ObjCInterface);
508*bdd1243dSDimitry Andric     }
509*bdd1243dSDimitry Andric 
510*bdd1243dSDimitry Andric     // The parent record doesn't exist which means the symbol shouldn't be
511*bdd1243dSDimitry Andric     // treated as part of the current product.
512*bdd1243dSDimitry Andric     if (!ParentRecord)
513*bdd1243dSDimitry Andric       return true;
514*bdd1243dSDimitry Andric 
515*bdd1243dSDimitry Andric     ReverseComponenents.push_back(std::move(CurrentParentComponent));
516*bdd1243dSDimitry Andric     CurrentParent = &ParentRecord->ParentInformation;
517*bdd1243dSDimitry Andric   }
518*bdd1243dSDimitry Andric 
519*bdd1243dSDimitry Andric   for (const auto &PC : reverse(ReverseComponenents))
520*bdd1243dSDimitry Andric     ComponentTransformer(PC);
521*bdd1243dSDimitry Andric 
522*bdd1243dSDimitry Andric   return false;
523*bdd1243dSDimitry Andric }
524*bdd1243dSDimitry Andric Object serializeParentContext(const PathComponent &PC, Language Lang) {
525*bdd1243dSDimitry Andric   Object ParentContextElem;
526*bdd1243dSDimitry Andric   ParentContextElem["usr"] = PC.USR;
527*bdd1243dSDimitry Andric   ParentContextElem["name"] = PC.Name;
528*bdd1243dSDimitry Andric   ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
529*bdd1243dSDimitry Andric   return ParentContextElem;
530*bdd1243dSDimitry Andric }
531*bdd1243dSDimitry Andric 
532*bdd1243dSDimitry Andric template <typename RecordTy>
533*bdd1243dSDimitry Andric Array generateParentContexts(const RecordTy &Record, const APISet &API,
534*bdd1243dSDimitry Andric                              Language Lang) {
535*bdd1243dSDimitry Andric   Array ParentContexts;
536*bdd1243dSDimitry Andric   if (generatePathComponents(
537*bdd1243dSDimitry Andric           Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
538*bdd1243dSDimitry Andric             ParentContexts.push_back(serializeParentContext(PC, Lang));
539*bdd1243dSDimitry Andric           }))
540*bdd1243dSDimitry Andric     ParentContexts.clear();
541*bdd1243dSDimitry Andric   ParentContexts.pop_back();
542*bdd1243dSDimitry Andric 
543*bdd1243dSDimitry Andric   return ParentContexts;
544*bdd1243dSDimitry Andric }
545*bdd1243dSDimitry Andric 
54681ad6265SDimitry Andric } // namespace
54781ad6265SDimitry Andric 
54881ad6265SDimitry Andric void SymbolGraphSerializer::anchor() {}
54981ad6265SDimitry Andric 
55081ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer.
55181ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
55281ad6265SDimitry Andric 
55381ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const {
55481ad6265SDimitry Andric   Object Metadata;
55581ad6265SDimitry Andric   serializeObject(Metadata, "formatVersion",
55681ad6265SDimitry Andric                   serializeSemanticVersion(FormatVersion));
55781ad6265SDimitry Andric   Metadata["generator"] = clang::getClangFullVersion();
55881ad6265SDimitry Andric   return Metadata;
55981ad6265SDimitry Andric }
56081ad6265SDimitry Andric 
56181ad6265SDimitry Andric Object SymbolGraphSerializer::serializeModule() const {
56281ad6265SDimitry Andric   Object Module;
56381ad6265SDimitry Andric   // The user is expected to always pass `--product-name=` on the command line
56481ad6265SDimitry Andric   // to populate this field.
565*bdd1243dSDimitry Andric   Module["name"] = API.ProductName;
56681ad6265SDimitry Andric   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
56781ad6265SDimitry Andric   return Module;
56881ad6265SDimitry Andric }
56981ad6265SDimitry Andric 
57081ad6265SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
571*bdd1243dSDimitry Andric   // Skip explicitly ignored symbols.
572*bdd1243dSDimitry Andric   if (IgnoresList.shouldIgnore(Record.Name))
573*bdd1243dSDimitry Andric     return true;
574*bdd1243dSDimitry Andric 
57581ad6265SDimitry Andric   // Skip unconditionally unavailable symbols
576*bdd1243dSDimitry Andric   if (Record.Availabilities.isUnconditionallyUnavailable())
57781ad6265SDimitry Andric     return true;
57881ad6265SDimitry Andric 
57981ad6265SDimitry Andric   // Filter out symbols prefixed with an underscored as they are understood to
58081ad6265SDimitry Andric   // be symbols clients should not use.
58181ad6265SDimitry Andric   if (Record.Name.startswith("_"))
58281ad6265SDimitry Andric     return true;
58381ad6265SDimitry Andric 
58481ad6265SDimitry Andric   return false;
58581ad6265SDimitry Andric }
58681ad6265SDimitry Andric 
58781ad6265SDimitry Andric template <typename RecordTy>
588*bdd1243dSDimitry Andric std::optional<Object>
58981ad6265SDimitry Andric SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
59081ad6265SDimitry Andric   if (shouldSkip(Record))
591*bdd1243dSDimitry Andric     return std::nullopt;
59281ad6265SDimitry Andric 
59381ad6265SDimitry Andric   Object Obj;
59481ad6265SDimitry Andric   serializeObject(Obj, "identifier",
59581ad6265SDimitry Andric                   serializeIdentifier(Record, API.getLanguage()));
59681ad6265SDimitry Andric   serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
59781ad6265SDimitry Andric   serializeObject(Obj, "names", serializeNames(Record));
59881ad6265SDimitry Andric   serializeObject(
59981ad6265SDimitry Andric       Obj, "location",
60081ad6265SDimitry Andric       serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
601*bdd1243dSDimitry Andric   serializeArray(Obj, "availability",
602*bdd1243dSDimitry Andric                  serializeAvailability(Record.Availabilities));
60381ad6265SDimitry Andric   serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
60481ad6265SDimitry Andric   serializeArray(Obj, "declarationFragments",
60581ad6265SDimitry Andric                  serializeDeclarationFragments(Record.Declaration));
60681ad6265SDimitry Andric   // TODO: Once we keep track of symbol access information serialize it
60781ad6265SDimitry Andric   // correctly here.
60881ad6265SDimitry Andric   Obj["accessLevel"] = "public";
609*bdd1243dSDimitry Andric   SmallVector<StringRef, 4> PathComponentsNames;
610*bdd1243dSDimitry Andric   // If this returns true it indicates that we couldn't find a symbol in the
611*bdd1243dSDimitry Andric   // hierarchy.
612*bdd1243dSDimitry Andric   if (generatePathComponents(Record, API,
613*bdd1243dSDimitry Andric                              [&PathComponentsNames](const PathComponent &PC) {
614*bdd1243dSDimitry Andric                                PathComponentsNames.push_back(PC.Name);
615*bdd1243dSDimitry Andric                              }))
616*bdd1243dSDimitry Andric     return {};
617*bdd1243dSDimitry Andric 
618*bdd1243dSDimitry Andric   serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
61981ad6265SDimitry Andric 
62081ad6265SDimitry Andric   serializeFunctionSignatureMixin(Obj, Record);
62181ad6265SDimitry Andric 
62281ad6265SDimitry Andric   return Obj;
62381ad6265SDimitry Andric }
62481ad6265SDimitry Andric 
62581ad6265SDimitry Andric template <typename MemberTy>
62681ad6265SDimitry Andric void SymbolGraphSerializer::serializeMembers(
62781ad6265SDimitry Andric     const APIRecord &Record,
62881ad6265SDimitry Andric     const SmallVector<std::unique_ptr<MemberTy>> &Members) {
629*bdd1243dSDimitry Andric   // Members should not be serialized if we aren't recursing.
630*bdd1243dSDimitry Andric   if (!ShouldRecurse)
631*bdd1243dSDimitry Andric     return;
63281ad6265SDimitry Andric   for (const auto &Member : Members) {
63381ad6265SDimitry Andric     auto MemberRecord = serializeAPIRecord(*Member);
63481ad6265SDimitry Andric     if (!MemberRecord)
63581ad6265SDimitry Andric       continue;
63681ad6265SDimitry Andric 
63781ad6265SDimitry Andric     Symbols.emplace_back(std::move(*MemberRecord));
63881ad6265SDimitry Andric     serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
63981ad6265SDimitry Andric   }
64081ad6265SDimitry Andric }
64181ad6265SDimitry Andric 
64281ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
64381ad6265SDimitry Andric   switch (Kind) {
64481ad6265SDimitry Andric   case RelationshipKind::MemberOf:
64581ad6265SDimitry Andric     return "memberOf";
64681ad6265SDimitry Andric   case RelationshipKind::InheritsFrom:
64781ad6265SDimitry Andric     return "inheritsFrom";
64881ad6265SDimitry Andric   case RelationshipKind::ConformsTo:
64981ad6265SDimitry Andric     return "conformsTo";
65081ad6265SDimitry Andric   }
65181ad6265SDimitry Andric   llvm_unreachable("Unhandled relationship kind");
65281ad6265SDimitry Andric }
65381ad6265SDimitry Andric 
65481ad6265SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
65581ad6265SDimitry Andric                                                   SymbolReference Source,
65681ad6265SDimitry Andric                                                   SymbolReference Target) {
65781ad6265SDimitry Andric   Object Relationship;
65881ad6265SDimitry Andric   Relationship["source"] = Source.USR;
65981ad6265SDimitry Andric   Relationship["target"] = Target.USR;
660*bdd1243dSDimitry Andric   Relationship["targetFallback"] = Target.Name;
66181ad6265SDimitry Andric   Relationship["kind"] = getRelationshipString(Kind);
66281ad6265SDimitry Andric 
66381ad6265SDimitry Andric   Relationships.emplace_back(std::move(Relationship));
66481ad6265SDimitry Andric }
66581ad6265SDimitry Andric 
66681ad6265SDimitry Andric void SymbolGraphSerializer::serializeGlobalFunctionRecord(
66781ad6265SDimitry Andric     const GlobalFunctionRecord &Record) {
66881ad6265SDimitry Andric   auto Obj = serializeAPIRecord(Record);
66981ad6265SDimitry Andric   if (!Obj)
67081ad6265SDimitry Andric     return;
67181ad6265SDimitry Andric 
67281ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Obj));
67381ad6265SDimitry Andric }
67481ad6265SDimitry Andric 
67581ad6265SDimitry Andric void SymbolGraphSerializer::serializeGlobalVariableRecord(
67681ad6265SDimitry Andric     const GlobalVariableRecord &Record) {
67781ad6265SDimitry Andric   auto Obj = serializeAPIRecord(Record);
67881ad6265SDimitry Andric   if (!Obj)
67981ad6265SDimitry Andric     return;
68081ad6265SDimitry Andric 
68181ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Obj));
68281ad6265SDimitry Andric }
68381ad6265SDimitry Andric 
68481ad6265SDimitry Andric void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
68581ad6265SDimitry Andric   auto Enum = serializeAPIRecord(Record);
68681ad6265SDimitry Andric   if (!Enum)
68781ad6265SDimitry Andric     return;
68881ad6265SDimitry Andric 
68981ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Enum));
69081ad6265SDimitry Andric   serializeMembers(Record, Record.Constants);
69181ad6265SDimitry Andric }
69281ad6265SDimitry Andric 
69381ad6265SDimitry Andric void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
69481ad6265SDimitry Andric   auto Struct = serializeAPIRecord(Record);
69581ad6265SDimitry Andric   if (!Struct)
69681ad6265SDimitry Andric     return;
69781ad6265SDimitry Andric 
69881ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Struct));
69981ad6265SDimitry Andric   serializeMembers(Record, Record.Fields);
70081ad6265SDimitry Andric }
70181ad6265SDimitry Andric 
70281ad6265SDimitry Andric void SymbolGraphSerializer::serializeObjCContainerRecord(
70381ad6265SDimitry Andric     const ObjCContainerRecord &Record) {
70481ad6265SDimitry Andric   auto ObjCContainer = serializeAPIRecord(Record);
70581ad6265SDimitry Andric   if (!ObjCContainer)
70681ad6265SDimitry Andric     return;
70781ad6265SDimitry Andric 
70881ad6265SDimitry Andric   Symbols.emplace_back(std::move(*ObjCContainer));
70981ad6265SDimitry Andric 
71081ad6265SDimitry Andric   serializeMembers(Record, Record.Ivars);
71181ad6265SDimitry Andric   serializeMembers(Record, Record.Methods);
71281ad6265SDimitry Andric   serializeMembers(Record, Record.Properties);
71381ad6265SDimitry Andric 
71481ad6265SDimitry Andric   for (const auto &Protocol : Record.Protocols)
71581ad6265SDimitry Andric     // Record that Record conforms to Protocol.
71681ad6265SDimitry Andric     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
71781ad6265SDimitry Andric 
71881ad6265SDimitry Andric   if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
71981ad6265SDimitry Andric     if (!ObjCInterface->SuperClass.empty())
72081ad6265SDimitry Andric       // If Record is an Objective-C interface record and it has a super class,
72181ad6265SDimitry Andric       // record that Record is inherited from SuperClass.
72281ad6265SDimitry Andric       serializeRelationship(RelationshipKind::InheritsFrom, Record,
72381ad6265SDimitry Andric                             ObjCInterface->SuperClass);
72481ad6265SDimitry Andric 
72581ad6265SDimitry Andric     // Members of categories extending an interface are serialized as members of
72681ad6265SDimitry Andric     // the interface.
72781ad6265SDimitry Andric     for (const auto *Category : ObjCInterface->Categories) {
72881ad6265SDimitry Andric       serializeMembers(Record, Category->Ivars);
72981ad6265SDimitry Andric       serializeMembers(Record, Category->Methods);
73081ad6265SDimitry Andric       serializeMembers(Record, Category->Properties);
73181ad6265SDimitry Andric 
732*bdd1243dSDimitry Andric       // Surface the protocols of the category to the interface.
73381ad6265SDimitry Andric       for (const auto &Protocol : Category->Protocols)
73481ad6265SDimitry Andric         serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
73581ad6265SDimitry Andric     }
73681ad6265SDimitry Andric   }
73781ad6265SDimitry Andric }
73881ad6265SDimitry Andric 
73981ad6265SDimitry Andric void SymbolGraphSerializer::serializeMacroDefinitionRecord(
74081ad6265SDimitry Andric     const MacroDefinitionRecord &Record) {
74181ad6265SDimitry Andric   auto Macro = serializeAPIRecord(Record);
74281ad6265SDimitry Andric 
74381ad6265SDimitry Andric   if (!Macro)
74481ad6265SDimitry Andric     return;
74581ad6265SDimitry Andric 
74681ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Macro));
74781ad6265SDimitry Andric }
74881ad6265SDimitry Andric 
749*bdd1243dSDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
750*bdd1243dSDimitry Andric   switch (Record->getKind()) {
751*bdd1243dSDimitry Andric   case APIRecord::RK_Unknown:
752*bdd1243dSDimitry Andric     llvm_unreachable("Records should have a known kind!");
753*bdd1243dSDimitry Andric   case APIRecord::RK_GlobalFunction:
754*bdd1243dSDimitry Andric     serializeGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
755*bdd1243dSDimitry Andric     break;
756*bdd1243dSDimitry Andric   case APIRecord::RK_GlobalVariable:
757*bdd1243dSDimitry Andric     serializeGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
758*bdd1243dSDimitry Andric     break;
759*bdd1243dSDimitry Andric   case APIRecord::RK_Enum:
760*bdd1243dSDimitry Andric     serializeEnumRecord(*cast<EnumRecord>(Record));
761*bdd1243dSDimitry Andric     break;
762*bdd1243dSDimitry Andric   case APIRecord::RK_Struct:
763*bdd1243dSDimitry Andric     serializeStructRecord(*cast<StructRecord>(Record));
764*bdd1243dSDimitry Andric     break;
765*bdd1243dSDimitry Andric   case APIRecord::RK_ObjCInterface:
766*bdd1243dSDimitry Andric     serializeObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
767*bdd1243dSDimitry Andric     break;
768*bdd1243dSDimitry Andric   case APIRecord::RK_ObjCProtocol:
769*bdd1243dSDimitry Andric     serializeObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
770*bdd1243dSDimitry Andric     break;
771*bdd1243dSDimitry Andric   case APIRecord::RK_MacroDefinition:
772*bdd1243dSDimitry Andric     serializeMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
773*bdd1243dSDimitry Andric     break;
774*bdd1243dSDimitry Andric   case APIRecord::RK_Typedef:
775*bdd1243dSDimitry Andric     serializeTypedefRecord(*cast<TypedefRecord>(Record));
776*bdd1243dSDimitry Andric     break;
777*bdd1243dSDimitry Andric   default:
778*bdd1243dSDimitry Andric     if (auto Obj = serializeAPIRecord(*Record)) {
779*bdd1243dSDimitry Andric       Symbols.emplace_back(std::move(*Obj));
780*bdd1243dSDimitry Andric       auto &ParentInformation = Record->ParentInformation;
781*bdd1243dSDimitry Andric       if (!ParentInformation.empty())
782*bdd1243dSDimitry Andric         serializeRelationship(RelationshipKind::MemberOf, *Record,
783*bdd1243dSDimitry Andric                               *ParentInformation.ParentRecord);
784*bdd1243dSDimitry Andric     }
785*bdd1243dSDimitry Andric     break;
786*bdd1243dSDimitry Andric   }
787*bdd1243dSDimitry Andric }
788*bdd1243dSDimitry Andric 
78981ad6265SDimitry Andric void SymbolGraphSerializer::serializeTypedefRecord(
79081ad6265SDimitry Andric     const TypedefRecord &Record) {
79181ad6265SDimitry Andric   // Typedefs of anonymous types have their entries unified with the underlying
79281ad6265SDimitry Andric   // type.
79381ad6265SDimitry Andric   bool ShouldDrop = Record.UnderlyingType.Name.empty();
79481ad6265SDimitry Andric   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
79581ad6265SDimitry Andric   // the same name
79681ad6265SDimitry Andric   ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
79781ad6265SDimitry Andric   if (ShouldDrop)
79881ad6265SDimitry Andric     return;
79981ad6265SDimitry Andric 
80081ad6265SDimitry Andric   auto Typedef = serializeAPIRecord(Record);
80181ad6265SDimitry Andric   if (!Typedef)
80281ad6265SDimitry Andric     return;
80381ad6265SDimitry Andric 
80481ad6265SDimitry Andric   (*Typedef)["type"] = Record.UnderlyingType.USR;
80581ad6265SDimitry Andric 
80681ad6265SDimitry Andric   Symbols.emplace_back(std::move(*Typedef));
80781ad6265SDimitry Andric }
80881ad6265SDimitry Andric 
80981ad6265SDimitry Andric Object SymbolGraphSerializer::serialize() {
81081ad6265SDimitry Andric   // Serialize global variables in the API set.
81181ad6265SDimitry Andric   for (const auto &GlobalVar : API.getGlobalVariables())
81281ad6265SDimitry Andric     serializeGlobalVariableRecord(*GlobalVar.second);
81381ad6265SDimitry Andric 
81481ad6265SDimitry Andric   for (const auto &GlobalFunction : API.getGlobalFunctions())
81581ad6265SDimitry Andric     serializeGlobalFunctionRecord(*GlobalFunction.second);
81681ad6265SDimitry Andric 
81781ad6265SDimitry Andric   // Serialize enum records in the API set.
81881ad6265SDimitry Andric   for (const auto &Enum : API.getEnums())
81981ad6265SDimitry Andric     serializeEnumRecord(*Enum.second);
82081ad6265SDimitry Andric 
82181ad6265SDimitry Andric   // Serialize struct records in the API set.
82281ad6265SDimitry Andric   for (const auto &Struct : API.getStructs())
82381ad6265SDimitry Andric     serializeStructRecord(*Struct.second);
82481ad6265SDimitry Andric 
82581ad6265SDimitry Andric   // Serialize Objective-C interface records in the API set.
82681ad6265SDimitry Andric   for (const auto &ObjCInterface : API.getObjCInterfaces())
82781ad6265SDimitry Andric     serializeObjCContainerRecord(*ObjCInterface.second);
82881ad6265SDimitry Andric 
82981ad6265SDimitry Andric   // Serialize Objective-C protocol records in the API set.
83081ad6265SDimitry Andric   for (const auto &ObjCProtocol : API.getObjCProtocols())
83181ad6265SDimitry Andric     serializeObjCContainerRecord(*ObjCProtocol.second);
83281ad6265SDimitry Andric 
83381ad6265SDimitry Andric   for (const auto &Macro : API.getMacros())
83481ad6265SDimitry Andric     serializeMacroDefinitionRecord(*Macro.second);
83581ad6265SDimitry Andric 
83681ad6265SDimitry Andric   for (const auto &Typedef : API.getTypedefs())
83781ad6265SDimitry Andric     serializeTypedefRecord(*Typedef.second);
83881ad6265SDimitry Andric 
839*bdd1243dSDimitry Andric   return serializeCurrentGraph();
840*bdd1243dSDimitry Andric }
841*bdd1243dSDimitry Andric 
842*bdd1243dSDimitry Andric Object SymbolGraphSerializer::serializeCurrentGraph() {
843*bdd1243dSDimitry Andric   Object Root;
844*bdd1243dSDimitry Andric   serializeObject(Root, "metadata", serializeMetadata());
845*bdd1243dSDimitry Andric   serializeObject(Root, "module", serializeModule());
846*bdd1243dSDimitry Andric 
84781ad6265SDimitry Andric   Root["symbols"] = std::move(Symbols);
84881ad6265SDimitry Andric   Root["relationships"] = std::move(Relationships);
84981ad6265SDimitry Andric 
85081ad6265SDimitry Andric   return Root;
85181ad6265SDimitry Andric }
85281ad6265SDimitry Andric 
85381ad6265SDimitry Andric void SymbolGraphSerializer::serialize(raw_ostream &os) {
85481ad6265SDimitry Andric   Object root = serialize();
85581ad6265SDimitry Andric   if (Options.Compact)
85681ad6265SDimitry Andric     os << formatv("{0}", Value(std::move(root))) << "\n";
85781ad6265SDimitry Andric   else
85881ad6265SDimitry Andric     os << formatv("{0:2}", Value(std::move(root))) << "\n";
85981ad6265SDimitry Andric }
860*bdd1243dSDimitry Andric 
861*bdd1243dSDimitry Andric std::optional<Object>
862*bdd1243dSDimitry Andric SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
863*bdd1243dSDimitry Andric                                                 const APISet &API) {
864*bdd1243dSDimitry Andric   APIRecord *Record = API.findRecordForUSR(USR);
865*bdd1243dSDimitry Andric   if (!Record)
866*bdd1243dSDimitry Andric     return {};
867*bdd1243dSDimitry Andric 
868*bdd1243dSDimitry Andric   Object Root;
869*bdd1243dSDimitry Andric   APIIgnoresList EmptyIgnores;
870*bdd1243dSDimitry Andric   SymbolGraphSerializer Serializer(API, EmptyIgnores,
871*bdd1243dSDimitry Andric                                    /*Options.Compact*/ {true},
872*bdd1243dSDimitry Andric                                    /*ShouldRecurse*/ false);
873*bdd1243dSDimitry Andric   Serializer.serializeSingleRecord(Record);
874*bdd1243dSDimitry Andric   serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
875*bdd1243dSDimitry Andric 
876*bdd1243dSDimitry Andric   Language Lang = API.getLanguage();
877*bdd1243dSDimitry Andric   serializeArray(Root, "parentContexts",
878*bdd1243dSDimitry Andric                  generateParentContexts(*Record, API, Lang));
879*bdd1243dSDimitry Andric 
880*bdd1243dSDimitry Andric   Array RelatedSymbols;
881*bdd1243dSDimitry Andric 
882*bdd1243dSDimitry Andric   for (const auto &Fragment : Record->Declaration.getFragments()) {
883*bdd1243dSDimitry Andric     // If we don't have a USR there isn't much we can do.
884*bdd1243dSDimitry Andric     if (Fragment.PreciseIdentifier.empty())
885*bdd1243dSDimitry Andric       continue;
886*bdd1243dSDimitry Andric 
887*bdd1243dSDimitry Andric     APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
888*bdd1243dSDimitry Andric 
889*bdd1243dSDimitry Andric     // If we can't find the record let's skip.
890*bdd1243dSDimitry Andric     if (!RelatedRecord)
891*bdd1243dSDimitry Andric       continue;
892*bdd1243dSDimitry Andric 
893*bdd1243dSDimitry Andric     Object RelatedSymbol;
894*bdd1243dSDimitry Andric     RelatedSymbol["usr"] = RelatedRecord->USR;
895*bdd1243dSDimitry Andric     RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
896*bdd1243dSDimitry Andric     // TODO: once we record this properly let's serialize it right.
897*bdd1243dSDimitry Andric     RelatedSymbol["accessLevel"] = "public";
898*bdd1243dSDimitry Andric     RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
899*bdd1243dSDimitry Andric     RelatedSymbol["moduleName"] = API.ProductName;
900*bdd1243dSDimitry Andric     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
901*bdd1243dSDimitry Andric 
902*bdd1243dSDimitry Andric     serializeArray(RelatedSymbol, "parentContexts",
903*bdd1243dSDimitry Andric                    generateParentContexts(*RelatedRecord, API, Lang));
904*bdd1243dSDimitry Andric     RelatedSymbols.push_back(std::move(RelatedSymbol));
905*bdd1243dSDimitry Andric   }
906*bdd1243dSDimitry Andric 
907*bdd1243dSDimitry Andric   serializeArray(Root, "relatedSymbols", RelatedSymbols);
908*bdd1243dSDimitry Andric   return Root;
909*bdd1243dSDimitry Andric }
910