21#include "llvm/ADT/STLExtras.h"
22#include "llvm/ADT/STLFunctionalExtras.h"
23#include "llvm/ADT/SmallVector.h"
24#include "llvm/Support/Casting.h"
25#include "llvm/Support/Compiler.h"
26#include "llvm/Support/JSON.h"
27#include "llvm/Support/Path.h"
28#include "llvm/Support/VersionTuple.h"
41void serializeObject(Object &
Paren, StringRef Key, std::optional<Object> Obj) {
43 Paren[Key] = std::move(*Obj);
48void serializeArray(Object &
Paren, StringRef Key, std::optional<Array> Array) {
50 Paren[Key] = std::move(*Array);
69std::optional<Object> serializeSemanticVersion(
const VersionTuple &
V) {
74 Version[
"major"] =
V.getMajor();
75 Version[
"minor"] =
V.getMinor().value_or(0);
76 Version[
"patch"] =
V.getSubminor().value_or(0);
84Object serializeOperatingSystem(
const Triple &T) {
86 OS[
"name"] = T.getOSTypeName(T.getOS());
87 serializeObject(OS,
"minimumVersion",
88 serializeSemanticVersion(T.getMinimumSupportedOSVersion()));
96Object serializePlatform(
const Triple &T) {
98 Platform[
"architecture"] = T.getArchName();
99 Platform[
"vendor"] = T.getVendorName();
100 Platform[
"operatingSystem"] = serializeOperatingSystem(T);
106 assert(Loc.
isValid() &&
"invalid source position");
109 SourcePosition[
"line"] = Loc.
getLine();
110 SourcePosition[
"character"] = Loc.
getColumn();
112 return SourcePosition;
121 bool IncludeFileURI =
false) {
123 serializeObject(
SourceLocation,
"position", serializeSourcePosition(Loc));
125 if (IncludeFileURI) {
126 std::string FileURI =
"file://";
128 FileURI += sys::path::convert_to_slash(Loc.
getFilename());
139 serializeObject(
SourceRange,
"start", serializeSourcePosition(BeginLoc));
140 serializeObject(
SourceRange,
"end", serializeSourcePosition(EndLoc));
160 Array AvailabilityArray;
163 Object UnconditionallyDeprecated;
164 UnconditionallyDeprecated[
"domain"] =
"*";
165 UnconditionallyDeprecated[
"isUnconditionallyDeprecated"] =
true;
166 AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated));
171 for (
const auto &AvailInfo : Availabilities) {
173 Availability[
"domain"] = AvailInfo.Domain;
174 if (AvailInfo.Unavailable)
175 Availability[
"isUnconditionallyUnavailable"] =
true;
177 serializeObject(Availability,
"introducedVersion",
178 serializeSemanticVersion(AvailInfo.Introduced));
179 serializeObject(Availability,
"deprecatedVersion",
180 serializeSemanticVersion(AvailInfo.Deprecated));
181 serializeObject(Availability,
"obsoletedVersion",
182 serializeSemanticVersion(AvailInfo.Obsoleted));
184 AvailabilityArray.emplace_back(std::move(Availability));
187 return AvailabilityArray;
196 return "objective-c";
200 case Language::ObjCXX:
201 case Language::OpenCL:
202 case Language::OpenCLCXX:
204 case Language::RenderScript:
209 case Language::Unknown:
211 case Language::LLVM_IR:
212 llvm_unreachable(
"Unsupported language kind");
215 llvm_unreachable(
"Unhandled language kind");
246std::optional<Object> serializeDocComment(
const DocComment &Comment) {
252 for (
const auto &CommentLine : Comment) {
254 Line[
"text"] = CommentLine.Text;
255 serializeObject(Line,
"range",
256 serializeSourceRange(CommentLine.Begin, CommentLine.End));
257 LinesArray.emplace_back(std::move(Line));
259 serializeArray(
DocComment,
"lines", LinesArray);
306 Fragment[
"spelling"] = F.Spelling;
308 if (!F.PreciseIdentifier.empty())
309 Fragment[
"preciseIdentifier"] = F.PreciseIdentifier;
310 Fragments.emplace_back(std::move(Fragment));
327 Names[
"title"] =
Record.Name;
328 serializeArray(Names,
"subHeading",
329 serializeDeclarationFragments(
Record.SubHeading));
332 DeclarationFragments::FragmentKind::Identifier,
334 serializeArray(Names,
"navigator",
335 serializeDeclarationFragments(NavigatorFragments));
341 auto AddLangPrefix = [&
Lang](StringRef S) -> std::string {
348 llvm_unreachable(
"Records should have an explicit kind");
351 Kind[
"identifier"] = AddLangPrefix(
"func");
352 Kind[
"displayName"] =
"Function";
355 Kind[
"identifier"] = AddLangPrefix(
"var");
356 Kind[
"displayName"] =
"Global Variable";
359 Kind[
"identifier"] = AddLangPrefix(
"enum.case");
360 Kind[
"displayName"] =
"Enumeration Case";
363 Kind[
"identifier"] = AddLangPrefix(
"enum");
364 Kind[
"displayName"] =
"Enumeration";
367 Kind[
"identifier"] = AddLangPrefix(
"property");
368 Kind[
"displayName"] =
"Instance Property";
371 Kind[
"identifier"] = AddLangPrefix(
"struct");
372 Kind[
"displayName"] =
"Structure";
375 Kind[
"identifier"] = AddLangPrefix(
"ivar");
376 Kind[
"displayName"] =
"Instance Variable";
379 Kind[
"identifier"] = AddLangPrefix(
"method");
380 Kind[
"displayName"] =
"Instance Method";
383 Kind[
"identifier"] = AddLangPrefix(
"type.method");
384 Kind[
"displayName"] =
"Type Method";
387 Kind[
"identifier"] = AddLangPrefix(
"property");
388 Kind[
"displayName"] =
"Instance Property";
391 Kind[
"identifier"] = AddLangPrefix(
"type.property");
392 Kind[
"displayName"] =
"Type Property";
395 Kind[
"identifier"] = AddLangPrefix(
"class");
396 Kind[
"displayName"] =
"Class";
400 llvm_unreachable(
"Serializing standalone Objective-C category symbols is "
404 Kind[
"identifier"] = AddLangPrefix(
"protocol");
405 Kind[
"displayName"] =
"Protocol";
408 Kind[
"identifier"] = AddLangPrefix(
"macro");
409 Kind[
"displayName"] =
"Macro";
412 Kind[
"identifier"] = AddLangPrefix(
"typealias");
413 Kind[
"displayName"] =
"Type Alias";
426 return serializeSymbolKind(
Record.getKind(), Lang);
429template <
typename RecordTy>
431serializeFunctionSignatureMixinImpl(
const RecordTy &Record, std::true_type) {
432 const auto &FS =
Record.Signature;
437 serializeArray(Signature,
"returns",
438 serializeDeclarationFragments(FS.getReturnType()));
441 for (
const auto &
P : FS.getParameters()) {
444 serializeArray(
Parameter,
"declarationFragments",
445 serializeDeclarationFragments(
P.Fragments));
450 Signature[
"parameters"] = std::move(Parameters);
455template <
typename RecordTy>
457serializeFunctionSignatureMixinImpl(
const RecordTy &Record, std::false_type) {
471template <
typename RecordTy>
472void serializeFunctionSignatureMixin(Object &
Paren,
const RecordTy &Record) {
473 serializeObject(
Paren,
"functionSignature",
474 serializeFunctionSignatureMixinImpl(
478struct PathComponent {
484 : USR(USR), Name(Name),
Kind(
Kind) {}
487template <
typename RecordTy>
488bool generatePathComponents(
489 const RecordTy &Record,
const APISet &API,
490 function_ref<
void(
const PathComponent &)> ComponentTransformer) {
493 const auto *CurrentParent = &
Record.ParentInformation;
494 bool FailedToFindParent =
false;
495 while (CurrentParent && !CurrentParent->empty()) {
496 PathComponent CurrentParentComponent(CurrentParent->ParentUSR,
497 CurrentParent->ParentName,
498 CurrentParent->ParentKind);
500 auto *ParentRecord = CurrentParent->ParentRecord;
507 if (
auto *CategoryRecord =
508 dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) {
510 CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR,
511 CategoryRecord->Interface.Name,
518 FailedToFindParent =
true;
522 ReverseComponenents.push_back(std::move(CurrentParentComponent));
523 CurrentParent = &ParentRecord->ParentInformation;
526 for (
const auto &PC : reverse(ReverseComponenents))
527 ComponentTransformer(PC);
529 return FailedToFindParent;
532Object serializeParentContext(
const PathComponent &PC,
Language Lang) {
534 ParentContextElem[
"usr"] = PC.USR;
535 ParentContextElem[
"name"] = PC.Name;
536 ParentContextElem[
"kind"] = serializeSymbolKind(PC.Kind, Lang)[
"identifier"];
537 return ParentContextElem;
540template <
typename RecordTy>
541Array generateParentContexts(
const RecordTy &Record,
const APISet &API,
543 Array ParentContexts;
544 generatePathComponents(Record, API,
545 [Lang, &ParentContexts](
const PathComponent &PC) {
546 ParentContexts.push_back(
547 serializeParentContext(PC, Lang));
550 return ParentContexts;
555void SymbolGraphSerializer::anchor() {}
558const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};
560Object SymbolGraphSerializer::serializeMetadata()
const {
562 serializeObject(Metadata,
"formatVersion",
563 serializeSemanticVersion(FormatVersion));
568Object SymbolGraphSerializer::serializeModule()
const {
577bool SymbolGraphSerializer::shouldSkip(
const APIRecord &Record)
const {
583 if (
Record.Availabilities.isUnconditionallyUnavailable())
588 if (
Record.Name.startswith(
"_"))
594template <
typename RecordTy>
596SymbolGraphSerializer::serializeAPIRecord(
const RecordTy &Record)
const {
597 if (shouldSkip(Record))
601 serializeObject(Obj,
"identifier",
603 serializeObject(Obj,
"kind", serializeSymbolKind(Record,
API.
getLanguage()));
604 serializeObject(Obj,
"names", serializeNames(Record));
607 serializeSourceLocation(
Record.Location,
true));
608 serializeArray(Obj,
"availability",
609 serializeAvailability(
Record.Availabilities));
610 serializeObject(Obj,
"docComment", serializeDocComment(
Record.Comment));
611 serializeArray(Obj,
"declarationFragments",
612 serializeDeclarationFragments(
Record.Declaration));
615 Obj[
"accessLevel"] =
"public";
619 if (generatePathComponents(Record,
API,
620 [&PathComponentsNames](
const PathComponent &PC) {
621 PathComponentsNames.push_back(PC.Name);
625 serializeArray(Obj,
"pathComponents", Array(PathComponentsNames));
627 serializeFunctionSignatureMixin(Obj, Record);
632template <
typename MemberTy>
633void SymbolGraphSerializer::serializeMembers(
635 const SmallVector<std::unique_ptr<MemberTy>> &Members) {
639 for (
const auto &
Member : Members) {
640 auto MemberRecord = serializeAPIRecord(*
Member);
644 Symbols.emplace_back(std::move(*MemberRecord));
654 return "inheritsFrom";
658 llvm_unreachable(
"Unhandled relationship kind");
661void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind,
665 Relationship[
"source"] = Source.
USR;
666 Relationship[
"target"] =
Target.USR;
667 Relationship[
"targetFallback"] =
Target.Name;
670 Relationships.emplace_back(std::move(Relationship));
673void SymbolGraphSerializer::serializeGlobalFunctionRecord(
675 auto Obj = serializeAPIRecord(Record);
679 Symbols.emplace_back(std::move(*Obj));
682void SymbolGraphSerializer::serializeGlobalVariableRecord(
684 auto Obj = serializeAPIRecord(Record);
688 Symbols.emplace_back(std::move(*Obj));
691void SymbolGraphSerializer::serializeEnumRecord(
const EnumRecord &Record) {
692 auto Enum = serializeAPIRecord(Record);
696 Symbols.emplace_back(std::move(*
Enum));
697 serializeMembers(Record,
Record.Constants);
700void SymbolGraphSerializer::serializeStructRecord(
const StructRecord &Record) {
701 auto Struct = serializeAPIRecord(Record);
705 Symbols.emplace_back(std::move(*Struct));
706 serializeMembers(Record,
Record.Fields);
709void SymbolGraphSerializer::serializeObjCContainerRecord(
711 auto ObjCContainer = serializeAPIRecord(Record);
715 Symbols.emplace_back(std::move(*ObjCContainer));
717 serializeMembers(Record,
Record.Ivars);
718 serializeMembers(Record,
Record.Methods);
719 serializeMembers(Record,
Record.Properties);
721 for (
const auto &Protocol :
Record.Protocols)
725 if (
auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) {
726 if (!ObjCInterface->SuperClass.empty())
730 ObjCInterface->SuperClass);
734 for (
const auto *
Category : ObjCInterface->Categories) {
735 serializeMembers(Record,
Category->Ivars);
736 serializeMembers(Record,
Category->Methods);
737 serializeMembers(Record,
Category->Properties);
740 for (
const auto &Protocol :
Category->Protocols)
746void SymbolGraphSerializer::serializeMacroDefinitionRecord(
748 auto Macro = serializeAPIRecord(Record);
753 Symbols.emplace_back(std::move(*Macro));
756void SymbolGraphSerializer::serializeSingleRecord(
const APIRecord *Record) {
757 switch (
Record->getKind()) {
759 llvm_unreachable(
"Records should have a known kind!");
761 serializeGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record));
764 serializeGlobalVariableRecord(*cast<GlobalVariableRecord>(Record));
767 serializeEnumRecord(*cast<EnumRecord>(Record));
770 serializeStructRecord(*cast<StructRecord>(Record));
773 serializeObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record));
776 serializeObjCContainerRecord(*cast<ObjCProtocolRecord>(Record));
779 serializeMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record));
782 serializeTypedefRecord(*cast<TypedefRecord>(Record));
785 if (
auto Obj = serializeAPIRecord(*Record)) {
786 Symbols.emplace_back(std::move(*Obj));
787 auto &ParentInformation =
Record->ParentInformation;
788 if (!ParentInformation.empty())
790 *ParentInformation.ParentRecord);
796void SymbolGraphSerializer::serializeTypedefRecord(
800 bool ShouldDrop =
Record.UnderlyingType.Name.empty();
803 ShouldDrop |= (
Record.UnderlyingType.Name ==
Record.Name);
807 auto Typedef = serializeAPIRecord(Record);
811 (*Typedef)[
"type"] =
Record.UnderlyingType.USR;
813 Symbols.emplace_back(std::move(*Typedef));
819 serializeGlobalVariableRecord(*GlobalVar.second);
822 serializeGlobalFunctionRecord(*GlobalFunction.second);
826 serializeEnumRecord(*
Enum.second);
830 serializeStructRecord(*Struct.second);
834 serializeObjCContainerRecord(*ObjCInterface.second);
838 serializeObjCContainerRecord(*ObjCProtocol.second);
841 serializeMacroDefinitionRecord(*Macro.second);
844 serializeTypedefRecord(*Typedef.second);
846 return serializeCurrentGraph();
849Object SymbolGraphSerializer::serializeCurrentGraph() {
851 serializeObject(Root,
"metadata", serializeMetadata());
852 serializeObject(Root,
"module", serializeModule());
854 Root[
"symbols"] = std::move(Symbols);
855 Root[
"relationships"] = std::move(Relationships);
863 os << formatv(
"{0}",
Value(std::move(root))) <<
"\n";
865 os << formatv(
"{0:2}",
Value(std::move(root))) <<
"\n";
875 if (isa<ObjCCategoryRecord>(Record))
883 Serializer.serializeSingleRecord(Record);
884 serializeObject(Root,
"symbolGraph", Serializer.serializeCurrentGraph());
887 serializeArray(Root,
"parentContexts",
888 generateParentContexts(*Record,
API, Lang));
890 Array RelatedSymbols;
892 for (
const auto &Fragment : Record->Declaration.getFragments()) {
894 if (Fragment.PreciseIdentifier.empty())
903 Object RelatedSymbol;
904 RelatedSymbol[
"usr"] = RelatedRecord->
USR;
905 RelatedSymbol[
"declarationLanguage"] = getLanguageName(Lang);
907 RelatedSymbol[
"accessLevel"] =
"public";
912 serializeArray(RelatedSymbol,
"parentContexts",
913 generateParentContexts(*RelatedRecord,
API, Lang));
914 RelatedSymbols.push_back(std::move(RelatedSymbol));
917 serializeArray(Root,
"relatedSymbols", RelatedSymbols);
This file defines the APIRecord-based structs and the APISet class.
This file defines the Declaration Fragments related classes.
This file defines the ExtractAPI APISerializer interface.
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.
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.
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.
Language
The language for the input, used to select and validate the language standard and possible actions.
@ Parameter
The parameter type of a method or function.
std::string getClangFullVersion()
Retrieves a string representing the complete clang version, which includes the clang version number,...
YAML serialization mapping.