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 Array AvailabilityArray;
168
169 if (Avail.isUnconditionallyDeprecated()) {
170 Object UnconditionallyDeprecated;
171 UnconditionallyDeprecated["domain"] = "*";
172 UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
173 AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
174 }
175 Object Availability;
176
177 Availability["domain"] = Avail.Domain;
178
179 if (Avail.isUnavailable()) {
180 Availability["isUnconditionallyUnavailable"] = true;
181 } else {
182 serializeObject(Availability, "introduced",
183 serializeSemanticVersion(Avail.Introduced));
184 serializeObject(Availability, "deprecated",
185 serializeSemanticVersion(Avail.Deprecated));
186 serializeObject(Availability, "obsoleted",
187 serializeSemanticVersion(Avail.Obsoleted));
188 }
189
190 AvailabilityArray.emplace_back(std::move(Availability));
191 return AvailabilityArray;
192}
193
194/// Get the language name string for interface language references.
195StringRef getLanguageName(Language Lang) {
196 switch (Lang) {
197 case Language::C:
198 return "c";
199 case Language::ObjC:
200 return "objective-c";
201 case Language::CXX:
202 return "c++";
203 case Language::ObjCXX:
204 return "objective-c++";
205
206 // Unsupported language currently
207 case Language::OpenCL:
208 case Language::OpenCLCXX:
209 case Language::CUDA:
210 case Language::RenderScript:
211 case Language::HIP:
212 case Language::HLSL:
213
214 // Languages that the frontend cannot parse and compile
215 case Language::Unknown:
216 case Language::Asm:
217 case Language::LLVM_IR:
218 case Language::CIR:
219 llvm_unreachable("Unsupported language kind");
220 }
221
222 llvm_unreachable("Unhandled language kind");
223}
224
225/// Serialize the identifier object as specified by the Symbol Graph format.
226///
227/// The identifier property of a symbol contains the USR for precise and unique
228/// references, and the interface language name.
229Object serializeIdentifier(const APIRecord &Record, Language Lang) {
231 Identifier["precise"] = Record.USR;
232 Identifier["interfaceLanguage"] = getLanguageName(Lang);
233
234 return Identifier;
235}
236
237/// Serialize the documentation comments attached to a symbol, as specified by
238/// the Symbol Graph format.
239///
240/// The Symbol Graph \c docComment object contains an array of lines. Each line
241/// represents one line of striped documentation comment, with source range
242/// information.
243/// e.g.
244/// \code
245/// /// This is a documentation comment
246/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line.
247/// /// with multiple lines.
248/// ^~~~~~~~~~~~~~~~~~~~~~~' Second line.
249/// \endcode
250///
251/// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
252/// the formatted lines.
253std::optional<Object> serializeDocComment(const DocComment &Comment) {
254 if (Comment.empty())
255 return std::nullopt;
256
258
259 Array LinesArray;
260 for (const auto &CommentLine : Comment) {
261 Object Line;
262 Line["text"] = CommentLine.Text;
263 serializeObject(Line, "range",
264 serializeSourceRange(CommentLine.Begin, CommentLine.End));
265 LinesArray.emplace_back(std::move(Line));
266 }
267
268 serializeArray(DocComment, "lines", std::move(LinesArray));
269
270 return DocComment;
271}
272
273/// Serialize the declaration fragments of a symbol.
274///
275/// The Symbol Graph declaration fragments is an array of tagged important
276/// parts of a symbol's declaration. The fragments sequence can be joined to
277/// form spans of declaration text, with attached information useful for
278/// purposes like syntax-highlighting etc. For example:
279/// \code
280/// const int pi; -> "declarationFragments" : [
281/// {
282/// "kind" : "keyword",
283/// "spelling" : "const"
284/// },
285/// {
286/// "kind" : "text",
287/// "spelling" : " "
288/// },
289/// {
290/// "kind" : "typeIdentifier",
291/// "preciseIdentifier" : "c:I",
292/// "spelling" : "int"
293/// },
294/// {
295/// "kind" : "text",
296/// "spelling" : " "
297/// },
298/// {
299/// "kind" : "identifier",
300/// "spelling" : "pi"
301/// }
302/// ]
303/// \endcode
304///
305/// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
306/// formatted declaration fragments array.
307std::optional<Array>
308serializeDeclarationFragments(const DeclarationFragments &DF) {
309 if (DF.getFragments().empty())
310 return std::nullopt;
311
312 Array Fragments;
313 for (const auto &F : DF.getFragments()) {
314 Object Fragment;
315 Fragment["spelling"] = F.Spelling;
316 Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
317 if (!F.PreciseIdentifier.empty())
318 Fragment["preciseIdentifier"] = F.PreciseIdentifier;
319 Fragments.emplace_back(std::move(Fragment));
320 }
321
322 return Fragments;
323}
324
325/// Serialize the \c names field of a symbol as specified by the Symbol Graph
326/// format.
327///
328/// The Symbol Graph names field contains multiple representations of a symbol
329/// that can be used for different applications:
330/// - \c title : The simple declared name of the symbol;
331/// - \c subHeading : An array of declaration fragments that provides tags,
332/// and potentially more tokens (for example the \c +/- symbol for
333/// Objective-C methods). Can be used as sub-headings for documentation.
334Object serializeNames(const APIRecord *Record) {
335 Object Names;
336 Names["title"] = Record->Name;
337
338 serializeArray(Names, "subHeading",
339 serializeDeclarationFragments(Record->SubHeading));
340 DeclarationFragments NavigatorFragments;
341 NavigatorFragments.append(Record->Name,
342 DeclarationFragments::FragmentKind::Identifier,
343 /*PreciseIdentifier*/ "");
344 serializeArray(Names, "navigator",
345 serializeDeclarationFragments(NavigatorFragments));
346
347 return Names;
348}
349
350Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
351 auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
352 return (getLanguageName(Lang) + "." + S).str();
353 };
354
355 Object Kind;
356 switch (RK) {
358 Kind["identifier"] = AddLangPrefix("unknown");
359 Kind["displayName"] = "Unknown";
360 break;
362 Kind["identifier"] = AddLangPrefix("namespace");
363 Kind["displayName"] = "Namespace";
364 break;
366 Kind["identifier"] = AddLangPrefix("func");
367 Kind["displayName"] = "Function";
368 break;
370 Kind["identifier"] = AddLangPrefix("func");
371 Kind["displayName"] = "Function Template";
372 break;
374 Kind["identifier"] = AddLangPrefix("func");
375 Kind["displayName"] = "Function Template Specialization";
376 break;
378 Kind["identifier"] = AddLangPrefix("var");
379 Kind["displayName"] = "Global Variable Template";
380 break;
382 Kind["identifier"] = AddLangPrefix("var");
383 Kind["displayName"] = "Global Variable Template Specialization";
384 break;
386 Kind["identifier"] = AddLangPrefix("var");
387 Kind["displayName"] = "Global Variable Template Partial Specialization";
388 break;
390 Kind["identifier"] = AddLangPrefix("var");
391 Kind["displayName"] = "Global Variable";
392 break;
394 Kind["identifier"] = AddLangPrefix("enum.case");
395 Kind["displayName"] = "Enumeration Case";
396 break;
398 Kind["identifier"] = AddLangPrefix("enum");
399 Kind["displayName"] = "Enumeration";
400 break;
402 Kind["identifier"] = AddLangPrefix("property");
403 Kind["displayName"] = "Instance Property";
404 break;
406 Kind["identifier"] = AddLangPrefix("struct");
407 Kind["displayName"] = "Structure";
408 break;
410 Kind["identifier"] = AddLangPrefix("property");
411 Kind["displayName"] = "Instance Property";
412 break;
414 Kind["identifier"] = AddLangPrefix("union");
415 Kind["displayName"] = "Union";
416 break;
418 Kind["identifier"] = AddLangPrefix("property");
419 Kind["displayName"] = "Instance Property";
420 break;
422 Kind["identifier"] = AddLangPrefix("type.property");
423 Kind["displayName"] = "Type Property";
424 break;
429 Kind["identifier"] = AddLangPrefix("class");
430 Kind["displayName"] = "Class";
431 break;
433 Kind["identifier"] = AddLangPrefix("method");
434 Kind["displayName"] = "Method Template";
435 break;
437 Kind["identifier"] = AddLangPrefix("method");
438 Kind["displayName"] = "Method Template Specialization";
439 break;
441 Kind["identifier"] = AddLangPrefix("property");
442 Kind["displayName"] = "Template Property";
443 break;
445 Kind["identifier"] = AddLangPrefix("concept");
446 Kind["displayName"] = "Concept";
447 break;
449 Kind["identifier"] = AddLangPrefix("type.method");
450 Kind["displayName"] = "Static Method";
451 break;
453 Kind["identifier"] = AddLangPrefix("method");
454 Kind["displayName"] = "Instance Method";
455 break;
457 Kind["identifier"] = AddLangPrefix("method");
458 Kind["displayName"] = "Constructor";
459 break;
461 Kind["identifier"] = AddLangPrefix("method");
462 Kind["displayName"] = "Destructor";
463 break;
465 Kind["identifier"] = AddLangPrefix("ivar");
466 Kind["displayName"] = "Instance Variable";
467 break;
469 Kind["identifier"] = AddLangPrefix("method");
470 Kind["displayName"] = "Instance Method";
471 break;
473 Kind["identifier"] = AddLangPrefix("type.method");
474 Kind["displayName"] = "Type Method";
475 break;
477 Kind["identifier"] = AddLangPrefix("property");
478 Kind["displayName"] = "Instance Property";
479 break;
481 Kind["identifier"] = AddLangPrefix("type.property");
482 Kind["displayName"] = "Type Property";
483 break;
485 Kind["identifier"] = AddLangPrefix("class");
486 Kind["displayName"] = "Class";
487 break;
489 Kind["identifier"] = AddLangPrefix("class.extension");
490 Kind["displayName"] = "Class Extension";
491 break;
493 Kind["identifier"] = AddLangPrefix("protocol");
494 Kind["displayName"] = "Protocol";
495 break;
497 Kind["identifier"] = AddLangPrefix("macro");
498 Kind["displayName"] = "Macro";
499 break;
501 Kind["identifier"] = AddLangPrefix("typealias");
502 Kind["displayName"] = "Type Alias";
503 break;
504 default:
505 llvm_unreachable("API Record with uninstantiable kind");
506 }
507
508 return Kind;
509}
510
511/// Serialize the symbol kind information.
512///
513/// The Symbol Graph symbol kind property contains a shorthand \c identifier
514/// which is prefixed by the source language name, useful for tooling to parse
515/// the kind, and a \c displayName for rendering human-readable names.
516Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
517 return serializeSymbolKind(Record.getKind(), Lang);
518}
519
520/// Serialize the function signature field, as specified by the
521/// Symbol Graph format.
522///
523/// The Symbol Graph function signature property contains two arrays.
524/// - The \c returns array is the declaration fragments of the return type;
525/// - The \c parameters array contains names and declaration fragments of the
526/// parameters.
527template <typename RecordTy>
528void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
529 const auto &FS = Record.Signature;
530 if (FS.empty())
531 return;
532
533 Object Signature;
534 serializeArray(Signature, "returns",
535 serializeDeclarationFragments(FS.getReturnType()));
536
537 Array Parameters;
538 for (const auto &P : FS.getParameters()) {
540 Parameter["name"] = P.Name;
541 serializeArray(Parameter, "declarationFragments",
542 serializeDeclarationFragments(P.Fragments));
543 Parameters.emplace_back(std::move(Parameter));
544 }
545
546 if (!Parameters.empty())
547 Signature["parameters"] = std::move(Parameters);
548
549 serializeObject(Paren, "functionSignature", std::move(Signature));
550}
551
552template <typename RecordTy>
553void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
554 const auto &Template = Record.Templ;
555 if (Template.empty())
556 return;
557
558 Object Generics;
559 Array GenericParameters;
560 for (const auto &Param : Template.getParameters()) {
562 Parameter["name"] = Param.Name;
563 Parameter["index"] = Param.Index;
564 Parameter["depth"] = Param.Depth;
565 GenericParameters.emplace_back(std::move(Parameter));
566 }
567 if (!GenericParameters.empty())
568 Generics["parameters"] = std::move(GenericParameters);
569
570 Array GenericConstraints;
571 for (const auto &Constr : Template.getConstraints()) {
572 Object Constraint;
573 Constraint["kind"] = Constr.Kind;
574 Constraint["lhs"] = Constr.LHS;
575 Constraint["rhs"] = Constr.RHS;
576 GenericConstraints.emplace_back(std::move(Constraint));
577 }
578
579 if (!GenericConstraints.empty())
580 Generics["constraints"] = std::move(GenericConstraints);
581
582 serializeObject(Paren, "swiftGenerics", Generics);
583}
584
585Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents,
586 Language Lang) {
587 Array ParentContexts;
588
589 for (const auto &Parent : Parents) {
590 Object Elem;
591 Elem["usr"] = Parent.USR;
592 Elem["name"] = Parent.Name;
593 if (Parent.Record)
594 Elem["kind"] =
595 serializeSymbolKind(Parent.Record->getKind(), Lang)["identifier"];
596 else
597 Elem["kind"] =
598 serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"];
599 ParentContexts.emplace_back(std::move(Elem));
600 }
601
602 return ParentContexts;
603}
604
605/// Walk the records parent information in reverse to generate a hierarchy
606/// suitable for serialization.
608generateHierarchyFromRecord(const APIRecord *Record) {
609 SmallVector<SymbolReference, 8> ReverseHierarchy;
610 for (const auto *Current = Record; Current != nullptr;
611 Current = Current->Parent.Record)
612 ReverseHierarchy.emplace_back(Current);
613
615 std::make_move_iterator(ReverseHierarchy.rbegin()),
616 std::make_move_iterator(ReverseHierarchy.rend()));
617}
618
619SymbolReference getHierarchyReference(const APIRecord *Record,
620 const APISet &API) {
621 // If the parent is a category extended from internal module then we need to
622 // pretend this belongs to the associated interface.
623 if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) {
624 return CategoryRecord->Interface;
625 // FIXME: TODO generate path components correctly for categories extending
626 // an external module.
627 }
628
629 return SymbolReference(Record);
630}
631
632} // namespace
633
634Object *ExtendedModule::addSymbol(Object &&Symbol) {
635 Symbols.emplace_back(std::move(Symbol));
636 return Symbols.back().getAsObject();
637}
638
639void ExtendedModule::addRelationship(Object &&Relationship) {
640 Relationships.emplace_back(std::move(Relationship));
641}
642
643/// Defines the format version emitted by SymbolGraphSerializer.
644const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
645
646Object SymbolGraphSerializer::serializeMetadata() const {
647 Object Metadata;
648 serializeObject(Metadata, "formatVersion",
649 serializeSemanticVersion(FormatVersion));
650 Metadata["generator"] = clang::getClangFullVersion();
651 return Metadata;
652}
653
654Object
655SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const {
656 Object Module;
657 Module["name"] = ModuleName;
658 serializeObject(Module, "platform", serializePlatform(API.getTarget()));
659 return Module;
660}
661
662bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {
663 if (!Record)
664 return true;
665
666 // Skip unconditionally unavailable symbols
667 if (Record->Availability.isUnconditionallyUnavailable())
668 return true;
669
670 // Filter out symbols without a name as we can generate correct symbol graphs
671 // for them. In practice these are anonymous record types that aren't attached
672 // to a declaration.
673 if (auto *Tag = dyn_cast<TagRecord>(Record)) {
674 if (Tag->IsEmbeddedInVarDeclarator)
675 return true;
676 }
677
678 // Filter out symbols prefixed with an underscored as they are understood to
679 // be symbols clients should not use.
680 if (Record->Name.starts_with("_"))
681 return true;
682
683 // Skip explicitly ignored symbols.
684 if (IgnoresList.shouldIgnore(Record->Name))
685 return true;
686
687 return false;
688}
689
690ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {
691 if (!ForceEmitToMainModule && ModuleForCurrentSymbol)
692 return *ModuleForCurrentSymbol;
693
694 return MainModule;
695}
696
697Array SymbolGraphSerializer::serializePathComponents(
698 const APIRecord *Record) const {
699 return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));
700}
701
702StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) {
703 switch (Kind) {
704 case RelationshipKind::MemberOf:
705 return "memberOf";
706 case RelationshipKind::InheritsFrom:
707 return "inheritsFrom";
708 case RelationshipKind::ConformsTo:
709 return "conformsTo";
710 case RelationshipKind::ExtensionTo:
711 return "extensionTo";
712 }
713 llvm_unreachable("Unhandled relationship kind");
714}
715
716void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
717 const SymbolReference &Source,
718 const SymbolReference &Target,
719 ExtendedModule &Into) {
720 Object Relationship;
721 SmallString<64> TestRelLabel;
722 if (EmitSymbolLabelsForTesting) {
723 llvm::raw_svector_ostream OS(TestRelLabel);
724 OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ "
725 << Source.USR << " $ ";
726 if (Target.USR.empty())
727 OS << Target.Name;
728 else
729 OS << Target.USR;
730 Relationship["!testRelLabel"] = TestRelLabel;
731 }
732 Relationship["source"] = Source.USR;
733 Relationship["target"] = Target.USR;
734 Relationship["targetFallback"] = Target.Name;
735 Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind);
736
737 if (ForceEmitToMainModule)
738 MainModule.addRelationship(std::move(Relationship));
739 else
740 Into.addRelationship(std::move(Relationship));
741}
742
743StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) {
744 switch (Kind) {
745 case ConstraintKind::Conformance:
746 return "conformance";
747 case ConstraintKind::ConditionalConformance:
748 return "conditionalConformance";
749 }
750 llvm_unreachable("Unhandled constraint kind");
751}
752
753void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) {
754 Object Obj;
755
756 // If we need symbol labels for testing emit the USR as the value and the key
757 // starts with '!'' to ensure it ends up at the top of the object.
758 if (EmitSymbolLabelsForTesting)
759 Obj["!testLabel"] = Record->USR;
760
761 serializeObject(Obj, "identifier",
762 serializeIdentifier(*Record, API.getLanguage()));
763 serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage()));
764 serializeObject(Obj, "names", serializeNames(Record));
765 serializeObject(
766 Obj, "location",
767 serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true));
768 serializeArray(Obj, "availability",
769 serializeAvailability(Record->Availability));
770 serializeObject(Obj, "docComment", serializeDocComment(Record->Comment));
771 serializeArray(Obj, "declarationFragments",
772 serializeDeclarationFragments(Record->Declaration));
773
774 Obj["pathComponents"] = serializePathComponents(Record);
775 Obj["accessLevel"] = Record->Access.getAccess();
776
777 ExtendedModule &Module = getModuleForCurrentSymbol();
778 // If the hierarchy has at least one parent and child.
779 if (Hierarchy.size() >= 2)
780 serializeRelationship(MemberOf, Hierarchy.back(),
781 Hierarchy[Hierarchy.size() - 2], Module);
782
783 CurrentSymbol = Module.addSymbol(std::move(Obj));
784}
785
787 if (!Record)
788 return true;
789 if (shouldSkip(Record))
790 return true;
791 Hierarchy.push_back(getHierarchyReference(Record, API));
792 // Defer traversal mechanics to APISetVisitor base implementation
793 auto RetVal = Base::traverseAPIRecord(Record);
794 Hierarchy.pop_back();
795 return RetVal;
796}
797
799 serializeAPIRecord(Record);
800 return true;
801}
802
805 if (!CurrentSymbol)
806 return true;
807
808 serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
809 return true;
810}
811
813 if (!CurrentSymbol)
814 return true;
815
816 for (const auto &Base : Record->Bases)
817 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base,
818 getModuleForCurrentSymbol());
819 return true;
820}
821
824 if (!CurrentSymbol)
825 return true;
826
827 serializeTemplateMixin(*CurrentSymbol, *Record);
828 return true;
829}
830
833 if (!CurrentSymbol)
834 return true;
835
836 serializeTemplateMixin(*CurrentSymbol, *Record);
837 return true;
838}
839
841 const CXXMethodRecord *Record) {
842 if (!CurrentSymbol)
843 return true;
844
845 serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
846 return true;
847}
848
851 if (!CurrentSymbol)
852 return true;
853
854 serializeTemplateMixin(*CurrentSymbol, *Record);
855 return true;
856}
857
860 if (!CurrentSymbol)
861 return true;
862
863 serializeTemplateMixin(*CurrentSymbol, *Record);
864 return true;
865}
866
868 if (!CurrentSymbol)
869 return true;
870
871 serializeTemplateMixin(*CurrentSymbol, *Record);
872 return true;
873}
874
877 if (!CurrentSymbol)
878 return true;
879
880 serializeTemplateMixin(*CurrentSymbol, *Record);
881 return true;
882}
883
887 if (!CurrentSymbol)
888 return true;
889
890 serializeTemplateMixin(*CurrentSymbol, *Record);
891 return true;
892}
893
896 if (!CurrentSymbol)
897 return true;
898
899 serializeTemplateMixin(*CurrentSymbol, *Record);
900 return true;
901}
902
905 if (!CurrentSymbol)
906 return true;
907
908 for (const auto &Protocol : Record->Protocols)
909 serializeRelationship(ConformsTo, Record, Protocol,
910 getModuleForCurrentSymbol());
911
912 return true;
913}
914
917 if (!CurrentSymbol)
918 return true;
919
920 if (!Record->SuperClass.empty())
921 serializeRelationship(InheritsFrom, Record, Record->SuperClass,
922 getModuleForCurrentSymbol());
923 return true;
924}
925
927 const ObjCCategoryRecord *Record) {
928 auto *CurrentModule = ModuleForCurrentSymbol;
929 if (Record->isExtendingExternalModule())
930 ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source];
931
933 return false;
934
935 bool RetVal = traverseRecordContext(Record);
936 ModuleForCurrentSymbol = CurrentModule;
937 return RetVal;
938}
939
941 const ObjCCategoryRecord *Record) {
943}
944
946 const ObjCCategoryRecord *Record) {
947 // If we need to create a record for the category in the future do so here,
948 // otherwise everything is set up to pretend that the category is in fact the
949 // interface it extends.
950 for (const auto &Protocol : Record->Protocols)
951 serializeRelationship(ConformsTo, Record->Interface, Protocol,
952 getModuleForCurrentSymbol());
953
954 return true;
955}
956
958 const ObjCMethodRecord *Record) {
959 if (!CurrentSymbol)
960 return true;
961
962 serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
963 return true;
964}
965
968 // FIXME: serialize ivar access control here.
969 return true;
970}
971
973 const TypedefRecord *Record) {
974 // Short-circuit walking up the class hierarchy and handle creating typedef
975 // symbol objects manually as there are additional symbol dropping rules to
976 // respect.
978}
979
981 // Typedefs of anonymous types have their entries unified with the underlying
982 // type.
983 bool ShouldDrop = Record->UnderlyingType.Name.empty();
984 // enums declared with `NS_OPTION` have a named enum and a named typedef, with
985 // the same name
986 ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
987 if (ShouldDrop)
988 return true;
989
990 // Create the symbol record if the other symbol droppping rules permit it.
991 serializeAPIRecord(Record);
992 if (!CurrentSymbol)
993 return true;
994
995 (*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
996
997 return true;
998}
999
1000void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1001 switch (Record->getKind()) {
1002 // dispatch to the relevant walkUpFromMethod
1003#define CONCRETE_RECORD(CLASS, BASE, KIND) \
1004 case APIRecord::KIND: { \
1005 walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \
1006 break; \
1007 }
1009 // otherwise fallback on the only behavior we can implement safely.
1012 break;
1013 default:
1014 llvm_unreachable("API Record with uninstantiable kind");
1015 }
1016}
1017
1018Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1019 ExtendedModule &&EM) {
1020 Object Root;
1021 serializeObject(Root, "metadata", serializeMetadata());
1022 serializeObject(Root, "module", serializeModuleObject(ModuleName));
1023
1024 Root["symbols"] = std::move(EM.Symbols);
1025 Root["relationships"] = std::move(EM.Relationships);
1026
1027 return Root;
1028}
1029
1030void SymbolGraphSerializer::serializeGraphToStream(
1031 raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1032 ExtendedModule &&EM) {
1033 Object Root = serializeGraph(ModuleName, std::move(EM));
1034 if (Options.Compact)
1035 OS << formatv("{0}", Value(std::move(Root))) << "\n";
1036 else
1037 OS << formatv("{0:2}", Value(std::move(Root))) << "\n";
1038}
1039
1041 raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1043 SymbolGraphSerializer Serializer(API, IgnoresList,
1044 Options.EmitSymbolLabelsForTesting);
1045 Serializer.traverseAPISet();
1046 Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1047 std::move(Serializer.MainModule));
1048 // FIXME: TODO handle extended modules here
1049}
1050
1052 raw_ostream &MainOutput, const APISet &API,
1053 const APIIgnoresList &IgnoresList,
1054 llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1055 CreateOutputStream,
1057 SymbolGraphSerializer Serializer(API, IgnoresList,
1058 Options.EmitSymbolLabelsForTesting);
1059 Serializer.traverseAPISet();
1060
1061 Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1062 std::move(Serializer.MainModule));
1063
1064 for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1065 if (auto ExtensionOS =
1066 CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName))
1067 Serializer.serializeGraphToStream(*ExtensionOS, Options,
1068 ExtensionSGF.getKey(),
1069 std::move(ExtensionSGF.getValue()));
1070 }
1071}
1072
1073std::optional<Object>
1075 const APISet &API) {
1077 if (!Record)
1078 return {};
1079
1080 Object Root;
1081 APIIgnoresList EmptyIgnores;
1082 SymbolGraphSerializer Serializer(API, EmptyIgnores,
1083 /*EmitSymbolLabelsForTesting*/ false,
1084 /*ForceEmitToMainModule*/ true);
1085
1086 // Set up serializer parent chain
1087 Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1088
1089 Serializer.serializeSingleRecord(Record);
1090 serializeObject(Root, "symbolGraph",
1091 Serializer.serializeGraph(API.ProductName,
1092 std::move(Serializer.MainModule)));
1093
1094 Language Lang = API.getLanguage();
1095 serializeArray(Root, "parentContexts",
1096 generateParentContexts(Serializer.Hierarchy, Lang));
1097
1098 Array RelatedSymbols;
1099
1100 for (const auto &Fragment : Record->Declaration.getFragments()) {
1101 // If we don't have a USR there isn't much we can do.
1102 if (Fragment.PreciseIdentifier.empty())
1103 continue;
1104
1105 APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1106
1107 // If we can't find the record let's skip.
1108 if (!RelatedRecord)
1109 continue;
1110
1111 Object RelatedSymbol;
1112 RelatedSymbol["usr"] = RelatedRecord->USR;
1113 RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1114 RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
1115 RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1116 RelatedSymbol["moduleName"] = API.ProductName;
1117 RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1118
1119 serializeArray(RelatedSymbol, "parentContexts",
1120 generateParentContexts(
1121 generateHierarchyFromRecord(RelatedRecord), Lang));
1122
1123 RelatedSymbols.push_back(std::move(RelatedSymbol));
1124 }
1125
1126 serializeArray(Root, "relatedSymbols", RelatedSymbols);
1127 return Root;
1128}
This file defines the APIRecord-based structs and the APISet class.
#define V(N, I)
Definition: ASTContext.h:3284
NodeId Parent
Definition: ASTDiff.cpp:191
StringRef P
This file defines the Declaration Fragments related classes.
StringRef Identifier
Definition: Format.cpp:2979
llvm::MachO::Target Target
Definition: MachO.h:48
llvm::MachO::Record Record
Definition: MachO.h:31
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:1397
Language getLanguage() const
Get the language used by the APIs.
Definition: API.h:1403
const std::string ProductName
Definition: API.h:1459
const llvm::Triple & getTarget() const
Get the target triple for the ExtractAPI invocation.
Definition: API.h:1400
APIRecord * findRecordForUSR(StringRef USR) const
Finds the APIRecord for a given USR.
Definition: API.cpp:89
const std::string & getAccess() const
DeclarationFragments is a vector of tagged important parts of a symbol's declaration.
DeclarationFragments & append(DeclarationFragments Other)
Append another DeclarationFragments to the end.
const std::vector< Fragment > & getFragments() const
static StringRef getFragmentKindString(FragmentKind Kind)
Get the string description of a FragmentKind Kind.
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
bool isUnavailable() const
Check if the symbol is unavailable unconditionally or on the active platform and os version.
Definition: Availability.h:84
VersionTuple Introduced
Definition: Availability.h:67
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:223
@ RK_GlobalVariableTemplatePartialSpecialization
Definition: API.h:219
@ RK_GlobalVariableTemplateSpecialization
Definition: API.h:218
@ 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:402
This holds information associated with Objective-C categories.
Definition: API.h:1273
The base representation of an Objective-C container record.
Definition: API.h:1149
This holds information associated with Objective-C instance variables.
Definition: API.h:1049
This holds information associated with Objective-C interfaces/classes.
Definition: API.h:1306
This holds information associated with Objective-C methods.
Definition: API.h:1071
Common options to customize the visitor output.
This holds information associated with typedefs.
Definition: API.h:1374