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