1145449b1SDimitry Andric //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===//
2145449b1SDimitry Andric //
3145449b1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4145449b1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5145449b1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6145449b1SDimitry Andric //
7145449b1SDimitry Andric //===----------------------------------------------------------------------===//
8145449b1SDimitry Andric ///
9145449b1SDimitry Andric /// \file
10145449b1SDimitry Andric /// This file implements the SymbolGraphSerializer.
11145449b1SDimitry Andric ///
12145449b1SDimitry Andric //===----------------------------------------------------------------------===//
13145449b1SDimitry Andric
14145449b1SDimitry Andric #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
15e3b55780SDimitry Andric #include "clang/Basic/SourceLocation.h"
16145449b1SDimitry Andric #include "clang/Basic/Version.h"
17ac9a064cSDimitry Andric #include "clang/ExtractAPI/API.h"
18145449b1SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h"
19e3b55780SDimitry Andric #include "llvm/ADT/STLExtras.h"
20e3b55780SDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h"
21ac9a064cSDimitry Andric #include "llvm/ADT/SmallVector.h"
22e3b55780SDimitry Andric #include "llvm/Support/Casting.h"
23e3b55780SDimitry Andric #include "llvm/Support/Compiler.h"
24145449b1SDimitry Andric #include "llvm/Support/Path.h"
25145449b1SDimitry Andric #include "llvm/Support/VersionTuple.h"
26ac9a064cSDimitry Andric #include "llvm/Support/raw_ostream.h"
27ac9a064cSDimitry Andric #include <iterator>
28e3b55780SDimitry Andric #include <optional>
29145449b1SDimitry Andric #include <type_traits>
30145449b1SDimitry Andric
31145449b1SDimitry Andric using namespace clang;
32145449b1SDimitry Andric using namespace clang::extractapi;
33145449b1SDimitry Andric using namespace llvm;
34145449b1SDimitry Andric
35145449b1SDimitry Andric namespace {
36145449b1SDimitry Andric
37145449b1SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren
38145449b1SDimitry Andric /// at position \p Key.
serializeObject(Object & Paren,StringRef Key,std::optional<Object> && Obj)39ac9a064cSDimitry Andric void serializeObject(Object &Paren, StringRef Key,
40ac9a064cSDimitry Andric std::optional<Object> &&Obj) {
41145449b1SDimitry Andric if (Obj)
42e3b55780SDimitry Andric Paren[Key] = std::move(*Obj);
43145449b1SDimitry Andric }
44145449b1SDimitry Andric
45145449b1SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at
46145449b1SDimitry Andric /// position \p Key.
serializeArray(Object & Paren,StringRef Key,std::optional<Array> && Array)47ac9a064cSDimitry Andric void serializeArray(Object &Paren, StringRef Key,
48ac9a064cSDimitry Andric std::optional<Array> &&Array) {
49145449b1SDimitry Andric if (Array)
50e3b55780SDimitry Andric Paren[Key] = std::move(*Array);
51145449b1SDimitry Andric }
52145449b1SDimitry Andric
53ac9a064cSDimitry Andric /// Helper function to inject a JSON array composed of the values in \p C into
54ac9a064cSDimitry Andric /// object \p Paren at position \p Key.
55ac9a064cSDimitry Andric template <typename ContainerTy>
serializeArray(Object & Paren,StringRef Key,ContainerTy && C)56ac9a064cSDimitry Andric void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) {
57ac9a064cSDimitry Andric Paren[Key] = Array(C);
58ac9a064cSDimitry Andric }
59ac9a064cSDimitry Andric
60145449b1SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
61145449b1SDimitry Andric /// format.
62145449b1SDimitry Andric ///
63145449b1SDimitry Andric /// A semantic version object contains three numeric fields, representing the
64145449b1SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple.
65145449b1SDimitry Andric /// For example version tuple 1.0.3 is serialized as:
66145449b1SDimitry Andric /// \code
67145449b1SDimitry Andric /// {
68145449b1SDimitry Andric /// "major" : 1,
69145449b1SDimitry Andric /// "minor" : 0,
70145449b1SDimitry Andric /// "patch" : 3
71145449b1SDimitry Andric /// }
72145449b1SDimitry Andric /// \endcode
73145449b1SDimitry Andric ///
74e3b55780SDimitry Andric /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
75e3b55780SDimitry Andric /// containing the semantic version representation of \p V.
serializeSemanticVersion(const VersionTuple & V)76e3b55780SDimitry Andric std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
77145449b1SDimitry Andric if (V.empty())
78e3b55780SDimitry Andric return std::nullopt;
79145449b1SDimitry Andric
80145449b1SDimitry Andric Object Version;
81145449b1SDimitry Andric Version["major"] = V.getMajor();
82145449b1SDimitry Andric Version["minor"] = V.getMinor().value_or(0);
83145449b1SDimitry Andric Version["patch"] = V.getSubminor().value_or(0);
84145449b1SDimitry Andric return Version;
85145449b1SDimitry Andric }
86145449b1SDimitry Andric
87145449b1SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property.
88145449b1SDimitry Andric ///
89145449b1SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an
90145449b1SDimitry Andric /// optional \c minimumVersion semantic version field.
serializeOperatingSystem(const Triple & T)91145449b1SDimitry Andric Object serializeOperatingSystem(const Triple &T) {
92145449b1SDimitry Andric Object OS;
93145449b1SDimitry Andric OS["name"] = T.getOSTypeName(T.getOS());
94145449b1SDimitry Andric serializeObject(OS, "minimumVersion",
95145449b1SDimitry Andric serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
96145449b1SDimitry Andric return OS;
97145449b1SDimitry Andric }
98145449b1SDimitry Andric
99145449b1SDimitry Andric /// Serialize the platform information in the Symbol Graph module section.
100145449b1SDimitry Andric ///
101145449b1SDimitry Andric /// The platform object describes a target platform triple in corresponding
102145449b1SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem.
serializePlatform(const Triple & T)103145449b1SDimitry Andric Object serializePlatform(const Triple &T) {
104145449b1SDimitry Andric Object Platform;
105145449b1SDimitry Andric Platform["architecture"] = T.getArchName();
106145449b1SDimitry Andric Platform["vendor"] = T.getVendorName();
107145449b1SDimitry Andric Platform["operatingSystem"] = serializeOperatingSystem(T);
108145449b1SDimitry Andric return Platform;
109145449b1SDimitry Andric }
110145449b1SDimitry Andric
111145449b1SDimitry Andric /// Serialize a source position.
serializeSourcePosition(const PresumedLoc & Loc)112145449b1SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) {
113145449b1SDimitry Andric assert(Loc.isValid() && "invalid source position");
114145449b1SDimitry Andric
115145449b1SDimitry Andric Object SourcePosition;
116b1c73532SDimitry Andric SourcePosition["line"] = Loc.getLine() - 1;
117b1c73532SDimitry Andric SourcePosition["character"] = Loc.getColumn() - 1;
118145449b1SDimitry Andric
119145449b1SDimitry Andric return SourcePosition;
120145449b1SDimitry Andric }
121145449b1SDimitry Andric
122145449b1SDimitry Andric /// Serialize a source location in file.
123145449b1SDimitry Andric ///
124145449b1SDimitry Andric /// \param Loc The presumed location to serialize.
125145449b1SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
126145449b1SDimitry Andric /// Defaults to false.
serializeSourceLocation(const PresumedLoc & Loc,bool IncludeFileURI=false)127145449b1SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc,
128145449b1SDimitry Andric bool IncludeFileURI = false) {
129145449b1SDimitry Andric Object SourceLocation;
130145449b1SDimitry Andric serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
131145449b1SDimitry Andric
132145449b1SDimitry Andric if (IncludeFileURI) {
133145449b1SDimitry Andric std::string FileURI = "file://";
134145449b1SDimitry Andric // Normalize file path to use forward slashes for the URI.
135145449b1SDimitry Andric FileURI += sys::path::convert_to_slash(Loc.getFilename());
136145449b1SDimitry Andric SourceLocation["uri"] = FileURI;
137145449b1SDimitry Andric }
138145449b1SDimitry Andric
139145449b1SDimitry Andric return SourceLocation;
140145449b1SDimitry Andric }
141145449b1SDimitry Andric
142145449b1SDimitry Andric /// Serialize a source range with begin and end locations.
serializeSourceRange(const PresumedLoc & BeginLoc,const PresumedLoc & EndLoc)143145449b1SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc,
144145449b1SDimitry Andric const PresumedLoc &EndLoc) {
145145449b1SDimitry Andric Object SourceRange;
146145449b1SDimitry Andric serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
147145449b1SDimitry Andric serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
148145449b1SDimitry Andric return SourceRange;
149145449b1SDimitry Andric }
150145449b1SDimitry Andric
151145449b1SDimitry Andric /// Serialize the availability attributes of a symbol.
152145449b1SDimitry Andric ///
153145449b1SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted
1544df029ccSDimitry Andric /// versions of the symbol as semantic versions, if not default.
1554df029ccSDimitry Andric /// Availability information also contains flags to indicate if the symbol is
1564df029ccSDimitry Andric /// unconditionally unavailable or deprecated,
1574df029ccSDimitry Andric /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
158145449b1SDimitry Andric ///
159e3b55780SDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes,
1604df029ccSDimitry Andric /// or an \c Array containing an object with the formatted availability
1614df029ccSDimitry Andric /// information.
serializeAvailability(const AvailabilityInfo & Avail)1624df029ccSDimitry Andric std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
1634df029ccSDimitry Andric if (Avail.isDefault())
164e3b55780SDimitry Andric return std::nullopt;
165145449b1SDimitry Andric
166e3b55780SDimitry Andric Array AvailabilityArray;
167ac9a064cSDimitry Andric
1684df029ccSDimitry Andric if (Avail.isUnconditionallyDeprecated()) {
169e3b55780SDimitry Andric Object UnconditionallyDeprecated;
170e3b55780SDimitry Andric UnconditionallyDeprecated["domain"] = "*";
171e3b55780SDimitry Andric UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
172e3b55780SDimitry Andric AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
173e3b55780SDimitry Andric }
174ac9a064cSDimitry Andric Object Availability;
175ac9a064cSDimitry Andric
176ac9a064cSDimitry Andric Availability["domain"] = Avail.Domain;
177ac9a064cSDimitry Andric
178ac9a064cSDimitry Andric if (Avail.isUnavailable()) {
179ac9a064cSDimitry Andric Availability["isUnconditionallyUnavailable"] = true;
180ac9a064cSDimitry Andric } else {
181ac9a064cSDimitry Andric serializeObject(Availability, "introduced",
182ac9a064cSDimitry Andric serializeSemanticVersion(Avail.Introduced));
183ac9a064cSDimitry Andric serializeObject(Availability, "deprecated",
184ac9a064cSDimitry Andric serializeSemanticVersion(Avail.Deprecated));
185ac9a064cSDimitry Andric serializeObject(Availability, "obsoleted",
186ac9a064cSDimitry Andric serializeSemanticVersion(Avail.Obsoleted));
1877fa27ce4SDimitry Andric }
188ac9a064cSDimitry Andric
189e3b55780SDimitry Andric AvailabilityArray.emplace_back(std::move(Availability));
190e3b55780SDimitry Andric return AvailabilityArray;
191145449b1SDimitry Andric }
192145449b1SDimitry Andric
193145449b1SDimitry Andric /// Get the language name string for interface language references.
getLanguageName(Language Lang)194145449b1SDimitry Andric StringRef getLanguageName(Language Lang) {
195145449b1SDimitry Andric switch (Lang) {
196145449b1SDimitry Andric case Language::C:
197145449b1SDimitry Andric return "c";
198145449b1SDimitry Andric case Language::ObjC:
199145449b1SDimitry Andric return "objective-c";
200b1c73532SDimitry Andric case Language::CXX:
201b1c73532SDimitry Andric return "c++";
202b1c73532SDimitry Andric case Language::ObjCXX:
203b1c73532SDimitry Andric return "objective-c++";
204145449b1SDimitry Andric
205145449b1SDimitry Andric // Unsupported language currently
206145449b1SDimitry Andric case Language::OpenCL:
207145449b1SDimitry Andric case Language::OpenCLCXX:
208145449b1SDimitry Andric case Language::CUDA:
209145449b1SDimitry Andric case Language::RenderScript:
210145449b1SDimitry Andric case Language::HIP:
211145449b1SDimitry Andric case Language::HLSL:
212145449b1SDimitry Andric
213145449b1SDimitry Andric // Languages that the frontend cannot parse and compile
214145449b1SDimitry Andric case Language::Unknown:
215145449b1SDimitry Andric case Language::Asm:
216145449b1SDimitry Andric case Language::LLVM_IR:
217ac9a064cSDimitry Andric case Language::CIR:
218145449b1SDimitry Andric llvm_unreachable("Unsupported language kind");
219145449b1SDimitry Andric }
220145449b1SDimitry Andric
221145449b1SDimitry Andric llvm_unreachable("Unhandled language kind");
222145449b1SDimitry Andric }
223145449b1SDimitry Andric
224145449b1SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format.
225145449b1SDimitry Andric ///
226145449b1SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique
227145449b1SDimitry Andric /// references, and the interface language name.
serializeIdentifier(const APIRecord & Record,Language Lang)228145449b1SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) {
229145449b1SDimitry Andric Object Identifier;
230145449b1SDimitry Andric Identifier["precise"] = Record.USR;
231145449b1SDimitry Andric Identifier["interfaceLanguage"] = getLanguageName(Lang);
232145449b1SDimitry Andric
233145449b1SDimitry Andric return Identifier;
234145449b1SDimitry Andric }
235145449b1SDimitry Andric
236145449b1SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by
237145449b1SDimitry Andric /// the Symbol Graph format.
238145449b1SDimitry Andric ///
239145449b1SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line
240145449b1SDimitry Andric /// represents one line of striped documentation comment, with source range
241145449b1SDimitry Andric /// information.
242145449b1SDimitry Andric /// e.g.
243145449b1SDimitry Andric /// \code
244145449b1SDimitry Andric /// /// This is a documentation comment
245145449b1SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line.
246145449b1SDimitry Andric /// /// with multiple lines.
247145449b1SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line.
248145449b1SDimitry Andric /// \endcode
249145449b1SDimitry Andric ///
250e3b55780SDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
251e3b55780SDimitry Andric /// the formatted lines.
serializeDocComment(const DocComment & Comment)252e3b55780SDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) {
253145449b1SDimitry Andric if (Comment.empty())
254e3b55780SDimitry Andric return std::nullopt;
255145449b1SDimitry Andric
256145449b1SDimitry Andric Object DocComment;
257ac9a064cSDimitry Andric
258145449b1SDimitry Andric Array LinesArray;
259145449b1SDimitry Andric for (const auto &CommentLine : Comment) {
260145449b1SDimitry Andric Object Line;
261145449b1SDimitry Andric Line["text"] = CommentLine.Text;
262145449b1SDimitry Andric serializeObject(Line, "range",
263145449b1SDimitry Andric serializeSourceRange(CommentLine.Begin, CommentLine.End));
264145449b1SDimitry Andric LinesArray.emplace_back(std::move(Line));
265145449b1SDimitry Andric }
266ac9a064cSDimitry Andric
267ac9a064cSDimitry Andric serializeArray(DocComment, "lines", std::move(LinesArray));
268145449b1SDimitry Andric
269145449b1SDimitry Andric return DocComment;
270145449b1SDimitry Andric }
271145449b1SDimitry Andric
272145449b1SDimitry Andric /// Serialize the declaration fragments of a symbol.
273145449b1SDimitry Andric ///
274145449b1SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important
275145449b1SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to
276145449b1SDimitry Andric /// form spans of declaration text, with attached information useful for
277145449b1SDimitry Andric /// purposes like syntax-highlighting etc. For example:
278145449b1SDimitry Andric /// \code
279145449b1SDimitry Andric /// const int pi; -> "declarationFragments" : [
280145449b1SDimitry Andric /// {
281145449b1SDimitry Andric /// "kind" : "keyword",
282145449b1SDimitry Andric /// "spelling" : "const"
283145449b1SDimitry Andric /// },
284145449b1SDimitry Andric /// {
285145449b1SDimitry Andric /// "kind" : "text",
286145449b1SDimitry Andric /// "spelling" : " "
287145449b1SDimitry Andric /// },
288145449b1SDimitry Andric /// {
289145449b1SDimitry Andric /// "kind" : "typeIdentifier",
290145449b1SDimitry Andric /// "preciseIdentifier" : "c:I",
291145449b1SDimitry Andric /// "spelling" : "int"
292145449b1SDimitry Andric /// },
293145449b1SDimitry Andric /// {
294145449b1SDimitry Andric /// "kind" : "text",
295145449b1SDimitry Andric /// "spelling" : " "
296145449b1SDimitry Andric /// },
297145449b1SDimitry Andric /// {
298145449b1SDimitry Andric /// "kind" : "identifier",
299145449b1SDimitry Andric /// "spelling" : "pi"
300145449b1SDimitry Andric /// }
301145449b1SDimitry Andric /// ]
302145449b1SDimitry Andric /// \endcode
303145449b1SDimitry Andric ///
304e3b55780SDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
305e3b55780SDimitry Andric /// formatted declaration fragments array.
306e3b55780SDimitry Andric std::optional<Array>
serializeDeclarationFragments(const DeclarationFragments & DF)307e3b55780SDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) {
308145449b1SDimitry Andric if (DF.getFragments().empty())
309e3b55780SDimitry Andric return std::nullopt;
310145449b1SDimitry Andric
311145449b1SDimitry Andric Array Fragments;
312145449b1SDimitry Andric for (const auto &F : DF.getFragments()) {
313145449b1SDimitry Andric Object Fragment;
314145449b1SDimitry Andric Fragment["spelling"] = F.Spelling;
315145449b1SDimitry Andric Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
316145449b1SDimitry Andric if (!F.PreciseIdentifier.empty())
317145449b1SDimitry Andric Fragment["preciseIdentifier"] = F.PreciseIdentifier;
318145449b1SDimitry Andric Fragments.emplace_back(std::move(Fragment));
319145449b1SDimitry Andric }
320145449b1SDimitry Andric
321145449b1SDimitry Andric return Fragments;
322145449b1SDimitry Andric }
323145449b1SDimitry Andric
324145449b1SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph
325145449b1SDimitry Andric /// format.
326145449b1SDimitry Andric ///
327145449b1SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol
328145449b1SDimitry Andric /// that can be used for different applications:
329145449b1SDimitry Andric /// - \c title : The simple declared name of the symbol;
330145449b1SDimitry Andric /// - \c subHeading : An array of declaration fragments that provides tags,
331145449b1SDimitry Andric /// and potentially more tokens (for example the \c +/- symbol for
332145449b1SDimitry Andric /// Objective-C methods). Can be used as sub-headings for documentation.
serializeNames(const APIRecord * Record)333ac9a064cSDimitry Andric Object serializeNames(const APIRecord *Record) {
334145449b1SDimitry Andric Object Names;
335ac9a064cSDimitry Andric Names["title"] = Record->Name;
336b1c73532SDimitry Andric
337145449b1SDimitry Andric serializeArray(Names, "subHeading",
338ac9a064cSDimitry Andric serializeDeclarationFragments(Record->SubHeading));
339145449b1SDimitry Andric DeclarationFragments NavigatorFragments;
340ac9a064cSDimitry Andric NavigatorFragments.append(Record->Name,
341145449b1SDimitry Andric DeclarationFragments::FragmentKind::Identifier,
342145449b1SDimitry Andric /*PreciseIdentifier*/ "");
343145449b1SDimitry Andric serializeArray(Names, "navigator",
344145449b1SDimitry Andric serializeDeclarationFragments(NavigatorFragments));
345145449b1SDimitry Andric
346145449b1SDimitry Andric return Names;
347145449b1SDimitry Andric }
348145449b1SDimitry Andric
serializeSymbolKind(APIRecord::RecordKind RK,Language Lang)349e3b55780SDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
350145449b1SDimitry Andric auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
351145449b1SDimitry Andric return (getLanguageName(Lang) + "." + S).str();
352145449b1SDimitry Andric };
353145449b1SDimitry Andric
354145449b1SDimitry Andric Object Kind;
355e3b55780SDimitry Andric switch (RK) {
356e3b55780SDimitry Andric case APIRecord::RK_Unknown:
357ac9a064cSDimitry Andric Kind["identifier"] = AddLangPrefix("unknown");
358ac9a064cSDimitry Andric Kind["displayName"] = "Unknown";
359e3b55780SDimitry Andric break;
360b1c73532SDimitry Andric case APIRecord::RK_Namespace:
361b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("namespace");
362b1c73532SDimitry Andric Kind["displayName"] = "Namespace";
363b1c73532SDimitry Andric break;
364145449b1SDimitry Andric case APIRecord::RK_GlobalFunction:
365145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("func");
366145449b1SDimitry Andric Kind["displayName"] = "Function";
367145449b1SDimitry Andric break;
368b1c73532SDimitry Andric case APIRecord::RK_GlobalFunctionTemplate:
369b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("func");
370b1c73532SDimitry Andric Kind["displayName"] = "Function Template";
371b1c73532SDimitry Andric break;
372b1c73532SDimitry Andric case APIRecord::RK_GlobalFunctionTemplateSpecialization:
373b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("func");
374b1c73532SDimitry Andric Kind["displayName"] = "Function Template Specialization";
375b1c73532SDimitry Andric break;
376b1c73532SDimitry Andric case APIRecord::RK_GlobalVariableTemplate:
377b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("var");
378b1c73532SDimitry Andric Kind["displayName"] = "Global Variable Template";
379b1c73532SDimitry Andric break;
380b1c73532SDimitry Andric case APIRecord::RK_GlobalVariableTemplateSpecialization:
381b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("var");
382b1c73532SDimitry Andric Kind["displayName"] = "Global Variable Template Specialization";
383b1c73532SDimitry Andric break;
384b1c73532SDimitry Andric case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
385b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("var");
386b1c73532SDimitry Andric Kind["displayName"] = "Global Variable Template Partial Specialization";
387b1c73532SDimitry Andric break;
388145449b1SDimitry Andric case APIRecord::RK_GlobalVariable:
389145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("var");
390145449b1SDimitry Andric Kind["displayName"] = "Global Variable";
391145449b1SDimitry Andric break;
392145449b1SDimitry Andric case APIRecord::RK_EnumConstant:
393145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("enum.case");
394145449b1SDimitry Andric Kind["displayName"] = "Enumeration Case";
395145449b1SDimitry Andric break;
396145449b1SDimitry Andric case APIRecord::RK_Enum:
397145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("enum");
398145449b1SDimitry Andric Kind["displayName"] = "Enumeration";
399145449b1SDimitry Andric break;
400145449b1SDimitry Andric case APIRecord::RK_StructField:
401145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("property");
402145449b1SDimitry Andric Kind["displayName"] = "Instance Property";
403145449b1SDimitry Andric break;
404145449b1SDimitry Andric case APIRecord::RK_Struct:
405145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("struct");
406145449b1SDimitry Andric Kind["displayName"] = "Structure";
407145449b1SDimitry Andric break;
4084df029ccSDimitry Andric case APIRecord::RK_UnionField:
409b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("property");
410b1c73532SDimitry Andric Kind["displayName"] = "Instance Property";
411b1c73532SDimitry Andric break;
412b1c73532SDimitry Andric case APIRecord::RK_Union:
413b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("union");
414b1c73532SDimitry Andric Kind["displayName"] = "Union";
415b1c73532SDimitry Andric break;
4164df029ccSDimitry Andric case APIRecord::RK_CXXField:
4174df029ccSDimitry Andric Kind["identifier"] = AddLangPrefix("property");
4184df029ccSDimitry Andric Kind["displayName"] = "Instance Property";
4194df029ccSDimitry Andric break;
420b1c73532SDimitry Andric case APIRecord::RK_StaticField:
421b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("type.property");
422b1c73532SDimitry Andric Kind["displayName"] = "Type Property";
423b1c73532SDimitry Andric break;
424b1c73532SDimitry Andric case APIRecord::RK_ClassTemplate:
425b1c73532SDimitry Andric case APIRecord::RK_ClassTemplateSpecialization:
426b1c73532SDimitry Andric case APIRecord::RK_ClassTemplatePartialSpecialization:
427b1c73532SDimitry Andric case APIRecord::RK_CXXClass:
428b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("class");
429b1c73532SDimitry Andric Kind["displayName"] = "Class";
430b1c73532SDimitry Andric break;
431b1c73532SDimitry Andric case APIRecord::RK_CXXMethodTemplate:
432b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("method");
433b1c73532SDimitry Andric Kind["displayName"] = "Method Template";
434b1c73532SDimitry Andric break;
435b1c73532SDimitry Andric case APIRecord::RK_CXXMethodTemplateSpecialization:
436b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("method");
437b1c73532SDimitry Andric Kind["displayName"] = "Method Template Specialization";
438b1c73532SDimitry Andric break;
439b1c73532SDimitry Andric case APIRecord::RK_CXXFieldTemplate:
440b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("property");
441b1c73532SDimitry Andric Kind["displayName"] = "Template Property";
442b1c73532SDimitry Andric break;
443b1c73532SDimitry Andric case APIRecord::RK_Concept:
444b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("concept");
445b1c73532SDimitry Andric Kind["displayName"] = "Concept";
446b1c73532SDimitry Andric break;
447b1c73532SDimitry Andric case APIRecord::RK_CXXStaticMethod:
448b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("type.method");
449b1c73532SDimitry Andric Kind["displayName"] = "Static Method";
450b1c73532SDimitry Andric break;
451b1c73532SDimitry Andric case APIRecord::RK_CXXInstanceMethod:
452b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("method");
453b1c73532SDimitry Andric Kind["displayName"] = "Instance Method";
454b1c73532SDimitry Andric break;
455b1c73532SDimitry Andric case APIRecord::RK_CXXConstructorMethod:
456b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("method");
457b1c73532SDimitry Andric Kind["displayName"] = "Constructor";
458b1c73532SDimitry Andric break;
459b1c73532SDimitry Andric case APIRecord::RK_CXXDestructorMethod:
460b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("method");
461b1c73532SDimitry Andric Kind["displayName"] = "Destructor";
462b1c73532SDimitry Andric break;
463145449b1SDimitry Andric case APIRecord::RK_ObjCIvar:
464145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("ivar");
465145449b1SDimitry Andric Kind["displayName"] = "Instance Variable";
466145449b1SDimitry Andric break;
467e3b55780SDimitry Andric case APIRecord::RK_ObjCInstanceMethod:
468145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("method");
469145449b1SDimitry Andric Kind["displayName"] = "Instance Method";
470e3b55780SDimitry Andric break;
471e3b55780SDimitry Andric case APIRecord::RK_ObjCClassMethod:
472145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("type.method");
473145449b1SDimitry Andric Kind["displayName"] = "Type Method";
474145449b1SDimitry Andric break;
475e3b55780SDimitry Andric case APIRecord::RK_ObjCInstanceProperty:
476145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("property");
477145449b1SDimitry Andric Kind["displayName"] = "Instance Property";
478145449b1SDimitry Andric break;
479e3b55780SDimitry Andric case APIRecord::RK_ObjCClassProperty:
480e3b55780SDimitry Andric Kind["identifier"] = AddLangPrefix("type.property");
481e3b55780SDimitry Andric Kind["displayName"] = "Type Property";
482e3b55780SDimitry Andric break;
483145449b1SDimitry Andric case APIRecord::RK_ObjCInterface:
484145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("class");
485145449b1SDimitry Andric Kind["displayName"] = "Class";
486145449b1SDimitry Andric break;
487145449b1SDimitry Andric case APIRecord::RK_ObjCCategory:
488b1c73532SDimitry Andric Kind["identifier"] = AddLangPrefix("class.extension");
489b1c73532SDimitry Andric Kind["displayName"] = "Class Extension";
490b1c73532SDimitry Andric break;
491145449b1SDimitry Andric case APIRecord::RK_ObjCProtocol:
492145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("protocol");
493145449b1SDimitry Andric Kind["displayName"] = "Protocol";
494145449b1SDimitry Andric break;
495145449b1SDimitry Andric case APIRecord::RK_MacroDefinition:
496145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("macro");
497145449b1SDimitry Andric Kind["displayName"] = "Macro";
498145449b1SDimitry Andric break;
499145449b1SDimitry Andric case APIRecord::RK_Typedef:
500145449b1SDimitry Andric Kind["identifier"] = AddLangPrefix("typealias");
501145449b1SDimitry Andric Kind["displayName"] = "Type Alias";
502145449b1SDimitry Andric break;
503ac9a064cSDimitry Andric default:
504ac9a064cSDimitry Andric llvm_unreachable("API Record with uninstantiable kind");
505145449b1SDimitry Andric }
506145449b1SDimitry Andric
507145449b1SDimitry Andric return Kind;
508145449b1SDimitry Andric }
509145449b1SDimitry Andric
510e3b55780SDimitry Andric /// Serialize the symbol kind information.
511e3b55780SDimitry Andric ///
512e3b55780SDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier
513e3b55780SDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse
514e3b55780SDimitry Andric /// the kind, and a \c displayName for rendering human-readable names.
serializeSymbolKind(const APIRecord & Record,Language Lang)515e3b55780SDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
516ac9a064cSDimitry Andric return serializeSymbolKind(Record.KindForDisplay, Lang);
517e3b55780SDimitry Andric }
518e3b55780SDimitry Andric
519ac9a064cSDimitry Andric /// Serialize the function signature field, as specified by the
520ac9a064cSDimitry Andric /// Symbol Graph format.
521ac9a064cSDimitry Andric ///
522ac9a064cSDimitry Andric /// The Symbol Graph function signature property contains two arrays.
523ac9a064cSDimitry Andric /// - The \c returns array is the declaration fragments of the return type;
524ac9a064cSDimitry Andric /// - The \c parameters array contains names and declaration fragments of the
525ac9a064cSDimitry Andric /// parameters.
526145449b1SDimitry Andric template <typename RecordTy>
serializeFunctionSignatureMixin(Object & Paren,const RecordTy & Record)527ac9a064cSDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
528145449b1SDimitry Andric const auto &FS = Record.Signature;
529145449b1SDimitry Andric if (FS.empty())
530ac9a064cSDimitry Andric return;
531145449b1SDimitry Andric
532145449b1SDimitry Andric Object Signature;
533145449b1SDimitry Andric serializeArray(Signature, "returns",
534145449b1SDimitry Andric serializeDeclarationFragments(FS.getReturnType()));
535145449b1SDimitry Andric
536145449b1SDimitry Andric Array Parameters;
537145449b1SDimitry Andric for (const auto &P : FS.getParameters()) {
538145449b1SDimitry Andric Object Parameter;
539145449b1SDimitry Andric Parameter["name"] = P.Name;
540145449b1SDimitry Andric serializeArray(Parameter, "declarationFragments",
541145449b1SDimitry Andric serializeDeclarationFragments(P.Fragments));
542145449b1SDimitry Andric Parameters.emplace_back(std::move(Parameter));
543145449b1SDimitry Andric }
544145449b1SDimitry Andric
545145449b1SDimitry Andric if (!Parameters.empty())
546145449b1SDimitry Andric Signature["parameters"] = std::move(Parameters);
547145449b1SDimitry Andric
548ac9a064cSDimitry Andric serializeObject(Paren, "functionSignature", std::move(Signature));
549145449b1SDimitry Andric }
550145449b1SDimitry Andric
551145449b1SDimitry Andric template <typename RecordTy>
serializeTemplateMixin(Object & Paren,const RecordTy & Record)552ac9a064cSDimitry Andric void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
553b1c73532SDimitry Andric const auto &Template = Record.Templ;
554b1c73532SDimitry Andric if (Template.empty())
555ac9a064cSDimitry Andric return;
556b1c73532SDimitry Andric
557b1c73532SDimitry Andric Object Generics;
558b1c73532SDimitry Andric Array GenericParameters;
559b1c73532SDimitry Andric for (const auto &Param : Template.getParameters()) {
560b1c73532SDimitry Andric Object Parameter;
561b1c73532SDimitry Andric Parameter["name"] = Param.Name;
562b1c73532SDimitry Andric Parameter["index"] = Param.Index;
563b1c73532SDimitry Andric Parameter["depth"] = Param.Depth;
564b1c73532SDimitry Andric GenericParameters.emplace_back(std::move(Parameter));
565b1c73532SDimitry Andric }
566b1c73532SDimitry Andric if (!GenericParameters.empty())
567b1c73532SDimitry Andric Generics["parameters"] = std::move(GenericParameters);
568b1c73532SDimitry Andric
569b1c73532SDimitry Andric Array GenericConstraints;
570b1c73532SDimitry Andric for (const auto &Constr : Template.getConstraints()) {
571b1c73532SDimitry Andric Object Constraint;
572b1c73532SDimitry Andric Constraint["kind"] = Constr.Kind;
573b1c73532SDimitry Andric Constraint["lhs"] = Constr.LHS;
574b1c73532SDimitry Andric Constraint["rhs"] = Constr.RHS;
575b1c73532SDimitry Andric GenericConstraints.emplace_back(std::move(Constraint));
576b1c73532SDimitry Andric }
577b1c73532SDimitry Andric
578b1c73532SDimitry Andric if (!GenericConstraints.empty())
579b1c73532SDimitry Andric Generics["constraints"] = std::move(GenericConstraints);
580b1c73532SDimitry Andric
581ac9a064cSDimitry Andric serializeObject(Paren, "swiftGenerics", Generics);
582b1c73532SDimitry Andric }
583b1c73532SDimitry Andric
generateParentContexts(const SmallVectorImpl<SymbolReference> & Parents,Language Lang)584ac9a064cSDimitry Andric Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents,
585e3b55780SDimitry Andric Language Lang) {
586e3b55780SDimitry Andric Array ParentContexts;
587ac9a064cSDimitry Andric
588ac9a064cSDimitry Andric for (const auto &Parent : Parents) {
589ac9a064cSDimitry Andric Object Elem;
590ac9a064cSDimitry Andric Elem["usr"] = Parent.USR;
591ac9a064cSDimitry Andric Elem["name"] = Parent.Name;
592ac9a064cSDimitry Andric if (Parent.Record)
593ac9a064cSDimitry Andric Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay,
594ac9a064cSDimitry Andric Lang)["identifier"];
595ac9a064cSDimitry Andric else
596ac9a064cSDimitry Andric Elem["kind"] =
597ac9a064cSDimitry Andric serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"];
598ac9a064cSDimitry Andric ParentContexts.emplace_back(std::move(Elem));
599ac9a064cSDimitry Andric }
600e3b55780SDimitry Andric
601e3b55780SDimitry Andric return ParentContexts;
602e3b55780SDimitry Andric }
603ac9a064cSDimitry Andric
604ac9a064cSDimitry Andric /// Walk the records parent information in reverse to generate a hierarchy
605ac9a064cSDimitry Andric /// suitable for serialization.
606ac9a064cSDimitry Andric SmallVector<SymbolReference, 8>
generateHierarchyFromRecord(const APIRecord * Record)607ac9a064cSDimitry Andric generateHierarchyFromRecord(const APIRecord *Record) {
608ac9a064cSDimitry Andric SmallVector<SymbolReference, 8> ReverseHierarchy;
609ac9a064cSDimitry Andric for (const auto *Current = Record; Current != nullptr;
610ac9a064cSDimitry Andric Current = Current->Parent.Record)
611ac9a064cSDimitry Andric ReverseHierarchy.emplace_back(Current);
612ac9a064cSDimitry Andric
613ac9a064cSDimitry Andric return SmallVector<SymbolReference, 8>(
614ac9a064cSDimitry Andric std::make_move_iterator(ReverseHierarchy.rbegin()),
615ac9a064cSDimitry Andric std::make_move_iterator(ReverseHierarchy.rend()));
616ac9a064cSDimitry Andric }
617ac9a064cSDimitry Andric
getHierarchyReference(const APIRecord * Record,const APISet & API)618ac9a064cSDimitry Andric SymbolReference getHierarchyReference(const APIRecord *Record,
619ac9a064cSDimitry Andric const APISet &API) {
620ac9a064cSDimitry Andric // If the parent is a category extended from internal module then we need to
621ac9a064cSDimitry Andric // pretend this belongs to the associated interface.
622ac9a064cSDimitry Andric if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) {
623ac9a064cSDimitry Andric return CategoryRecord->Interface;
624ac9a064cSDimitry Andric // FIXME: TODO generate path components correctly for categories extending
625ac9a064cSDimitry Andric // an external module.
626ac9a064cSDimitry Andric }
627ac9a064cSDimitry Andric
628ac9a064cSDimitry Andric return SymbolReference(Record);
629ac9a064cSDimitry Andric }
630ac9a064cSDimitry Andric
631145449b1SDimitry Andric } // namespace
632145449b1SDimitry Andric
addSymbol(Object && Symbol)633ac9a064cSDimitry Andric Object *ExtendedModule::addSymbol(Object &&Symbol) {
634ac9a064cSDimitry Andric Symbols.emplace_back(std::move(Symbol));
635ac9a064cSDimitry Andric return Symbols.back().getAsObject();
636ac9a064cSDimitry Andric }
637ac9a064cSDimitry Andric
addRelationship(Object && Relationship)638ac9a064cSDimitry Andric void ExtendedModule::addRelationship(Object &&Relationship) {
639ac9a064cSDimitry Andric Relationships.emplace_back(std::move(Relationship));
640ac9a064cSDimitry Andric }
641ac9a064cSDimitry Andric
642145449b1SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer.
643145449b1SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
644145449b1SDimitry Andric
serializeMetadata() const645145449b1SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const {
646145449b1SDimitry Andric Object Metadata;
647145449b1SDimitry Andric serializeObject(Metadata, "formatVersion",
648145449b1SDimitry Andric serializeSemanticVersion(FormatVersion));
649145449b1SDimitry Andric Metadata["generator"] = clang::getClangFullVersion();
650145449b1SDimitry Andric return Metadata;
651145449b1SDimitry Andric }
652145449b1SDimitry Andric
653ac9a064cSDimitry Andric Object
serializeModuleObject(StringRef ModuleName) const654ac9a064cSDimitry Andric SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const {
655145449b1SDimitry Andric Object Module;
656ac9a064cSDimitry Andric Module["name"] = ModuleName;
657145449b1SDimitry Andric serializeObject(Module, "platform", serializePlatform(API.getTarget()));
658145449b1SDimitry Andric return Module;
659145449b1SDimitry Andric }
660145449b1SDimitry Andric
shouldSkip(const APIRecord * Record) const661ac9a064cSDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {
662ac9a064cSDimitry Andric if (!Record)
663e3b55780SDimitry Andric return true;
664e3b55780SDimitry Andric
665145449b1SDimitry Andric // Skip unconditionally unavailable symbols
666ac9a064cSDimitry Andric if (Record->Availability.isUnconditionallyUnavailable())
667145449b1SDimitry Andric return true;
668145449b1SDimitry Andric
669ac9a064cSDimitry Andric // Filter out symbols without a name as we can generate correct symbol graphs
670ac9a064cSDimitry Andric // for them. In practice these are anonymous record types that aren't attached
671ac9a064cSDimitry Andric // to a declaration.
672ac9a064cSDimitry Andric if (auto *Tag = dyn_cast<TagRecord>(Record)) {
673ac9a064cSDimitry Andric if (Tag->IsEmbeddedInVarDeclarator)
674ac9a064cSDimitry Andric return true;
675ac9a064cSDimitry Andric }
676ac9a064cSDimitry Andric
677145449b1SDimitry Andric // Filter out symbols prefixed with an underscored as they are understood to
678145449b1SDimitry Andric // be symbols clients should not use.
679ac9a064cSDimitry Andric if (Record->Name.starts_with("_"))
680ac9a064cSDimitry Andric return true;
681ac9a064cSDimitry Andric
682ac9a064cSDimitry Andric // Skip explicitly ignored symbols.
683ac9a064cSDimitry Andric if (IgnoresList.shouldIgnore(Record->Name))
684145449b1SDimitry Andric return true;
685145449b1SDimitry Andric
686145449b1SDimitry Andric return false;
687145449b1SDimitry Andric }
688145449b1SDimitry Andric
getModuleForCurrentSymbol()689ac9a064cSDimitry Andric ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {
690ac9a064cSDimitry Andric if (!ForceEmitToMainModule && ModuleForCurrentSymbol)
691ac9a064cSDimitry Andric return *ModuleForCurrentSymbol;
692145449b1SDimitry Andric
693ac9a064cSDimitry Andric return MainModule;
694145449b1SDimitry Andric }
695145449b1SDimitry Andric
serializePathComponents(const APIRecord * Record) const696ac9a064cSDimitry Andric Array SymbolGraphSerializer::serializePathComponents(
697ac9a064cSDimitry Andric const APIRecord *Record) const {
698ac9a064cSDimitry Andric return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));
699145449b1SDimitry Andric }
700145449b1SDimitry Andric
getRelationshipString(RelationshipKind Kind)701145449b1SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
702145449b1SDimitry Andric switch (Kind) {
703145449b1SDimitry Andric case RelationshipKind::MemberOf:
704145449b1SDimitry Andric return "memberOf";
705145449b1SDimitry Andric case RelationshipKind::InheritsFrom:
706145449b1SDimitry Andric return "inheritsFrom";
707145449b1SDimitry Andric case RelationshipKind::ConformsTo:
708145449b1SDimitry Andric return "conformsTo";
709b1c73532SDimitry Andric case RelationshipKind::ExtensionTo:
710b1c73532SDimitry Andric return "extensionTo";
711145449b1SDimitry Andric }
712145449b1SDimitry Andric llvm_unreachable("Unhandled relationship kind");
713145449b1SDimitry Andric }
714145449b1SDimitry Andric
serializeRelationship(RelationshipKind Kind,const SymbolReference & Source,const SymbolReference & Target,ExtendedModule & Into)715ac9a064cSDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
716ac9a064cSDimitry Andric const SymbolReference &Source,
717ac9a064cSDimitry Andric const SymbolReference &Target,
718ac9a064cSDimitry Andric ExtendedModule &Into) {
719ac9a064cSDimitry Andric Object Relationship;
720ac9a064cSDimitry Andric SmallString<64> TestRelLabel;
721ac9a064cSDimitry Andric if (EmitSymbolLabelsForTesting) {
722ac9a064cSDimitry Andric llvm::raw_svector_ostream OS(TestRelLabel);
723ac9a064cSDimitry Andric OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ "
724ac9a064cSDimitry Andric << Source.USR << " $ ";
725ac9a064cSDimitry Andric if (Target.USR.empty())
726ac9a064cSDimitry Andric OS << Target.Name;
727ac9a064cSDimitry Andric else
728ac9a064cSDimitry Andric OS << Target.USR;
729ac9a064cSDimitry Andric Relationship["!testRelLabel"] = TestRelLabel;
730ac9a064cSDimitry Andric }
731ac9a064cSDimitry Andric Relationship["source"] = Source.USR;
732ac9a064cSDimitry Andric Relationship["target"] = Target.USR;
733ac9a064cSDimitry Andric Relationship["targetFallback"] = Target.Name;
734ac9a064cSDimitry Andric Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind);
735ac9a064cSDimitry Andric
736ac9a064cSDimitry Andric if (ForceEmitToMainModule)
737ac9a064cSDimitry Andric MainModule.addRelationship(std::move(Relationship));
738ac9a064cSDimitry Andric else
739ac9a064cSDimitry Andric Into.addRelationship(std::move(Relationship));
740ac9a064cSDimitry Andric }
741ac9a064cSDimitry Andric
getConstraintString(ConstraintKind Kind)742b1c73532SDimitry Andric StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
743b1c73532SDimitry Andric switch (Kind) {
744b1c73532SDimitry Andric case ConstraintKind::Conformance:
745b1c73532SDimitry Andric return "conformance";
746b1c73532SDimitry Andric case ConstraintKind::ConditionalConformance:
747b1c73532SDimitry Andric return "conditionalConformance";
748b1c73532SDimitry Andric }
749b1c73532SDimitry Andric llvm_unreachable("Unhandled constraint kind");
750b1c73532SDimitry Andric }
751b1c73532SDimitry Andric
serializeAPIRecord(const APIRecord * Record)752ac9a064cSDimitry Andric void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) {
753b1c73532SDimitry Andric Object Obj;
754ac9a064cSDimitry Andric
755ac9a064cSDimitry Andric // If we need symbol labels for testing emit the USR as the value and the key
756ac9a064cSDimitry Andric // starts with '!'' to ensure it ends up at the top of the object.
757ac9a064cSDimitry Andric if (EmitSymbolLabelsForTesting)
758ac9a064cSDimitry Andric Obj["!testLabel"] = Record->USR;
759ac9a064cSDimitry Andric
760b1c73532SDimitry Andric serializeObject(Obj, "identifier",
761ac9a064cSDimitry Andric serializeIdentifier(*Record, API.getLanguage()));
762ac9a064cSDimitry Andric serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage()));
763ac9a064cSDimitry Andric serializeObject(Obj, "names", serializeNames(Record));
764ac9a064cSDimitry Andric serializeObject(
765ac9a064cSDimitry Andric Obj, "location",
766ac9a064cSDimitry Andric serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true));
767ac9a064cSDimitry Andric serializeArray(Obj, "availability",
768ac9a064cSDimitry Andric serializeAvailability(Record->Availability));
769ac9a064cSDimitry Andric serializeObject(Obj, "docComment", serializeDocComment(Record->Comment));
770ac9a064cSDimitry Andric serializeArray(Obj, "declarationFragments",
771ac9a064cSDimitry Andric serializeDeclarationFragments(Record->Declaration));
772ac9a064cSDimitry Andric
773ac9a064cSDimitry Andric Obj["pathComponents"] = serializePathComponents(Record);
774ac9a064cSDimitry Andric Obj["accessLevel"] = Record->Access.getAccess();
775ac9a064cSDimitry Andric
776ac9a064cSDimitry Andric ExtendedModule &Module = getModuleForCurrentSymbol();
777ac9a064cSDimitry Andric // If the hierarchy has at least one parent and child.
778ac9a064cSDimitry Andric if (Hierarchy.size() >= 2)
779ac9a064cSDimitry Andric serializeRelationship(MemberOf, Hierarchy.back(),
780ac9a064cSDimitry Andric Hierarchy[Hierarchy.size() - 2], Module);
781ac9a064cSDimitry Andric
782ac9a064cSDimitry Andric CurrentSymbol = Module.addSymbol(std::move(Obj));
783b1c73532SDimitry Andric }
784b1c73532SDimitry Andric
traverseAPIRecord(const APIRecord * Record)785ac9a064cSDimitry Andric bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) {
786ac9a064cSDimitry Andric if (!Record)
787ac9a064cSDimitry Andric return true;
788ac9a064cSDimitry Andric if (shouldSkip(Record))
789ac9a064cSDimitry Andric return true;
790ac9a064cSDimitry Andric Hierarchy.push_back(getHierarchyReference(Record, API));
791ac9a064cSDimitry Andric // Defer traversal mechanics to APISetVisitor base implementation
792ac9a064cSDimitry Andric auto RetVal = Base::traverseAPIRecord(Record);
793ac9a064cSDimitry Andric Hierarchy.pop_back();
794ac9a064cSDimitry Andric return RetVal;
795b1c73532SDimitry Andric }
796b1c73532SDimitry Andric
visitAPIRecord(const APIRecord * Record)797ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) {
798ac9a064cSDimitry Andric serializeAPIRecord(Record);
799ac9a064cSDimitry Andric return true;
800ac9a064cSDimitry Andric }
801145449b1SDimitry Andric
visitGlobalFunctionRecord(const GlobalFunctionRecord * Record)802ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitGlobalFunctionRecord(
803ac9a064cSDimitry Andric const GlobalFunctionRecord *Record) {
804ac9a064cSDimitry Andric if (!CurrentSymbol)
805ac9a064cSDimitry Andric return true;
806145449b1SDimitry Andric
807ac9a064cSDimitry Andric serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
808ac9a064cSDimitry Andric return true;
809ac9a064cSDimitry Andric }
810ac9a064cSDimitry Andric
visitCXXClassRecord(const CXXClassRecord * Record)811ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) {
812ac9a064cSDimitry Andric if (!CurrentSymbol)
813ac9a064cSDimitry Andric return true;
814ac9a064cSDimitry Andric
815ac9a064cSDimitry Andric for (const auto &Base : Record->Bases)
816ac9a064cSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base,
817ac9a064cSDimitry Andric getModuleForCurrentSymbol());
818ac9a064cSDimitry Andric return true;
819ac9a064cSDimitry Andric }
820ac9a064cSDimitry Andric
visitClassTemplateRecord(const ClassTemplateRecord * Record)821ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitClassTemplateRecord(
822ac9a064cSDimitry Andric const ClassTemplateRecord *Record) {
823ac9a064cSDimitry Andric if (!CurrentSymbol)
824ac9a064cSDimitry Andric return true;
825ac9a064cSDimitry Andric
826ac9a064cSDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record);
827ac9a064cSDimitry Andric return true;
828ac9a064cSDimitry Andric }
829ac9a064cSDimitry Andric
visitClassTemplatePartialSpecializationRecord(const ClassTemplatePartialSpecializationRecord * Record)830ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
831ac9a064cSDimitry Andric const ClassTemplatePartialSpecializationRecord *Record) {
832ac9a064cSDimitry Andric if (!CurrentSymbol)
833ac9a064cSDimitry Andric return true;
834ac9a064cSDimitry Andric
835ac9a064cSDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record);
836ac9a064cSDimitry Andric return true;
837ac9a064cSDimitry Andric }
838ac9a064cSDimitry Andric
visitCXXMethodRecord(const CXXMethodRecord * Record)839ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitCXXMethodRecord(
840ac9a064cSDimitry Andric const CXXMethodRecord *Record) {
841ac9a064cSDimitry Andric if (!CurrentSymbol)
842ac9a064cSDimitry Andric return true;
843ac9a064cSDimitry Andric
844ac9a064cSDimitry Andric serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
845ac9a064cSDimitry Andric return true;
846ac9a064cSDimitry Andric }
847ac9a064cSDimitry Andric
visitCXXMethodTemplateRecord(const CXXMethodTemplateRecord * Record)848ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitCXXMethodTemplateRecord(
849ac9a064cSDimitry Andric const CXXMethodTemplateRecord *Record) {
850ac9a064cSDimitry Andric if (!CurrentSymbol)
851ac9a064cSDimitry Andric return true;
852ac9a064cSDimitry Andric
853ac9a064cSDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record);
854ac9a064cSDimitry Andric return true;
855ac9a064cSDimitry Andric }
856ac9a064cSDimitry Andric
visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord * Record)857ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitCXXFieldTemplateRecord(
858ac9a064cSDimitry Andric const CXXFieldTemplateRecord *Record) {
859ac9a064cSDimitry Andric if (!CurrentSymbol)
860ac9a064cSDimitry Andric return true;
861ac9a064cSDimitry Andric
862ac9a064cSDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record);
863ac9a064cSDimitry Andric return true;
864ac9a064cSDimitry Andric }
865ac9a064cSDimitry Andric
visitConceptRecord(const ConceptRecord * Record)866ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) {
867ac9a064cSDimitry Andric if (!CurrentSymbol)
868ac9a064cSDimitry Andric return true;
869ac9a064cSDimitry Andric
870ac9a064cSDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record);
871ac9a064cSDimitry Andric return true;
872ac9a064cSDimitry Andric }
873ac9a064cSDimitry Andric
visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord * Record)874ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
875ac9a064cSDimitry Andric const GlobalVariableTemplateRecord *Record) {
876ac9a064cSDimitry Andric if (!CurrentSymbol)
877ac9a064cSDimitry Andric return true;
878ac9a064cSDimitry Andric
879ac9a064cSDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record);
880ac9a064cSDimitry Andric return true;
881ac9a064cSDimitry Andric }
882ac9a064cSDimitry Andric
883ac9a064cSDimitry Andric bool SymbolGraphSerializer::
visitGlobalVariableTemplatePartialSpecializationRecord(const GlobalVariableTemplatePartialSpecializationRecord * Record)884ac9a064cSDimitry Andric visitGlobalVariableTemplatePartialSpecializationRecord(
885ac9a064cSDimitry Andric const GlobalVariableTemplatePartialSpecializationRecord *Record) {
886ac9a064cSDimitry Andric if (!CurrentSymbol)
887ac9a064cSDimitry Andric return true;
888ac9a064cSDimitry Andric
889ac9a064cSDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record);
890ac9a064cSDimitry Andric return true;
891ac9a064cSDimitry Andric }
892ac9a064cSDimitry Andric
visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord * Record)893ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
894ac9a064cSDimitry Andric const GlobalFunctionTemplateRecord *Record) {
895ac9a064cSDimitry Andric if (!CurrentSymbol)
896ac9a064cSDimitry Andric return true;
897ac9a064cSDimitry Andric
898ac9a064cSDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record);
899ac9a064cSDimitry Andric return true;
900ac9a064cSDimitry Andric }
901ac9a064cSDimitry Andric
visitObjCContainerRecord(const ObjCContainerRecord * Record)902ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitObjCContainerRecord(
903ac9a064cSDimitry Andric const ObjCContainerRecord *Record) {
904ac9a064cSDimitry Andric if (!CurrentSymbol)
905ac9a064cSDimitry Andric return true;
906ac9a064cSDimitry Andric
907ac9a064cSDimitry Andric for (const auto &Protocol : Record->Protocols)
908ac9a064cSDimitry Andric serializeRelationship(ConformsTo, Record, Protocol,
909ac9a064cSDimitry Andric getModuleForCurrentSymbol());
910ac9a064cSDimitry Andric
911ac9a064cSDimitry Andric return true;
912ac9a064cSDimitry Andric }
913ac9a064cSDimitry Andric
visitObjCInterfaceRecord(const ObjCInterfaceRecord * Record)914ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitObjCInterfaceRecord(
915ac9a064cSDimitry Andric const ObjCInterfaceRecord *Record) {
916ac9a064cSDimitry Andric if (!CurrentSymbol)
917ac9a064cSDimitry Andric return true;
918ac9a064cSDimitry Andric
919ac9a064cSDimitry Andric if (!Record->SuperClass.empty())
920ac9a064cSDimitry Andric serializeRelationship(InheritsFrom, Record, Record->SuperClass,
921ac9a064cSDimitry Andric getModuleForCurrentSymbol());
922ac9a064cSDimitry Andric return true;
923ac9a064cSDimitry Andric }
924ac9a064cSDimitry Andric
traverseObjCCategoryRecord(const ObjCCategoryRecord * Record)925ac9a064cSDimitry Andric bool SymbolGraphSerializer::traverseObjCCategoryRecord(
926ac9a064cSDimitry Andric const ObjCCategoryRecord *Record) {
927ac9a064cSDimitry Andric if (SkipSymbolsInCategoriesToExternalTypes &&
928ac9a064cSDimitry Andric !API.findRecordForUSR(Record->Interface.USR))
929ac9a064cSDimitry Andric return true;
930ac9a064cSDimitry Andric
931ac9a064cSDimitry Andric auto *CurrentModule = ModuleForCurrentSymbol;
932ac9a064cSDimitry Andric if (Record->isExtendingExternalModule())
933ac9a064cSDimitry Andric ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source];
934ac9a064cSDimitry Andric
935ac9a064cSDimitry Andric if (!walkUpFromObjCCategoryRecord(Record))
936ac9a064cSDimitry Andric return false;
937ac9a064cSDimitry Andric
938ac9a064cSDimitry Andric bool RetVal = traverseRecordContext(Record);
939ac9a064cSDimitry Andric ModuleForCurrentSymbol = CurrentModule;
940ac9a064cSDimitry Andric return RetVal;
941ac9a064cSDimitry Andric }
942ac9a064cSDimitry Andric
walkUpFromObjCCategoryRecord(const ObjCCategoryRecord * Record)943ac9a064cSDimitry Andric bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord(
944ac9a064cSDimitry Andric const ObjCCategoryRecord *Record) {
945ac9a064cSDimitry Andric return visitObjCCategoryRecord(Record);
946ac9a064cSDimitry Andric }
947ac9a064cSDimitry Andric
visitObjCCategoryRecord(const ObjCCategoryRecord * Record)948ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitObjCCategoryRecord(
949ac9a064cSDimitry Andric const ObjCCategoryRecord *Record) {
950ac9a064cSDimitry Andric // If we need to create a record for the category in the future do so here,
951ac9a064cSDimitry Andric // otherwise everything is set up to pretend that the category is in fact the
952ac9a064cSDimitry Andric // interface it extends.
953ac9a064cSDimitry Andric for (const auto &Protocol : Record->Protocols)
954ac9a064cSDimitry Andric serializeRelationship(ConformsTo, Record->Interface, Protocol,
955ac9a064cSDimitry Andric getModuleForCurrentSymbol());
956ac9a064cSDimitry Andric
957ac9a064cSDimitry Andric return true;
958ac9a064cSDimitry Andric }
959ac9a064cSDimitry Andric
visitObjCMethodRecord(const ObjCMethodRecord * Record)960ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitObjCMethodRecord(
961ac9a064cSDimitry Andric const ObjCMethodRecord *Record) {
962ac9a064cSDimitry Andric if (!CurrentSymbol)
963ac9a064cSDimitry Andric return true;
964ac9a064cSDimitry Andric
965ac9a064cSDimitry Andric serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
966ac9a064cSDimitry Andric return true;
967ac9a064cSDimitry Andric }
968ac9a064cSDimitry Andric
visitObjCInstanceVariableRecord(const ObjCInstanceVariableRecord * Record)969ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitObjCInstanceVariableRecord(
970ac9a064cSDimitry Andric const ObjCInstanceVariableRecord *Record) {
971ac9a064cSDimitry Andric // FIXME: serialize ivar access control here.
972ac9a064cSDimitry Andric return true;
973ac9a064cSDimitry Andric }
974ac9a064cSDimitry Andric
walkUpFromTypedefRecord(const TypedefRecord * Record)975ac9a064cSDimitry Andric bool SymbolGraphSerializer::walkUpFromTypedefRecord(
976ac9a064cSDimitry Andric const TypedefRecord *Record) {
977ac9a064cSDimitry Andric // Short-circuit walking up the class hierarchy and handle creating typedef
978ac9a064cSDimitry Andric // symbol objects manually as there are additional symbol dropping rules to
979ac9a064cSDimitry Andric // respect.
980ac9a064cSDimitry Andric return visitTypedefRecord(Record);
981ac9a064cSDimitry Andric }
982ac9a064cSDimitry Andric
visitTypedefRecord(const TypedefRecord * Record)983ac9a064cSDimitry Andric bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) {
984ac9a064cSDimitry Andric // Typedefs of anonymous types have their entries unified with the underlying
985ac9a064cSDimitry Andric // type.
986ac9a064cSDimitry Andric bool ShouldDrop = Record->UnderlyingType.Name.empty();
987ac9a064cSDimitry Andric // enums declared with `NS_OPTION` have a named enum and a named typedef, with
988ac9a064cSDimitry Andric // the same name
989ac9a064cSDimitry Andric ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
990ac9a064cSDimitry Andric if (ShouldDrop)
991ac9a064cSDimitry Andric return true;
992ac9a064cSDimitry Andric
993ac9a064cSDimitry Andric // Create the symbol record if the other symbol droppping rules permit it.
994ac9a064cSDimitry Andric serializeAPIRecord(Record);
995ac9a064cSDimitry Andric if (!CurrentSymbol)
996ac9a064cSDimitry Andric return true;
997ac9a064cSDimitry Andric
998ac9a064cSDimitry Andric (*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
999ac9a064cSDimitry Andric
1000ac9a064cSDimitry Andric return true;
1001145449b1SDimitry Andric }
1002145449b1SDimitry Andric
serializeSingleRecord(const APIRecord * Record)1003e3b55780SDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1004e3b55780SDimitry Andric switch (Record->getKind()) {
1005ac9a064cSDimitry Andric // dispatch to the relevant walkUpFromMethod
1006ac9a064cSDimitry Andric #define CONCRETE_RECORD(CLASS, BASE, KIND) \
1007ac9a064cSDimitry Andric case APIRecord::KIND: { \
1008ac9a064cSDimitry Andric walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \
1009ac9a064cSDimitry Andric break; \
1010ac9a064cSDimitry Andric }
1011ac9a064cSDimitry Andric #include "clang/ExtractAPI/APIRecords.inc"
1012ac9a064cSDimitry Andric // otherwise fallback on the only behavior we can implement safely.
1013e3b55780SDimitry Andric case APIRecord::RK_Unknown:
1014ac9a064cSDimitry Andric visitAPIRecord(Record);
1015e3b55780SDimitry Andric break;
1016e3b55780SDimitry Andric default:
1017ac9a064cSDimitry Andric llvm_unreachable("API Record with uninstantiable kind");
1018e3b55780SDimitry Andric }
1019e3b55780SDimitry Andric }
1020e3b55780SDimitry Andric
serializeGraph(StringRef ModuleName,ExtendedModule && EM)1021ac9a064cSDimitry Andric Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1022ac9a064cSDimitry Andric ExtendedModule &&EM) {
1023e3b55780SDimitry Andric Object Root;
1024e3b55780SDimitry Andric serializeObject(Root, "metadata", serializeMetadata());
1025ac9a064cSDimitry Andric serializeObject(Root, "module", serializeModuleObject(ModuleName));
1026e3b55780SDimitry Andric
1027ac9a064cSDimitry Andric Root["symbols"] = std::move(EM.Symbols);
1028ac9a064cSDimitry Andric Root["relationships"] = std::move(EM.Relationships);
1029145449b1SDimitry Andric
1030145449b1SDimitry Andric return Root;
1031145449b1SDimitry Andric }
1032145449b1SDimitry Andric
serializeGraphToStream(raw_ostream & OS,SymbolGraphSerializerOption Options,StringRef ModuleName,ExtendedModule && EM)1033ac9a064cSDimitry Andric void SymbolGraphSerializer::serializeGraphToStream(
1034ac9a064cSDimitry Andric raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1035ac9a064cSDimitry Andric ExtendedModule &&EM) {
1036ac9a064cSDimitry Andric Object Root = serializeGraph(ModuleName, std::move(EM));
1037145449b1SDimitry Andric if (Options.Compact)
1038ac9a064cSDimitry Andric OS << formatv("{0}", json::Value(std::move(Root))) << "\n";
1039145449b1SDimitry Andric else
1040ac9a064cSDimitry Andric OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n";
1041ac9a064cSDimitry Andric }
1042ac9a064cSDimitry Andric
serializeMainSymbolGraph(raw_ostream & OS,const APISet & API,const APIIgnoresList & IgnoresList,SymbolGraphSerializerOption Options)1043ac9a064cSDimitry Andric void SymbolGraphSerializer::serializeMainSymbolGraph(
1044ac9a064cSDimitry Andric raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1045ac9a064cSDimitry Andric SymbolGraphSerializerOption Options) {
1046ac9a064cSDimitry Andric SymbolGraphSerializer Serializer(
1047ac9a064cSDimitry Andric API, IgnoresList, Options.EmitSymbolLabelsForTesting,
1048ac9a064cSDimitry Andric /*ForceEmitToMainModule=*/true,
1049ac9a064cSDimitry Andric /*SkipSymbolsInCategoriesToExternalTypes=*/true);
1050ac9a064cSDimitry Andric
1051ac9a064cSDimitry Andric Serializer.traverseAPISet();
1052ac9a064cSDimitry Andric Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1053ac9a064cSDimitry Andric std::move(Serializer.MainModule));
1054ac9a064cSDimitry Andric // FIXME: TODO handle extended modules here
1055ac9a064cSDimitry Andric }
1056ac9a064cSDimitry Andric
serializeWithExtensionGraphs(raw_ostream & MainOutput,const APISet & API,const APIIgnoresList & IgnoresList,llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream> (Twine BaseName)> CreateOutputStream,SymbolGraphSerializerOption Options)1057ac9a064cSDimitry Andric void SymbolGraphSerializer::serializeWithExtensionGraphs(
1058ac9a064cSDimitry Andric raw_ostream &MainOutput, const APISet &API,
1059ac9a064cSDimitry Andric const APIIgnoresList &IgnoresList,
1060ac9a064cSDimitry Andric llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1061ac9a064cSDimitry Andric CreateOutputStream,
1062ac9a064cSDimitry Andric SymbolGraphSerializerOption Options) {
1063ac9a064cSDimitry Andric SymbolGraphSerializer Serializer(API, IgnoresList,
1064ac9a064cSDimitry Andric Options.EmitSymbolLabelsForTesting);
1065ac9a064cSDimitry Andric Serializer.traverseAPISet();
1066ac9a064cSDimitry Andric
1067ac9a064cSDimitry Andric Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1068ac9a064cSDimitry Andric std::move(Serializer.MainModule));
1069ac9a064cSDimitry Andric
1070ac9a064cSDimitry Andric for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1071ac9a064cSDimitry Andric if (auto ExtensionOS =
1072ac9a064cSDimitry Andric CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName))
1073ac9a064cSDimitry Andric Serializer.serializeGraphToStream(*ExtensionOS, Options,
1074ac9a064cSDimitry Andric ExtensionSGF.getKey(),
1075ac9a064cSDimitry Andric std::move(ExtensionSGF.getValue()));
1076ac9a064cSDimitry Andric }
1077145449b1SDimitry Andric }
1078e3b55780SDimitry Andric
1079e3b55780SDimitry Andric std::optional<Object>
serializeSingleSymbolSGF(StringRef USR,const APISet & API)1080e3b55780SDimitry Andric SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1081e3b55780SDimitry Andric const APISet &API) {
1082e3b55780SDimitry Andric APIRecord *Record = API.findRecordForUSR(USR);
1083e3b55780SDimitry Andric if (!Record)
1084e3b55780SDimitry Andric return {};
1085e3b55780SDimitry Andric
1086e3b55780SDimitry Andric Object Root;
1087e3b55780SDimitry Andric APIIgnoresList EmptyIgnores;
1088e3b55780SDimitry Andric SymbolGraphSerializer Serializer(API, EmptyIgnores,
1089ac9a064cSDimitry Andric /*EmitSymbolLabelsForTesting*/ false,
1090ac9a064cSDimitry Andric /*ForceEmitToMainModule*/ true);
1091ac9a064cSDimitry Andric
1092ac9a064cSDimitry Andric // Set up serializer parent chain
1093ac9a064cSDimitry Andric Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1094ac9a064cSDimitry Andric
1095e3b55780SDimitry Andric Serializer.serializeSingleRecord(Record);
1096ac9a064cSDimitry Andric serializeObject(Root, "symbolGraph",
1097ac9a064cSDimitry Andric Serializer.serializeGraph(API.ProductName,
1098ac9a064cSDimitry Andric std::move(Serializer.MainModule)));
1099e3b55780SDimitry Andric
1100e3b55780SDimitry Andric Language Lang = API.getLanguage();
1101e3b55780SDimitry Andric serializeArray(Root, "parentContexts",
1102ac9a064cSDimitry Andric generateParentContexts(Serializer.Hierarchy, Lang));
1103e3b55780SDimitry Andric
1104e3b55780SDimitry Andric Array RelatedSymbols;
1105e3b55780SDimitry Andric
1106e3b55780SDimitry Andric for (const auto &Fragment : Record->Declaration.getFragments()) {
1107e3b55780SDimitry Andric // If we don't have a USR there isn't much we can do.
1108e3b55780SDimitry Andric if (Fragment.PreciseIdentifier.empty())
1109e3b55780SDimitry Andric continue;
1110e3b55780SDimitry Andric
1111e3b55780SDimitry Andric APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1112e3b55780SDimitry Andric
1113e3b55780SDimitry Andric // If we can't find the record let's skip.
1114e3b55780SDimitry Andric if (!RelatedRecord)
1115e3b55780SDimitry Andric continue;
1116e3b55780SDimitry Andric
1117e3b55780SDimitry Andric Object RelatedSymbol;
1118e3b55780SDimitry Andric RelatedSymbol["usr"] = RelatedRecord->USR;
1119e3b55780SDimitry Andric RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1120ac9a064cSDimitry Andric RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
1121e3b55780SDimitry Andric RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1122e3b55780SDimitry Andric RelatedSymbol["moduleName"] = API.ProductName;
1123e3b55780SDimitry Andric RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1124e3b55780SDimitry Andric
1125e3b55780SDimitry Andric serializeArray(RelatedSymbol, "parentContexts",
1126ac9a064cSDimitry Andric generateParentContexts(
1127ac9a064cSDimitry Andric generateHierarchyFromRecord(RelatedRecord), Lang));
1128ac9a064cSDimitry Andric
1129e3b55780SDimitry Andric RelatedSymbols.push_back(std::move(RelatedSymbol));
1130e3b55780SDimitry Andric }
1131e3b55780SDimitry Andric
1132e3b55780SDimitry Andric serializeArray(Root, "relatedSymbols", RelatedSymbols);
1133e3b55780SDimitry Andric return Root;
1134e3b55780SDimitry Andric }
1135