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.KindForDisplay, 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"] = serializeSymbolKind(Parent.Record->KindForDisplay,
595 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 if (SkipSymbolsInCategoriesToExternalTypes &&
929 !API.findRecordForUSR(Record->Interface.USR))
930 return true;
931
932 auto *CurrentModule = ModuleForCurrentSymbol;
933 if (Record->isExtendingExternalModule())
934 ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source];
935
937 return false;
938
939 bool RetVal = traverseRecordContext(Record);
940 ModuleForCurrentSymbol = CurrentModule;
941 return RetVal;
942}
943
945 const ObjCCategoryRecord *Record) {
947}
948
950 const ObjCCategoryRecord *Record) {
951 // If we need to create a record for the category in the future do so here,
952 // otherwise everything is set up to pretend that the category is in fact the
953 // interface it extends.
954 for (const auto &Protocol : Record->Protocols)
955 serializeRelationship(ConformsTo, Record->Interface, Protocol,
956 getModuleForCurrentSymbol());
957
958 return true;
959}
960
962 const ObjCMethodRecord *Record) {
963 if (!CurrentSymbol)
964 return true;
965
966 serializeFunctionSignatureMixin(*CurrentSymbol, *Record);
967 return true;
968}
969
972 // FIXME: serialize ivar access control here.
973 return true;
974}
975
977 const TypedefRecord *Record) {
978 // Short-circuit walking up the class hierarchy and handle creating typedef
979 // symbol objects manually as there are additional symbol dropping rules to
980 // respect.
982}
983
985 // Typedefs of anonymous types have their entries unified with the underlying
986 // type.
987 bool ShouldDrop = Record->UnderlyingType.Name.empty();
988 // enums declared with `NS_OPTION` have a named enum and a named typedef, with
989 // the same name
990 ShouldDrop |= (Record->UnderlyingType.Name == Record->Name);
991 if (ShouldDrop)
992 return true;
993
994 // Create the symbol record if the other symbol droppping rules permit it.
995 serializeAPIRecord(Record);
996 if (!CurrentSymbol)
997 return true;
998
999 (*CurrentSymbol)["type"] = Record->UnderlyingType.USR;
1000
1001 return true;
1002}
1003
1004void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {
1005 switch (Record->getKind()) {
1006 // dispatch to the relevant walkUpFromMethod
1007#define CONCRETE_RECORD(CLASS, BASE, KIND) \
1008 case APIRecord::KIND: { \
1009 walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \
1010 break; \
1011 }
1013 // otherwise fallback on the only behavior we can implement safely.
1016 break;
1017 default:
1018 llvm_unreachable("API Record with uninstantiable kind");
1019 }
1020}
1021
1022Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName,
1023 ExtendedModule &&EM) {
1024 Object Root;
1025 serializeObject(Root, "metadata", serializeMetadata());
1026 serializeObject(Root, "module", serializeModuleObject(ModuleName));
1027
1028 Root["symbols"] = std::move(EM.Symbols);
1029 Root["relationships"] = std::move(EM.Relationships);
1030
1031 return Root;
1032}
1033
1034void SymbolGraphSerializer::serializeGraphToStream(
1035 raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName,
1036 ExtendedModule &&EM) {
1037 Object Root = serializeGraph(ModuleName, std::move(EM));
1038 if (Options.Compact)
1039 OS << formatv("{0}", Value(std::move(Root))) << "\n";
1040 else
1041 OS << formatv("{0:2}", Value(std::move(Root))) << "\n";
1042}
1043
1045 raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList,
1047 SymbolGraphSerializer Serializer(
1048 API, IgnoresList, Options.EmitSymbolLabelsForTesting,
1049 /*ForceEmitToMainModule=*/true,
1050 /*SkipSymbolsInCategoriesToExternalTypes=*/true);
1051
1052 Serializer.traverseAPISet();
1053 Serializer.serializeGraphToStream(OS, Options, API.ProductName,
1054 std::move(Serializer.MainModule));
1055 // FIXME: TODO handle extended modules here
1056}
1057
1059 raw_ostream &MainOutput, const APISet &API,
1060 const APIIgnoresList &IgnoresList,
1061 llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)>
1062 CreateOutputStream,
1064 SymbolGraphSerializer Serializer(API, IgnoresList,
1065 Options.EmitSymbolLabelsForTesting);
1066 Serializer.traverseAPISet();
1067
1068 Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName,
1069 std::move(Serializer.MainModule));
1070
1071 for (auto &ExtensionSGF : Serializer.ExtendedModules) {
1072 if (auto ExtensionOS =
1073 CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName))
1074 Serializer.serializeGraphToStream(*ExtensionOS, Options,
1075 ExtensionSGF.getKey(),
1076 std::move(ExtensionSGF.getValue()));
1077 }
1078}
1079
1080std::optional<Object>
1082 const APISet &API) {
1084 if (!Record)
1085 return {};
1086
1087 Object Root;
1088 APIIgnoresList EmptyIgnores;
1089 SymbolGraphSerializer Serializer(API, EmptyIgnores,
1090 /*EmitSymbolLabelsForTesting*/ false,
1091 /*ForceEmitToMainModule*/ true);
1092
1093 // Set up serializer parent chain
1094 Serializer.Hierarchy = generateHierarchyFromRecord(Record);
1095
1096 Serializer.serializeSingleRecord(Record);
1097 serializeObject(Root, "symbolGraph",
1098 Serializer.serializeGraph(API.ProductName,
1099 std::move(Serializer.MainModule)));
1100
1101 Language Lang = API.getLanguage();
1102 serializeArray(Root, "parentContexts",
1103 generateParentContexts(Serializer.Hierarchy, Lang));
1104
1105 Array RelatedSymbols;
1106
1107 for (const auto &Fragment : Record->Declaration.getFragments()) {
1108 // If we don't have a USR there isn't much we can do.
1109 if (Fragment.PreciseIdentifier.empty())
1110 continue;
1111
1112 APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1113
1114 // If we can't find the record let's skip.
1115 if (!RelatedRecord)
1116 continue;
1117
1118 Object RelatedSymbol;
1119 RelatedSymbol["usr"] = RelatedRecord->USR;
1120 RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1121 RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess();
1122 RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1123 RelatedSymbol["moduleName"] = API.ProductName;
1124 RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1125
1126 serializeArray(RelatedSymbol, "parentContexts",
1127 generateParentContexts(
1128 generateHierarchyFromRecord(RelatedRecord), Lang));
1129
1130 RelatedSymbols.push_back(std::move(RelatedSymbol));
1131 }
1132
1133 serializeArray(Root, "relatedSymbols", RelatedSymbols);
1134 return Root;
1135}
This file defines the APIRecord-based structs and the APISet class.
#define V(N, I)
Definition: ASTContext.h:3285
NodeId Parent
Definition: ASTDiff.cpp:191
StringRef P
This file defines the Declaration Fragments related classes.
StringRef Identifier
Definition: Format.cpp:2983
llvm::MachO::Target Target
Definition: MachO.h:50
llvm::MachO::Record Record
Definition: MachO.h:31
SourceLocation Loc
Definition: SemaObjC.cpp:755
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.
const char * getFilename() const
Return the presumed filename of this location.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
A trivial tuple used to represent a source range.
APISet holds the set of API records collected from given inputs.
Definition: API.h:1400
Language getLanguage() const
Get the language used by the APIs.
Definition: API.h:1406
const std::string ProductName
Definition: API.h:1462
const llvm::Triple & getTarget() const
Get the target triple for the ExtractAPI invocation.
Definition: API.h:1403
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:5395
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:405
This holds information associated with Objective-C categories.
Definition: API.h:1276
The base representation of an Objective-C container record.
Definition: API.h:1152
This holds information associated with Objective-C instance variables.
Definition: API.h:1052
This holds information associated with Objective-C interfaces/classes.
Definition: API.h:1309
This holds information associated with Objective-C methods.
Definition: API.h:1074
Common options to customize the visitor output.
This holds information associated with typedefs.
Definition: API.h:1377