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/DeclarationFragments.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/STLFunctionalExtras.h"
21 #include "llvm/ADT/SmallVector.h"
22 #include "llvm/Support/Casting.h"
23 #include "llvm/Support/Compiler.h"
24 #include "llvm/Support/Path.h"
25 #include "llvm/Support/VersionTuple.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <iterator>
28 #include <optional>
29 #include <type_traits>
30
31 using namespace clang;
32 using namespace clang::extractapi;
33 using namespace llvm;
34
35 namespace {
36
37 /// Helper function to inject a JSON object \p Obj into another object \p Paren
38 /// at position \p Key.
serializeObject(Object & Paren,StringRef Key,std::optional<Object> && Obj)39 void serializeObject(Object &Paren, StringRef Key,
40 std::optional<Object> &&Obj) {
41 if (Obj)
42 Paren[Key] = std::move(*Obj);
43 }
44
45 /// Helper function to inject a JSON array \p Array into object \p Paren at
46 /// position \p Key.
serializeArray(Object & Paren,StringRef Key,std::optional<Array> && Array)47 void serializeArray(Object &Paren, StringRef Key,
48 std::optional<Array> &&Array) {
49 if (Array)
50 Paren[Key] = std::move(*Array);
51 }
52
53 /// Helper function to inject a JSON array composed of the values in \p C into
54 /// object \p Paren at position \p Key.
55 template <typename ContainerTy>
serializeArray(Object & Paren,StringRef Key,ContainerTy && C)56 void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) {
57 Paren[Key] = Array(C);
58 }
59
60 /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
61 /// format.
62 ///
63 /// A semantic version object contains three numeric fields, representing the
64 /// \c major, \c minor, and \c patch parts of the version tuple.
65 /// For example version tuple 1.0.3 is serialized as:
66 /// \code
67 /// {
68 /// "major" : 1,
69 /// "minor" : 0,
70 /// "patch" : 3
71 /// }
72 /// \endcode
73 ///
74 /// \returns \c std::nullopt if the version \p V is empty, or an \c Object
75 /// containing the semantic version representation of \p V.
serializeSemanticVersion(const VersionTuple & V)76 std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
77 if (V.empty())
78 return std::nullopt;
79
80 Object Version;
81 Version["major"] = V.getMajor();
82 Version["minor"] = V.getMinor().value_or(0);
83 Version["patch"] = V.getSubminor().value_or(0);
84 return Version;
85 }
86
87 /// Serialize the OS information in the Symbol Graph platform property.
88 ///
89 /// The OS information in Symbol Graph contains the \c name of the OS, and an
90 /// optional \c minimumVersion semantic version field.
serializeOperatingSystem(const Triple & T)91 Object serializeOperatingSystem(const Triple &T) {
92 Object OS;
93 OS["name"] = T.getOSTypeName(T.getOS());
94 serializeObject(OS, "minimumVersion",
95 serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
96 return OS;
97 }
98
99 /// Serialize the platform information in the Symbol Graph module section.
100 ///
101 /// The platform object describes a target platform triple in corresponding
102 /// three fields: \c architecture, \c vendor, and \c operatingSystem.
serializePlatform(const Triple & T)103 Object serializePlatform(const Triple &T) {
104 Object Platform;
105 Platform["architecture"] = T.getArchName();
106 Platform["vendor"] = T.getVendorName();
107 Platform["operatingSystem"] = serializeOperatingSystem(T);
108 return Platform;
109 }
110
111 /// Serialize a source position.
serializeSourcePosition(const PresumedLoc & Loc)112 Object serializeSourcePosition(const PresumedLoc &Loc) {
113 assert(Loc.isValid() && "invalid source position");
114
115 Object SourcePosition;
116 SourcePosition["line"] = Loc.getLine() - 1;
117 SourcePosition["character"] = Loc.getColumn() - 1;
118
119 return SourcePosition;
120 }
121
122 /// Serialize a source location in file.
123 ///
124 /// \param Loc The presumed location to serialize.
125 /// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
126 /// Defaults to false.
serializeSourceLocation(const PresumedLoc & Loc,bool IncludeFileURI=false)127 Object serializeSourceLocation(const PresumedLoc &Loc,
128 bool IncludeFileURI = false) {
129 Object SourceLocation;
130 serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
131
132 if (IncludeFileURI) {
133 std::string FileURI = "file://";
134 // Normalize file path to use forward slashes for the URI.
135 FileURI += sys::path::convert_to_slash(Loc.getFilename());
136 SourceLocation["uri"] = FileURI;
137 }
138
139 return SourceLocation;
140 }
141
142 /// Serialize a source range with begin and end locations.
serializeSourceRange(const PresumedLoc & BeginLoc,const PresumedLoc & EndLoc)143 Object serializeSourceRange(const PresumedLoc &BeginLoc,
144 const PresumedLoc &EndLoc) {
145 Object SourceRange;
146 serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
147 serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
148 return SourceRange;
149 }
150
151 /// Serialize the availability attributes of a symbol.
152 ///
153 /// Availability information contains the introduced, deprecated, and obsoleted
154 /// versions of the symbol as semantic versions, if not default.
155 /// Availability information also contains flags to indicate if the symbol is
156 /// unconditionally unavailable or deprecated,
157 /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)).
158 ///
159 /// \returns \c std::nullopt if the symbol has default availability attributes,
160 /// or an \c Array containing an object with the formatted availability
161 /// information.
serializeAvailability(const AvailabilityInfo & Avail)162 std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) {
163 if (Avail.isDefault())
164 return std::nullopt;
165
166 Array AvailabilityArray;
167
168 if (Avail.isUnconditionallyDeprecated()) {
169 Object UnconditionallyDeprecated;
170 UnconditionallyDeprecated["domain"] = "*";
171 UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
172 AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
173 }
174 Object Availability;
175
176 Availability["domain"] = Avail.Domain;
177
178 if (Avail.isUnavailable()) {
179 Availability["isUnconditionallyUnavailable"] = true;
180 } else {
181 serializeObject(Availability, "introduced",
182 serializeSemanticVersion(Avail.Introduced));
183 serializeObject(Availability, "deprecated",
184 serializeSemanticVersion(Avail.Deprecated));
185 serializeObject(Availability, "obsoleted",
186 serializeSemanticVersion(Avail.Obsoleted));
187 }
188
189 AvailabilityArray.emplace_back(std::move(Availability));
190 return AvailabilityArray;
191 }
192
193 /// Get the language name string for interface language references.
getLanguageName(Language Lang)194 StringRef getLanguageName(Language Lang) {
195 switch (Lang) {
196 case Language::C:
197 return "c";
198 case Language::ObjC:
199 return "objective-c";
200 case Language::CXX:
201 return "c++";
202 case Language::ObjCXX:
203 return "objective-c++";
204
205 // Unsupported language currently
206 case Language::OpenCL:
207 case Language::OpenCLCXX:
208 case Language::CUDA:
209 case Language::RenderScript:
210 case Language::HIP:
211 case Language::HLSL:
212
213 // Languages that the frontend cannot parse and compile
214 case Language::Unknown:
215 case Language::Asm:
216 case Language::LLVM_IR:
217 case Language::CIR:
218 llvm_unreachable("Unsupported language kind");
219 }
220
221 llvm_unreachable("Unhandled language kind");
222 }
223
224 /// Serialize the identifier object as specified by the Symbol Graph format.
225 ///
226 /// The identifier property of a symbol contains the USR for precise and unique
227 /// references, and the interface language name.
serializeIdentifier(const APIRecord & Record,Language Lang)228 Object serializeIdentifier(const APIRecord &Record, Language Lang) {
229 Object Identifier;
230 Identifier["precise"] = Record.USR;
231 Identifier["interfaceLanguage"] = getLanguageName(Lang);
232
233 return Identifier;
234 }
235
236 /// Serialize the documentation comments attached to a symbol, as specified by
237 /// the Symbol Graph format.
238 ///
239 /// The Symbol Graph \c docComment object contains an array of lines. Each line
240 /// represents one line of striped documentation comment, with source range
241 /// information.
242 /// e.g.
243 /// \code
244 /// /// This is a documentation comment
245 /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line.
246 /// /// with multiple lines.
247 /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line.
248 /// \endcode
249 ///
250 /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
251 /// the formatted lines.
serializeDocComment(const DocComment & Comment)252 std::optional<Object> serializeDocComment(const DocComment &Comment) {
253 if (Comment.empty())
254 return std::nullopt;
255
256 Object DocComment;
257
258 Array LinesArray;
259 for (const auto &CommentLine : Comment) {
260 Object Line;
261 Line["text"] = CommentLine.Text;
262 serializeObject(Line, "range",
263 serializeSourceRange(CommentLine.Begin, CommentLine.End));
264 LinesArray.emplace_back(std::move(Line));
265 }
266
267 serializeArray(DocComment, "lines", std::move(LinesArray));
268
269 return DocComment;
270 }
271
272 /// Serialize the declaration fragments of a symbol.
273 ///
274 /// The Symbol Graph declaration fragments is an array of tagged important
275 /// parts of a symbol's declaration. The fragments sequence can be joined to
276 /// form spans of declaration text, with attached information useful for
277 /// purposes like syntax-highlighting etc. For example:
278 /// \code
279 /// const int pi; -> "declarationFragments" : [
280 /// {
281 /// "kind" : "keyword",
282 /// "spelling" : "const"
283 /// },
284 /// {
285 /// "kind" : "text",
286 /// "spelling" : " "
287 /// },
288 /// {
289 /// "kind" : "typeIdentifier",
290 /// "preciseIdentifier" : "c:I",
291 /// "spelling" : "int"
292 /// },
293 /// {
294 /// "kind" : "text",
295 /// "spelling" : " "
296 /// },
297 /// {
298 /// "kind" : "identifier",
299 /// "spelling" : "pi"
300 /// }
301 /// ]
302 /// \endcode
303 ///
304 /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
305 /// formatted declaration fragments array.
306 std::optional<Array>
serializeDeclarationFragments(const DeclarationFragments & DF)307 serializeDeclarationFragments(const DeclarationFragments &DF) {
308 if (DF.getFragments().empty())
309 return std::nullopt;
310
311 Array Fragments;
312 for (const auto &F : DF.getFragments()) {
313 Object Fragment;
314 Fragment["spelling"] = F.Spelling;
315 Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
316 if (!F.PreciseIdentifier.empty())
317 Fragment["preciseIdentifier"] = F.PreciseIdentifier;
318 Fragments.emplace_back(std::move(Fragment));
319 }
320
321 return Fragments;
322 }
323
324 /// Serialize the \c names field of a symbol as specified by the Symbol Graph
325 /// format.
326 ///
327 /// The Symbol Graph names field contains multiple representations of a symbol
328 /// that can be used for different applications:
329 /// - \c title : The simple declared name of the symbol;
330 /// - \c subHeading : An array of declaration fragments that provides tags,
331 /// and potentially more tokens (for example the \c +/- symbol for
332 /// Objective-C methods). Can be used as sub-headings for documentation.
serializeNames(const APIRecord * Record)333 Object serializeNames(const APIRecord *Record) {
334 Object Names;
335 Names["title"] = Record->Name;
336
337 serializeArray(Names, "subHeading",
338 serializeDeclarationFragments(Record->SubHeading));
339 DeclarationFragments NavigatorFragments;
340 NavigatorFragments.append(Record->Name,
341 DeclarationFragments::FragmentKind::Identifier,
342 /*PreciseIdentifier*/ "");
343 serializeArray(Names, "navigator",
344 serializeDeclarationFragments(NavigatorFragments));
345
346 return Names;
347 }
348
serializeSymbolKind(APIRecord::RecordKind RK,Language Lang)349 Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
350 auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
351 return (getLanguageName(Lang) + "." + S).str();
352 };
353
354 Object Kind;
355 switch (RK) {
356 case APIRecord::RK_Unknown:
357 Kind["identifier"] = AddLangPrefix("unknown");
358 Kind["displayName"] = "Unknown";
359 break;
360 case APIRecord::RK_Namespace:
361 Kind["identifier"] = AddLangPrefix("namespace");
362 Kind["displayName"] = "Namespace";
363 break;
364 case APIRecord::RK_GlobalFunction:
365 Kind["identifier"] = AddLangPrefix("func");
366 Kind["displayName"] = "Function";
367 break;
368 case APIRecord::RK_GlobalFunctionTemplate:
369 Kind["identifier"] = AddLangPrefix("func");
370 Kind["displayName"] = "Function Template";
371 break;
372 case APIRecord::RK_GlobalFunctionTemplateSpecialization:
373 Kind["identifier"] = AddLangPrefix("func");
374 Kind["displayName"] = "Function Template Specialization";
375 break;
376 case APIRecord::RK_GlobalVariableTemplate:
377 Kind["identifier"] = AddLangPrefix("var");
378 Kind["displayName"] = "Global Variable Template";
379 break;
380 case APIRecord::RK_GlobalVariableTemplateSpecialization:
381 Kind["identifier"] = AddLangPrefix("var");
382 Kind["displayName"] = "Global Variable Template Specialization";
383 break;
384 case APIRecord::RK_GlobalVariableTemplatePartialSpecialization:
385 Kind["identifier"] = AddLangPrefix("var");
386 Kind["displayName"] = "Global Variable Template Partial Specialization";
387 break;
388 case APIRecord::RK_GlobalVariable:
389 Kind["identifier"] = AddLangPrefix("var");
390 Kind["displayName"] = "Global Variable";
391 break;
392 case APIRecord::RK_EnumConstant:
393 Kind["identifier"] = AddLangPrefix("enum.case");
394 Kind["displayName"] = "Enumeration Case";
395 break;
396 case APIRecord::RK_Enum:
397 Kind["identifier"] = AddLangPrefix("enum");
398 Kind["displayName"] = "Enumeration";
399 break;
400 case APIRecord::RK_StructField:
401 Kind["identifier"] = AddLangPrefix("property");
402 Kind["displayName"] = "Instance Property";
403 break;
404 case APIRecord::RK_Struct:
405 Kind["identifier"] = AddLangPrefix("struct");
406 Kind["displayName"] = "Structure";
407 break;
408 case APIRecord::RK_UnionField:
409 Kind["identifier"] = AddLangPrefix("property");
410 Kind["displayName"] = "Instance Property";
411 break;
412 case APIRecord::RK_Union:
413 Kind["identifier"] = AddLangPrefix("union");
414 Kind["displayName"] = "Union";
415 break;
416 case APIRecord::RK_CXXField:
417 Kind["identifier"] = AddLangPrefix("property");
418 Kind["displayName"] = "Instance Property";
419 break;
420 case APIRecord::RK_StaticField:
421 Kind["identifier"] = AddLangPrefix("type.property");
422 Kind["displayName"] = "Type Property";
423 break;
424 case APIRecord::RK_ClassTemplate:
425 case APIRecord::RK_ClassTemplateSpecialization:
426 case APIRecord::RK_ClassTemplatePartialSpecialization:
427 case APIRecord::RK_CXXClass:
428 Kind["identifier"] = AddLangPrefix("class");
429 Kind["displayName"] = "Class";
430 break;
431 case APIRecord::RK_CXXMethodTemplate:
432 Kind["identifier"] = AddLangPrefix("method");
433 Kind["displayName"] = "Method Template";
434 break;
435 case APIRecord::RK_CXXMethodTemplateSpecialization:
436 Kind["identifier"] = AddLangPrefix("method");
437 Kind["displayName"] = "Method Template Specialization";
438 break;
439 case APIRecord::RK_CXXFieldTemplate:
440 Kind["identifier"] = AddLangPrefix("property");
441 Kind["displayName"] = "Template Property";
442 break;
443 case APIRecord::RK_Concept:
444 Kind["identifier"] = AddLangPrefix("concept");
445 Kind["displayName"] = "Concept";
446 break;
447 case APIRecord::RK_CXXStaticMethod:
448 Kind["identifier"] = AddLangPrefix("type.method");
449 Kind["displayName"] = "Static Method";
450 break;
451 case APIRecord::RK_CXXInstanceMethod:
452 Kind["identifier"] = AddLangPrefix("method");
453 Kind["displayName"] = "Instance Method";
454 break;
455 case APIRecord::RK_CXXConstructorMethod:
456 Kind["identifier"] = AddLangPrefix("method");
457 Kind["displayName"] = "Constructor";
458 break;
459 case APIRecord::RK_CXXDestructorMethod:
460 Kind["identifier"] = AddLangPrefix("method");
461 Kind["displayName"] = "Destructor";
462 break;
463 case APIRecord::RK_ObjCIvar:
464 Kind["identifier"] = AddLangPrefix("ivar");
465 Kind["displayName"] = "Instance Variable";
466 break;
467 case APIRecord::RK_ObjCInstanceMethod:
468 Kind["identifier"] = AddLangPrefix("method");
469 Kind["displayName"] = "Instance Method";
470 break;
471 case APIRecord::RK_ObjCClassMethod:
472 Kind["identifier"] = AddLangPrefix("type.method");
473 Kind["displayName"] = "Type Method";
474 break;
475 case APIRecord::RK_ObjCInstanceProperty:
476 Kind["identifier"] = AddLangPrefix("property");
477 Kind["displayName"] = "Instance Property";
478 break;
479 case APIRecord::RK_ObjCClassProperty:
480 Kind["identifier"] = AddLangPrefix("type.property");
481 Kind["displayName"] = "Type Property";
482 break;
483 case APIRecord::RK_ObjCInterface:
484 Kind["identifier"] = AddLangPrefix("class");
485 Kind["displayName"] = "Class";
486 break;
487 case APIRecord::RK_ObjCCategory:
488 Kind["identifier"] = AddLangPrefix("class.extension");
489 Kind["displayName"] = "Class Extension";
490 break;
491 case APIRecord::RK_ObjCProtocol:
492 Kind["identifier"] = AddLangPrefix("protocol");
493 Kind["displayName"] = "Protocol";
494 break;
495 case APIRecord::RK_MacroDefinition:
496 Kind["identifier"] = AddLangPrefix("macro");
497 Kind["displayName"] = "Macro";
498 break;
499 case APIRecord::RK_Typedef:
500 Kind["identifier"] = AddLangPrefix("typealias");
501 Kind["displayName"] = "Type Alias";
502 break;
503 default:
504 llvm_unreachable("API Record with uninstantiable kind");
505 }
506
507 return Kind;
508 }
509
510 /// Serialize the symbol kind information.
511 ///
512 /// The Symbol Graph symbol kind property contains a shorthand \c identifier
513 /// which is prefixed by the source language name, useful for tooling to parse
514 /// the kind, and a \c displayName for rendering human-readable names.
serializeSymbolKind(const APIRecord & Record,Language Lang)515 Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
516 return serializeSymbolKind(Record.KindForDisplay, Lang);
517 }
518
519 /// Serialize the function signature field, as specified by the
520 /// Symbol Graph format.
521 ///
522 /// The Symbol Graph function signature property contains two arrays.
523 /// - The \c returns array is the declaration fragments of the return type;
524 /// - The \c parameters array contains names and declaration fragments of the
525 /// parameters.
526 template <typename RecordTy>
serializeFunctionSignatureMixin(Object & Paren,const RecordTy & Record)527 void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
528 const auto &FS = Record.Signature;
529 if (FS.empty())
530 return;
531
532 Object Signature;
533 serializeArray(Signature, "returns",
534 serializeDeclarationFragments(FS.getReturnType()));
535
536 Array Parameters;
537 for (const auto &P : FS.getParameters()) {
538 Object Parameter;
539 Parameter["name"] = P.Name;
540 serializeArray(Parameter, "declarationFragments",
541 serializeDeclarationFragments(P.Fragments));
542 Parameters.emplace_back(std::move(Parameter));
543 }
544
545 if (!Parameters.empty())
546 Signature["parameters"] = std::move(Parameters);
547
548 serializeObject(Paren, "functionSignature", std::move(Signature));
549 }
550
551 template <typename RecordTy>
serializeTemplateMixin(Object & Paren,const RecordTy & Record)552 void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
553 const auto &Template = Record.Templ;
554 if (Template.empty())
555 return;
556
557 Object Generics;
558 Array GenericParameters;
559 for (const auto &Param : Template.getParameters()) {
560 Object Parameter;
561 Parameter["name"] = Param.Name;
562 Parameter["index"] = Param.Index;
563 Parameter["depth"] = Param.Depth;
564 GenericParameters.emplace_back(std::move(Parameter));
565 }
566 if (!GenericParameters.empty())
567 Generics["parameters"] = std::move(GenericParameters);
568
569 Array GenericConstraints;
570 for (const auto &Constr : Template.getConstraints()) {
571 Object Constraint;
572 Constraint["kind"] = Constr.Kind;
573 Constraint["lhs"] = Constr.LHS;
574 Constraint["rhs"] = Constr.RHS;
575 GenericConstraints.emplace_back(std::move(Constraint));
576 }
577
578 if (!GenericConstraints.empty())
579 Generics["constraints"] = std::move(GenericConstraints);
580
581 serializeObject(Paren, "swiftGenerics", Generics);
582 }
583
generateParentContexts(const SmallVectorImpl<SymbolReference> & Parents,Language Lang)584 Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents,
585 Language Lang) {
586 Array ParentContexts;
587
588 for (const auto &Parent : Parents) {
589 Object Elem;
590 Elem["usr"] = Parent.USR;
591 Elem["name"] = Parent.Name;
592 if (Parent.Record)
593 Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay,
594 Lang)["identifier"];
595 else
596 Elem["kind"] =
597 serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"];
598 ParentContexts.emplace_back(std::move(Elem));
599 }
600
601 return ParentContexts;
602 }
603
604 /// Walk the records parent information in reverse to generate a hierarchy
605 /// suitable for serialization.
606 SmallVector<SymbolReference, 8>
generateHierarchyFromRecord(const APIRecord * Record)607 generateHierarchyFromRecord(const APIRecord *Record) {
608 SmallVector<SymbolReference, 8> ReverseHierarchy;
609 for (const auto *Current = Record; Current != nullptr;
610 Current = Current->Parent.Record)
611 ReverseHierarchy.emplace_back(Current);
612
613 return SmallVector<SymbolReference, 8>(
614 std::make_move_iterator(ReverseHierarchy.rbegin()),
615 std::make_move_iterator(ReverseHierarchy.rend()));
616 }
617
getHierarchyReference(const APIRecord * Record,const APISet & API)618 SymbolReference getHierarchyReference(const APIRecord *Record,
619 const APISet &API) {
620 // If the parent is a category extended from internal module then we need to
621 // pretend this belongs to the associated interface.
622 if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) {
623 return CategoryRecord->Interface;
624 // FIXME: TODO generate path components correctly for categories extending
625 // an external module.
626 }
627
628 return SymbolReference(Record);
629 }
630
631 } // namespace
632
addSymbol(Object && Symbol)633 Object *ExtendedModule::addSymbol(Object &&Symbol) {
634 Symbols.emplace_back(std::move(Symbol));
635 return Symbols.back().getAsObject();
636 }
637
addRelationship(Object && Relationship)638 void ExtendedModule::addRelationship(Object &&Relationship) {
639 Relationships.emplace_back(std::move(Relationship));
640 }
641
642 /// Defines the format version emitted by SymbolGraphSerializer.
643 const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
644
serializeMetadata() const645 Object SymbolGraphSerializer::serializeMetadata() const {
646 Object Metadata;
647 serializeObject(Metadata, "formatVersion",
648 serializeSemanticVersion(FormatVersion));
649 Metadata["generator"] = clang::getClangFullVersion();
650 return Metadata;
651 }
652
653 Object
serializeModuleObject(StringRef ModuleName) const654 SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const {
655 Object Module;
656 Module["name"] = ModuleName;
657 serializeObject(Module, "platform", serializePlatform(API.getTarget()));
658 return Module;
659 }
660
shouldSkip(const APIRecord * Record) const661 bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {
662 if (!Record)
663 return true;
664
665 // Skip unconditionally unavailable symbols
666 if (Record->Availability.isUnconditionallyUnavailable())
667 return true;
668
669 // Filter out symbols without a name as we can generate correct symbol graphs
670 // for them. In practice these are anonymous record types that aren't attached
671 // to a declaration.
672 if (auto *Tag = dyn_cast<TagRecord>(Record)) {
673 if (Tag->IsEmbeddedInVarDeclarator)
674 return true;
675 }
676
677 // Filter out symbols prefixed with an underscored as they are understood to
678 // be symbols clients should not use.
679 if (Record->Name.starts_with("_"))
680 return true;
681
682 // Skip explicitly ignored symbols.
683 if (IgnoresList.shouldIgnore(Record->Name))
684 return true;
685
686 return false;
687 }
688
getModuleForCurrentSymbol()689 ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {
690 if (!ForceEmitToMainModule && ModuleForCurrentSymbol)
691 return *ModuleForCurrentSymbol;
692
693 return MainModule;
694 }
695
serializePathComponents(const APIRecord * Record) const696 Array SymbolGraphSerializer::serializePathComponents(
697 const APIRecord *Record) const {
698 return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));
699 }
700
getRelationshipString(RelationshipKind Kind)701 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
702 switch (Kind) {
703 case RelationshipKind::MemberOf:
704 return "memberOf";
705 case RelationshipKind::InheritsFrom:
706 return "inheritsFrom";
707 case RelationshipKind::ConformsTo:
708 return "conformsTo";
709 case RelationshipKind::ExtensionTo:
710 return "extensionTo";
711 }
712 llvm_unreachable("Unhandled relationship kind");
713 }
714
serializeRelationship(RelationshipKind Kind,const SymbolReference & Source,const SymbolReference & Target,ExtendedModule & Into)715 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
716 const SymbolReference &Source,
717 const SymbolReference &Target,
718 ExtendedModule &Into) {
719 Object Relationship;
720 SmallString<64> TestRelLabel;
721 if (EmitSymbolLabelsForTesting) {
722 llvm::raw_svector_ostream OS(TestRelLabel);
723 OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ "
724 << Source.USR << " $ ";
725 if (Target.USR.empty())
726 OS << Target.Name;
727 else
728 OS << Target.USR;
729 Relationship["!testRelLabel"] = TestRelLabel;
730 }
731 Relationship["source"] = Source.USR;
732 Relationship["target"] = Target.USR;
733 Relationship["targetFallback"] = Target.Name;
734 Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind);
735
736 if (ForceEmitToMainModule)
737 MainModule.addRelationship(std::move(Relationship));
738 else
739 Into.addRelationship(std::move(Relationship));
740 }
741
getConstraintString(ConstraintKind Kind)742 StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
743 switch (Kind) {
744 case ConstraintKind::Conformance:
745 return "conformance";
746 case ConstraintKind::ConditionalConformance:
747 return "conditionalConformance";
748 }
749 llvm_unreachable("Unhandled constraint kind");
750 }
751
serializeAPIRecord(const APIRecord * Record)752 void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) {
753 Object Obj;
754
755 // If we need symbol labels for testing emit the USR as the value and the key
756 // starts with '!'' to ensure it ends up at the top of the object.
757 if (EmitSymbolLabelsForTesting)
758 Obj["!testLabel"] = Record->USR;
759
760 serializeObject(Obj, "identifier",
761 serializeIdentifier(*Record, API.getLanguage()));
762 serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage()));
763 serializeObject(Obj, "names", serializeNames(Record));
764 serializeObject(
765 Obj, "location",
766 serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true));
767 serializeArray(Obj, "availability",
768 serializeAvailability(Record->Availability));
769 serializeObject(Obj, "docComment", serializeDocComment(Record->Comment));
770 serializeArray(Obj, "declarationFragments",
771 serializeDeclarationFragments(Record->Declaration));
772
773 Obj["pathComponents"] = serializePathComponents(Record);
774 Obj["accessLevel"] = Record->Access.getAccess();
775
776 ExtendedModule &Module = getModuleForCurrentSymbol();
777 // If the hierarchy has at least one parent and child.
778 if (Hierarchy.size() >= 2)
779 serializeRelationship(MemberOf, Hierarchy.back(),
780 Hierarchy[Hierarchy.size() - 2], Module);
781
782 CurrentSymbol = Module.addSymbol(std::move(Obj));
783 }
784
traverseAPIRecord(const APIRecord * Record)785 bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) {
786 if (!Record)
787 return true;
788 if (shouldSkip(Record))
789 return true;
790 Hierarchy.push_back(getHierarchyReference(Record, API));
791 // Defer traversal mechanics to APISetVisitor base implementation
792 auto RetVal = Base::traverseAPIRecord(Record);
793 Hierarchy.pop_back();
794 return RetVal;
795 }
796
visitAPIRecord(const APIRecord * Record)797 bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) {
798 serializeAPIRecord(Record);
799 return true;
800 }
801
visitGlobalFunctionRecord(const GlobalFunctionRecord * Record)802 bool SymbolGraphSerializer::visitGlobalFunctionRecord(
803 const GlobalFunctionRecord *Record) {
804 if (!CurrentSymbol)
805 return true;
806
807 serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
808 return true;
809 }
810
visitCXXClassRecord(const CXXClassRecord * Record)811 bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) {
812 if (!CurrentSymbol)
813 return true;
814
815 for (const auto &Base : Record->Bases)
816 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base,
817 getModuleForCurrentSymbol());
818 return true;
819 }
820
visitClassTemplateRecord(const ClassTemplateRecord * Record)821 bool SymbolGraphSerializer::visitClassTemplateRecord(
822 const ClassTemplateRecord *Record) {
823 if (!CurrentSymbol)
824 return true;
825
826 serializeTemplateMixin(*CurrentSymbol, *Record);
827 return true;
828 }
829
visitClassTemplatePartialSpecializationRecord(const ClassTemplatePartialSpecializationRecord * Record)830 bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(
831 const ClassTemplatePartialSpecializationRecord *Record) {
832 if (!CurrentSymbol)
833 return true;
834
835 serializeTemplateMixin(*CurrentSymbol, *Record);
836 return true;
837 }
838
visitCXXMethodRecord(const CXXMethodRecord * Record)839 bool SymbolGraphSerializer::visitCXXMethodRecord(
840 const CXXMethodRecord *Record) {
841 if (!CurrentSymbol)
842 return true;
843
844 serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
845 return true;
846 }
847
visitCXXMethodTemplateRecord(const CXXMethodTemplateRecord * Record)848 bool SymbolGraphSerializer::visitCXXMethodTemplateRecord(
849 const CXXMethodTemplateRecord *Record) {
850 if (!CurrentSymbol)
851 return true;
852
853 serializeTemplateMixin(*CurrentSymbol, *Record);
854 return true;
855 }
856
visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord * Record)857 bool SymbolGraphSerializer::visitCXXFieldTemplateRecord(
858 const CXXFieldTemplateRecord *Record) {
859 if (!CurrentSymbol)
860 return true;
861
862 serializeTemplateMixin(*CurrentSymbol, *Record);
863 return true;
864 }
865
visitConceptRecord(const ConceptRecord * Record)866 bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) {
867 if (!CurrentSymbol)
868 return true;
869
870 serializeTemplateMixin(*CurrentSymbol, *Record);
871 return true;
872 }
873
visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord * Record)874 bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord(
875 const GlobalVariableTemplateRecord *Record) {
876 if (!CurrentSymbol)
877 return true;
878
879 serializeTemplateMixin(*CurrentSymbol, *Record);
880 return true;
881 }
882
883 bool SymbolGraphSerializer::
visitGlobalVariableTemplatePartialSpecializationRecord(const GlobalVariableTemplatePartialSpecializationRecord * Record)884 visitGlobalVariableTemplatePartialSpecializationRecord(
885 const GlobalVariableTemplatePartialSpecializationRecord *Record) {
886 if (!CurrentSymbol)
887 return true;
888
889 serializeTemplateMixin(*CurrentSymbol, *Record);
890 return true;
891 }
892
visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord * Record)893 bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(
894 const GlobalFunctionTemplateRecord *Record) {
895 if (!CurrentSymbol)
896 return true;
897
898 serializeTemplateMixin(*CurrentSymbol, *Record);
899 return true;
900 }
901
visitObjCContainerRecord(const ObjCContainerRecord * Record)902 bool SymbolGraphSerializer::visitObjCContainerRecord(
903 const ObjCContainerRecord *Record) {
904 if (!CurrentSymbol)
905 return true;
906
907 for (const auto &Protocol : Record->Protocols)
908 serializeRelationship(ConformsTo, Record, Protocol,
909 getModuleForCurrentSymbol());
910
911 return true;
912 }
913
visitObjCInterfaceRecord(const ObjCInterfaceRecord * Record)914 bool SymbolGraphSerializer::visitObjCInterfaceRecord(
915 const ObjCInterfaceRecord *Record) {
916 if (!CurrentSymbol)
917 return true;
918
919 if (!Record->SuperClass.empty())
920 serializeRelationship(InheritsFrom, Record, Record->SuperClass,
921 getModuleForCurrentSymbol());
922 return true;
923 }
924
traverseObjCCategoryRecord(const ObjCCategoryRecord * Record)925 bool SymbolGraphSerializer::traverseObjCCategoryRecord(
926 const ObjCCategoryRecord *Record) {
927 if (SkipSymbolsInCategoriesToExternalTypes &&
928 !API.findRecordForUSR(Record->Interface.USR))
929 return true;
930
931 auto *CurrentModule = ModuleForCurrentSymbol;
932 if (Record->isExtendingExternalModule())
933 ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source];
934
935 if (!walkUpFromObjCCategoryRecord(Record))
936 return false;
937
938 bool RetVal = traverseRecordContext(Record);
939 ModuleForCurrentSymbol = CurrentModule;
940 return RetVal;
941 }
942
walkUpFromObjCCategoryRecord(const ObjCCategoryRecord * Record)943 bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord(
944 const ObjCCategoryRecord *Record) {
945 return visitObjCCategoryRecord(Record);
946 }
947
visitObjCCategoryRecord(const ObjCCategoryRecord * Record)948 bool SymbolGraphSerializer::visitObjCCategoryRecord(
949 const ObjCCategoryRecord *Record) {
950 // If we need to create a record for the category in the future do so here,
951 // otherwise everything is set up to pretend that the category is in fact the
952 // interface it extends.
953 for (const auto &Protocol : Record->Protocols)
954 serializeRelationship(ConformsTo, Record->Interface, Protocol,
955 getModuleForCurrentSymbol());
956
957 return true;
958 }
959
visitObjCMethodRecord(const ObjCMethodRecord * Record)960 bool SymbolGraphSerializer::visitObjCMethodRecord(
961 const ObjCMethodRecord *Record) {
962 if (!CurrentSymbol)
963 return true;
964
965 serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
966 return true;
967 }
968
visitObjCInstanceVariableRecord(const ObjCInstanceVariableRecord * Record)969 bool SymbolGraphSerializer::visitObjCInstanceVariableRecord(
970 const ObjCInstanceVariableRecord *Record) {
971 // FIXME: serialize ivar access control here.
972 return true;
973 }
974
walkUpFromTypedefRecord(const TypedefRecord * Record)975 bool SymbolGraphSerializer::walkUpFromTypedefRecord(
976 const TypedefRecord *Record) {
977 // Short-circuit walking up the class hierarchy and handle creating typedef
978 // symbol objects manually as there are additional symbol dropping rules to
979 // respect.
980 return visitTypedefRecord(Record);
981 }
982
visitTypedefRecord(const TypedefRecord * Record)983 bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) {
984 // Typedefs of anonymous types have their entries unified with the underlying
985 // type.
986 bool ShouldDrop = Record->UnderlyingType.Name.empty();
987 // enums declared with `NS_OPTION` have a named enum and a named typedef, with
988 // the same name
989 ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
990 if (ShouldDrop)
991 return true;
992
993 // Create the symbol record if the other symbol droppping rules permit it.
994 serializeAPIRecord(Record);
995 if (!CurrentSymbol)
996 return true;
997
998 (*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
999
1000 return true;
1001 }
1002
serializeSingleRecord(const APIRecord * Record)1003 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1004 switch (Record->getKind()) {
1005 // dispatch to the relevant walkUpFromMethod
1006 #define CONCRETE_RECORD(CLASS, BASE, KIND) \
1007 case APIRecord::KIND: { \
1008 walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \
1009 break; \
1010 }
1011 #include "clang/ExtractAPI/APIRecords.inc"
1012 // otherwise fallback on the only behavior we can implement safely.
1013 case APIRecord::RK_Unknown:
1014 visitAPIRecord(Record);
1015 break;
1016 default:
1017 llvm_unreachable("API Record with uninstantiable kind");
1018 }
1019 }
1020
serializeGraph(StringRef ModuleName,ExtendedModule && EM)1021 Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1022 ExtendedModule &&EM) {
1023 Object Root;
1024 serializeObject(Root, "metadata", serializeMetadata());
1025 serializeObject(Root, "module", serializeModuleObject(ModuleName));
1026
1027 Root["symbols"] = std::move(EM.Symbols);
1028 Root["relationships"] = std::move(EM.Relationships);
1029
1030 return Root;
1031 }
1032
serializeGraphToStream(raw_ostream & OS,SymbolGraphSerializerOption Options,StringRef ModuleName,ExtendedModule && EM)1033 void SymbolGraphSerializer::serializeGraphToStream(
1034 raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1035 ExtendedModule &&EM) {
1036 Object Root = serializeGraph(ModuleName, std::move(EM));
1037 if (Options.Compact)
1038 OS << formatv("{0}", json::Value(std::move(Root))) << "\n";
1039 else
1040 OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n";
1041 }
1042
serializeMainSymbolGraph(raw_ostream & OS,const APISet & API,const APIIgnoresList & IgnoresList,SymbolGraphSerializerOption Options)1043 void SymbolGraphSerializer::serializeMainSymbolGraph(
1044 raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1045 SymbolGraphSerializerOption Options) {
1046 SymbolGraphSerializer Serializer(
1047 API, IgnoresList, Options.EmitSymbolLabelsForTesting,
1048 /*ForceEmitToMainModule=*/true,
1049 /*SkipSymbolsInCategoriesToExternalTypes=*/true);
1050
1051 Serializer.traverseAPISet();
1052 Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1053 std::move(Serializer.MainModule));
1054 // FIXME: TODO handle extended modules here
1055 }
1056
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)1057 void SymbolGraphSerializer::serializeWithExtensionGraphs(
1058 raw_ostream &MainOutput, const APISet &API,
1059 const APIIgnoresList &IgnoresList,
1060 llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1061 CreateOutputStream,
1062 SymbolGraphSerializerOption Options) {
1063 SymbolGraphSerializer Serializer(API, IgnoresList,
1064 Options.EmitSymbolLabelsForTesting);
1065 Serializer.traverseAPISet();
1066
1067 Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1068 std::move(Serializer.MainModule));
1069
1070 for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1071 if (auto ExtensionOS =
1072 CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName))
1073 Serializer.serializeGraphToStream(*ExtensionOS, Options,
1074 ExtensionSGF.getKey(),
1075 std::move(ExtensionSGF.getValue()));
1076 }
1077 }
1078
1079 std::optional<Object>
serializeSingleSymbolSGF(StringRef USR,const APISet & API)1080 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR,
1081 const APISet &API) {
1082 APIRecord *Record = API.findRecordForUSR(USR);
1083 if (!Record)
1084 return {};
1085
1086 Object Root;
1087 APIIgnoresList EmptyIgnores;
1088 SymbolGraphSerializer Serializer(API, EmptyIgnores,
1089 /*EmitSymbolLabelsForTesting*/ false,
1090 /*ForceEmitToMainModule*/ true);
1091
1092 // Set up serializer parent chain
1093 Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1094
1095 Serializer.serializeSingleRecord(Record);
1096 serializeObject(Root, "symbolGraph",
1097 Serializer.serializeGraph(API.ProductName,
1098 std::move(Serializer.MainModule)));
1099
1100 Language Lang = API.getLanguage();
1101 serializeArray(Root, "parentContexts",
1102 generateParentContexts(Serializer.Hierarchy, Lang));
1103
1104 Array RelatedSymbols;
1105
1106 for (const auto &Fragment : Record->Declaration.getFragments()) {
1107 // If we don't have a USR there isn't much we can do.
1108 if (Fragment.PreciseIdentifier.empty())
1109 continue;
1110
1111 APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1112
1113 // If we can't find the record let's skip.
1114 if (!RelatedRecord)
1115 continue;
1116
1117 Object RelatedSymbol;
1118 RelatedSymbol["usr"] = RelatedRecord->USR;
1119 RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1120 RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
1121 RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1122 RelatedSymbol["moduleName"] = API.ProductName;
1123 RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1124
1125 serializeArray(RelatedSymbol, "parentContexts",
1126 generateParentContexts(
1127 generateHierarchyFromRecord(RelatedRecord), Lang));
1128
1129 RelatedSymbols.push_back(std::move(RelatedSymbol));
1130 }
1131
1132 serializeArray(Root, "relatedSymbols", RelatedSymbols);
1133 return Root;
1134 }
1135