181ad6265SDimitry Andric //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===// 281ad6265SDimitry Andric // 381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric // 781ad6265SDimitry Andric //===----------------------------------------------------------------------===// 881ad6265SDimitry Andric /// 981ad6265SDimitry Andric /// \file 1081ad6265SDimitry Andric /// This file implements the SymbolGraphSerializer. 1181ad6265SDimitry Andric /// 1281ad6265SDimitry Andric //===----------------------------------------------------------------------===// 1381ad6265SDimitry Andric 1481ad6265SDimitry Andric #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 15bdd1243dSDimitry Andric #include "clang/Basic/SourceLocation.h" 1681ad6265SDimitry Andric #include "clang/Basic/Version.h" 1781ad6265SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h" 18bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 19bdd1243dSDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h" 20bdd1243dSDimitry Andric #include "llvm/Support/Casting.h" 21bdd1243dSDimitry Andric #include "llvm/Support/Compiler.h" 2281ad6265SDimitry Andric #include "llvm/Support/Path.h" 2381ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h" 24bdd1243dSDimitry Andric #include <optional> 2581ad6265SDimitry Andric #include <type_traits> 2681ad6265SDimitry Andric 2781ad6265SDimitry Andric using namespace clang; 2881ad6265SDimitry Andric using namespace clang::extractapi; 2981ad6265SDimitry Andric using namespace llvm; 3081ad6265SDimitry Andric using namespace llvm::json; 3181ad6265SDimitry Andric 3281ad6265SDimitry Andric namespace { 3381ad6265SDimitry Andric 3481ad6265SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren 3581ad6265SDimitry Andric /// at position \p Key. 36bdd1243dSDimitry Andric void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) { 3781ad6265SDimitry Andric if (Obj) 38bdd1243dSDimitry Andric Paren[Key] = std::move(*Obj); 3981ad6265SDimitry Andric } 4081ad6265SDimitry Andric 415f757f3fSDimitry Andric /// Helper function to inject a StringRef \p String into an object \p Paren at 425f757f3fSDimitry Andric /// position \p Key 435f757f3fSDimitry Andric void serializeString(Object &Paren, StringRef Key, 445f757f3fSDimitry Andric std::optional<std::string> String) { 455f757f3fSDimitry Andric if (String) 465f757f3fSDimitry Andric Paren[Key] = std::move(*String); 475f757f3fSDimitry Andric } 485f757f3fSDimitry Andric 4981ad6265SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at 5081ad6265SDimitry Andric /// position \p Key. 51bdd1243dSDimitry Andric void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) { 5281ad6265SDimitry Andric if (Array) 53bdd1243dSDimitry Andric Paren[Key] = std::move(*Array); 5481ad6265SDimitry Andric } 5581ad6265SDimitry Andric 5681ad6265SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 5781ad6265SDimitry Andric /// format. 5881ad6265SDimitry Andric /// 5981ad6265SDimitry Andric /// A semantic version object contains three numeric fields, representing the 6081ad6265SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple. 6181ad6265SDimitry Andric /// For example version tuple 1.0.3 is serialized as: 6281ad6265SDimitry Andric /// \code 6381ad6265SDimitry Andric /// { 6481ad6265SDimitry Andric /// "major" : 1, 6581ad6265SDimitry Andric /// "minor" : 0, 6681ad6265SDimitry Andric /// "patch" : 3 6781ad6265SDimitry Andric /// } 6881ad6265SDimitry Andric /// \endcode 6981ad6265SDimitry Andric /// 70bdd1243dSDimitry Andric /// \returns \c std::nullopt if the version \p V is empty, or an \c Object 71bdd1243dSDimitry Andric /// containing the semantic version representation of \p V. 72bdd1243dSDimitry Andric std::optional<Object> serializeSemanticVersion(const VersionTuple &V) { 7381ad6265SDimitry Andric if (V.empty()) 74bdd1243dSDimitry Andric return std::nullopt; 7581ad6265SDimitry Andric 7681ad6265SDimitry Andric Object Version; 7781ad6265SDimitry Andric Version["major"] = V.getMajor(); 7881ad6265SDimitry Andric Version["minor"] = V.getMinor().value_or(0); 7981ad6265SDimitry Andric Version["patch"] = V.getSubminor().value_or(0); 8081ad6265SDimitry Andric return Version; 8181ad6265SDimitry Andric } 8281ad6265SDimitry Andric 8381ad6265SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property. 8481ad6265SDimitry Andric /// 8581ad6265SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an 8681ad6265SDimitry Andric /// optional \c minimumVersion semantic version field. 8781ad6265SDimitry Andric Object serializeOperatingSystem(const Triple &T) { 8881ad6265SDimitry Andric Object OS; 8981ad6265SDimitry Andric OS["name"] = T.getOSTypeName(T.getOS()); 9081ad6265SDimitry Andric serializeObject(OS, "minimumVersion", 9181ad6265SDimitry Andric serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 9281ad6265SDimitry Andric return OS; 9381ad6265SDimitry Andric } 9481ad6265SDimitry Andric 9581ad6265SDimitry Andric /// Serialize the platform information in the Symbol Graph module section. 9681ad6265SDimitry Andric /// 9781ad6265SDimitry Andric /// The platform object describes a target platform triple in corresponding 9881ad6265SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem. 9981ad6265SDimitry Andric Object serializePlatform(const Triple &T) { 10081ad6265SDimitry Andric Object Platform; 10181ad6265SDimitry Andric Platform["architecture"] = T.getArchName(); 10281ad6265SDimitry Andric Platform["vendor"] = T.getVendorName(); 10381ad6265SDimitry Andric Platform["operatingSystem"] = serializeOperatingSystem(T); 10481ad6265SDimitry Andric return Platform; 10581ad6265SDimitry Andric } 10681ad6265SDimitry Andric 10781ad6265SDimitry Andric /// Serialize a source position. 10881ad6265SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) { 10981ad6265SDimitry Andric assert(Loc.isValid() && "invalid source position"); 11081ad6265SDimitry Andric 11181ad6265SDimitry Andric Object SourcePosition; 1125f757f3fSDimitry Andric SourcePosition["line"] = Loc.getLine() - 1; 1135f757f3fSDimitry Andric SourcePosition["character"] = Loc.getColumn() - 1; 11481ad6265SDimitry Andric 11581ad6265SDimitry Andric return SourcePosition; 11681ad6265SDimitry Andric } 11781ad6265SDimitry Andric 11881ad6265SDimitry Andric /// Serialize a source location in file. 11981ad6265SDimitry Andric /// 12081ad6265SDimitry Andric /// \param Loc The presumed location to serialize. 12181ad6265SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 12281ad6265SDimitry Andric /// Defaults to false. 12381ad6265SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc, 12481ad6265SDimitry Andric bool IncludeFileURI = false) { 12581ad6265SDimitry Andric Object SourceLocation; 12681ad6265SDimitry Andric serializeObject(SourceLocation, "position", serializeSourcePosition(Loc)); 12781ad6265SDimitry Andric 12881ad6265SDimitry Andric if (IncludeFileURI) { 12981ad6265SDimitry Andric std::string FileURI = "file://"; 13081ad6265SDimitry Andric // Normalize file path to use forward slashes for the URI. 13181ad6265SDimitry Andric FileURI += sys::path::convert_to_slash(Loc.getFilename()); 13281ad6265SDimitry Andric SourceLocation["uri"] = FileURI; 13381ad6265SDimitry Andric } 13481ad6265SDimitry Andric 13581ad6265SDimitry Andric return SourceLocation; 13681ad6265SDimitry Andric } 13781ad6265SDimitry Andric 13881ad6265SDimitry Andric /// Serialize a source range with begin and end locations. 13981ad6265SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc, 14081ad6265SDimitry Andric const PresumedLoc &EndLoc) { 14181ad6265SDimitry Andric Object SourceRange; 14281ad6265SDimitry Andric serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 14381ad6265SDimitry Andric serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 14481ad6265SDimitry Andric return SourceRange; 14581ad6265SDimitry Andric } 14681ad6265SDimitry Andric 14781ad6265SDimitry Andric /// Serialize the availability attributes of a symbol. 14881ad6265SDimitry Andric /// 14981ad6265SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted 150*7a6dacacSDimitry Andric /// versions of the symbol as semantic versions, if not default. 151*7a6dacacSDimitry Andric /// Availability information also contains flags to indicate if the symbol is 152*7a6dacacSDimitry Andric /// unconditionally unavailable or deprecated, 153*7a6dacacSDimitry Andric /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). 15481ad6265SDimitry Andric /// 155bdd1243dSDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes, 156*7a6dacacSDimitry Andric /// or an \c Array containing an object with the formatted availability 157*7a6dacacSDimitry Andric /// information. 158*7a6dacacSDimitry Andric std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) { 159*7a6dacacSDimitry Andric if (Avail.isDefault()) 160bdd1243dSDimitry Andric return std::nullopt; 16181ad6265SDimitry Andric 162*7a6dacacSDimitry Andric Object Availability; 163bdd1243dSDimitry Andric Array AvailabilityArray; 164*7a6dacacSDimitry Andric Availability["domain"] = Avail.Domain; 165*7a6dacacSDimitry Andric serializeObject(Availability, "introduced", 166*7a6dacacSDimitry Andric serializeSemanticVersion(Avail.Introduced)); 167*7a6dacacSDimitry Andric serializeObject(Availability, "deprecated", 168*7a6dacacSDimitry Andric serializeSemanticVersion(Avail.Deprecated)); 169*7a6dacacSDimitry Andric serializeObject(Availability, "obsoleted", 170*7a6dacacSDimitry Andric serializeSemanticVersion(Avail.Obsoleted)); 171*7a6dacacSDimitry Andric if (Avail.isUnconditionallyDeprecated()) { 172bdd1243dSDimitry Andric Object UnconditionallyDeprecated; 173bdd1243dSDimitry Andric UnconditionallyDeprecated["domain"] = "*"; 174bdd1243dSDimitry Andric UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true; 175bdd1243dSDimitry Andric AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated)); 176bdd1243dSDimitry Andric } 177*7a6dacacSDimitry Andric if (Avail.isUnconditionallyUnavailable()) { 178*7a6dacacSDimitry Andric Object UnconditionallyUnavailable; 179*7a6dacacSDimitry Andric UnconditionallyUnavailable["domain"] = "*"; 180*7a6dacacSDimitry Andric UnconditionallyUnavailable["isUnconditionallyUnavailable"] = true; 181*7a6dacacSDimitry Andric AvailabilityArray.emplace_back(std::move(UnconditionallyUnavailable)); 18206c3fb27SDimitry Andric } 183bdd1243dSDimitry Andric AvailabilityArray.emplace_back(std::move(Availability)); 184bdd1243dSDimitry Andric return AvailabilityArray; 18581ad6265SDimitry Andric } 18681ad6265SDimitry Andric 18781ad6265SDimitry Andric /// Get the language name string for interface language references. 18881ad6265SDimitry Andric StringRef getLanguageName(Language Lang) { 18981ad6265SDimitry Andric switch (Lang) { 19081ad6265SDimitry Andric case Language::C: 19181ad6265SDimitry Andric return "c"; 19281ad6265SDimitry Andric case Language::ObjC: 19381ad6265SDimitry Andric return "objective-c"; 1945f757f3fSDimitry Andric case Language::CXX: 1955f757f3fSDimitry Andric return "c++"; 1965f757f3fSDimitry Andric case Language::ObjCXX: 1975f757f3fSDimitry Andric return "objective-c++"; 19881ad6265SDimitry Andric 19981ad6265SDimitry Andric // Unsupported language currently 20081ad6265SDimitry Andric case Language::OpenCL: 20181ad6265SDimitry Andric case Language::OpenCLCXX: 20281ad6265SDimitry Andric case Language::CUDA: 20381ad6265SDimitry Andric case Language::RenderScript: 20481ad6265SDimitry Andric case Language::HIP: 20581ad6265SDimitry Andric case Language::HLSL: 20681ad6265SDimitry Andric 20781ad6265SDimitry Andric // Languages that the frontend cannot parse and compile 20881ad6265SDimitry Andric case Language::Unknown: 20981ad6265SDimitry Andric case Language::Asm: 21081ad6265SDimitry Andric case Language::LLVM_IR: 21181ad6265SDimitry Andric llvm_unreachable("Unsupported language kind"); 21281ad6265SDimitry Andric } 21381ad6265SDimitry Andric 21481ad6265SDimitry Andric llvm_unreachable("Unhandled language kind"); 21581ad6265SDimitry Andric } 21681ad6265SDimitry Andric 21781ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format. 21881ad6265SDimitry Andric /// 21981ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique 22081ad6265SDimitry Andric /// references, and the interface language name. 22181ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) { 22281ad6265SDimitry Andric Object Identifier; 22381ad6265SDimitry Andric Identifier["precise"] = Record.USR; 22481ad6265SDimitry Andric Identifier["interfaceLanguage"] = getLanguageName(Lang); 22581ad6265SDimitry Andric 22681ad6265SDimitry Andric return Identifier; 22781ad6265SDimitry Andric } 22881ad6265SDimitry Andric 22981ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by 23081ad6265SDimitry Andric /// the Symbol Graph format. 23181ad6265SDimitry Andric /// 23281ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line 23381ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range 23481ad6265SDimitry Andric /// information. 23581ad6265SDimitry Andric /// e.g. 23681ad6265SDimitry Andric /// \code 23781ad6265SDimitry Andric /// /// This is a documentation comment 23881ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 23981ad6265SDimitry Andric /// /// with multiple lines. 24081ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 24181ad6265SDimitry Andric /// \endcode 24281ad6265SDimitry Andric /// 243bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing 244bdd1243dSDimitry Andric /// the formatted lines. 245bdd1243dSDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) { 24681ad6265SDimitry Andric if (Comment.empty()) 247bdd1243dSDimitry Andric return std::nullopt; 24881ad6265SDimitry Andric 24981ad6265SDimitry Andric Object DocComment; 25081ad6265SDimitry Andric Array LinesArray; 25181ad6265SDimitry Andric for (const auto &CommentLine : Comment) { 25281ad6265SDimitry Andric Object Line; 25381ad6265SDimitry Andric Line["text"] = CommentLine.Text; 25481ad6265SDimitry Andric serializeObject(Line, "range", 25581ad6265SDimitry Andric serializeSourceRange(CommentLine.Begin, CommentLine.End)); 25681ad6265SDimitry Andric LinesArray.emplace_back(std::move(Line)); 25781ad6265SDimitry Andric } 25881ad6265SDimitry Andric serializeArray(DocComment, "lines", LinesArray); 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric return DocComment; 26181ad6265SDimitry Andric } 26281ad6265SDimitry Andric 26381ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol. 26481ad6265SDimitry Andric /// 26581ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important 26681ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to 26781ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for 26881ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example: 26981ad6265SDimitry Andric /// \code 27081ad6265SDimitry Andric /// const int pi; -> "declarationFragments" : [ 27181ad6265SDimitry Andric /// { 27281ad6265SDimitry Andric /// "kind" : "keyword", 27381ad6265SDimitry Andric /// "spelling" : "const" 27481ad6265SDimitry Andric /// }, 27581ad6265SDimitry Andric /// { 27681ad6265SDimitry Andric /// "kind" : "text", 27781ad6265SDimitry Andric /// "spelling" : " " 27881ad6265SDimitry Andric /// }, 27981ad6265SDimitry Andric /// { 28081ad6265SDimitry Andric /// "kind" : "typeIdentifier", 28181ad6265SDimitry Andric /// "preciseIdentifier" : "c:I", 28281ad6265SDimitry Andric /// "spelling" : "int" 28381ad6265SDimitry Andric /// }, 28481ad6265SDimitry Andric /// { 28581ad6265SDimitry Andric /// "kind" : "text", 28681ad6265SDimitry Andric /// "spelling" : " " 28781ad6265SDimitry Andric /// }, 28881ad6265SDimitry Andric /// { 28981ad6265SDimitry Andric /// "kind" : "identifier", 29081ad6265SDimitry Andric /// "spelling" : "pi" 29181ad6265SDimitry Andric /// } 29281ad6265SDimitry Andric /// ] 29381ad6265SDimitry Andric /// \endcode 29481ad6265SDimitry Andric /// 295bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the 296bdd1243dSDimitry Andric /// formatted declaration fragments array. 297bdd1243dSDimitry Andric std::optional<Array> 298bdd1243dSDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) { 29981ad6265SDimitry Andric if (DF.getFragments().empty()) 300bdd1243dSDimitry Andric return std::nullopt; 30181ad6265SDimitry Andric 30281ad6265SDimitry Andric Array Fragments; 30381ad6265SDimitry Andric for (const auto &F : DF.getFragments()) { 30481ad6265SDimitry Andric Object Fragment; 30581ad6265SDimitry Andric Fragment["spelling"] = F.Spelling; 30681ad6265SDimitry Andric Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 30781ad6265SDimitry Andric if (!F.PreciseIdentifier.empty()) 30881ad6265SDimitry Andric Fragment["preciseIdentifier"] = F.PreciseIdentifier; 30981ad6265SDimitry Andric Fragments.emplace_back(std::move(Fragment)); 31081ad6265SDimitry Andric } 31181ad6265SDimitry Andric 31281ad6265SDimitry Andric return Fragments; 31381ad6265SDimitry Andric } 31481ad6265SDimitry Andric 31581ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph 31681ad6265SDimitry Andric /// format. 31781ad6265SDimitry Andric /// 31881ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol 31981ad6265SDimitry Andric /// that can be used for different applications: 32081ad6265SDimitry Andric /// - \c title : The simple declared name of the symbol; 32181ad6265SDimitry Andric /// - \c subHeading : An array of declaration fragments that provides tags, 32281ad6265SDimitry Andric /// and potentially more tokens (for example the \c +/- symbol for 32381ad6265SDimitry Andric /// Objective-C methods). Can be used as sub-headings for documentation. 32481ad6265SDimitry Andric Object serializeNames(const APIRecord &Record) { 32581ad6265SDimitry Andric Object Names; 3265f757f3fSDimitry Andric if (auto *CategoryRecord = 3275f757f3fSDimitry Andric dyn_cast_or_null<const ObjCCategoryRecord>(&Record)) 3285f757f3fSDimitry Andric Names["title"] = 3295f757f3fSDimitry Andric (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str(); 3305f757f3fSDimitry Andric else 33181ad6265SDimitry Andric Names["title"] = Record.Name; 3325f757f3fSDimitry Andric 33381ad6265SDimitry Andric serializeArray(Names, "subHeading", 33481ad6265SDimitry Andric serializeDeclarationFragments(Record.SubHeading)); 33581ad6265SDimitry Andric DeclarationFragments NavigatorFragments; 33681ad6265SDimitry Andric NavigatorFragments.append(Record.Name, 33781ad6265SDimitry Andric DeclarationFragments::FragmentKind::Identifier, 33881ad6265SDimitry Andric /*PreciseIdentifier*/ ""); 33981ad6265SDimitry Andric serializeArray(Names, "navigator", 34081ad6265SDimitry Andric serializeDeclarationFragments(NavigatorFragments)); 34181ad6265SDimitry Andric 34281ad6265SDimitry Andric return Names; 34381ad6265SDimitry Andric } 34481ad6265SDimitry Andric 345bdd1243dSDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { 34681ad6265SDimitry Andric auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 34781ad6265SDimitry Andric return (getLanguageName(Lang) + "." + S).str(); 34881ad6265SDimitry Andric }; 34981ad6265SDimitry Andric 35081ad6265SDimitry Andric Object Kind; 351bdd1243dSDimitry Andric switch (RK) { 352bdd1243dSDimitry Andric case APIRecord::RK_Unknown: 353bdd1243dSDimitry Andric llvm_unreachable("Records should have an explicit kind"); 354bdd1243dSDimitry Andric break; 3555f757f3fSDimitry Andric case APIRecord::RK_Namespace: 3565f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("namespace"); 3575f757f3fSDimitry Andric Kind["displayName"] = "Namespace"; 3585f757f3fSDimitry Andric break; 35981ad6265SDimitry Andric case APIRecord::RK_GlobalFunction: 36081ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 36181ad6265SDimitry Andric Kind["displayName"] = "Function"; 36281ad6265SDimitry Andric break; 3635f757f3fSDimitry Andric case APIRecord::RK_GlobalFunctionTemplate: 3645f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 3655f757f3fSDimitry Andric Kind["displayName"] = "Function Template"; 3665f757f3fSDimitry Andric break; 3675f757f3fSDimitry Andric case APIRecord::RK_GlobalFunctionTemplateSpecialization: 3685f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 3695f757f3fSDimitry Andric Kind["displayName"] = "Function Template Specialization"; 3705f757f3fSDimitry Andric break; 3715f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplate: 3725f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 3735f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template"; 3745f757f3fSDimitry Andric break; 3755f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplateSpecialization: 3765f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 3775f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template Specialization"; 3785f757f3fSDimitry Andric break; 3795f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplatePartialSpecialization: 3805f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 3815f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template Partial Specialization"; 3825f757f3fSDimitry Andric break; 38381ad6265SDimitry Andric case APIRecord::RK_GlobalVariable: 38481ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 38581ad6265SDimitry Andric Kind["displayName"] = "Global Variable"; 38681ad6265SDimitry Andric break; 38781ad6265SDimitry Andric case APIRecord::RK_EnumConstant: 38881ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum.case"); 38981ad6265SDimitry Andric Kind["displayName"] = "Enumeration Case"; 39081ad6265SDimitry Andric break; 39181ad6265SDimitry Andric case APIRecord::RK_Enum: 39281ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum"); 39381ad6265SDimitry Andric Kind["displayName"] = "Enumeration"; 39481ad6265SDimitry Andric break; 39581ad6265SDimitry Andric case APIRecord::RK_StructField: 39681ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 39781ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 39881ad6265SDimitry Andric break; 39981ad6265SDimitry Andric case APIRecord::RK_Struct: 40081ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("struct"); 40181ad6265SDimitry Andric Kind["displayName"] = "Structure"; 40281ad6265SDimitry Andric break; 403*7a6dacacSDimitry Andric case APIRecord::RK_UnionField: 4045f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 4055f757f3fSDimitry Andric Kind["displayName"] = "Instance Property"; 4065f757f3fSDimitry Andric break; 4075f757f3fSDimitry Andric case APIRecord::RK_Union: 4085f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("union"); 4095f757f3fSDimitry Andric Kind["displayName"] = "Union"; 4105f757f3fSDimitry Andric break; 411*7a6dacacSDimitry Andric case APIRecord::RK_CXXField: 412*7a6dacacSDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 413*7a6dacacSDimitry Andric Kind["displayName"] = "Instance Property"; 414*7a6dacacSDimitry Andric break; 4155f757f3fSDimitry Andric case APIRecord::RK_StaticField: 4165f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("type.property"); 4175f757f3fSDimitry Andric Kind["displayName"] = "Type Property"; 4185f757f3fSDimitry Andric break; 4195f757f3fSDimitry Andric case APIRecord::RK_ClassTemplate: 4205f757f3fSDimitry Andric case APIRecord::RK_ClassTemplateSpecialization: 4215f757f3fSDimitry Andric case APIRecord::RK_ClassTemplatePartialSpecialization: 4225f757f3fSDimitry Andric case APIRecord::RK_CXXClass: 4235f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("class"); 4245f757f3fSDimitry Andric Kind["displayName"] = "Class"; 4255f757f3fSDimitry Andric break; 4265f757f3fSDimitry Andric case APIRecord::RK_CXXMethodTemplate: 4275f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4285f757f3fSDimitry Andric Kind["displayName"] = "Method Template"; 4295f757f3fSDimitry Andric break; 4305f757f3fSDimitry Andric case APIRecord::RK_CXXMethodTemplateSpecialization: 4315f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4325f757f3fSDimitry Andric Kind["displayName"] = "Method Template Specialization"; 4335f757f3fSDimitry Andric break; 4345f757f3fSDimitry Andric case APIRecord::RK_CXXFieldTemplate: 4355f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 4365f757f3fSDimitry Andric Kind["displayName"] = "Template Property"; 4375f757f3fSDimitry Andric break; 4385f757f3fSDimitry Andric case APIRecord::RK_Concept: 4395f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("concept"); 4405f757f3fSDimitry Andric Kind["displayName"] = "Concept"; 4415f757f3fSDimitry Andric break; 4425f757f3fSDimitry Andric case APIRecord::RK_CXXStaticMethod: 4435f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("type.method"); 4445f757f3fSDimitry Andric Kind["displayName"] = "Static Method"; 4455f757f3fSDimitry Andric break; 4465f757f3fSDimitry Andric case APIRecord::RK_CXXInstanceMethod: 4475f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4485f757f3fSDimitry Andric Kind["displayName"] = "Instance Method"; 4495f757f3fSDimitry Andric break; 4505f757f3fSDimitry Andric case APIRecord::RK_CXXConstructorMethod: 4515f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4525f757f3fSDimitry Andric Kind["displayName"] = "Constructor"; 4535f757f3fSDimitry Andric break; 4545f757f3fSDimitry Andric case APIRecord::RK_CXXDestructorMethod: 4555f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4565f757f3fSDimitry Andric Kind["displayName"] = "Destructor"; 4575f757f3fSDimitry Andric break; 45881ad6265SDimitry Andric case APIRecord::RK_ObjCIvar: 45981ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("ivar"); 46081ad6265SDimitry Andric Kind["displayName"] = "Instance Variable"; 46181ad6265SDimitry Andric break; 462bdd1243dSDimitry Andric case APIRecord::RK_ObjCInstanceMethod: 46381ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 46481ad6265SDimitry Andric Kind["displayName"] = "Instance Method"; 465bdd1243dSDimitry Andric break; 466bdd1243dSDimitry Andric case APIRecord::RK_ObjCClassMethod: 46781ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("type.method"); 46881ad6265SDimitry Andric Kind["displayName"] = "Type Method"; 46981ad6265SDimitry Andric break; 470bdd1243dSDimitry Andric case APIRecord::RK_ObjCInstanceProperty: 47181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 47281ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 47381ad6265SDimitry Andric break; 474bdd1243dSDimitry Andric case APIRecord::RK_ObjCClassProperty: 475bdd1243dSDimitry Andric Kind["identifier"] = AddLangPrefix("type.property"); 476bdd1243dSDimitry Andric Kind["displayName"] = "Type Property"; 477bdd1243dSDimitry Andric break; 47881ad6265SDimitry Andric case APIRecord::RK_ObjCInterface: 47981ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("class"); 48081ad6265SDimitry Andric Kind["displayName"] = "Class"; 48181ad6265SDimitry Andric break; 48281ad6265SDimitry Andric case APIRecord::RK_ObjCCategory: 4835f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("class.extension"); 4845f757f3fSDimitry Andric Kind["displayName"] = "Class Extension"; 4855f757f3fSDimitry Andric break; 4865f757f3fSDimitry Andric case APIRecord::RK_ObjCCategoryModule: 4875f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("module.extension"); 4885f757f3fSDimitry Andric Kind["displayName"] = "Module Extension"; 48981ad6265SDimitry Andric break; 49081ad6265SDimitry Andric case APIRecord::RK_ObjCProtocol: 49181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("protocol"); 49281ad6265SDimitry Andric Kind["displayName"] = "Protocol"; 49381ad6265SDimitry Andric break; 49481ad6265SDimitry Andric case APIRecord::RK_MacroDefinition: 49581ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("macro"); 49681ad6265SDimitry Andric Kind["displayName"] = "Macro"; 49781ad6265SDimitry Andric break; 49881ad6265SDimitry Andric case APIRecord::RK_Typedef: 49981ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("typealias"); 50081ad6265SDimitry Andric Kind["displayName"] = "Type Alias"; 50181ad6265SDimitry Andric break; 50281ad6265SDimitry Andric } 50381ad6265SDimitry Andric 50481ad6265SDimitry Andric return Kind; 50581ad6265SDimitry Andric } 50681ad6265SDimitry Andric 507bdd1243dSDimitry Andric /// Serialize the symbol kind information. 508bdd1243dSDimitry Andric /// 509bdd1243dSDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier 510bdd1243dSDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse 511bdd1243dSDimitry Andric /// the kind, and a \c displayName for rendering human-readable names. 512bdd1243dSDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 513bdd1243dSDimitry Andric return serializeSymbolKind(Record.getKind(), Lang); 514bdd1243dSDimitry Andric } 515bdd1243dSDimitry Andric 51681ad6265SDimitry Andric template <typename RecordTy> 517bdd1243dSDimitry Andric std::optional<Object> 518bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { 51981ad6265SDimitry Andric const auto &FS = Record.Signature; 52081ad6265SDimitry Andric if (FS.empty()) 521bdd1243dSDimitry Andric return std::nullopt; 52281ad6265SDimitry Andric 52381ad6265SDimitry Andric Object Signature; 52481ad6265SDimitry Andric serializeArray(Signature, "returns", 52581ad6265SDimitry Andric serializeDeclarationFragments(FS.getReturnType())); 52681ad6265SDimitry Andric 52781ad6265SDimitry Andric Array Parameters; 52881ad6265SDimitry Andric for (const auto &P : FS.getParameters()) { 52981ad6265SDimitry Andric Object Parameter; 53081ad6265SDimitry Andric Parameter["name"] = P.Name; 53181ad6265SDimitry Andric serializeArray(Parameter, "declarationFragments", 53281ad6265SDimitry Andric serializeDeclarationFragments(P.Fragments)); 53381ad6265SDimitry Andric Parameters.emplace_back(std::move(Parameter)); 53481ad6265SDimitry Andric } 53581ad6265SDimitry Andric 53681ad6265SDimitry Andric if (!Parameters.empty()) 53781ad6265SDimitry Andric Signature["parameters"] = std::move(Parameters); 53881ad6265SDimitry Andric 53981ad6265SDimitry Andric return Signature; 54081ad6265SDimitry Andric } 54181ad6265SDimitry Andric 54281ad6265SDimitry Andric template <typename RecordTy> 543bdd1243dSDimitry Andric std::optional<Object> 544bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { 545bdd1243dSDimitry Andric return std::nullopt; 54681ad6265SDimitry Andric } 54781ad6265SDimitry Andric 54881ad6265SDimitry Andric /// Serialize the function signature field, as specified by the 54981ad6265SDimitry Andric /// Symbol Graph format. 55081ad6265SDimitry Andric /// 55181ad6265SDimitry Andric /// The Symbol Graph function signature property contains two arrays. 55281ad6265SDimitry Andric /// - The \c returns array is the declaration fragments of the return type; 55381ad6265SDimitry Andric /// - The \c parameters array contains names and declaration fragments of the 55481ad6265SDimitry Andric /// parameters. 55581ad6265SDimitry Andric /// 556bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the 55781ad6265SDimitry Andric /// formatted function signature. 55881ad6265SDimitry Andric template <typename RecordTy> 55981ad6265SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 56081ad6265SDimitry Andric serializeObject(Paren, "functionSignature", 56181ad6265SDimitry Andric serializeFunctionSignatureMixinImpl( 56281ad6265SDimitry Andric Record, has_function_signature<RecordTy>())); 56381ad6265SDimitry Andric } 56481ad6265SDimitry Andric 5655f757f3fSDimitry Andric template <typename RecordTy> 5665f757f3fSDimitry Andric std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, 5675f757f3fSDimitry Andric std::true_type) { 5685f757f3fSDimitry Andric const auto &AccessControl = Record.Access; 5695f757f3fSDimitry Andric std::string Access; 5705f757f3fSDimitry Andric if (AccessControl.empty()) 5715f757f3fSDimitry Andric return std::nullopt; 5725f757f3fSDimitry Andric Access = AccessControl.getAccess(); 5735f757f3fSDimitry Andric return Access; 5745f757f3fSDimitry Andric } 5755f757f3fSDimitry Andric 5765f757f3fSDimitry Andric template <typename RecordTy> 5775f757f3fSDimitry Andric std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, 5785f757f3fSDimitry Andric std::false_type) { 5795f757f3fSDimitry Andric return std::nullopt; 5805f757f3fSDimitry Andric } 5815f757f3fSDimitry Andric 5825f757f3fSDimitry Andric template <typename RecordTy> 5835f757f3fSDimitry Andric void serializeAccessMixin(Object &Paren, const RecordTy &Record) { 5845f757f3fSDimitry Andric auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>()); 5855f757f3fSDimitry Andric if (!accessLevel.has_value()) 5865f757f3fSDimitry Andric accessLevel = "public"; 5875f757f3fSDimitry Andric serializeString(Paren, "accessLevel", accessLevel); 5885f757f3fSDimitry Andric } 5895f757f3fSDimitry Andric 5905f757f3fSDimitry Andric template <typename RecordTy> 5915f757f3fSDimitry Andric std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, 5925f757f3fSDimitry Andric std::true_type) { 5935f757f3fSDimitry Andric const auto &Template = Record.Templ; 5945f757f3fSDimitry Andric if (Template.empty()) 5955f757f3fSDimitry Andric return std::nullopt; 5965f757f3fSDimitry Andric 5975f757f3fSDimitry Andric Object Generics; 5985f757f3fSDimitry Andric Array GenericParameters; 5995f757f3fSDimitry Andric for (const auto &Param : Template.getParameters()) { 6005f757f3fSDimitry Andric Object Parameter; 6015f757f3fSDimitry Andric Parameter["name"] = Param.Name; 6025f757f3fSDimitry Andric Parameter["index"] = Param.Index; 6035f757f3fSDimitry Andric Parameter["depth"] = Param.Depth; 6045f757f3fSDimitry Andric GenericParameters.emplace_back(std::move(Parameter)); 6055f757f3fSDimitry Andric } 6065f757f3fSDimitry Andric if (!GenericParameters.empty()) 6075f757f3fSDimitry Andric Generics["parameters"] = std::move(GenericParameters); 6085f757f3fSDimitry Andric 6095f757f3fSDimitry Andric Array GenericConstraints; 6105f757f3fSDimitry Andric for (const auto &Constr : Template.getConstraints()) { 6115f757f3fSDimitry Andric Object Constraint; 6125f757f3fSDimitry Andric Constraint["kind"] = Constr.Kind; 6135f757f3fSDimitry Andric Constraint["lhs"] = Constr.LHS; 6145f757f3fSDimitry Andric Constraint["rhs"] = Constr.RHS; 6155f757f3fSDimitry Andric GenericConstraints.emplace_back(std::move(Constraint)); 6165f757f3fSDimitry Andric } 6175f757f3fSDimitry Andric 6185f757f3fSDimitry Andric if (!GenericConstraints.empty()) 6195f757f3fSDimitry Andric Generics["constraints"] = std::move(GenericConstraints); 6205f757f3fSDimitry Andric 6215f757f3fSDimitry Andric return Generics; 6225f757f3fSDimitry Andric } 6235f757f3fSDimitry Andric 6245f757f3fSDimitry Andric template <typename RecordTy> 6255f757f3fSDimitry Andric std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, 6265f757f3fSDimitry Andric std::false_type) { 6275f757f3fSDimitry Andric return std::nullopt; 6285f757f3fSDimitry Andric } 6295f757f3fSDimitry Andric 6305f757f3fSDimitry Andric template <typename RecordTy> 6315f757f3fSDimitry Andric void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { 6325f757f3fSDimitry Andric serializeObject(Paren, "swiftGenerics", 6335f757f3fSDimitry Andric serializeTemplateMixinImpl(Record, has_template<RecordTy>())); 6345f757f3fSDimitry Andric } 6355f757f3fSDimitry Andric 636bdd1243dSDimitry Andric struct PathComponent { 637bdd1243dSDimitry Andric StringRef USR; 638bdd1243dSDimitry Andric StringRef Name; 639bdd1243dSDimitry Andric APIRecord::RecordKind Kind; 640bdd1243dSDimitry Andric 641bdd1243dSDimitry Andric PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind) 642bdd1243dSDimitry Andric : USR(USR), Name(Name), Kind(Kind) {} 643bdd1243dSDimitry Andric }; 644bdd1243dSDimitry Andric 645bdd1243dSDimitry Andric template <typename RecordTy> 646bdd1243dSDimitry Andric bool generatePathComponents( 647bdd1243dSDimitry Andric const RecordTy &Record, const APISet &API, 648bdd1243dSDimitry Andric function_ref<void(const PathComponent &)> ComponentTransformer) { 649bdd1243dSDimitry Andric SmallVector<PathComponent, 4> ReverseComponenents; 650bdd1243dSDimitry Andric ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind()); 651bdd1243dSDimitry Andric const auto *CurrentParent = &Record.ParentInformation; 65206c3fb27SDimitry Andric bool FailedToFindParent = false; 653bdd1243dSDimitry Andric while (CurrentParent && !CurrentParent->empty()) { 654bdd1243dSDimitry Andric PathComponent CurrentParentComponent(CurrentParent->ParentUSR, 655bdd1243dSDimitry Andric CurrentParent->ParentName, 656bdd1243dSDimitry Andric CurrentParent->ParentKind); 657bdd1243dSDimitry Andric 658bdd1243dSDimitry Andric auto *ParentRecord = CurrentParent->ParentRecord; 659bdd1243dSDimitry Andric // Slow path if we don't have a direct reference to the ParentRecord 660bdd1243dSDimitry Andric if (!ParentRecord) 661bdd1243dSDimitry Andric ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); 662bdd1243dSDimitry Andric 6635f757f3fSDimitry Andric // If the parent is a category extended from internal module then we need to 6645f757f3fSDimitry Andric // pretend this belongs to the associated interface. 665bdd1243dSDimitry Andric if (auto *CategoryRecord = 666bdd1243dSDimitry Andric dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) { 6675f757f3fSDimitry Andric if (!CategoryRecord->IsFromExternalModule) { 668bdd1243dSDimitry Andric ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); 669bdd1243dSDimitry Andric CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, 670bdd1243dSDimitry Andric CategoryRecord->Interface.Name, 671bdd1243dSDimitry Andric APIRecord::RK_ObjCInterface); 672bdd1243dSDimitry Andric } 6735f757f3fSDimitry Andric } 674bdd1243dSDimitry Andric 675bdd1243dSDimitry Andric // The parent record doesn't exist which means the symbol shouldn't be 676bdd1243dSDimitry Andric // treated as part of the current product. 67706c3fb27SDimitry Andric if (!ParentRecord) { 67806c3fb27SDimitry Andric FailedToFindParent = true; 67906c3fb27SDimitry Andric break; 68006c3fb27SDimitry Andric } 681bdd1243dSDimitry Andric 682bdd1243dSDimitry Andric ReverseComponenents.push_back(std::move(CurrentParentComponent)); 683bdd1243dSDimitry Andric CurrentParent = &ParentRecord->ParentInformation; 684bdd1243dSDimitry Andric } 685bdd1243dSDimitry Andric 686bdd1243dSDimitry Andric for (const auto &PC : reverse(ReverseComponenents)) 687bdd1243dSDimitry Andric ComponentTransformer(PC); 688bdd1243dSDimitry Andric 68906c3fb27SDimitry Andric return FailedToFindParent; 690bdd1243dSDimitry Andric } 69106c3fb27SDimitry Andric 692bdd1243dSDimitry Andric Object serializeParentContext(const PathComponent &PC, Language Lang) { 693bdd1243dSDimitry Andric Object ParentContextElem; 694bdd1243dSDimitry Andric ParentContextElem["usr"] = PC.USR; 695bdd1243dSDimitry Andric ParentContextElem["name"] = PC.Name; 696bdd1243dSDimitry Andric ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"]; 697bdd1243dSDimitry Andric return ParentContextElem; 698bdd1243dSDimitry Andric } 699bdd1243dSDimitry Andric 700bdd1243dSDimitry Andric template <typename RecordTy> 701bdd1243dSDimitry Andric Array generateParentContexts(const RecordTy &Record, const APISet &API, 702bdd1243dSDimitry Andric Language Lang) { 703bdd1243dSDimitry Andric Array ParentContexts; 70406c3fb27SDimitry Andric generatePathComponents( 705bdd1243dSDimitry Andric Record, API, [Lang, &ParentContexts](const PathComponent &PC) { 706bdd1243dSDimitry Andric ParentContexts.push_back(serializeParentContext(PC, Lang)); 70706c3fb27SDimitry Andric }); 708bdd1243dSDimitry Andric 709bdd1243dSDimitry Andric return ParentContexts; 710bdd1243dSDimitry Andric } 71181ad6265SDimitry Andric } // namespace 71281ad6265SDimitry Andric 71381ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer. 71481ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 71581ad6265SDimitry Andric 71681ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const { 71781ad6265SDimitry Andric Object Metadata; 71881ad6265SDimitry Andric serializeObject(Metadata, "formatVersion", 71981ad6265SDimitry Andric serializeSemanticVersion(FormatVersion)); 72081ad6265SDimitry Andric Metadata["generator"] = clang::getClangFullVersion(); 72181ad6265SDimitry Andric return Metadata; 72281ad6265SDimitry Andric } 72381ad6265SDimitry Andric 72481ad6265SDimitry Andric Object SymbolGraphSerializer::serializeModule() const { 72581ad6265SDimitry Andric Object Module; 72681ad6265SDimitry Andric // The user is expected to always pass `--product-name=` on the command line 72781ad6265SDimitry Andric // to populate this field. 728bdd1243dSDimitry Andric Module["name"] = API.ProductName; 72981ad6265SDimitry Andric serializeObject(Module, "platform", serializePlatform(API.getTarget())); 73081ad6265SDimitry Andric return Module; 73181ad6265SDimitry Andric } 73281ad6265SDimitry Andric 73381ad6265SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { 734bdd1243dSDimitry Andric // Skip explicitly ignored symbols. 735bdd1243dSDimitry Andric if (IgnoresList.shouldIgnore(Record.Name)) 736bdd1243dSDimitry Andric return true; 737bdd1243dSDimitry Andric 73881ad6265SDimitry Andric // Skip unconditionally unavailable symbols 739*7a6dacacSDimitry Andric if (Record.Availability.isUnconditionallyUnavailable()) 74081ad6265SDimitry Andric return true; 74181ad6265SDimitry Andric 74281ad6265SDimitry Andric // Filter out symbols prefixed with an underscored as they are understood to 74381ad6265SDimitry Andric // be symbols clients should not use. 7445f757f3fSDimitry Andric if (Record.Name.starts_with("_")) 74581ad6265SDimitry Andric return true; 74681ad6265SDimitry Andric 74781ad6265SDimitry Andric return false; 74881ad6265SDimitry Andric } 74981ad6265SDimitry Andric 75081ad6265SDimitry Andric template <typename RecordTy> 751bdd1243dSDimitry Andric std::optional<Object> 75281ad6265SDimitry Andric SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { 75381ad6265SDimitry Andric if (shouldSkip(Record)) 754bdd1243dSDimitry Andric return std::nullopt; 75581ad6265SDimitry Andric 75681ad6265SDimitry Andric Object Obj; 75781ad6265SDimitry Andric serializeObject(Obj, "identifier", 75881ad6265SDimitry Andric serializeIdentifier(Record, API.getLanguage())); 75981ad6265SDimitry Andric serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); 76081ad6265SDimitry Andric serializeObject(Obj, "names", serializeNames(Record)); 76181ad6265SDimitry Andric serializeObject( 76281ad6265SDimitry Andric Obj, "location", 76381ad6265SDimitry Andric serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); 764bdd1243dSDimitry Andric serializeArray(Obj, "availability", 765*7a6dacacSDimitry Andric serializeAvailability(Record.Availability)); 76681ad6265SDimitry Andric serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); 76781ad6265SDimitry Andric serializeArray(Obj, "declarationFragments", 76881ad6265SDimitry Andric serializeDeclarationFragments(Record.Declaration)); 769bdd1243dSDimitry Andric SmallVector<StringRef, 4> PathComponentsNames; 770bdd1243dSDimitry Andric // If this returns true it indicates that we couldn't find a symbol in the 771bdd1243dSDimitry Andric // hierarchy. 772bdd1243dSDimitry Andric if (generatePathComponents(Record, API, 773bdd1243dSDimitry Andric [&PathComponentsNames](const PathComponent &PC) { 774bdd1243dSDimitry Andric PathComponentsNames.push_back(PC.Name); 775bdd1243dSDimitry Andric })) 776bdd1243dSDimitry Andric return {}; 777bdd1243dSDimitry Andric 778bdd1243dSDimitry Andric serializeArray(Obj, "pathComponents", Array(PathComponentsNames)); 77981ad6265SDimitry Andric 78081ad6265SDimitry Andric serializeFunctionSignatureMixin(Obj, Record); 7815f757f3fSDimitry Andric serializeAccessMixin(Obj, Record); 7825f757f3fSDimitry Andric serializeTemplateMixin(Obj, Record); 78381ad6265SDimitry Andric 78481ad6265SDimitry Andric return Obj; 78581ad6265SDimitry Andric } 78681ad6265SDimitry Andric 78781ad6265SDimitry Andric template <typename MemberTy> 78881ad6265SDimitry Andric void SymbolGraphSerializer::serializeMembers( 78981ad6265SDimitry Andric const APIRecord &Record, 79081ad6265SDimitry Andric const SmallVector<std::unique_ptr<MemberTy>> &Members) { 791bdd1243dSDimitry Andric // Members should not be serialized if we aren't recursing. 792bdd1243dSDimitry Andric if (!ShouldRecurse) 793bdd1243dSDimitry Andric return; 79481ad6265SDimitry Andric for (const auto &Member : Members) { 79581ad6265SDimitry Andric auto MemberRecord = serializeAPIRecord(*Member); 79681ad6265SDimitry Andric if (!MemberRecord) 79781ad6265SDimitry Andric continue; 79881ad6265SDimitry Andric 79981ad6265SDimitry Andric Symbols.emplace_back(std::move(*MemberRecord)); 80081ad6265SDimitry Andric serializeRelationship(RelationshipKind::MemberOf, *Member, Record); 80181ad6265SDimitry Andric } 80281ad6265SDimitry Andric } 80381ad6265SDimitry Andric 80481ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 80581ad6265SDimitry Andric switch (Kind) { 80681ad6265SDimitry Andric case RelationshipKind::MemberOf: 80781ad6265SDimitry Andric return "memberOf"; 80881ad6265SDimitry Andric case RelationshipKind::InheritsFrom: 80981ad6265SDimitry Andric return "inheritsFrom"; 81081ad6265SDimitry Andric case RelationshipKind::ConformsTo: 81181ad6265SDimitry Andric return "conformsTo"; 8125f757f3fSDimitry Andric case RelationshipKind::ExtensionTo: 8135f757f3fSDimitry Andric return "extensionTo"; 81481ad6265SDimitry Andric } 81581ad6265SDimitry Andric llvm_unreachable("Unhandled relationship kind"); 81681ad6265SDimitry Andric } 81781ad6265SDimitry Andric 8185f757f3fSDimitry Andric StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { 8195f757f3fSDimitry Andric switch (Kind) { 8205f757f3fSDimitry Andric case ConstraintKind::Conformance: 8215f757f3fSDimitry Andric return "conformance"; 8225f757f3fSDimitry Andric case ConstraintKind::ConditionalConformance: 8235f757f3fSDimitry Andric return "conditionalConformance"; 8245f757f3fSDimitry Andric } 8255f757f3fSDimitry Andric llvm_unreachable("Unhandled constraint kind"); 8265f757f3fSDimitry Andric } 8275f757f3fSDimitry Andric 82881ad6265SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 82981ad6265SDimitry Andric SymbolReference Source, 83081ad6265SDimitry Andric SymbolReference Target) { 83181ad6265SDimitry Andric Object Relationship; 83281ad6265SDimitry Andric Relationship["source"] = Source.USR; 83381ad6265SDimitry Andric Relationship["target"] = Target.USR; 834bdd1243dSDimitry Andric Relationship["targetFallback"] = Target.Name; 83581ad6265SDimitry Andric Relationship["kind"] = getRelationshipString(Kind); 83681ad6265SDimitry Andric 83781ad6265SDimitry Andric Relationships.emplace_back(std::move(Relationship)); 83881ad6265SDimitry Andric } 83981ad6265SDimitry Andric 8405f757f3fSDimitry Andric void SymbolGraphSerializer::visitNamespaceRecord( 8415f757f3fSDimitry Andric const NamespaceRecord &Record) { 8425f757f3fSDimitry Andric auto Namespace = serializeAPIRecord(Record); 8435f757f3fSDimitry Andric if (!Namespace) 8445f757f3fSDimitry Andric return; 8455f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Namespace)); 8465f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 8475f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 8485f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 8495f757f3fSDimitry Andric } 8505f757f3fSDimitry Andric 85106c3fb27SDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionRecord( 85281ad6265SDimitry Andric const GlobalFunctionRecord &Record) { 85381ad6265SDimitry Andric auto Obj = serializeAPIRecord(Record); 85481ad6265SDimitry Andric if (!Obj) 85581ad6265SDimitry Andric return; 85681ad6265SDimitry Andric 85781ad6265SDimitry Andric Symbols.emplace_back(std::move(*Obj)); 85881ad6265SDimitry Andric } 85981ad6265SDimitry Andric 86006c3fb27SDimitry Andric void SymbolGraphSerializer::visitGlobalVariableRecord( 86181ad6265SDimitry Andric const GlobalVariableRecord &Record) { 86281ad6265SDimitry Andric auto Obj = serializeAPIRecord(Record); 86381ad6265SDimitry Andric if (!Obj) 86481ad6265SDimitry Andric return; 86581ad6265SDimitry Andric 86681ad6265SDimitry Andric Symbols.emplace_back(std::move(*Obj)); 86781ad6265SDimitry Andric } 86881ad6265SDimitry Andric 86906c3fb27SDimitry Andric void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) { 87081ad6265SDimitry Andric auto Enum = serializeAPIRecord(Record); 87181ad6265SDimitry Andric if (!Enum) 87281ad6265SDimitry Andric return; 87381ad6265SDimitry Andric 87481ad6265SDimitry Andric Symbols.emplace_back(std::move(*Enum)); 87581ad6265SDimitry Andric serializeMembers(Record, Record.Constants); 87681ad6265SDimitry Andric } 87781ad6265SDimitry Andric 878*7a6dacacSDimitry Andric void SymbolGraphSerializer::visitRecordRecord(const RecordRecord &Record) { 879*7a6dacacSDimitry Andric auto SerializedRecord = serializeAPIRecord(Record); 880*7a6dacacSDimitry Andric if (!SerializedRecord) 88181ad6265SDimitry Andric return; 88281ad6265SDimitry Andric 883*7a6dacacSDimitry Andric Symbols.emplace_back(std::move(*SerializedRecord)); 88481ad6265SDimitry Andric serializeMembers(Record, Record.Fields); 88581ad6265SDimitry Andric } 88681ad6265SDimitry Andric 8875f757f3fSDimitry Andric void SymbolGraphSerializer::visitStaticFieldRecord( 8885f757f3fSDimitry Andric const StaticFieldRecord &Record) { 8895f757f3fSDimitry Andric auto StaticField = serializeAPIRecord(Record); 8905f757f3fSDimitry Andric if (!StaticField) 8915f757f3fSDimitry Andric return; 8925f757f3fSDimitry Andric Symbols.emplace_back(std::move(*StaticField)); 8935f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context); 8945f757f3fSDimitry Andric } 8955f757f3fSDimitry Andric 8965f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) { 8975f757f3fSDimitry Andric auto Class = serializeAPIRecord(Record); 8985f757f3fSDimitry Andric if (!Class) 8995f757f3fSDimitry Andric return; 9005f757f3fSDimitry Andric 9015f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Class)); 9025f757f3fSDimitry Andric for (const auto &Base : Record.Bases) 9035f757f3fSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 9045f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 9055f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 9065f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 9075f757f3fSDimitry Andric } 9085f757f3fSDimitry Andric 9095f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplateRecord( 9105f757f3fSDimitry Andric const ClassTemplateRecord &Record) { 9115f757f3fSDimitry Andric auto Class = serializeAPIRecord(Record); 9125f757f3fSDimitry Andric if (!Class) 9135f757f3fSDimitry Andric return; 9145f757f3fSDimitry Andric 9155f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Class)); 9165f757f3fSDimitry Andric for (const auto &Base : Record.Bases) 9175f757f3fSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 9185f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 9195f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 9205f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 9215f757f3fSDimitry Andric } 9225f757f3fSDimitry Andric 9235f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplateSpecializationRecord( 9245f757f3fSDimitry Andric const ClassTemplateSpecializationRecord &Record) { 9255f757f3fSDimitry Andric auto Class = serializeAPIRecord(Record); 9265f757f3fSDimitry Andric if (!Class) 9275f757f3fSDimitry Andric return; 9285f757f3fSDimitry Andric 9295f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Class)); 9305f757f3fSDimitry Andric 9315f757f3fSDimitry Andric for (const auto &Base : Record.Bases) 9325f757f3fSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 9335f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 9345f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 9355f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 9365f757f3fSDimitry Andric } 9375f757f3fSDimitry Andric 9385f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( 9395f757f3fSDimitry Andric const ClassTemplatePartialSpecializationRecord &Record) { 9405f757f3fSDimitry Andric auto Class = serializeAPIRecord(Record); 9415f757f3fSDimitry Andric if (!Class) 9425f757f3fSDimitry Andric return; 9435f757f3fSDimitry Andric 9445f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Class)); 9455f757f3fSDimitry Andric 9465f757f3fSDimitry Andric for (const auto &Base : Record.Bases) 9475f757f3fSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 9485f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 9495f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 9505f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 9515f757f3fSDimitry Andric } 9525f757f3fSDimitry Andric 9535f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXInstanceMethodRecord( 9545f757f3fSDimitry Andric const CXXInstanceMethodRecord &Record) { 9555f757f3fSDimitry Andric auto InstanceMethod = serializeAPIRecord(Record); 9565f757f3fSDimitry Andric if (!InstanceMethod) 9575f757f3fSDimitry Andric return; 9585f757f3fSDimitry Andric 9595f757f3fSDimitry Andric Symbols.emplace_back(std::move(*InstanceMethod)); 9605f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 9615f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 9625f757f3fSDimitry Andric } 9635f757f3fSDimitry Andric 9645f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXStaticMethodRecord( 9655f757f3fSDimitry Andric const CXXStaticMethodRecord &Record) { 9665f757f3fSDimitry Andric auto StaticMethod = serializeAPIRecord(Record); 9675f757f3fSDimitry Andric if (!StaticMethod) 9685f757f3fSDimitry Andric return; 9695f757f3fSDimitry Andric 9705f757f3fSDimitry Andric Symbols.emplace_back(std::move(*StaticMethod)); 9715f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 9725f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 9735f757f3fSDimitry Andric } 9745f757f3fSDimitry Andric 9755f757f3fSDimitry Andric void SymbolGraphSerializer::visitMethodTemplateRecord( 9765f757f3fSDimitry Andric const CXXMethodTemplateRecord &Record) { 9775f757f3fSDimitry Andric if (!ShouldRecurse) 9785f757f3fSDimitry Andric // Ignore child symbols 9795f757f3fSDimitry Andric return; 9805f757f3fSDimitry Andric auto MethodTemplate = serializeAPIRecord(Record); 9815f757f3fSDimitry Andric if (!MethodTemplate) 9825f757f3fSDimitry Andric return; 9835f757f3fSDimitry Andric Symbols.emplace_back(std::move(*MethodTemplate)); 9845f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 9855f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 9865f757f3fSDimitry Andric } 9875f757f3fSDimitry Andric 9885f757f3fSDimitry Andric void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord( 9895f757f3fSDimitry Andric const CXXMethodTemplateSpecializationRecord &Record) { 9905f757f3fSDimitry Andric if (!ShouldRecurse) 9915f757f3fSDimitry Andric // Ignore child symbols 9925f757f3fSDimitry Andric return; 9935f757f3fSDimitry Andric auto MethodTemplateSpecialization = serializeAPIRecord(Record); 9945f757f3fSDimitry Andric if (!MethodTemplateSpecialization) 9955f757f3fSDimitry Andric return; 9965f757f3fSDimitry Andric Symbols.emplace_back(std::move(*MethodTemplateSpecialization)); 9975f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 9985f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 9995f757f3fSDimitry Andric } 10005f757f3fSDimitry Andric 10015f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) { 10025f757f3fSDimitry Andric if (!ShouldRecurse) 10035f757f3fSDimitry Andric return; 10045f757f3fSDimitry Andric auto CXXField = serializeAPIRecord(Record); 10055f757f3fSDimitry Andric if (!CXXField) 10065f757f3fSDimitry Andric return; 10075f757f3fSDimitry Andric Symbols.emplace_back(std::move(*CXXField)); 10085f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 10095f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 10105f757f3fSDimitry Andric } 10115f757f3fSDimitry Andric 10125f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXFieldTemplateRecord( 10135f757f3fSDimitry Andric const CXXFieldTemplateRecord &Record) { 10145f757f3fSDimitry Andric if (!ShouldRecurse) 10155f757f3fSDimitry Andric // Ignore child symbols 10165f757f3fSDimitry Andric return; 10175f757f3fSDimitry Andric auto CXXFieldTemplate = serializeAPIRecord(Record); 10185f757f3fSDimitry Andric if (!CXXFieldTemplate) 10195f757f3fSDimitry Andric return; 10205f757f3fSDimitry Andric Symbols.emplace_back(std::move(*CXXFieldTemplate)); 10215f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 10225f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 10235f757f3fSDimitry Andric } 10245f757f3fSDimitry Andric 10255f757f3fSDimitry Andric void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { 10265f757f3fSDimitry Andric auto Concept = serializeAPIRecord(Record); 10275f757f3fSDimitry Andric if (!Concept) 10285f757f3fSDimitry Andric return; 10295f757f3fSDimitry Andric 10305f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Concept)); 10315f757f3fSDimitry Andric } 10325f757f3fSDimitry Andric 10335f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( 10345f757f3fSDimitry Andric const GlobalVariableTemplateRecord &Record) { 10355f757f3fSDimitry Andric auto GlobalVariableTemplate = serializeAPIRecord(Record); 10365f757f3fSDimitry Andric if (!GlobalVariableTemplate) 10375f757f3fSDimitry Andric return; 10385f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalVariableTemplate)); 10395f757f3fSDimitry Andric } 10405f757f3fSDimitry Andric 10415f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord( 10425f757f3fSDimitry Andric const GlobalVariableTemplateSpecializationRecord &Record) { 10435f757f3fSDimitry Andric auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record); 10445f757f3fSDimitry Andric if (!GlobalVariableTemplateSpecialization) 10455f757f3fSDimitry Andric return; 10465f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization)); 10475f757f3fSDimitry Andric } 10485f757f3fSDimitry Andric 10495f757f3fSDimitry Andric void SymbolGraphSerializer:: 10505f757f3fSDimitry Andric visitGlobalVariableTemplatePartialSpecializationRecord( 10515f757f3fSDimitry Andric const GlobalVariableTemplatePartialSpecializationRecord &Record) { 10525f757f3fSDimitry Andric auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record); 10535f757f3fSDimitry Andric if (!GlobalVariableTemplatePartialSpecialization) 10545f757f3fSDimitry Andric return; 10555f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization)); 10565f757f3fSDimitry Andric } 10575f757f3fSDimitry Andric 10585f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( 10595f757f3fSDimitry Andric const GlobalFunctionTemplateRecord &Record) { 10605f757f3fSDimitry Andric auto GlobalFunctionTemplate = serializeAPIRecord(Record); 10615f757f3fSDimitry Andric if (!GlobalFunctionTemplate) 10625f757f3fSDimitry Andric return; 10635f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); 10645f757f3fSDimitry Andric } 10655f757f3fSDimitry Andric 10665f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord( 10675f757f3fSDimitry Andric const GlobalFunctionTemplateSpecializationRecord &Record) { 10685f757f3fSDimitry Andric auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record); 10695f757f3fSDimitry Andric if (!GlobalFunctionTemplateSpecialization) 10705f757f3fSDimitry Andric return; 10715f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization)); 10725f757f3fSDimitry Andric } 10735f757f3fSDimitry Andric 107406c3fb27SDimitry Andric void SymbolGraphSerializer::visitObjCContainerRecord( 107581ad6265SDimitry Andric const ObjCContainerRecord &Record) { 107681ad6265SDimitry Andric auto ObjCContainer = serializeAPIRecord(Record); 107781ad6265SDimitry Andric if (!ObjCContainer) 107881ad6265SDimitry Andric return; 107981ad6265SDimitry Andric 108081ad6265SDimitry Andric Symbols.emplace_back(std::move(*ObjCContainer)); 108181ad6265SDimitry Andric 108281ad6265SDimitry Andric serializeMembers(Record, Record.Ivars); 108381ad6265SDimitry Andric serializeMembers(Record, Record.Methods); 108481ad6265SDimitry Andric serializeMembers(Record, Record.Properties); 108581ad6265SDimitry Andric 108681ad6265SDimitry Andric for (const auto &Protocol : Record.Protocols) 108781ad6265SDimitry Andric // Record that Record conforms to Protocol. 108881ad6265SDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 108981ad6265SDimitry Andric 109081ad6265SDimitry Andric if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) { 109181ad6265SDimitry Andric if (!ObjCInterface->SuperClass.empty()) 109281ad6265SDimitry Andric // If Record is an Objective-C interface record and it has a super class, 109381ad6265SDimitry Andric // record that Record is inherited from SuperClass. 109481ad6265SDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, 109581ad6265SDimitry Andric ObjCInterface->SuperClass); 109681ad6265SDimitry Andric 109781ad6265SDimitry Andric // Members of categories extending an interface are serialized as members of 109881ad6265SDimitry Andric // the interface. 109981ad6265SDimitry Andric for (const auto *Category : ObjCInterface->Categories) { 110081ad6265SDimitry Andric serializeMembers(Record, Category->Ivars); 110181ad6265SDimitry Andric serializeMembers(Record, Category->Methods); 110281ad6265SDimitry Andric serializeMembers(Record, Category->Properties); 110381ad6265SDimitry Andric 1104bdd1243dSDimitry Andric // Surface the protocols of the category to the interface. 110581ad6265SDimitry Andric for (const auto &Protocol : Category->Protocols) 110681ad6265SDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 110781ad6265SDimitry Andric } 110881ad6265SDimitry Andric } 110981ad6265SDimitry Andric } 111081ad6265SDimitry Andric 11115f757f3fSDimitry Andric void SymbolGraphSerializer::visitObjCCategoryRecord( 11125f757f3fSDimitry Andric const ObjCCategoryRecord &Record) { 11135f757f3fSDimitry Andric if (!Record.IsFromExternalModule) 11145f757f3fSDimitry Andric return; 11155f757f3fSDimitry Andric 11165f757f3fSDimitry Andric // Check if the current Category' parent has been visited before, if so skip. 11175f757f3fSDimitry Andric if (!visitedCategories.contains(Record.Interface.Name)) { 11185f757f3fSDimitry Andric visitedCategories.insert(Record.Interface.Name); 11195f757f3fSDimitry Andric Object Obj; 11205f757f3fSDimitry Andric serializeObject(Obj, "identifier", 11215f757f3fSDimitry Andric serializeIdentifier(Record, API.getLanguage())); 11225f757f3fSDimitry Andric serializeObject(Obj, "kind", 11235f757f3fSDimitry Andric serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, 11245f757f3fSDimitry Andric API.getLanguage())); 11255f757f3fSDimitry Andric Obj["accessLevel"] = "public"; 11265f757f3fSDimitry Andric Symbols.emplace_back(std::move(Obj)); 11275f757f3fSDimitry Andric } 11285f757f3fSDimitry Andric 11295f757f3fSDimitry Andric Object Relationship; 11305f757f3fSDimitry Andric Relationship["source"] = Record.USR; 11315f757f3fSDimitry Andric Relationship["target"] = Record.Interface.USR; 11325f757f3fSDimitry Andric Relationship["targetFallback"] = Record.Interface.Name; 11335f757f3fSDimitry Andric Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo); 11345f757f3fSDimitry Andric Relationships.emplace_back(std::move(Relationship)); 11355f757f3fSDimitry Andric 11365f757f3fSDimitry Andric auto ObjCCategory = serializeAPIRecord(Record); 11375f757f3fSDimitry Andric 11385f757f3fSDimitry Andric if (!ObjCCategory) 11395f757f3fSDimitry Andric return; 11405f757f3fSDimitry Andric 11415f757f3fSDimitry Andric Symbols.emplace_back(std::move(*ObjCCategory)); 11425f757f3fSDimitry Andric serializeMembers(Record, Record.Methods); 11435f757f3fSDimitry Andric serializeMembers(Record, Record.Properties); 11445f757f3fSDimitry Andric 11455f757f3fSDimitry Andric // Surface the protocols of the category to the interface. 11465f757f3fSDimitry Andric for (const auto &Protocol : Record.Protocols) 11475f757f3fSDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 11485f757f3fSDimitry Andric } 11495f757f3fSDimitry Andric 115006c3fb27SDimitry Andric void SymbolGraphSerializer::visitMacroDefinitionRecord( 115181ad6265SDimitry Andric const MacroDefinitionRecord &Record) { 115281ad6265SDimitry Andric auto Macro = serializeAPIRecord(Record); 115381ad6265SDimitry Andric 115481ad6265SDimitry Andric if (!Macro) 115581ad6265SDimitry Andric return; 115681ad6265SDimitry Andric 115781ad6265SDimitry Andric Symbols.emplace_back(std::move(*Macro)); 115881ad6265SDimitry Andric } 115981ad6265SDimitry Andric 1160bdd1243dSDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { 1161bdd1243dSDimitry Andric switch (Record->getKind()) { 1162bdd1243dSDimitry Andric case APIRecord::RK_Unknown: 1163bdd1243dSDimitry Andric llvm_unreachable("Records should have a known kind!"); 1164bdd1243dSDimitry Andric case APIRecord::RK_GlobalFunction: 116506c3fb27SDimitry Andric visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record)); 1166bdd1243dSDimitry Andric break; 1167bdd1243dSDimitry Andric case APIRecord::RK_GlobalVariable: 116806c3fb27SDimitry Andric visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record)); 1169bdd1243dSDimitry Andric break; 1170bdd1243dSDimitry Andric case APIRecord::RK_Enum: 117106c3fb27SDimitry Andric visitEnumRecord(*cast<EnumRecord>(Record)); 1172bdd1243dSDimitry Andric break; 1173bdd1243dSDimitry Andric case APIRecord::RK_Struct: 1174*7a6dacacSDimitry Andric LLVM_FALLTHROUGH; 1175*7a6dacacSDimitry Andric case APIRecord::RK_Union: 1176*7a6dacacSDimitry Andric visitRecordRecord(*cast<RecordRecord>(Record)); 1177bdd1243dSDimitry Andric break; 11785f757f3fSDimitry Andric case APIRecord::RK_StaticField: 11795f757f3fSDimitry Andric visitStaticFieldRecord(*cast<StaticFieldRecord>(Record)); 11805f757f3fSDimitry Andric break; 11815f757f3fSDimitry Andric case APIRecord::RK_CXXClass: 11825f757f3fSDimitry Andric visitCXXClassRecord(*cast<CXXClassRecord>(Record)); 11835f757f3fSDimitry Andric break; 1184bdd1243dSDimitry Andric case APIRecord::RK_ObjCInterface: 118506c3fb27SDimitry Andric visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record)); 1186bdd1243dSDimitry Andric break; 1187bdd1243dSDimitry Andric case APIRecord::RK_ObjCProtocol: 118806c3fb27SDimitry Andric visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record)); 1189bdd1243dSDimitry Andric break; 11905f757f3fSDimitry Andric case APIRecord::RK_ObjCCategory: 11915f757f3fSDimitry Andric visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record)); 11925f757f3fSDimitry Andric break; 1193bdd1243dSDimitry Andric case APIRecord::RK_MacroDefinition: 119406c3fb27SDimitry Andric visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record)); 1195bdd1243dSDimitry Andric break; 1196bdd1243dSDimitry Andric case APIRecord::RK_Typedef: 119706c3fb27SDimitry Andric visitTypedefRecord(*cast<TypedefRecord>(Record)); 1198bdd1243dSDimitry Andric break; 1199bdd1243dSDimitry Andric default: 1200bdd1243dSDimitry Andric if (auto Obj = serializeAPIRecord(*Record)) { 1201bdd1243dSDimitry Andric Symbols.emplace_back(std::move(*Obj)); 1202bdd1243dSDimitry Andric auto &ParentInformation = Record->ParentInformation; 1203bdd1243dSDimitry Andric if (!ParentInformation.empty()) 1204bdd1243dSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, *Record, 1205bdd1243dSDimitry Andric *ParentInformation.ParentRecord); 1206bdd1243dSDimitry Andric } 1207bdd1243dSDimitry Andric break; 1208bdd1243dSDimitry Andric } 1209bdd1243dSDimitry Andric } 1210bdd1243dSDimitry Andric 121106c3fb27SDimitry Andric void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) { 121281ad6265SDimitry Andric // Typedefs of anonymous types have their entries unified with the underlying 121381ad6265SDimitry Andric // type. 121481ad6265SDimitry Andric bool ShouldDrop = Record.UnderlyingType.Name.empty(); 121581ad6265SDimitry Andric // enums declared with `NS_OPTION` have a named enum and a named typedef, with 121681ad6265SDimitry Andric // the same name 121781ad6265SDimitry Andric ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); 121881ad6265SDimitry Andric if (ShouldDrop) 121981ad6265SDimitry Andric return; 122081ad6265SDimitry Andric 122181ad6265SDimitry Andric auto Typedef = serializeAPIRecord(Record); 122281ad6265SDimitry Andric if (!Typedef) 122381ad6265SDimitry Andric return; 122481ad6265SDimitry Andric 122581ad6265SDimitry Andric (*Typedef)["type"] = Record.UnderlyingType.USR; 122681ad6265SDimitry Andric 122781ad6265SDimitry Andric Symbols.emplace_back(std::move(*Typedef)); 122881ad6265SDimitry Andric } 122981ad6265SDimitry Andric 123081ad6265SDimitry Andric Object SymbolGraphSerializer::serialize() { 123106c3fb27SDimitry Andric traverseAPISet(); 1232bdd1243dSDimitry Andric return serializeCurrentGraph(); 1233bdd1243dSDimitry Andric } 1234bdd1243dSDimitry Andric 1235bdd1243dSDimitry Andric Object SymbolGraphSerializer::serializeCurrentGraph() { 1236bdd1243dSDimitry Andric Object Root; 1237bdd1243dSDimitry Andric serializeObject(Root, "metadata", serializeMetadata()); 1238bdd1243dSDimitry Andric serializeObject(Root, "module", serializeModule()); 1239bdd1243dSDimitry Andric 124081ad6265SDimitry Andric Root["symbols"] = std::move(Symbols); 124181ad6265SDimitry Andric Root["relationships"] = std::move(Relationships); 124281ad6265SDimitry Andric 124381ad6265SDimitry Andric return Root; 124481ad6265SDimitry Andric } 124581ad6265SDimitry Andric 124681ad6265SDimitry Andric void SymbolGraphSerializer::serialize(raw_ostream &os) { 124781ad6265SDimitry Andric Object root = serialize(); 124881ad6265SDimitry Andric if (Options.Compact) 124981ad6265SDimitry Andric os << formatv("{0}", Value(std::move(root))) << "\n"; 125081ad6265SDimitry Andric else 125181ad6265SDimitry Andric os << formatv("{0:2}", Value(std::move(root))) << "\n"; 125281ad6265SDimitry Andric } 1253bdd1243dSDimitry Andric 1254bdd1243dSDimitry Andric std::optional<Object> 1255bdd1243dSDimitry Andric SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, 1256bdd1243dSDimitry Andric const APISet &API) { 1257bdd1243dSDimitry Andric APIRecord *Record = API.findRecordForUSR(USR); 1258bdd1243dSDimitry Andric if (!Record) 1259bdd1243dSDimitry Andric return {}; 1260bdd1243dSDimitry Andric 1261bdd1243dSDimitry Andric Object Root; 1262bdd1243dSDimitry Andric APIIgnoresList EmptyIgnores; 1263bdd1243dSDimitry Andric SymbolGraphSerializer Serializer(API, EmptyIgnores, 1264bdd1243dSDimitry Andric /*Options.Compact*/ {true}, 1265bdd1243dSDimitry Andric /*ShouldRecurse*/ false); 1266bdd1243dSDimitry Andric Serializer.serializeSingleRecord(Record); 1267bdd1243dSDimitry Andric serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph()); 1268bdd1243dSDimitry Andric 1269bdd1243dSDimitry Andric Language Lang = API.getLanguage(); 1270bdd1243dSDimitry Andric serializeArray(Root, "parentContexts", 1271bdd1243dSDimitry Andric generateParentContexts(*Record, API, Lang)); 1272bdd1243dSDimitry Andric 1273bdd1243dSDimitry Andric Array RelatedSymbols; 1274bdd1243dSDimitry Andric 1275bdd1243dSDimitry Andric for (const auto &Fragment : Record->Declaration.getFragments()) { 1276bdd1243dSDimitry Andric // If we don't have a USR there isn't much we can do. 1277bdd1243dSDimitry Andric if (Fragment.PreciseIdentifier.empty()) 1278bdd1243dSDimitry Andric continue; 1279bdd1243dSDimitry Andric 1280bdd1243dSDimitry Andric APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier); 1281bdd1243dSDimitry Andric 1282bdd1243dSDimitry Andric // If we can't find the record let's skip. 1283bdd1243dSDimitry Andric if (!RelatedRecord) 1284bdd1243dSDimitry Andric continue; 1285bdd1243dSDimitry Andric 1286bdd1243dSDimitry Andric Object RelatedSymbol; 1287bdd1243dSDimitry Andric RelatedSymbol["usr"] = RelatedRecord->USR; 1288bdd1243dSDimitry Andric RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); 1289bdd1243dSDimitry Andric // TODO: once we record this properly let's serialize it right. 1290bdd1243dSDimitry Andric RelatedSymbol["accessLevel"] = "public"; 1291bdd1243dSDimitry Andric RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); 1292bdd1243dSDimitry Andric RelatedSymbol["moduleName"] = API.ProductName; 1293bdd1243dSDimitry Andric RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; 1294bdd1243dSDimitry Andric 1295bdd1243dSDimitry Andric serializeArray(RelatedSymbol, "parentContexts", 1296bdd1243dSDimitry Andric generateParentContexts(*RelatedRecord, API, Lang)); 1297bdd1243dSDimitry Andric RelatedSymbols.push_back(std::move(RelatedSymbol)); 1298bdd1243dSDimitry Andric } 1299bdd1243dSDimitry Andric 1300bdd1243dSDimitry Andric serializeArray(Root, "relatedSymbols", RelatedSymbols); 1301bdd1243dSDimitry Andric return Root; 1302bdd1243dSDimitry Andric } 1303