1 //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 ///
9 /// \file
10 /// This file implements the SymbolGraphSerializer.
11 ///
12 //===----------------------------------------------------------------------===//
13
14 #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h"
15 #include "clang/Basic/SourceLocation.h"
16 #include "clang/Basic/Version.h"
17 #include "clang/ExtractAPI/DeclarationFragments.h"
18 #include "llvm/ADT/STLExtras.h"
19 #include "llvm/ADT/STLFunctionalExtras.h"
20 #include "llvm/Support/Casting.h"
21 #include "llvm/Support/Compiler.h"
22 #include "llvm/Support/Path.h"
23 #include "llvm/Support/VersionTuple.h"
24 #include <optional>
25 #include <type_traits>
26
27 using namespace clang;
28 using namespace clang::extractapi;
29 using namespace llvm;
30 using namespace llvm::json;
31
32 namespace {
33
34 /// Helper function to inject a JSON object \p Obj into another object \p Paren
35 /// at position \p Key.
serializeObject(Object & Paren,StringRef Key,std::optional<Object> Obj)36 void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
37 if (Obj)
38 Paren[Key] = std::move(*Obj);
39 }
40
41 /// Helper function to inject a StringRef \p String into an object \p Paren at
42 /// position \p Key
serializeString(Object & Paren,StringRef Key,std::optional<std::string> String)43 void serializeString(Object &Paren, StringRef Key,
44 std::optional<std::string> String) {
45 if (String)
46 Paren[Key] = std::move(*String);
47 }
48
49 /// Helper function to inject a JSON array \p Array into object \p Paren at
50 /// position \p Key.
serializeArray(Object & Paren,StringRef Key,std::optional<Array> Array)51 void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
52 if (Array)
53 Paren[Key] = std::move(*Array);
54 }
55
56 /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
57 /// format.
58 ///
59 /// A semantic version object contains three numeric fields, representing the
60 /// \c major, \c minor, and \c patch parts of the version tuple.
61 /// For example version tuple 1.0.3 is serialized as:
62 /// \code
63 /// {
64 /// "major" : 1,
65 /// "minor" : 0,
66 /// "patch" : 3
67 /// }
68 /// \endcode
69 ///
70 /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
71 /// containing the semantic version representation of \p V.
serializeSemanticVersion(const VersionTuple & V)72 std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
73 if (V.empty())
74 return std::nullopt;
75
76 Object Version;
77 Version["major"] = V.getMajor();
78 Version["minor"] = V.getMinor().value_or(0);
79 Version["patch"] = V.getSubminor().value_or(0);
80 return Version;
81 }
82
83 /// Serialize the OS information in the Symbol Graph platform property.
84 ///
85 /// The OS information in Symbol Graph contains the \c name of the OS, and an
86 /// optional \c minimumVersion semantic version field.
serializeOperatingSystem(const Triple & T)87 Object serializeOperatingSystem(const Triple &T) {
88 Object OS;
89 OS["name"] = T.getOSTypeName(T.getOS());
90 serializeObject(OS, "minimumVersion",
91 serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
92 return OS;
93 }
94
95 /// Serialize the platform information in the Symbol Graph module section.
96 ///
97 /// The platform object describes a target platform triple in corresponding
98 /// three fields: \c architecture, \c vendor, and \c operatingSystem.
serializePlatform(const Triple & T)99 Object serializePlatform(const Triple &T) {
100 Object Platform;
101 Platform["architecture"] = T.getArchName();
102 Platform["vendor"] = T.getVendorName();
103 Platform["operatingSystem"] = serializeOperatingSystem(T);
104 return Platform;
105 }
106
107 /// Serialize a source position.
serializeSourcePosition(const PresumedLoc & Loc)108 Object serializeSourcePosition(const PresumedLoc &Loc) {
109 assert(Loc.isValid() && "invalid source position");
110
111 Object SourcePosition;
112 SourcePosition["line"] = Loc.getLine() - 1;
113 SourcePosition["character"] = Loc.getColumn() - 1;
114
115 return SourcePosition;
116 }
117
118 /// Serialize a source location in file.
119 ///
120 /// \param Loc The presumed location to serialize.
121 /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
122 /// Defaults to false.
serializeSourceLocation(const PresumedLoc & Loc,bool IncludeFileURI=false)123 Object serializeSourceLocation(const PresumedLoc &Loc,
124 bool IncludeFileURI = false) {
125 Object SourceLocation;
126 serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
127
128 if (IncludeFileURI) {
129 std::string FileURI = "file://";
130 // Normalize file path to use forward slashes for the URI.
131 FileURI += sys::path::convert_to_slash(Loc.getFilename());
132 SourceLocation["uri"] = FileURI;
133 }
134
135 return SourceLocation;
136 }
137
138 /// Serialize a source range with begin and end locations.
serializeSourceRange(const PresumedLoc & BeginLoc,const PresumedLoc & EndLoc)139 Object serializeSourceRange(const PresumedLoc &BeginLoc,
140 const PresumedLoc &EndLoc) {
141 Object SourceRange;
142 serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
143 serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
144 return SourceRange;
145 }
146
147 /// Serialize the availability attributes of a symbol.
148 ///
149 /// Availability information contains the introduced, deprecated, and obsoleted
150 /// versions of the symbol as semantic versions, if not default.
151 /// Availability information also contains flags to indicate if the symbol is
152 /// unconditionally unavailable or deprecated,
153 /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
154 ///
155 /// \returns \c std::nullopt if the symbol has default availability attributes,
156 /// or an \c Array containing an object with the formatted availability
157 /// information.
serializeAvailability(const AvailabilityInfo & Avail)158 std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
159 if (Avail.isDefault())
160 return std::nullopt;
161
162 Object Availability;
163 Array AvailabilityArray;
164 Availability["domain"] = Avail.Domain;
165 serializeObject(Availability, "introduced",
166 serializeSemanticVersion(Avail.Introduced));
167 serializeObject(Availability, "deprecated",
168 serializeSemanticVersion(Avail.Deprecated));
169 serializeObject(Availability, "obsoleted",
170 serializeSemanticVersion(Avail.Obsoleted));
171 if (Avail.isUnconditionallyDeprecated()) {
172 Object UnconditionallyDeprecated;
173 UnconditionallyDeprecated["domain"] = "*";
174 UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
175 AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
176 }
177 if (Avail.isUnconditionallyUnavailable()) {
178 Object UnconditionallyUnavailable;
179 UnconditionallyUnavailable["domain"] = "*";
180 UnconditionallyUnavailable["isUnconditionallyUnavailable"] = true;
181 AvailabilityArray.emplace_back(std::move(UnconditionallyUnavailable));
182 }
183 AvailabilityArray.emplace_back(std::move(Availability));
184 return AvailabilityArray;
185 }
186
187 /// Get the language name string for interface language references.
getLanguageName(Language Lang)188 StringRef getLanguageName(Language Lang) {
189 switch (Lang) {
190 case Language::C:
191 return "c";
192 case Language::ObjC:
193 return "objective-c";
194 case Language::CXX:
195 return "c++";
196 case Language::ObjCXX:
197 return "objective-c++";
198
199 // Unsupported language currently
200 case Language::OpenCL:
201 case Language::OpenCLCXX:
202 case Language::CUDA:
203 case Language::RenderScript:
204 case Language::HIP:
205 case Language::HLSL:
206
207 // Languages that the frontend cannot parse and compile
208 case Language::Unknown:
209 case Language::Asm:
210 case Language::LLVM_IR:
211 llvm_unreachable("Unsupported language kind");
212 }
213
214 llvm_unreachable("Unhandled language kind");
215 }
216
217 /// Serialize the identifier object as specified by the Symbol Graph format.
218 ///
219 /// The identifier property of a symbol contains the USR for precise and unique
220 /// references, and the interface language name.
serializeIdentifier(const APIRecord & Record,Language Lang)221 Object serializeIdentifier(const APIRecord &Record, Language Lang) {
222 Object Identifier;
223 Identifier["precise"] = Record.USR;
224 Identifier["interfaceLanguage"] = getLanguageName(Lang);
225
226 return Identifier;
227 }
228
229 /// Serialize the documentation comments attached to a symbol, as specified by
230 /// the Symbol Graph format.
231 ///
232 /// The Symbol Graph \c docComment object contains an array of lines. Each line
233 /// represents one line of striped documentation comment, with source range
234 /// information.
235 /// e.g.
236 /// \code
237 /// /// This is a documentation comment
238 /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line.
239 /// /// with multiple lines.
240 /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line.
241 /// \endcode
242 ///
243 /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
244 /// the formatted lines.
serializeDocComment(const DocComment & Comment)245 std::optional<Object> serializeDocComment(const DocComment &Comment) {
246 if (Comment.empty())
247 return std::nullopt;
248
249 Object DocComment;
250 Array LinesArray;
251 for (const auto &CommentLine : Comment) {
252 Object Line;
253 Line["text"] = CommentLine.Text;
254 serializeObject(Line, "range",
255 serializeSourceRange(CommentLine.Begin, CommentLine.End));
256 LinesArray.emplace_back(std::move(Line));
257 }
258 serializeArray(DocComment, "lines", LinesArray);
259
260 return DocComment;
261 }
262
263 /// Serialize the declaration fragments of a symbol.
264 ///
265 /// The Symbol Graph declaration fragments is an array of tagged important
266 /// parts of a symbol's declaration. The fragments sequence can be joined to
267 /// form spans of declaration text, with attached information useful for
268 /// purposes like syntax-highlighting etc. For example:
269 /// \code
270 /// const int pi; -> "declarationFragments" : [
271 /// {
272 /// "kind" : "keyword",
273 /// "spelling" : "const"
274 /// },
275 /// {
276 /// "kind" : "text",
277 /// "spelling" : " "
278 /// },
279 /// {
280 /// "kind" : "typeIdentifier",
281 /// "preciseIdentifier" : "c:I",
282 /// "spelling" : "int"
283 /// },
284 /// {
285 /// "kind" : "text",
286 /// "spelling" : " "
287 /// },
288 /// {
289 /// "kind" : "identifier",
290 /// "spelling" : "pi"
291 /// }
292 /// ]
293 /// \endcode
294 ///
295 /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
296 /// formatted declaration fragments array.
297 std::optional<Array>
serializeDeclarationFragments(const DeclarationFragments & DF)298 serializeDeclarationFragments(const DeclarationFragments &DF) {
299 if (DF.getFragments().empty())
300 return std::nullopt;
301
302 Array Fragments;
303 for (const auto &F : DF.getFragments()) {
304 Object Fragment;
305 Fragment["spelling"] = F.Spelling;
306 Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
307 if (!F.PreciseIdentifier.empty())
308 Fragment["preciseIdentifier"] = F.PreciseIdentifier;
309 Fragments.emplace_back(std::move(Fragment));
310 }
311
312 return Fragments;
313 }
314
315 /// Serialize the \c names field of a symbol as specified by the Symbol Graph
316 /// format.
317 ///
318 /// The Symbol Graph names field contains multiple representations of a symbol
319 /// that can be used for different applications:
320 /// - \c title : The simple declared name of the symbol;
321 /// - \c subHeading : An array of declaration fragments that provides tags,
322 /// and potentially more tokens (for example the \c +/- symbol for
323 /// Objective-C methods). Can be used as sub-headings for documentation.
serializeNames(const APIRecord & Record)324 Object serializeNames(const APIRecord &Record) {
325 Object Names;
326 if (auto *CategoryRecord =
327 dyn_cast_or_null<const ObjCCategoryRecord>(&Record))
328 Names["title"] =
329 (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str();
330 else
331 Names["title"] = Record.Name;
332
333 serializeArray(Names, "subHeading",
334 serializeDeclarationFragments(Record.SubHeading));
335 DeclarationFragments NavigatorFragments;
336 NavigatorFragments.append(Record.Name,
337 DeclarationFragments::FragmentKind::Identifier,
338 /*PreciseIdentifier*/ "");
339 serializeArray(Names, "navigator",
340 serializeDeclarationFragments(NavigatorFragments));
341
342 return Names;
343 }
344
serializeSymbolKind(APIRecord::RecordKind RK,Language Lang)345 Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
346 auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
347 return (getLanguageName(Lang) + "." + S).str();
348 };
349
350 Object Kind;
351 switch (RK) {
352 case APIRecord::RK_Unknown:
353 llvm_unreachable("Records should have an explicit kind");
354 break;
355 case APIRecord::RK_Namespace:
356 Kind["identifier"] = AddLangPrefix("namespace");
357 Kind["displayName"] = "Namespace";
358 break;
359 case APIRecord::RK_GlobalFunction:
360 Kind["identifier"] = AddLangPrefix("func");
361 Kind["displayName"] = "Function";
362 break;
363 case APIRecord::RK_GlobalFunctionTemplate:
364 Kind["identifier"] = AddLangPrefix("func");
365 Kind["displayName"] = "Function Template";
366 break;
367 case APIRecord::RK_GlobalFunctionTemplateSpecialization:
368 Kind["identifier"] = AddLangPrefix("func");
369 Kind["displayName"] = "Function Template Specialization";
370 break;
371 case APIRecord::RK_GlobalVariableTemplate:
372 Kind["identifier"] = AddLangPrefix("var");
373 Kind["displayName"] = "Global Variable Template";
374 break;
375 case APIRecord::RK_GlobalVariableTemplateSpecialization:
376 Kind["identifier"] = AddLangPrefix("var");
377 Kind["displayName"] = "Global Variable Template Specialization";
378 break;
379 case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
380 Kind["identifier"] = AddLangPrefix("var");
381 Kind["displayName"] = "Global Variable Template Partial Specialization";
382 break;
383 case APIRecord::RK_GlobalVariable:
384 Kind["identifier"] = AddLangPrefix("var");
385 Kind["displayName"] = "Global Variable";
386 break;
387 case APIRecord::RK_EnumConstant:
388 Kind["identifier"] = AddLangPrefix("enum.case");
389 Kind["displayName"] = "Enumeration Case";
390 break;
391 case APIRecord::RK_Enum:
392 Kind["identifier"] = AddLangPrefix("enum");
393 Kind["displayName"] = "Enumeration";
394 break;
395 case APIRecord::RK_StructField:
396 Kind["identifier"] = AddLangPrefix("property");
397 Kind["displayName"] = "Instance Property";
398 break;
399 case APIRecord::RK_Struct:
400 Kind["identifier"] = AddLangPrefix("struct");
401 Kind["displayName"] = "Structure";
402 break;
403 case APIRecord::RK_UnionField:
404 Kind["identifier"] = AddLangPrefix("property");
405 Kind["displayName"] = "Instance Property";
406 break;
407 case APIRecord::RK_Union:
408 Kind["identifier"] = AddLangPrefix("union");
409 Kind["displayName"] = "Union";
410 break;
411 case APIRecord::RK_CXXField:
412 Kind["identifier"] = AddLangPrefix("property");
413 Kind["displayName"] = "Instance Property";
414 break;
415 case APIRecord::RK_StaticField:
416 Kind["identifier"] = AddLangPrefix("type.property");
417 Kind["displayName"] = "Type Property";
418 break;
419 case APIRecord::RK_ClassTemplate:
420 case APIRecord::RK_ClassTemplateSpecialization:
421 case APIRecord::RK_ClassTemplatePartialSpecialization:
422 case APIRecord::RK_CXXClass:
423 Kind["identifier"] = AddLangPrefix("class");
424 Kind["displayName"] = "Class";
425 break;
426 case APIRecord::RK_CXXMethodTemplate:
427 Kind["identifier"] = AddLangPrefix("method");
428 Kind["displayName"] = "Method Template";
429 break;
430 case APIRecord::RK_CXXMethodTemplateSpecialization:
431 Kind["identifier"] = AddLangPrefix("method");
432 Kind["displayName"] = "Method Template Specialization";
433 break;
434 case APIRecord::RK_CXXFieldTemplate:
435 Kind["identifier"] = AddLangPrefix("property");
436 Kind["displayName"] = "Template Property";
437 break;
438 case APIRecord::RK_Concept:
439 Kind["identifier"] = AddLangPrefix("concept");
440 Kind["displayName"] = "Concept";
441 break;
442 case APIRecord::RK_CXXStaticMethod:
443 Kind["identifier"] = AddLangPrefix("type.method");
444 Kind["displayName"] = "Static Method";
445 break;
446 case APIRecord::RK_CXXInstanceMethod:
447 Kind["identifier"] = AddLangPrefix("method");
448 Kind["displayName"] = "Instance Method";
449 break;
450 case APIRecord::RK_CXXConstructorMethod:
451 Kind["identifier"] = AddLangPrefix("method");
452 Kind["displayName"] = "Constructor";
453 break;
454 case APIRecord::RK_CXXDestructorMethod:
455 Kind["identifier"] = AddLangPrefix("method");
456 Kind["displayName"] = "Destructor";
457 break;
458 case APIRecord::RK_ObjCIvar:
459 Kind["identifier"] = AddLangPrefix("ivar");
460 Kind["displayName"] = "Instance Variable";
461 break;
462 case APIRecord::RK_ObjCInstanceMethod:
463 Kind["identifier"] = AddLangPrefix("method");
464 Kind["displayName"] = "Instance Method";
465 break;
466 case APIRecord::RK_ObjCClassMethod:
467 Kind["identifier"] = AddLangPrefix("type.method");
468 Kind["displayName"] = "Type Method";
469 break;
470 case APIRecord::RK_ObjCInstanceProperty:
471 Kind["identifier"] = AddLangPrefix("property");
472 Kind["displayName"] = "Instance Property";
473 break;
474 case APIRecord::RK_ObjCClassProperty:
475 Kind["identifier"] = AddLangPrefix("type.property");
476 Kind["displayName"] = "Type Property";
477 break;
478 case APIRecord::RK_ObjCInterface:
479 Kind["identifier"] = AddLangPrefix("class");
480 Kind["displayName"] = "Class";
481 break;
482 case APIRecord::RK_ObjCCategory:
483 Kind["identifier"] = AddLangPrefix("class.extension");
484 Kind["displayName"] = "Class Extension";
485 break;
486 case APIRecord::RK_ObjCCategoryModule:
487 Kind["identifier"] = AddLangPrefix("module.extension");
488 Kind["displayName"] = "Module Extension";
489 break;
490 case APIRecord::RK_ObjCProtocol:
491 Kind["identifier"] = AddLangPrefix("protocol");
492 Kind["displayName"] = "Protocol";
493 break;
494 case APIRecord::RK_MacroDefinition:
495 Kind["identifier"] = AddLangPrefix("macro");
496 Kind["displayName"] = "Macro";
497 break;
498 case APIRecord::RK_Typedef:
499 Kind["identifier"] = AddLangPrefix("typealias");
500 Kind["displayName"] = "Type Alias";
501 break;
502 }
503
504 return Kind;
505 }
506
507 /// Serialize the symbol kind information.
508 ///
509 /// The Symbol Graph symbol kind property contains a shorthand \c identifier
510 /// which is prefixed by the source language name, useful for tooling to parse
511 /// the kind, and a \c displayName for rendering human-readable names.
serializeSymbolKind(const APIRecord & Record,Language Lang)512 Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
513 return serializeSymbolKind(Record.getKind(), Lang);
514 }
515
516 template <typename RecordTy>
517 std::optional<Object>
serializeFunctionSignatureMixinImpl(const RecordTy & Record,std::true_type)518 serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
519 const auto &FS = Record.Signature;
520 if (FS.empty())
521 return std::nullopt;
522
523 Object Signature;
524 serializeArray(Signature, "returns",
525 serializeDeclarationFragments(FS.getReturnType()));
526
527 Array Parameters;
528 for (const auto &P : FS.getParameters()) {
529 Object Parameter;
530 Parameter["name"] = P.Name;
531 serializeArray(Parameter, "declarationFragments",
532 serializeDeclarationFragments(P.Fragments));
533 Parameters.emplace_back(std::move(Parameter));
534 }
535
536 if (!Parameters.empty())
537 Signature["parameters"] = std::move(Parameters);
538
539 return Signature;
540 }
541
542 template <typename RecordTy>
543 std::optional<Object>
serializeFunctionSignatureMixinImpl(const RecordTy & Record,std::false_type)544 serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
545 return std::nullopt;
546 }
547
548 /// Serialize the function signature field, as specified by the
549 /// Symbol Graph format.
550 ///
551 /// The Symbol Graph function signature property contains two arrays.
552 /// - The \c returns array is the declaration fragments of the return type;
553 /// - The \c parameters array contains names and declaration fragments of the
554 /// parameters.
555 ///
556 /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
557 /// formatted function signature.
558 template <typename RecordTy>
serializeFunctionSignatureMixin(Object & Paren,const RecordTy & Record)559 void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
560 serializeObject(Paren, "functionSignature",
561 serializeFunctionSignatureMixinImpl(
562 Record, has_function_signature<RecordTy>()));
563 }
564
565 template <typename RecordTy>
serializeAccessMixinImpl(const RecordTy & Record,std::true_type)566 std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
567 std::true_type) {
568 const auto &AccessControl = Record.Access;
569 std::string Access;
570 if (AccessControl.empty())
571 return std::nullopt;
572 Access = AccessControl.getAccess();
573 return Access;
574 }
575
576 template <typename RecordTy>
serializeAccessMixinImpl(const RecordTy & Record,std::false_type)577 std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
578 std::false_type) {
579 return std::nullopt;
580 }
581
582 template <typename RecordTy>
serializeAccessMixin(Object & Paren,const RecordTy & Record)583 void serializeAccessMixin(Object &Paren, const RecordTy &Record) {
584 auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>());
585 if (!accessLevel.has_value())
586 accessLevel = "public";
587 serializeString(Paren, "accessLevel", accessLevel);
588 }
589
590 template <typename RecordTy>
serializeTemplateMixinImpl(const RecordTy & Record,std::true_type)591 std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
592 std::true_type) {
593 const auto &Template = Record.Templ;
594 if (Template.empty())
595 return std::nullopt;
596
597 Object Generics;
598 Array GenericParameters;
599 for (const auto &Param : Template.getParameters()) {
600 Object Parameter;
601 Parameter["name"] = Param.Name;
602 Parameter["index"] = Param.Index;
603 Parameter["depth"] = Param.Depth;
604 GenericParameters.emplace_back(std::move(Parameter));
605 }
606 if (!GenericParameters.empty())
607 Generics["parameters"] = std::move(GenericParameters);
608
609 Array GenericConstraints;
610 for (const auto &Constr : Template.getConstraints()) {
611 Object Constraint;
612 Constraint["kind"] = Constr.Kind;
613 Constraint["lhs"] = Constr.LHS;
614 Constraint["rhs"] = Constr.RHS;
615 GenericConstraints.emplace_back(std::move(Constraint));
616 }
617
618 if (!GenericConstraints.empty())
619 Generics["constraints"] = std::move(GenericConstraints);
620
621 return Generics;
622 }
623
624 template <typename RecordTy>
serializeTemplateMixinImpl(const RecordTy & Record,std::false_type)625 std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
626 std::false_type) {
627 return std::nullopt;
628 }
629
630 template <typename RecordTy>
serializeTemplateMixin(Object & Paren,const RecordTy & Record)631 void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
632 serializeObject(Paren, "swiftGenerics",
633 serializeTemplateMixinImpl(Record, has_template<RecordTy>()));
634 }
635
636 struct PathComponent {
637 StringRef USR;
638 StringRef Name;
639 APIRecord::RecordKind Kind;
640
PathComponent__anon73d89d430111::PathComponent641 PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
642 : USR(USR), Name(Name), Kind(Kind) {}
643 };
644
645 template <typename RecordTy>
generatePathComponents(const RecordTy & Record,const APISet & API,function_ref<void (const PathComponent &)> ComponentTransformer)646 bool generatePathComponents(
647 const RecordTy &Record, const APISet &API,
648 function_ref<void(const PathComponent &)> ComponentTransformer) {
649 SmallVector<PathComponent, 4> ReverseComponenents;
650 ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
651 const auto *CurrentParent = &Record.ParentInformation;
652 bool FailedToFindParent = false;
653 while (CurrentParent && !CurrentParent->empty()) {
654 PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
655 CurrentParent->ParentName,
656 CurrentParent->ParentKind);
657
658 auto *ParentRecord = CurrentParent->ParentRecord;
659 // Slow path if we don't have a direct reference to the ParentRecord
660 if (!ParentRecord)
661 ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
662
663 // If the parent is a category extended from internal module then we need to
664 // pretend this belongs to the associated interface.
665 if (auto *CategoryRecord =
666 dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
667 if (!CategoryRecord->IsFromExternalModule) {
668 ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
669 CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
670 CategoryRecord->Interface.Name,
671 APIRecord::RK_ObjCInterface);
672 }
673 }
674
675 // The parent record doesn't exist which means the symbol shouldn't be
676 // treated as part of the current product.
677 if (!ParentRecord) {
678 FailedToFindParent = true;
679 break;
680 }
681
682 ReverseComponenents.push_back(std::move(CurrentParentComponent));
683 CurrentParent = &ParentRecord->ParentInformation;
684 }
685
686 for (const auto &PC : reverse(ReverseComponenents))
687 ComponentTransformer(PC);
688
689 return FailedToFindParent;
690 }
691
serializeParentContext(const PathComponent & PC,Language Lang)692 Object serializeParentContext(const PathComponent &PC, Language Lang) {
693 Object ParentContextElem;
694 ParentContextElem["usr"] = PC.USR;
695 ParentContextElem["name"] = PC.Name;
696 ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
697 return ParentContextElem;
698 }
699
700 template <typename RecordTy>
generateParentContexts(const RecordTy & Record,const APISet & API,Language Lang)701 Array generateParentContexts(const RecordTy &Record, const APISet &API,
702 Language Lang) {
703 Array ParentContexts;
704 generatePathComponents(
705 Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
706 ParentContexts.push_back(serializeParentContext(PC, Lang));
707 });
708
709 return ParentContexts;
710 }
711 } // namespace
712
713 /// Defines the format version emitted by SymbolGraphSerializer.
714 const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
715
serializeMetadata() const716 Object SymbolGraphSerializer::serializeMetadata() const {
717 Object Metadata;
718 serializeObject(Metadata, "formatVersion",
719 serializeSemanticVersion(FormatVersion));
720 Metadata["generator"] = clang::getClangFullVersion();
721 return Metadata;
722 }
723
serializeModule() const724 Object SymbolGraphSerializer::serializeModule() const {
725 Object Module;
726 // The user is expected to always pass `--product-name=` on the command line
727 // to populate this field.
728 Module["name"] = API.ProductName;
729 serializeObject(Module, "platform", serializePlatform(API.getTarget()));
730 return Module;
731 }
732
shouldSkip(const APIRecord & Record) const733 bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
734 // Skip explicitly ignored symbols.
735 if (IgnoresList.shouldIgnore(Record.Name))
736 return true;
737
738 // Skip unconditionally unavailable symbols
739 if (Record.Availability.isUnconditionallyUnavailable())
740 return true;
741
742 // Filter out symbols prefixed with an underscored as they are understood to
743 // be symbols clients should not use.
744 if (Record.Name.starts_with("_"))
745 return true;
746
747 return false;
748 }
749
750 template <typename RecordTy>
751 std::optional<Object>
serializeAPIRecord(const RecordTy & Record) const752 SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
753 if (shouldSkip(Record))
754 return std::nullopt;
755
756 Object Obj;
757 serializeObject(Obj, "identifier",
758 serializeIdentifier(Record, API.getLanguage()));
759 serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
760 serializeObject(Obj, "names", serializeNames(Record));
761 serializeObject(
762 Obj, "location",
763 serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
764 serializeArray(Obj, "availability",
765 serializeAvailability(Record.Availability));
766 serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
767 serializeArray(Obj, "declarationFragments",
768 serializeDeclarationFragments(Record.Declaration));
769 SmallVector<StringRef, 4> PathComponentsNames;
770 // If this returns true it indicates that we couldn't find a symbol in the
771 // hierarchy.
772 if (generatePathComponents(Record, API,
773 [&PathComponentsNames](const PathComponent &PC) {
774 PathComponentsNames.push_back(PC.Name);
775 }))
776 return {};
777
778 serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
779
780 serializeFunctionSignatureMixin(Obj, Record);
781 serializeAccessMixin(Obj, Record);
782 serializeTemplateMixin(Obj, Record);
783
784 return Obj;
785 }
786
787 template <typename MemberTy>
serializeMembers(const APIRecord & Record,const SmallVector<std::unique_ptr<MemberTy>> & Members)788 void SymbolGraphSerializer::serializeMembers(
789 const APIRecord &Record,
790 const SmallVector<std::unique_ptr<MemberTy>> &Members) {
791 // Members should not be serialized if we aren't recursing.
792 if (!ShouldRecurse)
793 return;
794 for (const auto &Member : Members) {
795 auto MemberRecord = serializeAPIRecord(*Member);
796 if (!MemberRecord)
797 continue;
798
799 Symbols.emplace_back(std::move(*MemberRecord));
800 serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
801 }
802 }
803
getRelationshipString(RelationshipKind Kind)804 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
805 switch (Kind) {
806 case RelationshipKind::MemberOf:
807 return "memberOf";
808 case RelationshipKind::InheritsFrom:
809 return "inheritsFrom";
810 case RelationshipKind::ConformsTo:
811 return "conformsTo";
812 case RelationshipKind::ExtensionTo:
813 return "extensionTo";
814 }
815 llvm_unreachable("Unhandled relationship kind");
816 }
817
getConstraintString(ConstraintKind Kind)818 StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
819 switch (Kind) {
820 case ConstraintKind::Conformance:
821 return "conformance";
822 case ConstraintKind::ConditionalConformance:
823 return "conditionalConformance";
824 }
825 llvm_unreachable("Unhandled constraint kind");
826 }
827
serializeRelationship(RelationshipKind Kind,SymbolReference Source,SymbolReference Target)828 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
829 SymbolReference Source,
830 SymbolReference Target) {
831 Object Relationship;
832 Relationship["source"] = Source.USR;
833 Relationship["target"] = Target.USR;
834 Relationship["targetFallback"] = Target.Name;
835 Relationship["kind"] = getRelationshipString(Kind);
836
837 Relationships.emplace_back(std::move(Relationship));
838 }
839
visitNamespaceRecord(const NamespaceRecord & Record)840 void SymbolGraphSerializer::visitNamespaceRecord(
841 const NamespaceRecord &Record) {
842 auto Namespace = serializeAPIRecord(Record);
843 if (!Namespace)
844 return;
845 Symbols.emplace_back(std::move(*Namespace));
846 if (!Record.ParentInformation.empty())
847 serializeRelationship(RelationshipKind::MemberOf, Record,
848 Record.ParentInformation.ParentRecord);
849 }
850
visitGlobalFunctionRecord(const GlobalFunctionRecord & Record)851 void SymbolGraphSerializer::visitGlobalFunctionRecord(
852 const GlobalFunctionRecord &Record) {
853 auto Obj = serializeAPIRecord(Record);
854 if (!Obj)
855 return;
856
857 Symbols.emplace_back(std::move(*Obj));
858 }
859
visitGlobalVariableRecord(const GlobalVariableRecord & Record)860 void SymbolGraphSerializer::visitGlobalVariableRecord(
861 const GlobalVariableRecord &Record) {
862 auto Obj = serializeAPIRecord(Record);
863 if (!Obj)
864 return;
865
866 Symbols.emplace_back(std::move(*Obj));
867 }
868
visitEnumRecord(const EnumRecord & Record)869 void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) {
870 auto Enum = serializeAPIRecord(Record);
871 if (!Enum)
872 return;
873
874 Symbols.emplace_back(std::move(*Enum));
875 serializeMembers(Record, Record.Constants);
876 }
877
visitRecordRecord(const RecordRecord & Record)878 void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) {
879 auto SerializedRecord = serializeAPIRecord(Record);
880 if (!SerializedRecord)
881 return;
882
883 Symbols.emplace_back(std::move(*SerializedRecord));
884 serializeMembers(Record, Record.Fields);
885 }
886
visitStaticFieldRecord(const StaticFieldRecord & Record)887 void SymbolGraphSerializer::visitStaticFieldRecord(
888 const StaticFieldRecord &Record) {
889 auto StaticField = serializeAPIRecord(Record);
890 if (!StaticField)
891 return;
892 Symbols.emplace_back(std::move(*StaticField));
893 serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context);
894 }
895
visitCXXClassRecord(const CXXClassRecord & Record)896 void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) {
897 auto Class = serializeAPIRecord(Record);
898 if (!Class)
899 return;
900
901 Symbols.emplace_back(std::move(*Class));
902 for (const auto &Base : Record.Bases)
903 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
904 if (!Record.ParentInformation.empty())
905 serializeRelationship(RelationshipKind::MemberOf, Record,
906 Record.ParentInformation.ParentRecord);
907 }
908
visitClassTemplateRecord(const ClassTemplateRecord & Record)909 void SymbolGraphSerializer::visitClassTemplateRecord(
910 const ClassTemplateRecord &Record) {
911 auto Class = serializeAPIRecord(Record);
912 if (!Class)
913 return;
914
915 Symbols.emplace_back(std::move(*Class));
916 for (const auto &Base : Record.Bases)
917 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
918 if (!Record.ParentInformation.empty())
919 serializeRelationship(RelationshipKind::MemberOf, Record,
920 Record.ParentInformation.ParentRecord);
921 }
922
visitClassTemplateSpecializationRecord(const ClassTemplateSpecializationRecord & Record)923 void SymbolGraphSerializer::visitClassTemplateSpecializationRecord(
924 const ClassTemplateSpecializationRecord &Record) {
925 auto Class = serializeAPIRecord(Record);
926 if (!Class)
927 return;
928
929 Symbols.emplace_back(std::move(*Class));
930
931 for (const auto &Base : Record.Bases)
932 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
933 if (!Record.ParentInformation.empty())
934 serializeRelationship(RelationshipKind::MemberOf, Record,
935 Record.ParentInformation.ParentRecord);
936 }
937
visitClassTemplatePartialSpecializationRecord(const ClassTemplatePartialSpecializationRecord & Record)938 void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
939 const ClassTemplatePartialSpecializationRecord &Record) {
940 auto Class = serializeAPIRecord(Record);
941 if (!Class)
942 return;
943
944 Symbols.emplace_back(std::move(*Class));
945
946 for (const auto &Base : Record.Bases)
947 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
948 if (!Record.ParentInformation.empty())
949 serializeRelationship(RelationshipKind::MemberOf, Record,
950 Record.ParentInformation.ParentRecord);
951 }
952
visitCXXInstanceMethodRecord(const CXXInstanceMethodRecord & Record)953 void SymbolGraphSerializer::visitCXXInstanceMethodRecord(
954 const CXXInstanceMethodRecord &Record) {
955 auto InstanceMethod = serializeAPIRecord(Record);
956 if (!InstanceMethod)
957 return;
958
959 Symbols.emplace_back(std::move(*InstanceMethod));
960 serializeRelationship(RelationshipKind::MemberOf, Record,
961 Record.ParentInformation.ParentRecord);
962 }
963
visitCXXStaticMethodRecord(const CXXStaticMethodRecord & Record)964 void SymbolGraphSerializer::visitCXXStaticMethodRecord(
965 const CXXStaticMethodRecord &Record) {
966 auto StaticMethod = serializeAPIRecord(Record);
967 if (!StaticMethod)
968 return;
969
970 Symbols.emplace_back(std::move(*StaticMethod));
971 serializeRelationship(RelationshipKind::MemberOf, Record,
972 Record.ParentInformation.ParentRecord);
973 }
974
visitMethodTemplateRecord(const CXXMethodTemplateRecord & Record)975 void SymbolGraphSerializer::visitMethodTemplateRecord(
976 const CXXMethodTemplateRecord &Record) {
977 if (!ShouldRecurse)
978 // Ignore child symbols
979 return;
980 auto MethodTemplate = serializeAPIRecord(Record);
981 if (!MethodTemplate)
982 return;
983 Symbols.emplace_back(std::move(*MethodTemplate));
984 serializeRelationship(RelationshipKind::MemberOf, Record,
985 Record.ParentInformation.ParentRecord);
986 }
987
visitMethodTemplateSpecializationRecord(const CXXMethodTemplateSpecializationRecord & Record)988 void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord(
989 const CXXMethodTemplateSpecializationRecord &Record) {
990 if (!ShouldRecurse)
991 // Ignore child symbols
992 return;
993 auto MethodTemplateSpecialization = serializeAPIRecord(Record);
994 if (!MethodTemplateSpecialization)
995 return;
996 Symbols.emplace_back(std::move(*MethodTemplateSpecialization));
997 serializeRelationship(RelationshipKind::MemberOf, Record,
998 Record.ParentInformation.ParentRecord);
999 }
1000
visitCXXFieldRecord(const CXXFieldRecord & Record)1001 void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) {
1002 if (!ShouldRecurse)
1003 return;
1004 auto CXXField = serializeAPIRecord(Record);
1005 if (!CXXField)
1006 return;
1007 Symbols.emplace_back(std::move(*CXXField));
1008 serializeRelationship(RelationshipKind::MemberOf, Record,
1009 Record.ParentInformation.ParentRecord);
1010 }
1011
visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord & Record)1012 void SymbolGraphSerializer::visitCXXFieldTemplateRecord(
1013 const CXXFieldTemplateRecord &Record) {
1014 if (!ShouldRecurse)
1015 // Ignore child symbols
1016 return;
1017 auto CXXFieldTemplate = serializeAPIRecord(Record);
1018 if (!CXXFieldTemplate)
1019 return;
1020 Symbols.emplace_back(std::move(*CXXFieldTemplate));
1021 serializeRelationship(RelationshipKind::MemberOf, Record,
1022 Record.ParentInformation.ParentRecord);
1023 }
1024
visitConceptRecord(const ConceptRecord & Record)1025 void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) {
1026 auto Concept = serializeAPIRecord(Record);
1027 if (!Concept)
1028 return;
1029
1030 Symbols.emplace_back(std::move(*Concept));
1031 }
1032
visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord & Record)1033 void SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
1034 const GlobalVariableTemplateRecord &Record) {
1035 auto GlobalVariableTemplate = serializeAPIRecord(Record);
1036 if (!GlobalVariableTemplate)
1037 return;
1038 Symbols.emplace_back(std::move(*GlobalVariableTemplate));
1039 }
1040
visitGlobalVariableTemplateSpecializationRecord(const GlobalVariableTemplateSpecializationRecord & Record)1041 void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord(
1042 const GlobalVariableTemplateSpecializationRecord &Record) {
1043 auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record);
1044 if (!GlobalVariableTemplateSpecialization)
1045 return;
1046 Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization));
1047 }
1048
1049 void SymbolGraphSerializer::
visitGlobalVariableTemplatePartialSpecializationRecord(const GlobalVariableTemplatePartialSpecializationRecord & Record)1050 visitGlobalVariableTemplatePartialSpecializationRecord(
1051 const GlobalVariableTemplatePartialSpecializationRecord &Record) {
1052 auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record);
1053 if (!GlobalVariableTemplatePartialSpecialization)
1054 return;
1055 Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization));
1056 }
1057
visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord & Record)1058 void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
1059 const GlobalFunctionTemplateRecord &Record) {
1060 auto GlobalFunctionTemplate = serializeAPIRecord(Record);
1061 if (!GlobalFunctionTemplate)
1062 return;
1063 Symbols.emplace_back(std::move(*GlobalFunctionTemplate));
1064 }
1065
visitGlobalFunctionTemplateSpecializationRecord(const GlobalFunctionTemplateSpecializationRecord & Record)1066 void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord(
1067 const GlobalFunctionTemplateSpecializationRecord &Record) {
1068 auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record);
1069 if (!GlobalFunctionTemplateSpecialization)
1070 return;
1071 Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization));
1072 }
1073
visitObjCContainerRecord(const ObjCContainerRecord & Record)1074 void SymbolGraphSerializer::visitObjCContainerRecord(
1075 const ObjCContainerRecord &Record) {
1076 auto ObjCContainer = serializeAPIRecord(Record);
1077 if (!ObjCContainer)
1078 return;
1079
1080 Symbols.emplace_back(std::move(*ObjCContainer));
1081
1082 serializeMembers(Record, Record.Ivars);
1083 serializeMembers(Record, Record.Methods);
1084 serializeMembers(Record, Record.Properties);
1085
1086 for (const auto &Protocol : Record.Protocols)
1087 // Record that Record conforms to Protocol.
1088 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1089
1090 if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
1091 if (!ObjCInterface->SuperClass.empty())
1092 // If Record is an Objective-C interface record and it has a super class,
1093 // record that Record is inherited from SuperClass.
1094 serializeRelationship(RelationshipKind::InheritsFrom, Record,
1095 ObjCInterface->SuperClass);
1096
1097 // Members of categories extending an interface are serialized as members of
1098 // the interface.
1099 for (const auto *Category : ObjCInterface->Categories) {
1100 serializeMembers(Record, Category->Ivars);
1101 serializeMembers(Record, Category->Methods);
1102 serializeMembers(Record, Category->Properties);
1103
1104 // Surface the protocols of the category to the interface.
1105 for (const auto &Protocol : Category->Protocols)
1106 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1107 }
1108 }
1109 }
1110
visitObjCCategoryRecord(const ObjCCategoryRecord & Record)1111 void SymbolGraphSerializer::visitObjCCategoryRecord(
1112 const ObjCCategoryRecord &Record) {
1113 if (!Record.IsFromExternalModule)
1114 return;
1115
1116 // Check if the current Category' parent has been visited before, if so skip.
1117 if (!visitedCategories.contains(Record.Interface.Name)) {
1118 visitedCategories.insert(Record.Interface.Name);
1119 Object Obj;
1120 serializeObject(Obj, "identifier",
1121 serializeIdentifier(Record, API.getLanguage()));
1122 serializeObject(Obj, "kind",
1123 serializeSymbolKind(APIRecord::RK_ObjCCategoryModule,
1124 API.getLanguage()));
1125 Obj["accessLevel"] = "public";
1126 Symbols.emplace_back(std::move(Obj));
1127 }
1128
1129 Object Relationship;
1130 Relationship["source"] = Record.USR;
1131 Relationship["target"] = Record.Interface.USR;
1132 Relationship["targetFallback"] = Record.Interface.Name;
1133 Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo);
1134 Relationships.emplace_back(std::move(Relationship));
1135
1136 auto ObjCCategory = serializeAPIRecord(Record);
1137
1138 if (!ObjCCategory)
1139 return;
1140
1141 Symbols.emplace_back(std::move(*ObjCCategory));
1142 serializeMembers(Record, Record.Methods);
1143 serializeMembers(Record, Record.Properties);
1144
1145 // Surface the protocols of the category to the interface.
1146 for (const auto &Protocol : Record.Protocols)
1147 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1148 }
1149
visitMacroDefinitionRecord(const MacroDefinitionRecord & Record)1150 void SymbolGraphSerializer::visitMacroDefinitionRecord(
1151 const MacroDefinitionRecord &Record) {
1152 auto Macro = serializeAPIRecord(Record);
1153
1154 if (!Macro)
1155 return;
1156
1157 Symbols.emplace_back(std::move(*Macro));
1158 }
1159
serializeSingleRecord(const APIRecord * Record)1160 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1161 switch (Record->getKind()) {
1162 case APIRecord::RK_Unknown:
1163 llvm_unreachable("Records should have a known kind!");
1164 case APIRecord::RK_GlobalFunction:
1165 visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
1166 break;
1167 case APIRecord::RK_GlobalVariable:
1168 visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
1169 break;
1170 case APIRecord::RK_Enum:
1171 visitEnumRecord(*cast<EnumRecord>(Record));
1172 break;
1173 case APIRecord::RK_Struct:
1174 LLVM_FALLTHROUGH;
1175 case APIRecord::RK_Union:
1176 visitRecordRecord(*cast<RecordRecord>(Record));
1177 break;
1178 case APIRecord::RK_StaticField:
1179 visitStaticFieldRecord(*cast<StaticFieldRecord>(Record));
1180 break;
1181 case APIRecord::RK_CXXClass:
1182 visitCXXClassRecord(*cast<CXXClassRecord>(Record));
1183 break;
1184 case APIRecord::RK_ObjCInterface:
1185 visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
1186 break;
1187 case APIRecord::RK_ObjCProtocol:
1188 visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
1189 break;
1190 case APIRecord::RK_ObjCCategory:
1191 visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record));
1192 break;
1193 case APIRecord::RK_MacroDefinition:
1194 visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
1195 break;
1196 case APIRecord::RK_Typedef:
1197 visitTypedefRecord(*cast<TypedefRecord>(Record));
1198 break;
1199 default:
1200 if (auto Obj = serializeAPIRecord(*Record)) {
1201 Symbols.emplace_back(std::move(*Obj));
1202 auto &ParentInformation = Record->ParentInformation;
1203 if (!ParentInformation.empty())
1204 serializeRelationship(RelationshipKind::MemberOf, *Record,
1205 *ParentInformation.ParentRecord);
1206 }
1207 break;
1208 }
1209 }
1210
visitTypedefRecord(const TypedefRecord & Record)1211 void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) {
1212 // Typedefs of anonymous types have their entries unified with the underlying
1213 // type.
1214 bool ShouldDrop = Record.UnderlyingType.Name.empty();
1215 // enums declared with `NS_OPTION` have a named enum and a named typedef, with
1216 // the same name
1217 ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
1218 if (ShouldDrop)
1219 return;
1220
1221 auto Typedef = serializeAPIRecord(Record);
1222 if (!Typedef)
1223 return;
1224
1225 (*Typedef)["type"] = Record.UnderlyingType.USR;
1226
1227 Symbols.emplace_back(std::move(*Typedef));
1228 }
1229
serialize()1230 Object SymbolGraphSerializer::serialize() {
1231 traverseAPISet();
1232 return serializeCurrentGraph();
1233 }
1234
serializeCurrentGraph()1235 Object SymbolGraphSerializer::serializeCurrentGraph() {
1236 Object Root;
1237 serializeObject(Root, "metadata", serializeMetadata());
1238 serializeObject(Root, "module", serializeModule());
1239
1240 Root["symbols"] = std::move(Symbols);
1241 Root["relationships"] = std::move(Relationships);
1242
1243 return Root;
1244 }
1245
serialize(raw_ostream & os)1246 void SymbolGraphSerializer::serialize(raw_ostream &os) {
1247 Object root = serialize();
1248 if (Options.Compact)
1249 os << formatv("{0}", Value(std::move(root))) << "\n";
1250 else
1251 os << formatv("{0:2}", Value(std::move(root))) << "\n";
1252 }
1253
1254 std::optional<Object>
serializeSingleSymbolSGF(StringRef USR,const APISet & API)1255 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1256 const APISet &API) {
1257 APIRecord *Record = API.findRecordForUSR(USR);
1258 if (!Record)
1259 return {};
1260
1261 Object Root;
1262 APIIgnoresList EmptyIgnores;
1263 SymbolGraphSerializer Serializer(API, EmptyIgnores,
1264 /*Options.Compact*/ {true},
1265 /*ShouldRecurse*/ false);
1266 Serializer.serializeSingleRecord(Record);
1267 serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
1268
1269 Language Lang = API.getLanguage();
1270 serializeArray(Root, "parentContexts",
1271 generateParentContexts(*Record, API, Lang));
1272
1273 Array RelatedSymbols;
1274
1275 for (const auto &Fragment : Record->Declaration.getFragments()) {
1276 // If we don't have a USR there isn't much we can do.
1277 if (Fragment.PreciseIdentifier.empty())
1278 continue;
1279
1280 APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1281
1282 // If we can't find the record let's skip.
1283 if (!RelatedRecord)
1284 continue;
1285
1286 Object RelatedSymbol;
1287 RelatedSymbol["usr"] = RelatedRecord->USR;
1288 RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1289 // TODO: once we record this properly let's serialize it right.
1290 RelatedSymbol["accessLevel"] = "public";
1291 RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1292 RelatedSymbol["moduleName"] = API.ProductName;
1293 RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1294
1295 serializeArray(RelatedSymbol, "parentContexts",
1296 generateParentContexts(*RelatedRecord, API, Lang));
1297 RelatedSymbols.push_back(std::move(RelatedSymbol));
1298 }
1299
1300 serializeArray(Root, "relatedSymbols", RelatedSymbols);
1301 return Root;
1302 }
1303