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