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