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