xref: /llvm-project/clang/lib/ExtractAPI/Serialization/SymbolGraphSerializer.cpp (revision a1580d7b59b65b17f2ce7fdb95f46379e7df4089)
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/API.h"
18 #include "clang/ExtractAPI/APIIgnoresList.h"
19 #include "clang/ExtractAPI/DeclarationFragments.h"
20 #include "clang/ExtractAPI/Serialization/SerializerBase.h"
21 #include "llvm/ADT/STLExtras.h"
22 #include "llvm/ADT/STLFunctionalExtras.h"
23 #include "llvm/ADT/SmallVector.h"
24 #include "llvm/Support/Casting.h"
25 #include "llvm/Support/Compiler.h"
26 #include "llvm/Support/JSON.h"
27 #include "llvm/Support/Path.h"
28 #include "llvm/Support/VersionTuple.h"
29 #include <optional>
30 #include <type_traits>
31 
32 using namespace clang;
33 using namespace clang::extractapi;
34 using namespace llvm;
35 using namespace llvm::json;
36 
37 namespace {
38 
39 /// Helper function to inject a JSON object \p Obj into another object \p Paren
40 /// at position \p Key.
41 void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) {
42   if (Obj)
43     Paren[Key] = std::move(*Obj);
44 }
45 
46 /// Helper function to inject a JSON array \p Array into object \p Paren at
47 /// position \p Key.
48 void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) {
49   if (Array)
50     Paren[Key] = std::move(*Array);
51 }
52 
53 /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
54 /// format.
55 ///
56 /// A semantic version object contains three numeric fields, representing the
57 /// \c major, \c minor, and \c patch parts of the version tuple.
58 /// For example version tuple 1.0.3 is serialized as:
59 /// \code
60 ///   {
61 ///     "major" : 1,
62 ///     "minor" : 0,
63 ///     "patch" : 3
64 ///   }
65 /// \endcode
66 ///
67 /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
68 /// containing the semantic version representation of \p V.
69 Optional<Object> serializeSemanticVersion(const VersionTuple &V) {
70   if (V.empty())
71     return std::nullopt;
72 
73   Object Version;
74   Version["major"] = V.getMajor();
75   Version["minor"] = V.getMinor().value_or(0);
76   Version["patch"] = V.getSubminor().value_or(0);
77   return Version;
78 }
79 
80 /// Serialize the OS information in the Symbol Graph platform property.
81 ///
82 /// The OS information in Symbol Graph contains the \c name of the OS, and an
83 /// optional \c minimumVersion semantic version field.
84 Object serializeOperatingSystem(const Triple &T) {
85   Object OS;
86   OS["name"] = T.getOSTypeName(T.getOS());
87   serializeObject(OS, "minimumVersion",
88                   serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
89   return OS;
90 }
91 
92 /// Serialize the platform information in the Symbol Graph module section.
93 ///
94 /// The platform object describes a target platform triple in corresponding
95 /// three fields: \c architecture, \c vendor, and \c operatingSystem.
96 Object serializePlatform(const Triple &T) {
97   Object Platform;
98   Platform["architecture"] = T.getArchName();
99   Platform["vendor"] = T.getVendorName();
100   Platform["operatingSystem"] = serializeOperatingSystem(T);
101   return Platform;
102 }
103 
104 /// Serialize a source position.
105 Object serializeSourcePosition(const PresumedLoc &Loc) {
106   assert(Loc.isValid() && "invalid source position");
107 
108   Object SourcePosition;
109   SourcePosition["line"] = Loc.getLine();
110   SourcePosition["character"] = Loc.getColumn();
111 
112   return SourcePosition;
113 }
114 
115 /// Serialize a source location in file.
116 ///
117 /// \param Loc The presumed location to serialize.
118 /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
119 /// Defaults to false.
120 Object serializeSourceLocation(const PresumedLoc &Loc,
121                                bool IncludeFileURI = false) {
122   Object SourceLocation;
123   serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
124 
125   if (IncludeFileURI) {
126     std::string FileURI = "file://";
127     // Normalize file path to use forward slashes for the URI.
128     FileURI += sys::path::convert_to_slash(Loc.getFilename());
129     SourceLocation["uri"] = FileURI;
130   }
131 
132   return SourceLocation;
133 }
134 
135 /// Serialize a source range with begin and end locations.
136 Object serializeSourceRange(const PresumedLoc &BeginLoc,
137                             const PresumedLoc &EndLoc) {
138   Object SourceRange;
139   serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
140   serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
141   return SourceRange;
142 }
143 
144 /// Serialize the availability attributes of a symbol.
145 ///
146 /// Availability information contains the introduced, deprecated, and obsoleted
147 /// versions of the symbol for a given domain (roughly corresponds to a
148 /// platform) as semantic versions, if not default.  Availability information
149 /// also contains flags to indicate if the symbol is unconditionally unavailable
150 /// or deprecated, i.e. \c __attribute__((unavailable)) and \c
151 /// __attribute__((deprecated)).
152 ///
153 /// \returns \c std::nullopt if the symbol has default availability attributes,
154 /// or an \c Array containing the formatted availability information.
155 Optional<Array> serializeAvailability(const AvailabilitySet &Availabilities) {
156   if (Availabilities.isDefault())
157     return std::nullopt;
158 
159   Array AvailabilityArray;
160 
161   if (Availabilities.isUnconditionallyDeprecated()) {
162     Object UnconditionallyDeprecated;
163     UnconditionallyDeprecated["domain"] = "*";
164     UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
165     AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
166   }
167 
168   // Note unconditionally unavailable records are skipped.
169 
170   for (const auto &AvailInfo : Availabilities) {
171     Object Availability;
172     Availability["domain"] = AvailInfo.Domain;
173     serializeObject(Availability, "introducedVersion",
174                     serializeSemanticVersion(AvailInfo.Introduced));
175     serializeObject(Availability, "deprecatedVersion",
176                     serializeSemanticVersion(AvailInfo.Deprecated));
177     serializeObject(Availability, "obsoletedVersion",
178                     serializeSemanticVersion(AvailInfo.Obsoleted));
179     AvailabilityArray.emplace_back(std::move(Availability));
180   }
181 
182   return AvailabilityArray;
183 }
184 
185 /// Get the language name string for interface language references.
186 StringRef getLanguageName(Language Lang) {
187   switch (Lang) {
188   case Language::C:
189     return "c";
190   case Language::ObjC:
191     return "objective-c";
192 
193   // Unsupported language currently
194   case Language::CXX:
195   case Language::ObjCXX:
196   case Language::OpenCL:
197   case Language::OpenCLCXX:
198   case Language::CUDA:
199   case Language::RenderScript:
200   case Language::HIP:
201   case Language::HLSL:
202 
203   // Languages that the frontend cannot parse and compile
204   case Language::Unknown:
205   case Language::Asm:
206   case Language::LLVM_IR:
207     llvm_unreachable("Unsupported language kind");
208   }
209 
210   llvm_unreachable("Unhandled language kind");
211 }
212 
213 /// Serialize the identifier object as specified by the Symbol Graph format.
214 ///
215 /// The identifier property of a symbol contains the USR for precise and unique
216 /// references, and the interface language name.
217 Object serializeIdentifier(const APIRecord &Record, Language Lang) {
218   Object Identifier;
219   Identifier["precise"] = Record.USR;
220   Identifier["interfaceLanguage"] = getLanguageName(Lang);
221 
222   return Identifier;
223 }
224 
225 /// Serialize the documentation comments attached to a symbol, as specified by
226 /// the Symbol Graph format.
227 ///
228 /// The Symbol Graph \c docComment object contains an array of lines. Each line
229 /// represents one line of striped documentation comment, with source range
230 /// information.
231 /// e.g.
232 /// \code
233 ///   /// This is a documentation comment
234 ///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.
235 ///   ///     with multiple lines.
236 ///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.
237 /// \endcode
238 ///
239 /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
240 /// the formatted lines.
241 Optional<Object> serializeDocComment(const DocComment &Comment) {
242   if (Comment.empty())
243     return std::nullopt;
244 
245   Object DocComment;
246   Array LinesArray;
247   for (const auto &CommentLine : Comment) {
248     Object Line;
249     Line["text"] = CommentLine.Text;
250     serializeObject(Line, "range",
251                     serializeSourceRange(CommentLine.Begin, CommentLine.End));
252     LinesArray.emplace_back(std::move(Line));
253   }
254   serializeArray(DocComment, "lines", LinesArray);
255 
256   return DocComment;
257 }
258 
259 /// Serialize the declaration fragments of a symbol.
260 ///
261 /// The Symbol Graph declaration fragments is an array of tagged important
262 /// parts of a symbol's declaration. The fragments sequence can be joined to
263 /// form spans of declaration text, with attached information useful for
264 /// purposes like syntax-highlighting etc. For example:
265 /// \code
266 ///   const int pi; -> "declarationFragments" : [
267 ///                      {
268 ///                        "kind" : "keyword",
269 ///                        "spelling" : "const"
270 ///                      },
271 ///                      {
272 ///                        "kind" : "text",
273 ///                        "spelling" : " "
274 ///                      },
275 ///                      {
276 ///                        "kind" : "typeIdentifier",
277 ///                        "preciseIdentifier" : "c:I",
278 ///                        "spelling" : "int"
279 ///                      },
280 ///                      {
281 ///                        "kind" : "text",
282 ///                        "spelling" : " "
283 ///                      },
284 ///                      {
285 ///                        "kind" : "identifier",
286 ///                        "spelling" : "pi"
287 ///                      }
288 ///                    ]
289 /// \endcode
290 ///
291 /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
292 /// formatted declaration fragments array.
293 Optional<Array> serializeDeclarationFragments(const DeclarationFragments &DF) {
294   if (DF.getFragments().empty())
295     return std::nullopt;
296 
297   Array Fragments;
298   for (const auto &F : DF.getFragments()) {
299     Object Fragment;
300     Fragment["spelling"] = F.Spelling;
301     Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
302     if (!F.PreciseIdentifier.empty())
303       Fragment["preciseIdentifier"] = F.PreciseIdentifier;
304     Fragments.emplace_back(std::move(Fragment));
305   }
306 
307   return Fragments;
308 }
309 
310 /// Serialize the \c names field of a symbol as specified by the Symbol Graph
311 /// format.
312 ///
313 /// The Symbol Graph names field contains multiple representations of a symbol
314 /// that can be used for different applications:
315 ///   - \c title : The simple declared name of the symbol;
316 ///   - \c subHeading : An array of declaration fragments that provides tags,
317 ///     and potentially more tokens (for example the \c +/- symbol for
318 ///     Objective-C methods). Can be used as sub-headings for documentation.
319 Object serializeNames(const APIRecord &Record) {
320   Object Names;
321   Names["title"] = Record.Name;
322   serializeArray(Names, "subHeading",
323                  serializeDeclarationFragments(Record.SubHeading));
324   DeclarationFragments NavigatorFragments;
325   NavigatorFragments.append(Record.Name,
326                             DeclarationFragments::FragmentKind::Identifier,
327                             /*PreciseIdentifier*/ "");
328   serializeArray(Names, "navigator",
329                  serializeDeclarationFragments(NavigatorFragments));
330 
331   return Names;
332 }
333 
334 Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
335   auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
336     return (getLanguageName(Lang) + "." + S).str();
337   };
338 
339   Object Kind;
340   switch (RK) {
341   case APIRecord::RK_Unknown:
342     llvm_unreachable("Records should have an explicit kind");
343     break;
344   case APIRecord::RK_GlobalFunction:
345     Kind["identifier"] = AddLangPrefix("func");
346     Kind["displayName"] = "Function";
347     break;
348   case APIRecord::RK_GlobalVariable:
349     Kind["identifier"] = AddLangPrefix("var");
350     Kind["displayName"] = "Global Variable";
351     break;
352   case APIRecord::RK_EnumConstant:
353     Kind["identifier"] = AddLangPrefix("enum.case");
354     Kind["displayName"] = "Enumeration Case";
355     break;
356   case APIRecord::RK_Enum:
357     Kind["identifier"] = AddLangPrefix("enum");
358     Kind["displayName"] = "Enumeration";
359     break;
360   case APIRecord::RK_StructField:
361     Kind["identifier"] = AddLangPrefix("property");
362     Kind["displayName"] = "Instance Property";
363     break;
364   case APIRecord::RK_Struct:
365     Kind["identifier"] = AddLangPrefix("struct");
366     Kind["displayName"] = "Structure";
367     break;
368   case APIRecord::RK_ObjCIvar:
369     Kind["identifier"] = AddLangPrefix("ivar");
370     Kind["displayName"] = "Instance Variable";
371     break;
372   case APIRecord::RK_ObjCInstanceMethod:
373     Kind["identifier"] = AddLangPrefix("method");
374     Kind["displayName"] = "Instance Method";
375     break;
376   case APIRecord::RK_ObjCClassMethod:
377     Kind["identifier"] = AddLangPrefix("type.method");
378     Kind["displayName"] = "Type Method";
379     break;
380   case APIRecord::RK_ObjCInstanceProperty:
381     Kind["identifier"] = AddLangPrefix("property");
382     Kind["displayName"] = "Instance Property";
383     break;
384   case APIRecord::RK_ObjCClassProperty:
385     Kind["identifier"] = AddLangPrefix("type.property");
386     Kind["displayName"] = "Type Property";
387     break;
388   case APIRecord::RK_ObjCInterface:
389     Kind["identifier"] = AddLangPrefix("class");
390     Kind["displayName"] = "Class";
391     break;
392   case APIRecord::RK_ObjCCategory:
393     // We don't serialize out standalone Objective-C category symbols yet.
394     llvm_unreachable("Serializing standalone Objective-C category symbols is "
395                      "not supported.");
396     break;
397   case APIRecord::RK_ObjCProtocol:
398     Kind["identifier"] = AddLangPrefix("protocol");
399     Kind["displayName"] = "Protocol";
400     break;
401   case APIRecord::RK_MacroDefinition:
402     Kind["identifier"] = AddLangPrefix("macro");
403     Kind["displayName"] = "Macro";
404     break;
405   case APIRecord::RK_Typedef:
406     Kind["identifier"] = AddLangPrefix("typealias");
407     Kind["displayName"] = "Type Alias";
408     break;
409   }
410 
411   return Kind;
412 }
413 
414 /// Serialize the symbol kind information.
415 ///
416 /// The Symbol Graph symbol kind property contains a shorthand \c identifier
417 /// which is prefixed by the source language name, useful for tooling to parse
418 /// the kind, and a \c displayName for rendering human-readable names.
419 Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
420   return serializeSymbolKind(Record.getKind(), Lang);
421 }
422 
423 template <typename RecordTy>
424 Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record,
425                                                      std::true_type) {
426   const auto &FS = Record.Signature;
427   if (FS.empty())
428     return std::nullopt;
429 
430   Object Signature;
431   serializeArray(Signature, "returns",
432                  serializeDeclarationFragments(FS.getReturnType()));
433 
434   Array Parameters;
435   for (const auto &P : FS.getParameters()) {
436     Object Parameter;
437     Parameter["name"] = P.Name;
438     serializeArray(Parameter, "declarationFragments",
439                    serializeDeclarationFragments(P.Fragments));
440     Parameters.emplace_back(std::move(Parameter));
441   }
442 
443   if (!Parameters.empty())
444     Signature["parameters"] = std::move(Parameters);
445 
446   return Signature;
447 }
448 
449 template <typename RecordTy>
450 Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record,
451                                                      std::false_type) {
452   return std::nullopt;
453 }
454 
455 /// Serialize the function signature field, as specified by the
456 /// Symbol Graph format.
457 ///
458 /// The Symbol Graph function signature property contains two arrays.
459 ///   - The \c returns array is the declaration fragments of the return type;
460 ///   - The \c parameters array contains names and declaration fragments of the
461 ///     parameters.
462 ///
463 /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
464 /// formatted function signature.
465 template <typename RecordTy>
466 void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
467   serializeObject(Paren, "functionSignature",
468                   serializeFunctionSignatureMixinImpl(
469                       Record, has_function_signature<RecordTy>()));
470 }
471 
472 struct PathComponent {
473   StringRef USR;
474   StringRef Name;
475   APIRecord::RecordKind Kind;
476 
477   PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
478       : USR(USR), Name(Name), Kind(Kind) {}
479 };
480 
481 template <typename RecordTy>
482 bool generatePathComponents(
483     const RecordTy &Record, const APISet &API,
484     function_ref<void(const PathComponent &)> ComponentTransformer) {
485   SmallVector<PathComponent, 4> ReverseComponenents;
486   ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
487   const auto *CurrentParent = &Record.ParentInformation;
488   while (CurrentParent && !CurrentParent->empty()) {
489     PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
490                                          CurrentParent->ParentName,
491                                          CurrentParent->ParentKind);
492 
493     auto *ParentRecord = CurrentParent->ParentRecord;
494     // Slow path if we don't have a direct reference to the ParentRecord
495     if (!ParentRecord)
496       ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
497 
498     // If the parent is a category then we need to pretend this belongs to the
499     // associated interface.
500     if (auto *CategoryRecord =
501             dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
502       ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
503       CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
504                                              CategoryRecord->Interface.Name,
505                                              APIRecord::RK_ObjCInterface);
506     }
507 
508     // The parent record doesn't exist which means the symbol shouldn't be
509     // treated as part of the current product.
510     if (!ParentRecord)
511       return true;
512 
513     ReverseComponenents.push_back(std::move(CurrentParentComponent));
514     CurrentParent = &ParentRecord->ParentInformation;
515   }
516 
517   for (const auto &PC : reverse(ReverseComponenents))
518     ComponentTransformer(PC);
519 
520   return false;
521 }
522 Object serializeParentContext(const PathComponent &PC, Language Lang) {
523   Object ParentContextElem;
524   ParentContextElem["usr"] = PC.USR;
525   ParentContextElem["name"] = PC.Name;
526   ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
527   return ParentContextElem;
528 }
529 
530 template <typename RecordTy>
531 Array generateParentContexts(const RecordTy &Record, const APISet &API,
532                              Language Lang) {
533   Array ParentContexts;
534   if (generatePathComponents(
535           Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
536             ParentContexts.push_back(serializeParentContext(PC, Lang));
537           }))
538     ParentContexts.clear();
539   ParentContexts.pop_back();
540 
541   return ParentContexts;
542 }
543 
544 } // namespace
545 
546 void SymbolGraphSerializer::anchor() {}
547 
548 /// Defines the format version emitted by SymbolGraphSerializer.
549 const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
550 
551 Object SymbolGraphSerializer::serializeMetadata() const {
552   Object Metadata;
553   serializeObject(Metadata, "formatVersion",
554                   serializeSemanticVersion(FormatVersion));
555   Metadata["generator"] = clang::getClangFullVersion();
556   return Metadata;
557 }
558 
559 Object SymbolGraphSerializer::serializeModule() const {
560   Object Module;
561   // The user is expected to always pass `--product-name=` on the command line
562   // to populate this field.
563   Module["name"] = API.ProductName;
564   serializeObject(Module, "platform", serializePlatform(API.getTarget()));
565   return Module;
566 }
567 
568 bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
569   // Skip explicitly ignored symbols.
570   if (IgnoresList.shouldIgnore(Record.Name))
571     return true;
572 
573   // Skip unconditionally unavailable symbols
574   if (Record.Availabilities.isUnconditionallyUnavailable())
575     return true;
576 
577   // Filter out symbols prefixed with an underscored as they are understood to
578   // be symbols clients should not use.
579   if (Record.Name.startswith("_"))
580     return true;
581 
582   return false;
583 }
584 
585 template <typename RecordTy>
586 Optional<Object>
587 SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
588   if (shouldSkip(Record))
589     return std::nullopt;
590 
591   Object Obj;
592   serializeObject(Obj, "identifier",
593                   serializeIdentifier(Record, API.getLanguage()));
594   serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage()));
595   serializeObject(Obj, "names", serializeNames(Record));
596   serializeObject(
597       Obj, "location",
598       serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true));
599   serializeArray(Obj, "availability",
600                  serializeAvailability(Record.Availabilities));
601   serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
602   serializeArray(Obj, "declarationFragments",
603                  serializeDeclarationFragments(Record.Declaration));
604   // TODO: Once we keep track of symbol access information serialize it
605   // correctly here.
606   Obj["accessLevel"] = "public";
607   SmallVector<StringRef, 4> PathComponentsNames;
608   // If this returns true it indicates that we couldn't find a symbol in the
609   // hierarchy.
610   if (generatePathComponents(Record, API,
611                              [&PathComponentsNames](const PathComponent &PC) {
612                                PathComponentsNames.push_back(PC.Name);
613                              }))
614     return {};
615 
616   serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
617 
618   serializeFunctionSignatureMixin(Obj, Record);
619 
620   return Obj;
621 }
622 
623 template <typename MemberTy>
624 void SymbolGraphSerializer::serializeMembers(
625     const APIRecord &Record,
626     const SmallVector<std::unique_ptr<MemberTy>> &Members) {
627   // Members should not be serialized if we aren't recursing.
628   if (!ShouldRecurse)
629     return;
630   for (const auto &Member : Members) {
631     auto MemberRecord = serializeAPIRecord(*Member);
632     if (!MemberRecord)
633       continue;
634 
635     Symbols.emplace_back(std::move(*MemberRecord));
636     serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
637   }
638 }
639 
640 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
641   switch (Kind) {
642   case RelationshipKind::MemberOf:
643     return "memberOf";
644   case RelationshipKind::InheritsFrom:
645     return "inheritsFrom";
646   case RelationshipKind::ConformsTo:
647     return "conformsTo";
648   }
649   llvm_unreachable("Unhandled relationship kind");
650 }
651 
652 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
653                                                   SymbolReference Source,
654                                                   SymbolReference Target) {
655   Object Relationship;
656   Relationship["source"] = Source.USR;
657   Relationship["target"] = Target.USR;
658   Relationship["targetFallback"] = Target.Name;
659   Relationship["kind"] = getRelationshipString(Kind);
660 
661   Relationships.emplace_back(std::move(Relationship));
662 }
663 
664 void SymbolGraphSerializer::serializeGlobalFunctionRecord(
665     const GlobalFunctionRecord &Record) {
666   auto Obj = serializeAPIRecord(Record);
667   if (!Obj)
668     return;
669 
670   Symbols.emplace_back(std::move(*Obj));
671 }
672 
673 void SymbolGraphSerializer::serializeGlobalVariableRecord(
674     const GlobalVariableRecord &Record) {
675   auto Obj = serializeAPIRecord(Record);
676   if (!Obj)
677     return;
678 
679   Symbols.emplace_back(std::move(*Obj));
680 }
681 
682 void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) {
683   auto Enum = serializeAPIRecord(Record);
684   if (!Enum)
685     return;
686 
687   Symbols.emplace_back(std::move(*Enum));
688   serializeMembers(Record, Record.Constants);
689 }
690 
691 void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) {
692   auto Struct = serializeAPIRecord(Record);
693   if (!Struct)
694     return;
695 
696   Symbols.emplace_back(std::move(*Struct));
697   serializeMembers(Record, Record.Fields);
698 }
699 
700 void SymbolGraphSerializer::serializeObjCContainerRecord(
701     const ObjCContainerRecord &Record) {
702   auto ObjCContainer = serializeAPIRecord(Record);
703   if (!ObjCContainer)
704     return;
705 
706   Symbols.emplace_back(std::move(*ObjCContainer));
707 
708   serializeMembers(Record, Record.Ivars);
709   serializeMembers(Record, Record.Methods);
710   serializeMembers(Record, Record.Properties);
711 
712   for (const auto &Protocol : Record.Protocols)
713     // Record that Record conforms to Protocol.
714     serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
715 
716   if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
717     if (!ObjCInterface->SuperClass.empty())
718       // If Record is an Objective-C interface record and it has a super class,
719       // record that Record is inherited from SuperClass.
720       serializeRelationship(RelationshipKind::InheritsFrom, Record,
721                             ObjCInterface->SuperClass);
722 
723     // Members of categories extending an interface are serialized as members of
724     // the interface.
725     for (const auto *Category : ObjCInterface->Categories) {
726       serializeMembers(Record, Category->Ivars);
727       serializeMembers(Record, Category->Methods);
728       serializeMembers(Record, Category->Properties);
729 
730       // Surface the protocols of the category to the interface.
731       for (const auto &Protocol : Category->Protocols)
732         serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
733     }
734   }
735 }
736 
737 void SymbolGraphSerializer::serializeMacroDefinitionRecord(
738     const MacroDefinitionRecord &Record) {
739   auto Macro = serializeAPIRecord(Record);
740 
741   if (!Macro)
742     return;
743 
744   Symbols.emplace_back(std::move(*Macro));
745 }
746 
747 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
748   switch (Record->getKind()) {
749   case APIRecord::RK_Unknown:
750     llvm_unreachable("Records should have a known kind!");
751   case APIRecord::RK_GlobalFunction:
752     serializeGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
753     break;
754   case APIRecord::RK_GlobalVariable:
755     serializeGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
756     break;
757   case APIRecord::RK_Enum:
758     serializeEnumRecord(*cast<EnumRecord>(Record));
759     break;
760   case APIRecord::RK_Struct:
761     serializeStructRecord(*cast<StructRecord>(Record));
762     break;
763   case APIRecord::RK_ObjCInterface:
764     serializeObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
765     break;
766   case APIRecord::RK_ObjCProtocol:
767     serializeObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
768     break;
769   case APIRecord::RK_MacroDefinition:
770     serializeMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
771     break;
772   case APIRecord::RK_Typedef:
773     serializeTypedefRecord(*cast<TypedefRecord>(Record));
774     break;
775   default:
776     if (auto Obj = serializeAPIRecord(*Record)) {
777       Symbols.emplace_back(std::move(*Obj));
778       auto &ParentInformation = Record->ParentInformation;
779       if (!ParentInformation.empty())
780         serializeRelationship(RelationshipKind::MemberOf, *Record,
781                               *ParentInformation.ParentRecord);
782     }
783     break;
784   }
785 }
786 
787 void SymbolGraphSerializer::serializeTypedefRecord(
788     const TypedefRecord &Record) {
789   // Typedefs of anonymous types have their entries unified with the underlying
790   // type.
791   bool ShouldDrop = Record.UnderlyingType.Name.empty();
792   // enums declared with `NS_OPTION` have a named enum and a named typedef, with
793   // the same name
794   ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
795   if (ShouldDrop)
796     return;
797 
798   auto Typedef = serializeAPIRecord(Record);
799   if (!Typedef)
800     return;
801 
802   (*Typedef)["type"] = Record.UnderlyingType.USR;
803 
804   Symbols.emplace_back(std::move(*Typedef));
805 }
806 
807 Object SymbolGraphSerializer::serialize() {
808   // Serialize global variables in the API set.
809   for (const auto &GlobalVar : API.getGlobalVariables())
810     serializeGlobalVariableRecord(*GlobalVar.second);
811 
812   for (const auto &GlobalFunction : API.getGlobalFunctions())
813     serializeGlobalFunctionRecord(*GlobalFunction.second);
814 
815   // Serialize enum records in the API set.
816   for (const auto &Enum : API.getEnums())
817     serializeEnumRecord(*Enum.second);
818 
819   // Serialize struct records in the API set.
820   for (const auto &Struct : API.getStructs())
821     serializeStructRecord(*Struct.second);
822 
823   // Serialize Objective-C interface records in the API set.
824   for (const auto &ObjCInterface : API.getObjCInterfaces())
825     serializeObjCContainerRecord(*ObjCInterface.second);
826 
827   // Serialize Objective-C protocol records in the API set.
828   for (const auto &ObjCProtocol : API.getObjCProtocols())
829     serializeObjCContainerRecord(*ObjCProtocol.second);
830 
831   for (const auto &Macro : API.getMacros())
832     serializeMacroDefinitionRecord(*Macro.second);
833 
834   for (const auto &Typedef : API.getTypedefs())
835     serializeTypedefRecord(*Typedef.second);
836 
837   return serializeCurrentGraph();
838 }
839 
840 Object SymbolGraphSerializer::serializeCurrentGraph() {
841   Object Root;
842   serializeObject(Root, "metadata", serializeMetadata());
843   serializeObject(Root, "module", serializeModule());
844 
845   Root["symbols"] = std::move(Symbols);
846   Root["relationships"] = std::move(Relationships);
847 
848   return Root;
849 }
850 
851 void SymbolGraphSerializer::serialize(raw_ostream &os) {
852   Object root = serialize();
853   if (Options.Compact)
854     os << formatv("{0}", Value(std::move(root))) << "\n";
855   else
856     os << formatv("{0:2}", Value(std::move(root))) << "\n";
857 }
858 
859 Optional<Object>
860 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
861                                                 const APISet &API) {
862   APIRecord *Record = API.findRecordForUSR(USR);
863   if (!Record)
864     return {};
865 
866   Object Root;
867   APIIgnoresList EmptyIgnores;
868   SymbolGraphSerializer Serializer(API, EmptyIgnores,
869                                    /*Options.Compact*/ {true},
870                                    /*ShouldRecurse*/ false);
871   Serializer.serializeSingleRecord(Record);
872   serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
873 
874   Language Lang = API.getLanguage();
875   serializeArray(Root, "parentContexts",
876                  generateParentContexts(*Record, API, Lang));
877 
878   Array RelatedSymbols;
879 
880   for (const auto &Fragment : Record->Declaration.getFragments()) {
881     // If we don't have a USR there isn't much we can do.
882     if (Fragment.PreciseIdentifier.empty())
883       continue;
884 
885     APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
886 
887     // If we can't find the record let's skip.
888     if (!RelatedRecord)
889       continue;
890 
891     Object RelatedSymbol;
892     RelatedSymbol["usr"] = RelatedRecord->USR;
893     RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
894     // TODO: once we record this properly let's serialize it right.
895     RelatedSymbol["accessLevel"] = "public";
896     RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
897     RelatedSymbol["moduleName"] = API.ProductName;
898     RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
899 
900     serializeArray(RelatedSymbol, "parentContexts",
901                    generateParentContexts(*RelatedRecord, API, Lang));
902     RelatedSymbols.push_back(std::move(RelatedSymbol));
903   }
904 
905   serializeArray(Root, "relatedSymbols", RelatedSymbols);
906   return Root;
907 }
908