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