clang 18.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"
18#include "llvm/ADT/STLExtras.h"
19#include "llvm/ADT/STLFunctionalExtras.h"
20#include "llvm/Support/Casting.h"
21#include "llvm/Support/Compiler.h"
22#include "llvm/Support/Path.h"
23#include "llvm/Support/VersionTuple.h"
24#include <optional>
25#include <type_traits>
26
27using namespace clang;
28using namespace clang::extractapi;
29using namespace llvm;
30using namespace llvm::json;
31
32namespace {
33
34/// Helper function to inject a JSON object \p Obj into another object \p Paren
35/// at position \p Key.
36void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) {
37 if (Obj)
38 Paren[Key] = std::move(*Obj);
39}
40
41/// Helper function to inject a StringRef \p String into an object \p Paren at
42/// position \p Key
43void serializeString(Object &Paren, StringRef Key,
44 std::optional<std::string> String) {
45 if (String)
46 Paren[Key] = std::move(*String);
47}
48
49/// Helper function to inject a JSON array \p Array into object \p Paren at
50/// position \p Key.
51void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) {
52 if (Array)
53 Paren[Key] = std::move(*Array);
54}
55
56/// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version
57/// format.
58///
59/// A semantic version object contains three numeric fields, representing the
60/// \c major, \c minor, and \c patch parts of the version tuple.
61/// For example version tuple 1.0.3 is serialized as:
62/// \code
63/// {
64/// "major" : 1,
65/// "minor" : 0,
66/// "patch" : 3
67/// }
68/// \endcode
69///
70/// \returns \c std::nullopt if the version \p V is empty, or an \c Object
71/// containing the semantic version representation of \p V.
72std::optional<Object> serializeSemanticVersion(const VersionTuple &V) {
73 if (V.empty())
74 return std::nullopt;
75
76 Object Version;
77 Version["major"] = V.getMajor();
78 Version["minor"] = V.getMinor().value_or(0);
79 Version["patch"] = V.getSubminor().value_or(0);
80 return Version;
81}
82
83/// Serialize the OS information in the Symbol Graph platform property.
84///
85/// The OS information in Symbol Graph contains the \c name of the OS, and an
86/// optional \c minimumVersion semantic version field.
87Object serializeOperatingSystem(const Triple &T) {
88 Object OS;
89 OS["name"] = T.getOSTypeName(T.getOS());
90 serializeObject(OS, "minimumVersion",
91 serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
92 return OS;
93}
94
95/// Serialize the platform information in the Symbol Graph module section.
96///
97/// The platform object describes a target platform triple in corresponding
98/// three fields: \c architecture, \c vendor, and \c operatingSystem.
99Object serializePlatform(const Triple &T) {
100 Object Platform;
101 Platform["architecture"] = T.getArchName();
102 Platform["vendor"] = T.getVendorName();
103 Platform["operatingSystem"] = serializeOperatingSystem(T);
104 return Platform;
105}
106
107/// Serialize a source position.
108Object serializeSourcePosition(const PresumedLoc &Loc) {
109 assert(Loc.isValid() && "invalid source position");
110
111 Object SourcePosition;
112 SourcePosition["line"] = Loc.getLine() - 1;
113 SourcePosition["character"] = Loc.getColumn() - 1;
114
115 return SourcePosition;
116}
117
118/// Serialize a source location in file.
119///
120/// \param Loc The presumed location to serialize.
121/// \param IncludeFileURI If true, include the file path of \p Loc as a URI.
122/// Defaults to false.
123Object serializeSourceLocation(const PresumedLoc &Loc,
124 bool IncludeFileURI = false) {
126 serializeObject(SourceLocation, "position", serializeSourcePosition(Loc));
127
128 if (IncludeFileURI) {
129 std::string FileURI = "file://";
130 // Normalize file path to use forward slashes for the URI.
131 FileURI += sys::path::convert_to_slash(Loc.getFilename());
132 SourceLocation["uri"] = FileURI;
133 }
134
135 return SourceLocation;
136}
137
138/// Serialize a source range with begin and end locations.
139Object serializeSourceRange(const PresumedLoc &BeginLoc,
140 const PresumedLoc &EndLoc) {
142 serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc));
143 serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc));
144 return SourceRange;
145}
146
147/// Serialize the availability attributes of a symbol.
148///
149/// Availability information contains the introduced, deprecated, and obsoleted
150/// versions of the symbol for a given domain (roughly corresponds to a
151/// platform) as semantic versions, if not default. Availability information
152/// also contains flags to indicate if the symbol is unconditionally unavailable
153/// or deprecated, i.e. \c __attribute__((unavailable)) and \c
154/// __attribute__((deprecated)).
155///
156/// \returns \c std::nullopt if the symbol has default availability attributes,
157/// or an \c Array containing the formatted availability information.
158std::optional<Array>
159serializeAvailability(const AvailabilitySet &Availabilities) {
160 if (Availabilities.isDefault())
161 return std::nullopt;
162
163 Array AvailabilityArray;
164
165 if (Availabilities.isUnconditionallyDeprecated()) {
166 Object UnconditionallyDeprecated;
167 UnconditionallyDeprecated["domain"] = "*";
168 UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true;
169 AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
170 }
171
172 // Note unconditionally unavailable records are skipped.
173
174 for (const auto &AvailInfo : Availabilities) {
175 Object Availability;
176 Availability["domain"] = AvailInfo.Domain;
177 if (AvailInfo.Unavailable)
178 Availability["isUnconditionallyUnavailable"] = true;
179 else {
180 serializeObject(Availability, "introduced",
181 serializeSemanticVersion(AvailInfo.Introduced));
182 serializeObject(Availability, "deprecated",
183 serializeSemanticVersion(AvailInfo.Deprecated));
184 serializeObject(Availability, "obsoleted",
185 serializeSemanticVersion(AvailInfo.Obsoleted));
186 }
187 AvailabilityArray.emplace_back(std::move(Availability));
188 }
189
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
203 // Unsupported language currently
204 case Language::ObjCXX:
205 case Language::OpenCL:
206 case Language::OpenCLCXX:
207 case Language::CUDA:
208 case Language::RenderScript:
209 case Language::HIP:
210 case Language::HLSL:
211
212 // Languages that the frontend cannot parse and compile
213 case Language::Unknown:
214 case Language::Asm:
215 case Language::LLVM_IR:
216 llvm_unreachable("Unsupported language kind");
217 }
218
219 llvm_unreachable("Unhandled language kind");
220}
221
222/// Serialize the identifier object as specified by the Symbol Graph format.
223///
224/// The identifier property of a symbol contains the USR for precise and unique
225/// references, and the interface language name.
226Object serializeIdentifier(const APIRecord &Record, Language Lang) {
228 Identifier["precise"] = Record.USR;
229 Identifier["interfaceLanguage"] = getLanguageName(Lang);
230
231 return Identifier;
232}
233
234/// Serialize the documentation comments attached to a symbol, as specified by
235/// the Symbol Graph format.
236///
237/// The Symbol Graph \c docComment object contains an array of lines. Each line
238/// represents one line of striped documentation comment, with source range
239/// information.
240/// e.g.
241/// \code
242/// /// This is a documentation comment
243/// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line.
244/// /// with multiple lines.
245/// ^~~~~~~~~~~~~~~~~~~~~~~' Second line.
246/// \endcode
247///
248/// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing
249/// the formatted lines.
250std::optional<Object> serializeDocComment(const DocComment &Comment) {
251 if (Comment.empty())
252 return std::nullopt;
253
255 Array LinesArray;
256 for (const auto &CommentLine : Comment) {
257 Object Line;
258 Line["text"] = CommentLine.Text;
259 serializeObject(Line, "range",
260 serializeSourceRange(CommentLine.Begin, CommentLine.End));
261 LinesArray.emplace_back(std::move(Line));
262 }
263 serializeArray(DocComment, "lines", LinesArray);
264
265 return DocComment;
266}
267
268/// Serialize the declaration fragments of a symbol.
269///
270/// The Symbol Graph declaration fragments is an array of tagged important
271/// parts of a symbol's declaration. The fragments sequence can be joined to
272/// form spans of declaration text, with attached information useful for
273/// purposes like syntax-highlighting etc. For example:
274/// \code
275/// const int pi; -> "declarationFragments" : [
276/// {
277/// "kind" : "keyword",
278/// "spelling" : "const"
279/// },
280/// {
281/// "kind" : "text",
282/// "spelling" : " "
283/// },
284/// {
285/// "kind" : "typeIdentifier",
286/// "preciseIdentifier" : "c:I",
287/// "spelling" : "int"
288/// },
289/// {
290/// "kind" : "text",
291/// "spelling" : " "
292/// },
293/// {
294/// "kind" : "identifier",
295/// "spelling" : "pi"
296/// }
297/// ]
298/// \endcode
299///
300/// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the
301/// formatted declaration fragments array.
302std::optional<Array>
303serializeDeclarationFragments(const DeclarationFragments &DF) {
304 if (DF.getFragments().empty())
305 return std::nullopt;
306
307 Array Fragments;
308 for (const auto &F : DF.getFragments()) {
309 Object Fragment;
310 Fragment["spelling"] = F.Spelling;
311 Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind);
312 if (!F.PreciseIdentifier.empty())
313 Fragment["preciseIdentifier"] = F.PreciseIdentifier;
314 Fragments.emplace_back(std::move(Fragment));
315 }
316
317 return Fragments;
318}
319
320/// Serialize the \c names field of a symbol as specified by the Symbol Graph
321/// format.
322///
323/// The Symbol Graph names field contains multiple representations of a symbol
324/// that can be used for different applications:
325/// - \c title : The simple declared name of the symbol;
326/// - \c subHeading : An array of declaration fragments that provides tags,
327/// and potentially more tokens (for example the \c +/- symbol for
328/// Objective-C methods). Can be used as sub-headings for documentation.
329Object serializeNames(const APIRecord &Record) {
330 Object Names;
331 if (auto *CategoryRecord =
332 dyn_cast_or_null<const ObjCCategoryRecord>(&Record))
333 Names["title"] =
334 (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str();
335 else
336 Names["title"] = Record.Name;
337
338 serializeArray(Names, "subHeading",
339 serializeDeclarationFragments(Record.SubHeading));
340 DeclarationFragments NavigatorFragments;
341 NavigatorFragments.append(Record.Name,
342 DeclarationFragments::FragmentKind::Identifier,
343 /*PreciseIdentifier*/ "");
344 serializeArray(Names, "navigator",
345 serializeDeclarationFragments(NavigatorFragments));
346
347 return Names;
348}
349
350Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) {
351 auto AddLangPrefix = [&Lang](StringRef S) -> std::string {
352 return (getLanguageName(Lang) + "." + S).str();
353 };
354
355 Object Kind;
356 switch (RK) {
358 llvm_unreachable("Records should have an explicit kind");
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("type.property");
418 Kind["displayName"] = "Type Property";
419 break;
424 Kind["identifier"] = AddLangPrefix("class");
425 Kind["displayName"] = "Class";
426 break;
428 Kind["identifier"] = AddLangPrefix("method");
429 Kind["displayName"] = "Method Template";
430 break;
432 Kind["identifier"] = AddLangPrefix("method");
433 Kind["displayName"] = "Method Template Specialization";
434 break;
436 Kind["identifier"] = AddLangPrefix("property");
437 Kind["displayName"] = "Template Property";
438 break;
440 Kind["identifier"] = AddLangPrefix("concept");
441 Kind["displayName"] = "Concept";
442 break;
444 Kind["identifier"] = AddLangPrefix("type.method");
445 Kind["displayName"] = "Static Method";
446 break;
448 Kind["identifier"] = AddLangPrefix("method");
449 Kind["displayName"] = "Instance Method";
450 break;
452 Kind["identifier"] = AddLangPrefix("method");
453 Kind["displayName"] = "Constructor";
454 break;
456 Kind["identifier"] = AddLangPrefix("method");
457 Kind["displayName"] = "Destructor";
458 break;
460 Kind["identifier"] = AddLangPrefix("ivar");
461 Kind["displayName"] = "Instance Variable";
462 break;
464 Kind["identifier"] = AddLangPrefix("method");
465 Kind["displayName"] = "Instance Method";
466 break;
468 Kind["identifier"] = AddLangPrefix("type.method");
469 Kind["displayName"] = "Type Method";
470 break;
472 Kind["identifier"] = AddLangPrefix("property");
473 Kind["displayName"] = "Instance Property";
474 break;
476 Kind["identifier"] = AddLangPrefix("type.property");
477 Kind["displayName"] = "Type Property";
478 break;
480 Kind["identifier"] = AddLangPrefix("class");
481 Kind["displayName"] = "Class";
482 break;
484 Kind["identifier"] = AddLangPrefix("class.extension");
485 Kind["displayName"] = "Class Extension";
486 break;
488 Kind["identifier"] = AddLangPrefix("module.extension");
489 Kind["displayName"] = "Module 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 }
504
505 return Kind;
506}
507
508/// Serialize the symbol kind information.
509///
510/// The Symbol Graph symbol kind property contains a shorthand \c identifier
511/// which is prefixed by the source language name, useful for tooling to parse
512/// the kind, and a \c displayName for rendering human-readable names.
513Object serializeSymbolKind(const APIRecord &Record, Language Lang) {
514 return serializeSymbolKind(Record.getKind(), Lang);
515}
516
517template <typename RecordTy>
518std::optional<Object>
519serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) {
520 const auto &FS = Record.Signature;
521 if (FS.empty())
522 return std::nullopt;
523
524 Object Signature;
525 serializeArray(Signature, "returns",
526 serializeDeclarationFragments(FS.getReturnType()));
527
528 Array Parameters;
529 for (const auto &P : FS.getParameters()) {
531 Parameter["name"] = P.Name;
532 serializeArray(Parameter, "declarationFragments",
533 serializeDeclarationFragments(P.Fragments));
534 Parameters.emplace_back(std::move(Parameter));
535 }
536
537 if (!Parameters.empty())
538 Signature["parameters"] = std::move(Parameters);
539
540 return Signature;
541}
542
543template <typename RecordTy>
544std::optional<Object>
545serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) {
546 return std::nullopt;
547}
548
549/// Serialize the function signature field, as specified by the
550/// Symbol Graph format.
551///
552/// The Symbol Graph function signature property contains two arrays.
553/// - The \c returns array is the declaration fragments of the return type;
554/// - The \c parameters array contains names and declaration fragments of the
555/// parameters.
556///
557/// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the
558/// formatted function signature.
559template <typename RecordTy>
560void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) {
561 serializeObject(Paren, "functionSignature",
562 serializeFunctionSignatureMixinImpl(
564}
565
566template <typename RecordTy>
567std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
568 std::true_type) {
569 const auto &AccessControl = Record.Access;
570 std::string Access;
571 if (AccessControl.empty())
572 return std::nullopt;
573 Access = AccessControl.getAccess();
574 return Access;
575}
576
577template <typename RecordTy>
578std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record,
579 std::false_type) {
580 return std::nullopt;
581}
582
583template <typename RecordTy>
584void serializeAccessMixin(Object &Paren, const RecordTy &Record) {
585 auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>());
586 if (!accessLevel.has_value())
587 accessLevel = "public";
588 serializeString(Paren, "accessLevel", accessLevel);
589}
590
591template <typename RecordTy>
592std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
593 std::true_type) {
594 const auto &Template = Record.Templ;
595 if (Template.empty())
596 return std::nullopt;
597
598 Object Generics;
599 Array GenericParameters;
600 for (const auto &Param : Template.getParameters()) {
602 Parameter["name"] = Param.Name;
603 Parameter["index"] = Param.Index;
604 Parameter["depth"] = Param.Depth;
605 GenericParameters.emplace_back(std::move(Parameter));
606 }
607 if (!GenericParameters.empty())
608 Generics["parameters"] = std::move(GenericParameters);
609
610 Array GenericConstraints;
611 for (const auto &Constr : Template.getConstraints()) {
612 Object Constraint;
613 Constraint["kind"] = Constr.Kind;
614 Constraint["lhs"] = Constr.LHS;
615 Constraint["rhs"] = Constr.RHS;
616 GenericConstraints.emplace_back(std::move(Constraint));
617 }
618
619 if (!GenericConstraints.empty())
620 Generics["constraints"] = std::move(GenericConstraints);
621
622 return Generics;
623}
624
625template <typename RecordTy>
626std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record,
627 std::false_type) {
628 return std::nullopt;
629}
630
631template <typename RecordTy>
632void serializeTemplateMixin(Object &Paren, const RecordTy &Record) {
633 serializeObject(Paren, "swiftGenerics",
634 serializeTemplateMixinImpl(Record, has_template<RecordTy>()));
635}
636
637struct PathComponent {
638 StringRef USR;
639 StringRef Name;
641
642 PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind)
643 : USR(USR), Name(Name), Kind(Kind) {}
644};
645
646template <typename RecordTy>
647bool generatePathComponents(
648 const RecordTy &Record, const APISet &API,
649 function_ref<void(const PathComponent &)> ComponentTransformer) {
650 SmallVector<PathComponent, 4> ReverseComponenents;
651 ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind());
652 const auto *CurrentParent = &Record.ParentInformation;
653 bool FailedToFindParent = false;
654 while (CurrentParent && !CurrentParent->empty()) {
655 PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
656 CurrentParent->ParentName,
657 CurrentParent->ParentKind);
658
659 auto *ParentRecord = CurrentParent->ParentRecord;
660 // Slow path if we don't have a direct reference to the ParentRecord
661 if (!ParentRecord)
662 ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR);
663
664 // If the parent is a category extended from internal module then we need to
665 // pretend this belongs to the associated interface.
666 if (auto *CategoryRecord =
667 dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
668 if (!CategoryRecord->IsFromExternalModule) {
669 ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR);
670 CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
671 CategoryRecord->Interface.Name,
673 }
674 }
675
676 // The parent record doesn't exist which means the symbol shouldn't be
677 // treated as part of the current product.
678 if (!ParentRecord) {
679 FailedToFindParent = true;
680 break;
681 }
682
683 ReverseComponenents.push_back(std::move(CurrentParentComponent));
684 CurrentParent = &ParentRecord->ParentInformation;
685 }
686
687 for (const auto &PC : reverse(ReverseComponenents))
688 ComponentTransformer(PC);
689
690 return FailedToFindParent;
691}
692
693Object serializeParentContext(const PathComponent &PC, Language Lang) {
694 Object ParentContextElem;
695 ParentContextElem["usr"] = PC.USR;
696 ParentContextElem["name"] = PC.Name;
697 ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"];
698 return ParentContextElem;
699}
700
701template <typename RecordTy>
702Array generateParentContexts(const RecordTy &Record, const APISet &API,
703 Language Lang) {
704 Array ParentContexts;
705 generatePathComponents(
706 Record, API, [Lang, &ParentContexts](const PathComponent &PC) {
707 ParentContexts.push_back(serializeParentContext(PC, Lang));
708 });
709
710 return ParentContexts;
711}
712} // namespace
713
714/// Defines the format version emitted by SymbolGraphSerializer.
715const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
716
717Object SymbolGraphSerializer::serializeMetadata() const {
718 Object Metadata;
719 serializeObject(Metadata, "formatVersion",
720 serializeSemanticVersion(FormatVersion));
721 Metadata["generator"] = clang::getClangFullVersion();
722 return Metadata;
723}
724
725Object SymbolGraphSerializer::serializeModule() const {
727 // The user is expected to always pass `--product-name=` on the command line
728 // to populate this field.
729 Module["name"] = API.ProductName;
730 serializeObject(Module, "platform", serializePlatform(API.getTarget()));
731 return Module;
732}
733
734bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const {
735 // Skip explicitly ignored symbols.
737 return true;
738
739 // Skip unconditionally unavailable symbols
740 if (Record.Availabilities.isUnconditionallyUnavailable())
741 return true;
742
743 // Filter out symbols prefixed with an underscored as they are understood to
744 // be symbols clients should not use.
745 if (Record.Name.startswith("_"))
746 return true;
747
748 return false;
749}
750
751template <typename RecordTy>
752std::optional<Object>
753SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const {
754 if (shouldSkip(Record))
755 return std::nullopt;
756
757 Object Obj;
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.Availabilities));
767 serializeObject(Obj, "docComment", serializeDocComment(Record.Comment));
768 serializeArray(Obj, "declarationFragments",
769 serializeDeclarationFragments(Record.Declaration));
770 SmallVector<StringRef, 4> PathComponentsNames;
771 // If this returns true it indicates that we couldn't find a symbol in the
772 // hierarchy.
773 if (generatePathComponents(Record, API,
774 [&PathComponentsNames](const PathComponent &PC) {
775 PathComponentsNames.push_back(PC.Name);
776 }))
777 return {};
778
779 serializeArray(Obj, "pathComponents", Array(PathComponentsNames));
780
781 serializeFunctionSignatureMixin(Obj, Record);
782 serializeAccessMixin(Obj, Record);
783 serializeTemplateMixin(Obj, Record);
784
785 return Obj;
786}
787
788template <typename MemberTy>
789void SymbolGraphSerializer::serializeMembers(
790 const APIRecord &Record,
791 const SmallVector<std::unique_ptr<MemberTy>> &Members) {
792 // Members should not be serialized if we aren't recursing.
793 if (!ShouldRecurse)
794 return;
795 for (const auto &Member : Members) {
796 auto MemberRecord = serializeAPIRecord(*Member);
797 if (!MemberRecord)
798 continue;
799
800 Symbols.emplace_back(std::move(*MemberRecord));
801 serializeRelationship(RelationshipKind::MemberOf, *Member, Record);
802 }
803}
804
806 switch (Kind) {
808 return "memberOf";
810 return "inheritsFrom";
812 return "conformsTo";
814 return "extensionTo";
815 }
816 llvm_unreachable("Unhandled relationship kind");
817}
818
820 switch (Kind) {
822 return "conformance";
824 return "conditionalConformance";
825 }
826 llvm_unreachable("Unhandled constraint kind");
827}
828
829void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
830 SymbolReference Source,
832 Object Relationship;
833 Relationship["source"] = Source.USR;
834 Relationship["target"] = Target.USR;
835 Relationship["targetFallback"] = Target.Name;
836 Relationship["kind"] = getRelationshipString(Kind);
837
838 Relationships.emplace_back(std::move(Relationship));
839}
840
842 const NamespaceRecord &Record) {
843 auto Namespace = serializeAPIRecord(Record);
844 if (!Namespace)
845 return;
846 Symbols.emplace_back(std::move(*Namespace));
847 if (!Record.ParentInformation.empty())
848 serializeRelationship(RelationshipKind::MemberOf, Record,
849 Record.ParentInformation.ParentRecord);
850}
851
853 const GlobalFunctionRecord &Record) {
854 auto Obj = serializeAPIRecord(Record);
855 if (!Obj)
856 return;
857
858 Symbols.emplace_back(std::move(*Obj));
859}
860
862 const GlobalVariableRecord &Record) {
863 auto Obj = serializeAPIRecord(Record);
864 if (!Obj)
865 return;
866
867 Symbols.emplace_back(std::move(*Obj));
868}
869
871 auto Enum = serializeAPIRecord(Record);
872 if (!Enum)
873 return;
874
875 Symbols.emplace_back(std::move(*Enum));
876 serializeMembers(Record, Record.Constants);
877}
878
880 auto Struct = serializeAPIRecord(Record);
881 if (!Struct)
882 return;
883
884 Symbols.emplace_back(std::move(*Struct));
885 serializeMembers(Record, Record.Fields);
886}
887
889 const StaticFieldRecord &Record) {
890 auto StaticField = serializeAPIRecord(Record);
891 if (!StaticField)
892 return;
893 Symbols.emplace_back(std::move(*StaticField));
894 serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context);
895}
896
898 auto Class = serializeAPIRecord(Record);
899 if (!Class)
900 return;
901
902 Symbols.emplace_back(std::move(*Class));
903 for (const auto &Base : Record.Bases)
904 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
905 if (!Record.ParentInformation.empty())
906 serializeRelationship(RelationshipKind::MemberOf, Record,
907 Record.ParentInformation.ParentRecord);
908}
909
911 const ClassTemplateRecord &Record) {
912 auto Class = serializeAPIRecord(Record);
913 if (!Class)
914 return;
915
916 Symbols.emplace_back(std::move(*Class));
917 for (const auto &Base : Record.Bases)
918 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
919 if (!Record.ParentInformation.empty())
920 serializeRelationship(RelationshipKind::MemberOf, Record,
921 Record.ParentInformation.ParentRecord);
922}
923
925 const ClassTemplateSpecializationRecord &Record) {
926 auto Class = serializeAPIRecord(Record);
927 if (!Class)
928 return;
929
930 Symbols.emplace_back(std::move(*Class));
931
932 for (const auto &Base : Record.Bases)
933 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
934 if (!Record.ParentInformation.empty())
935 serializeRelationship(RelationshipKind::MemberOf, Record,
936 Record.ParentInformation.ParentRecord);
937}
938
941 auto Class = serializeAPIRecord(Record);
942 if (!Class)
943 return;
944
945 Symbols.emplace_back(std::move(*Class));
946
947 for (const auto &Base : Record.Bases)
948 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base);
949 if (!Record.ParentInformation.empty())
950 serializeRelationship(RelationshipKind::MemberOf, Record,
951 Record.ParentInformation.ParentRecord);
952}
953
955 const CXXInstanceMethodRecord &Record) {
956 auto InstanceMethod = serializeAPIRecord(Record);
957 if (!InstanceMethod)
958 return;
959
960 Symbols.emplace_back(std::move(*InstanceMethod));
961 serializeRelationship(RelationshipKind::MemberOf, Record,
962 Record.ParentInformation.ParentRecord);
963}
964
966 const CXXStaticMethodRecord &Record) {
967 auto StaticMethod = serializeAPIRecord(Record);
968 if (!StaticMethod)
969 return;
970
971 Symbols.emplace_back(std::move(*StaticMethod));
972 serializeRelationship(RelationshipKind::MemberOf, Record,
973 Record.ParentInformation.ParentRecord);
974}
975
977 const CXXMethodTemplateRecord &Record) {
978 if (!ShouldRecurse)
979 // Ignore child symbols
980 return;
981 auto MethodTemplate = serializeAPIRecord(Record);
982 if (!MethodTemplate)
983 return;
984 Symbols.emplace_back(std::move(*MethodTemplate));
985 serializeRelationship(RelationshipKind::MemberOf, Record,
986 Record.ParentInformation.ParentRecord);
987}
988
991 if (!ShouldRecurse)
992 // Ignore child symbols
993 return;
994 auto MethodTemplateSpecialization = serializeAPIRecord(Record);
995 if (!MethodTemplateSpecialization)
996 return;
997 Symbols.emplace_back(std::move(*MethodTemplateSpecialization));
998 serializeRelationship(RelationshipKind::MemberOf, Record,
999 Record.ParentInformation.ParentRecord);
1000}
1001
1003 if (!ShouldRecurse)
1004 return;
1005 auto CXXField = serializeAPIRecord(Record);
1006 if (!CXXField)
1007 return;
1008 Symbols.emplace_back(std::move(*CXXField));
1009 serializeRelationship(RelationshipKind::MemberOf, Record,
1010 Record.ParentInformation.ParentRecord);
1011}
1012
1014 const CXXFieldTemplateRecord &Record) {
1015 if (!ShouldRecurse)
1016 // Ignore child symbols
1017 return;
1018 auto CXXFieldTemplate = serializeAPIRecord(Record);
1019 if (!CXXFieldTemplate)
1020 return;
1021 Symbols.emplace_back(std::move(*CXXFieldTemplate));
1022 serializeRelationship(RelationshipKind::MemberOf, Record,
1023 Record.ParentInformation.ParentRecord);
1024}
1025
1027 auto Concept = serializeAPIRecord(Record);
1028 if (!Concept)
1029 return;
1030
1031 Symbols.emplace_back(std::move(*Concept));
1032}
1033
1035 const GlobalVariableTemplateRecord &Record) {
1036 auto GlobalVariableTemplate = serializeAPIRecord(Record);
1037 if (!GlobalVariableTemplate)
1038 return;
1039 Symbols.emplace_back(std::move(*GlobalVariableTemplate));
1040}
1041
1044 auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record);
1045 if (!GlobalVariableTemplateSpecialization)
1046 return;
1047 Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization));
1048}
1049
1053 auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record);
1054 if (!GlobalVariableTemplatePartialSpecialization)
1055 return;
1056 Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization));
1057}
1058
1060 const GlobalFunctionTemplateRecord &Record) {
1061 auto GlobalFunctionTemplate = serializeAPIRecord(Record);
1062 if (!GlobalFunctionTemplate)
1063 return;
1064 Symbols.emplace_back(std::move(*GlobalFunctionTemplate));
1065}
1066
1069 auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record);
1070 if (!GlobalFunctionTemplateSpecialization)
1071 return;
1072 Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization));
1073}
1074
1076 const ObjCContainerRecord &Record) {
1077 auto ObjCContainer = serializeAPIRecord(Record);
1078 if (!ObjCContainer)
1079 return;
1080
1081 Symbols.emplace_back(std::move(*ObjCContainer));
1082
1083 serializeMembers(Record, Record.Ivars);
1084 serializeMembers(Record, Record.Methods);
1085 serializeMembers(Record, Record.Properties);
1086
1087 for (const auto &Protocol : Record.Protocols)
1088 // Record that Record conforms to Protocol.
1089 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1090
1091 if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
1092 if (!ObjCInterface->SuperClass.empty())
1093 // If Record is an Objective-C interface record and it has a super class,
1094 // record that Record is inherited from SuperClass.
1095 serializeRelationship(RelationshipKind::InheritsFrom, Record,
1096 ObjCInterface->SuperClass);
1097
1098 // Members of categories extending an interface are serialized as members of
1099 // the interface.
1100 for (const auto *Category : ObjCInterface->Categories) {
1101 serializeMembers(Record, Category->Ivars);
1102 serializeMembers(Record, Category->Methods);
1103 serializeMembers(Record, Category->Properties);
1104
1105 // Surface the protocols of the category to the interface.
1106 for (const auto &Protocol : Category->Protocols)
1107 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1108 }
1109 }
1110}
1111
1113 const ObjCCategoryRecord &Record) {
1114 if (!Record.IsFromExternalModule)
1115 return;
1116
1117 // Check if the current Category' parent has been visited before, if so skip.
1118 if (!visitedCategories.contains(Record.Interface.Name)) {
1119 visitedCategories.insert(Record.Interface.Name);
1120 Object Obj;
1121 serializeObject(Obj, "identifier",
1122 serializeIdentifier(Record, API.getLanguage()));
1123 serializeObject(Obj, "kind",
1124 serializeSymbolKind(APIRecord::RK_ObjCCategoryModule,
1125 API.getLanguage()));
1126 Obj["accessLevel"] = "public";
1127 Symbols.emplace_back(std::move(Obj));
1128 }
1129
1130 Object Relationship;
1131 Relationship["source"] = Record.USR;
1132 Relationship["target"] = Record.Interface.USR;
1133 Relationship["targetFallback"] = Record.Interface.Name;
1135 Relationships.emplace_back(std::move(Relationship));
1136
1137 auto ObjCCategory = serializeAPIRecord(Record);
1138
1139 if (!ObjCCategory)
1140 return;
1141
1142 Symbols.emplace_back(std::move(*ObjCCategory));
1143 serializeMembers(Record, Record.Methods);
1144 serializeMembers(Record, Record.Properties);
1145
1146 // Surface the protocols of the category to the interface.
1147 for (const auto &Protocol : Record.Protocols)
1148 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol);
1149}
1150
1152 const MacroDefinitionRecord &Record) {
1153 auto Macro = serializeAPIRecord(Record);
1154
1155 if (!Macro)
1156 return;
1157
1158 Symbols.emplace_back(std::move(*Macro));
1159}
1160
1162 switch (Record->getKind()) {
1164 llvm_unreachable("Records should have a known kind!");
1166 visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
1167 break;
1169 visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
1170 break;
1171 case APIRecord::RK_Enum:
1172 visitEnumRecord(*cast<EnumRecord>(Record));
1173 break;
1175 visitStructRecord(*cast<StructRecord>(Record));
1176 break;
1178 visitStaticFieldRecord(*cast<StaticFieldRecord>(Record));
1179 break;
1181 visitCXXClassRecord(*cast<CXXClassRecord>(Record));
1182 break;
1184 visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
1185 break;
1187 visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
1188 break;
1190 visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record));
1191 break;
1193 visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
1194 break;
1196 visitTypedefRecord(*cast<TypedefRecord>(Record));
1197 break;
1198 default:
1199 if (auto Obj = serializeAPIRecord(*Record)) {
1200 Symbols.emplace_back(std::move(*Obj));
1201 auto &ParentInformation = Record->ParentInformation;
1202 if (!ParentInformation.empty())
1203 serializeRelationship(RelationshipKind::MemberOf, *Record,
1204 *ParentInformation.ParentRecord);
1205 }
1206 break;
1207 }
1208}
1209
1211 // Typedefs of anonymous types have their entries unified with the underlying
1212 // type.
1213 bool ShouldDrop = Record.UnderlyingType.Name.empty();
1214 // enums declared with `NS_OPTION` have a named enum and a named typedef, with
1215 // the same name
1216 ShouldDrop |= (Record.UnderlyingType.Name == Record.Name);
1217 if (ShouldDrop)
1218 return;
1219
1220 auto Typedef = serializeAPIRecord(Record);
1221 if (!Typedef)
1222 return;
1223
1224 (*Typedef)["type"] = Record.UnderlyingType.USR;
1225
1226 Symbols.emplace_back(std::move(*Typedef));
1227}
1228
1231 return serializeCurrentGraph();
1232}
1233
1234Object SymbolGraphSerializer::serializeCurrentGraph() {
1235 Object Root;
1236 serializeObject(Root, "metadata", serializeMetadata());
1237 serializeObject(Root, "module", serializeModule());
1238
1239 Root["symbols"] = std::move(Symbols);
1240 Root["relationships"] = std::move(Relationships);
1241
1242 return Root;
1243}
1244
1246 Object root = serialize();
1247 if (Options.Compact)
1248 os << formatv("{0}", Value(std::move(root))) << "\n";
1249 else
1250 os << formatv("{0:2}", Value(std::move(root))) << "\n";
1251}
1252
1253std::optional<Object>
1255 const APISet &API) {
1256 APIRecord *Record = API.findRecordForUSR(USR);
1257 if (!Record)
1258 return {};
1259
1260 Object Root;
1261 APIIgnoresList EmptyIgnores;
1262 SymbolGraphSerializer Serializer(API, EmptyIgnores,
1263 /*Options.Compact*/ {true},
1264 /*ShouldRecurse*/ false);
1265 Serializer.serializeSingleRecord(Record);
1266 serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph());
1267
1268 Language Lang = API.getLanguage();
1269 serializeArray(Root, "parentContexts",
1270 generateParentContexts(*Record, API, Lang));
1271
1272 Array RelatedSymbols;
1273
1274 for (const auto &Fragment : Record->Declaration.getFragments()) {
1275 // If we don't have a USR there isn't much we can do.
1276 if (Fragment.PreciseIdentifier.empty())
1277 continue;
1278
1279 APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier);
1280
1281 // If we can't find the record let's skip.
1282 if (!RelatedRecord)
1283 continue;
1284
1285 Object RelatedSymbol;
1286 RelatedSymbol["usr"] = RelatedRecord->USR;
1287 RelatedSymbol["declarationLanguage"] = getLanguageName(Lang);
1288 // TODO: once we record this properly let's serialize it right.
1289 RelatedSymbol["accessLevel"] = "public";
1290 RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename();
1291 RelatedSymbol["moduleName"] = API.ProductName;
1292 RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader;
1293
1294 serializeArray(RelatedSymbol, "parentContexts",
1295 generateParentContexts(*RelatedRecord, API, Lang));
1296 RelatedSymbols.push_back(std::move(RelatedSymbol));
1297 }
1298
1299 serializeArray(Root, "relatedSymbols", RelatedSymbols);
1300 return Root;
1301}
#define V(N, I)
Definition: ASTContext.h:3241
StringRef P
This file defines the Declaration Fragments related classes.
int Category
Definition: Format.cpp:2979
StringRef Identifier
Definition: Format.cpp:2984
Defines the clang::SourceLocation class and associated facilities.
This file defines the SymbolGraphSerializer class.
Defines version macros and version-related utility functions for Clang.
Describes a module or submodule.
Definition: Module.h:105
Represents an unpacked "presumed" location which can be presented to the user.
unsigned getColumn() const
Return the presumed column number of this location.
const char * getFilename() const
Return the presumed filename of this location.
bool isValid() const
unsigned getLine() const
Return the presumed line number of this location.
Encodes a location in the source.
A trivial tuple used to represent a source range.
APISet holds the set of API records collected from given inputs.
Definition: API.h:1190
Language getLanguage() const
Get the language used by the APIs.
Definition: API.h:1515
const std::string ProductName
Definition: API.h:1666
const llvm::Triple & getTarget() const
Get the target triple for the ExtractAPI invocation.
Definition: API.h:1512
APIRecord * findRecordForUSR(StringRef USR) const
Finds the APIRecord for a given USR.
Definition: API.cpp:508
const std::string & getAccess() const
bool isUnconditionallyDeprecated() const
Check if the symbol is unconditionally deprecated.
bool isDefault() const
Determine if this AvailabilitySet represents default availability.
DeclarationFragments is a vector of tagged important parts of a symbol's declaration.
const std::vector< Fragment > & getFragments() const
static StringRef getFragmentKindString(FragmentKind Kind)
Get the string description of a FragmentKind Kind.
DeclarationFragments & append(StringRef Spelling, FragmentKind Kind, StringRef PreciseIdentifier="", const Decl *Declaration=nullptr)
Append a new Fragment to the end of the Fragments.
The visitor that organizes API information in the Symbol Graph format.
void visitGlobalVariableTemplateSpecializationRecord(const GlobalVariableTemplateSpecializationRecord &Record)
static StringRef getRelationshipString(RelationshipKind Kind)
Get the string representation of the relationship kind.
void visitCXXClassRecord(const CXXClassRecord &Record)
void visitGlobalVariableTemplatePartialSpecializationRecord(const GlobalVariableTemplatePartialSpecializationRecord &Record)
const APIIgnoresList & IgnoresList
The list of symbols to ignore.
void visitCXXFieldRecord(const CXXFieldRecord &Record)
void visitStructRecord(const StructRecord &Record)
Visit a struct record.
void visitObjCContainerRecord(const ObjCContainerRecord &Record)
Visit an Objective-C container record.
void visitMacroDefinitionRecord(const MacroDefinitionRecord &Record)
Visit a macro definition record.
void visitCXXFieldTemplateRecord(const CXXFieldTemplateRecord &Record)
void visitEnumRecord(const EnumRecord &Record)
Visit an enum record.
void visitGlobalVariableTemplateRecord(const GlobalVariableTemplateRecord &Record)
Object serialize()
Serialize the APIs in APISet in the Symbol Graph format.
void visitTypedefRecord(const TypedefRecord &Record)
Visit a typedef record.
void serializeSingleRecord(const APIRecord *Record)
Serialize a single record.
RelationshipKind
The kind of a relationship between two symbols.
@ InheritsFrom
The source symbol is inherited from the target symbol.
@ MemberOf
The source symbol is a member of the target symbol.
@ ExtensionTo
The source symbol is an extension to the target symbol.
@ ConformsTo
The source symbol conforms to the target symbol.
void visitGlobalFunctionRecord(const GlobalFunctionRecord &Record)
Visit a global function record.
void visitObjCCategoryRecord(const ObjCCategoryRecord &Record)
Visit an Objective-C category record.
void visitClassTemplateSpecializationRecord(const ClassTemplateSpecializationRecord &Record)
void visitConceptRecord(const ConceptRecord &Record)
void visitGlobalFunctionTemplateSpecializationRecord(const GlobalFunctionTemplateSpecializationRecord &Record)
void visitStaticFieldRecord(const StaticFieldRecord &Record)
void visitGlobalFunctionTemplateRecord(const GlobalFunctionTemplateRecord &Record)
static StringRef getConstraintString(ConstraintKind Kind)
void visitCXXStaticMethodRecord(const CXXStaticMethodRecord &Record)
void visitClassTemplateRecord(const ClassTemplateRecord &Record)
void visitClassTemplatePartialSpecializationRecord(const ClassTemplatePartialSpecializationRecord &Record)
void visitMethodTemplateRecord(const CXXMethodTemplateRecord &Record)
static std::optional< Object > serializeSingleSymbolSGF(StringRef USR, const APISet &API)
Serialize a single symbol SGF.
void visitGlobalVariableRecord(const GlobalVariableRecord &Record)
Visit a global variable record.
void visitCXXInstanceMethodRecord(const CXXInstanceMethodRecord &Record)
void visitMethodTemplateSpecializationRecord(const CXXMethodTemplateSpecializationRecord &Record)
void visitNamespaceRecord(const NamespaceRecord &Record)
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:5193
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.
@ Struct
The "struct" keyword introduces the elaborated-type-specifier.
@ Class
The "class" keyword introduces the elaborated-type-specifier.
@ Enum
The "enum" keyword introduces the elaborated-type-specifier.
std::string getClangFullVersion()
Retrieves a string representing the complete clang version, which includes the clang version number,...
Definition: Version.cpp:88
YAML serialization mapping.
Definition: Dominators.h:30
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:156
PresumedLoc Location
Definition: API.h:226
RecordKind
Discriminator for LLVM-style RTTI (dyn_cast<> et al.)
Definition: API.h:158
@ RK_GlobalFunctionTemplateSpecialization
Definition: API.h:163
@ RK_GlobalVariableTemplatePartialSpecialization
Definition: API.h:167
@ RK_GlobalVariableTemplateSpecialization
Definition: API.h:166
@ RK_ClassTemplatePartialSpecialization
Definition: API.h:179
bool IsFromSystemHeader
Whether the symbol was defined in a system header.
Definition: API.h:248
This holds information associated with enums.
Definition: API.h:461
This holds information associated with global functions.
Definition: API.h:290
This holds information associated with global functions.
Definition: API.h:361
This holds information associated with macro definitions.
Definition: API.h:1076
This holds information associated with Objective-C categories.
Definition: API.h:1007
The base representation of an Objective-C container record.
Definition: API.h:899
This holds information associated with structs.
Definition: API.h:499
bool Compact
Do not include unnecessary whitespaces to save space.
This represents a reference to another symbol that might come from external sources.
Definition: API.h:858
This holds information associated with typedefs.
Definition: API.h:1098
Check if a record type has a function signature mixin.
Definition: API.h:1124