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 41*5f757f3fSDimitry Andric /// Helper function to inject a StringRef \p String into an object \p Paren at 42*5f757f3fSDimitry Andric /// position \p Key 43*5f757f3fSDimitry Andric void serializeString(Object &Paren, StringRef Key, 44*5f757f3fSDimitry Andric std::optional<std::string> String) { 45*5f757f3fSDimitry Andric if (String) 46*5f757f3fSDimitry Andric Paren[Key] = std::move(*String); 47*5f757f3fSDimitry Andric } 48*5f757f3fSDimitry 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; 112*5f757f3fSDimitry Andric SourcePosition["line"] = Loc.getLine() - 1; 113*5f757f3fSDimitry 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 150bdd1243dSDimitry Andric /// versions of the symbol for a given domain (roughly corresponds to a 151bdd1243dSDimitry Andric /// platform) as semantic versions, if not default. Availability information 152bdd1243dSDimitry Andric /// also contains flags to indicate if the symbol is unconditionally unavailable 153bdd1243dSDimitry Andric /// or deprecated, i.e. \c __attribute__((unavailable)) and \c 154bdd1243dSDimitry Andric /// __attribute__((deprecated)). 15581ad6265SDimitry Andric /// 156bdd1243dSDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes, 157bdd1243dSDimitry Andric /// or an \c Array containing the formatted availability information. 158bdd1243dSDimitry Andric std::optional<Array> 159bdd1243dSDimitry Andric serializeAvailability(const AvailabilitySet &Availabilities) { 160bdd1243dSDimitry Andric if (Availabilities.isDefault()) 161bdd1243dSDimitry Andric return std::nullopt; 16281ad6265SDimitry Andric 163bdd1243dSDimitry Andric Array AvailabilityArray; 16481ad6265SDimitry Andric 165bdd1243dSDimitry Andric if (Availabilities.isUnconditionallyDeprecated()) { 166bdd1243dSDimitry Andric Object UnconditionallyDeprecated; 167bdd1243dSDimitry Andric UnconditionallyDeprecated["domain"] = "*"; 168bdd1243dSDimitry Andric UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true; 169bdd1243dSDimitry Andric AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated)); 170bdd1243dSDimitry Andric } 171bdd1243dSDimitry Andric 172bdd1243dSDimitry Andric // Note unconditionally unavailable records are skipped. 173bdd1243dSDimitry Andric 174bdd1243dSDimitry Andric for (const auto &AvailInfo : Availabilities) { 175bdd1243dSDimitry Andric Object Availability; 176bdd1243dSDimitry Andric Availability["domain"] = AvailInfo.Domain; 17706c3fb27SDimitry Andric if (AvailInfo.Unavailable) 17806c3fb27SDimitry Andric Availability["isUnconditionallyUnavailable"] = true; 17906c3fb27SDimitry Andric else { 180*5f757f3fSDimitry Andric serializeObject(Availability, "introduced", 181bdd1243dSDimitry Andric serializeSemanticVersion(AvailInfo.Introduced)); 182*5f757f3fSDimitry Andric serializeObject(Availability, "deprecated", 183bdd1243dSDimitry Andric serializeSemanticVersion(AvailInfo.Deprecated)); 184*5f757f3fSDimitry Andric serializeObject(Availability, "obsoleted", 185bdd1243dSDimitry Andric serializeSemanticVersion(AvailInfo.Obsoleted)); 18606c3fb27SDimitry Andric } 187bdd1243dSDimitry Andric AvailabilityArray.emplace_back(std::move(Availability)); 188bdd1243dSDimitry Andric } 189bdd1243dSDimitry Andric 190bdd1243dSDimitry Andric return AvailabilityArray; 19181ad6265SDimitry Andric } 19281ad6265SDimitry Andric 19381ad6265SDimitry Andric /// Get the language name string for interface language references. 19481ad6265SDimitry Andric StringRef getLanguageName(Language Lang) { 19581ad6265SDimitry Andric switch (Lang) { 19681ad6265SDimitry Andric case Language::C: 19781ad6265SDimitry Andric return "c"; 19881ad6265SDimitry Andric case Language::ObjC: 19981ad6265SDimitry Andric return "objective-c"; 200*5f757f3fSDimitry Andric case Language::CXX: 201*5f757f3fSDimitry Andric return "c++"; 202*5f757f3fSDimitry Andric case Language::ObjCXX: 203*5f757f3fSDimitry Andric return "objective-c++"; 20481ad6265SDimitry Andric 20581ad6265SDimitry Andric // Unsupported language currently 20681ad6265SDimitry Andric case Language::OpenCL: 20781ad6265SDimitry Andric case Language::OpenCLCXX: 20881ad6265SDimitry Andric case Language::CUDA: 20981ad6265SDimitry Andric case Language::RenderScript: 21081ad6265SDimitry Andric case Language::HIP: 21181ad6265SDimitry Andric case Language::HLSL: 21281ad6265SDimitry Andric 21381ad6265SDimitry Andric // Languages that the frontend cannot parse and compile 21481ad6265SDimitry Andric case Language::Unknown: 21581ad6265SDimitry Andric case Language::Asm: 21681ad6265SDimitry Andric case Language::LLVM_IR: 21781ad6265SDimitry Andric llvm_unreachable("Unsupported language kind"); 21881ad6265SDimitry Andric } 21981ad6265SDimitry Andric 22081ad6265SDimitry Andric llvm_unreachable("Unhandled language kind"); 22181ad6265SDimitry Andric } 22281ad6265SDimitry Andric 22381ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format. 22481ad6265SDimitry Andric /// 22581ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique 22681ad6265SDimitry Andric /// references, and the interface language name. 22781ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) { 22881ad6265SDimitry Andric Object Identifier; 22981ad6265SDimitry Andric Identifier["precise"] = Record.USR; 23081ad6265SDimitry Andric Identifier["interfaceLanguage"] = getLanguageName(Lang); 23181ad6265SDimitry Andric 23281ad6265SDimitry Andric return Identifier; 23381ad6265SDimitry Andric } 23481ad6265SDimitry Andric 23581ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by 23681ad6265SDimitry Andric /// the Symbol Graph format. 23781ad6265SDimitry Andric /// 23881ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line 23981ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range 24081ad6265SDimitry Andric /// information. 24181ad6265SDimitry Andric /// e.g. 24281ad6265SDimitry Andric /// \code 24381ad6265SDimitry Andric /// /// This is a documentation comment 24481ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 24581ad6265SDimitry Andric /// /// with multiple lines. 24681ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 24781ad6265SDimitry Andric /// \endcode 24881ad6265SDimitry Andric /// 249bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing 250bdd1243dSDimitry Andric /// the formatted lines. 251bdd1243dSDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) { 25281ad6265SDimitry Andric if (Comment.empty()) 253bdd1243dSDimitry Andric return std::nullopt; 25481ad6265SDimitry Andric 25581ad6265SDimitry Andric Object DocComment; 25681ad6265SDimitry Andric Array LinesArray; 25781ad6265SDimitry Andric for (const auto &CommentLine : Comment) { 25881ad6265SDimitry Andric Object Line; 25981ad6265SDimitry Andric Line["text"] = CommentLine.Text; 26081ad6265SDimitry Andric serializeObject(Line, "range", 26181ad6265SDimitry Andric serializeSourceRange(CommentLine.Begin, CommentLine.End)); 26281ad6265SDimitry Andric LinesArray.emplace_back(std::move(Line)); 26381ad6265SDimitry Andric } 26481ad6265SDimitry Andric serializeArray(DocComment, "lines", LinesArray); 26581ad6265SDimitry Andric 26681ad6265SDimitry Andric return DocComment; 26781ad6265SDimitry Andric } 26881ad6265SDimitry Andric 26981ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol. 27081ad6265SDimitry Andric /// 27181ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important 27281ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to 27381ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for 27481ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example: 27581ad6265SDimitry Andric /// \code 27681ad6265SDimitry Andric /// const int pi; -> "declarationFragments" : [ 27781ad6265SDimitry Andric /// { 27881ad6265SDimitry Andric /// "kind" : "keyword", 27981ad6265SDimitry Andric /// "spelling" : "const" 28081ad6265SDimitry Andric /// }, 28181ad6265SDimitry Andric /// { 28281ad6265SDimitry Andric /// "kind" : "text", 28381ad6265SDimitry Andric /// "spelling" : " " 28481ad6265SDimitry Andric /// }, 28581ad6265SDimitry Andric /// { 28681ad6265SDimitry Andric /// "kind" : "typeIdentifier", 28781ad6265SDimitry Andric /// "preciseIdentifier" : "c:I", 28881ad6265SDimitry Andric /// "spelling" : "int" 28981ad6265SDimitry Andric /// }, 29081ad6265SDimitry Andric /// { 29181ad6265SDimitry Andric /// "kind" : "text", 29281ad6265SDimitry Andric /// "spelling" : " " 29381ad6265SDimitry Andric /// }, 29481ad6265SDimitry Andric /// { 29581ad6265SDimitry Andric /// "kind" : "identifier", 29681ad6265SDimitry Andric /// "spelling" : "pi" 29781ad6265SDimitry Andric /// } 29881ad6265SDimitry Andric /// ] 29981ad6265SDimitry Andric /// \endcode 30081ad6265SDimitry Andric /// 301bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the 302bdd1243dSDimitry Andric /// formatted declaration fragments array. 303bdd1243dSDimitry Andric std::optional<Array> 304bdd1243dSDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) { 30581ad6265SDimitry Andric if (DF.getFragments().empty()) 306bdd1243dSDimitry Andric return std::nullopt; 30781ad6265SDimitry Andric 30881ad6265SDimitry Andric Array Fragments; 30981ad6265SDimitry Andric for (const auto &F : DF.getFragments()) { 31081ad6265SDimitry Andric Object Fragment; 31181ad6265SDimitry Andric Fragment["spelling"] = F.Spelling; 31281ad6265SDimitry Andric Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 31381ad6265SDimitry Andric if (!F.PreciseIdentifier.empty()) 31481ad6265SDimitry Andric Fragment["preciseIdentifier"] = F.PreciseIdentifier; 31581ad6265SDimitry Andric Fragments.emplace_back(std::move(Fragment)); 31681ad6265SDimitry Andric } 31781ad6265SDimitry Andric 31881ad6265SDimitry Andric return Fragments; 31981ad6265SDimitry Andric } 32081ad6265SDimitry Andric 32181ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph 32281ad6265SDimitry Andric /// format. 32381ad6265SDimitry Andric /// 32481ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol 32581ad6265SDimitry Andric /// that can be used for different applications: 32681ad6265SDimitry Andric /// - \c title : The simple declared name of the symbol; 32781ad6265SDimitry Andric /// - \c subHeading : An array of declaration fragments that provides tags, 32881ad6265SDimitry Andric /// and potentially more tokens (for example the \c +/- symbol for 32981ad6265SDimitry Andric /// Objective-C methods). Can be used as sub-headings for documentation. 33081ad6265SDimitry Andric Object serializeNames(const APIRecord &Record) { 33181ad6265SDimitry Andric Object Names; 332*5f757f3fSDimitry Andric if (auto *CategoryRecord = 333*5f757f3fSDimitry Andric dyn_cast_or_null<const ObjCCategoryRecord>(&Record)) 334*5f757f3fSDimitry Andric Names["title"] = 335*5f757f3fSDimitry Andric (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str(); 336*5f757f3fSDimitry Andric else 33781ad6265SDimitry Andric Names["title"] = Record.Name; 338*5f757f3fSDimitry Andric 33981ad6265SDimitry Andric serializeArray(Names, "subHeading", 34081ad6265SDimitry Andric serializeDeclarationFragments(Record.SubHeading)); 34181ad6265SDimitry Andric DeclarationFragments NavigatorFragments; 34281ad6265SDimitry Andric NavigatorFragments.append(Record.Name, 34381ad6265SDimitry Andric DeclarationFragments::FragmentKind::Identifier, 34481ad6265SDimitry Andric /*PreciseIdentifier*/ ""); 34581ad6265SDimitry Andric serializeArray(Names, "navigator", 34681ad6265SDimitry Andric serializeDeclarationFragments(NavigatorFragments)); 34781ad6265SDimitry Andric 34881ad6265SDimitry Andric return Names; 34981ad6265SDimitry Andric } 35081ad6265SDimitry Andric 351bdd1243dSDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { 35281ad6265SDimitry Andric auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 35381ad6265SDimitry Andric return (getLanguageName(Lang) + "." + S).str(); 35481ad6265SDimitry Andric }; 35581ad6265SDimitry Andric 35681ad6265SDimitry Andric Object Kind; 357bdd1243dSDimitry Andric switch (RK) { 358bdd1243dSDimitry Andric case APIRecord::RK_Unknown: 359bdd1243dSDimitry Andric llvm_unreachable("Records should have an explicit kind"); 360bdd1243dSDimitry Andric break; 361*5f757f3fSDimitry Andric case APIRecord::RK_Namespace: 362*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("namespace"); 363*5f757f3fSDimitry Andric Kind["displayName"] = "Namespace"; 364*5f757f3fSDimitry Andric break; 36581ad6265SDimitry Andric case APIRecord::RK_GlobalFunction: 36681ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 36781ad6265SDimitry Andric Kind["displayName"] = "Function"; 36881ad6265SDimitry Andric break; 369*5f757f3fSDimitry Andric case APIRecord::RK_GlobalFunctionTemplate: 370*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 371*5f757f3fSDimitry Andric Kind["displayName"] = "Function Template"; 372*5f757f3fSDimitry Andric break; 373*5f757f3fSDimitry Andric case APIRecord::RK_GlobalFunctionTemplateSpecialization: 374*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 375*5f757f3fSDimitry Andric Kind["displayName"] = "Function Template Specialization"; 376*5f757f3fSDimitry Andric break; 377*5f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplate: 378*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 379*5f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template"; 380*5f757f3fSDimitry Andric break; 381*5f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplateSpecialization: 382*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 383*5f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template Specialization"; 384*5f757f3fSDimitry Andric break; 385*5f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplatePartialSpecialization: 386*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 387*5f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template Partial Specialization"; 388*5f757f3fSDimitry Andric break; 38981ad6265SDimitry Andric case APIRecord::RK_GlobalVariable: 39081ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 39181ad6265SDimitry Andric Kind["displayName"] = "Global Variable"; 39281ad6265SDimitry Andric break; 39381ad6265SDimitry Andric case APIRecord::RK_EnumConstant: 39481ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum.case"); 39581ad6265SDimitry Andric Kind["displayName"] = "Enumeration Case"; 39681ad6265SDimitry Andric break; 39781ad6265SDimitry Andric case APIRecord::RK_Enum: 39881ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum"); 39981ad6265SDimitry Andric Kind["displayName"] = "Enumeration"; 40081ad6265SDimitry Andric break; 40181ad6265SDimitry Andric case APIRecord::RK_StructField: 40281ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 40381ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 40481ad6265SDimitry Andric break; 40581ad6265SDimitry Andric case APIRecord::RK_Struct: 40681ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("struct"); 40781ad6265SDimitry Andric Kind["displayName"] = "Structure"; 40881ad6265SDimitry Andric break; 409*5f757f3fSDimitry Andric case APIRecord::RK_CXXField: 410*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 411*5f757f3fSDimitry Andric Kind["displayName"] = "Instance Property"; 412*5f757f3fSDimitry Andric break; 413*5f757f3fSDimitry Andric case APIRecord::RK_Union: 414*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("union"); 415*5f757f3fSDimitry Andric Kind["displayName"] = "Union"; 416*5f757f3fSDimitry Andric break; 417*5f757f3fSDimitry Andric case APIRecord::RK_StaticField: 418*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("type.property"); 419*5f757f3fSDimitry Andric Kind["displayName"] = "Type Property"; 420*5f757f3fSDimitry Andric break; 421*5f757f3fSDimitry Andric case APIRecord::RK_ClassTemplate: 422*5f757f3fSDimitry Andric case APIRecord::RK_ClassTemplateSpecialization: 423*5f757f3fSDimitry Andric case APIRecord::RK_ClassTemplatePartialSpecialization: 424*5f757f3fSDimitry Andric case APIRecord::RK_CXXClass: 425*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("class"); 426*5f757f3fSDimitry Andric Kind["displayName"] = "Class"; 427*5f757f3fSDimitry Andric break; 428*5f757f3fSDimitry Andric case APIRecord::RK_CXXMethodTemplate: 429*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 430*5f757f3fSDimitry Andric Kind["displayName"] = "Method Template"; 431*5f757f3fSDimitry Andric break; 432*5f757f3fSDimitry Andric case APIRecord::RK_CXXMethodTemplateSpecialization: 433*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 434*5f757f3fSDimitry Andric Kind["displayName"] = "Method Template Specialization"; 435*5f757f3fSDimitry Andric break; 436*5f757f3fSDimitry Andric case APIRecord::RK_CXXFieldTemplate: 437*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 438*5f757f3fSDimitry Andric Kind["displayName"] = "Template Property"; 439*5f757f3fSDimitry Andric break; 440*5f757f3fSDimitry Andric case APIRecord::RK_Concept: 441*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("concept"); 442*5f757f3fSDimitry Andric Kind["displayName"] = "Concept"; 443*5f757f3fSDimitry Andric break; 444*5f757f3fSDimitry Andric case APIRecord::RK_CXXStaticMethod: 445*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("type.method"); 446*5f757f3fSDimitry Andric Kind["displayName"] = "Static Method"; 447*5f757f3fSDimitry Andric break; 448*5f757f3fSDimitry Andric case APIRecord::RK_CXXInstanceMethod: 449*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 450*5f757f3fSDimitry Andric Kind["displayName"] = "Instance Method"; 451*5f757f3fSDimitry Andric break; 452*5f757f3fSDimitry Andric case APIRecord::RK_CXXConstructorMethod: 453*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 454*5f757f3fSDimitry Andric Kind["displayName"] = "Constructor"; 455*5f757f3fSDimitry Andric break; 456*5f757f3fSDimitry Andric case APIRecord::RK_CXXDestructorMethod: 457*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 458*5f757f3fSDimitry Andric Kind["displayName"] = "Destructor"; 459*5f757f3fSDimitry Andric break; 46081ad6265SDimitry Andric case APIRecord::RK_ObjCIvar: 46181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("ivar"); 46281ad6265SDimitry Andric Kind["displayName"] = "Instance Variable"; 46381ad6265SDimitry Andric break; 464bdd1243dSDimitry Andric case APIRecord::RK_ObjCInstanceMethod: 46581ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 46681ad6265SDimitry Andric Kind["displayName"] = "Instance Method"; 467bdd1243dSDimitry Andric break; 468bdd1243dSDimitry Andric case APIRecord::RK_ObjCClassMethod: 46981ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("type.method"); 47081ad6265SDimitry Andric Kind["displayName"] = "Type Method"; 47181ad6265SDimitry Andric break; 472bdd1243dSDimitry Andric case APIRecord::RK_ObjCInstanceProperty: 47381ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 47481ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 47581ad6265SDimitry Andric break; 476bdd1243dSDimitry Andric case APIRecord::RK_ObjCClassProperty: 477bdd1243dSDimitry Andric Kind["identifier"] = AddLangPrefix("type.property"); 478bdd1243dSDimitry Andric Kind["displayName"] = "Type Property"; 479bdd1243dSDimitry Andric break; 48081ad6265SDimitry Andric case APIRecord::RK_ObjCInterface: 48181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("class"); 48281ad6265SDimitry Andric Kind["displayName"] = "Class"; 48381ad6265SDimitry Andric break; 48481ad6265SDimitry Andric case APIRecord::RK_ObjCCategory: 485*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("class.extension"); 486*5f757f3fSDimitry Andric Kind["displayName"] = "Class Extension"; 487*5f757f3fSDimitry Andric break; 488*5f757f3fSDimitry Andric case APIRecord::RK_ObjCCategoryModule: 489*5f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("module.extension"); 490*5f757f3fSDimitry Andric Kind["displayName"] = "Module Extension"; 49181ad6265SDimitry Andric break; 49281ad6265SDimitry Andric case APIRecord::RK_ObjCProtocol: 49381ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("protocol"); 49481ad6265SDimitry Andric Kind["displayName"] = "Protocol"; 49581ad6265SDimitry Andric break; 49681ad6265SDimitry Andric case APIRecord::RK_MacroDefinition: 49781ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("macro"); 49881ad6265SDimitry Andric Kind["displayName"] = "Macro"; 49981ad6265SDimitry Andric break; 50081ad6265SDimitry Andric case APIRecord::RK_Typedef: 50181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("typealias"); 50281ad6265SDimitry Andric Kind["displayName"] = "Type Alias"; 50381ad6265SDimitry Andric break; 50481ad6265SDimitry Andric } 50581ad6265SDimitry Andric 50681ad6265SDimitry Andric return Kind; 50781ad6265SDimitry Andric } 50881ad6265SDimitry Andric 509bdd1243dSDimitry Andric /// Serialize the symbol kind information. 510bdd1243dSDimitry Andric /// 511bdd1243dSDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier 512bdd1243dSDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse 513bdd1243dSDimitry Andric /// the kind, and a \c displayName for rendering human-readable names. 514bdd1243dSDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 515bdd1243dSDimitry Andric return serializeSymbolKind(Record.getKind(), Lang); 516bdd1243dSDimitry Andric } 517bdd1243dSDimitry Andric 51881ad6265SDimitry Andric template <typename RecordTy> 519bdd1243dSDimitry Andric std::optional<Object> 520bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { 52181ad6265SDimitry Andric const auto &FS = Record.Signature; 52281ad6265SDimitry Andric if (FS.empty()) 523bdd1243dSDimitry Andric return std::nullopt; 52481ad6265SDimitry Andric 52581ad6265SDimitry Andric Object Signature; 52681ad6265SDimitry Andric serializeArray(Signature, "returns", 52781ad6265SDimitry Andric serializeDeclarationFragments(FS.getReturnType())); 52881ad6265SDimitry Andric 52981ad6265SDimitry Andric Array Parameters; 53081ad6265SDimitry Andric for (const auto &P : FS.getParameters()) { 53181ad6265SDimitry Andric Object Parameter; 53281ad6265SDimitry Andric Parameter["name"] = P.Name; 53381ad6265SDimitry Andric serializeArray(Parameter, "declarationFragments", 53481ad6265SDimitry Andric serializeDeclarationFragments(P.Fragments)); 53581ad6265SDimitry Andric Parameters.emplace_back(std::move(Parameter)); 53681ad6265SDimitry Andric } 53781ad6265SDimitry Andric 53881ad6265SDimitry Andric if (!Parameters.empty()) 53981ad6265SDimitry Andric Signature["parameters"] = std::move(Parameters); 54081ad6265SDimitry Andric 54181ad6265SDimitry Andric return Signature; 54281ad6265SDimitry Andric } 54381ad6265SDimitry Andric 54481ad6265SDimitry Andric template <typename RecordTy> 545bdd1243dSDimitry Andric std::optional<Object> 546bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { 547bdd1243dSDimitry Andric return std::nullopt; 54881ad6265SDimitry Andric } 54981ad6265SDimitry Andric 55081ad6265SDimitry Andric /// Serialize the function signature field, as specified by the 55181ad6265SDimitry Andric /// Symbol Graph format. 55281ad6265SDimitry Andric /// 55381ad6265SDimitry Andric /// The Symbol Graph function signature property contains two arrays. 55481ad6265SDimitry Andric /// - The \c returns array is the declaration fragments of the return type; 55581ad6265SDimitry Andric /// - The \c parameters array contains names and declaration fragments of the 55681ad6265SDimitry Andric /// parameters. 55781ad6265SDimitry Andric /// 558bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the 55981ad6265SDimitry Andric /// formatted function signature. 56081ad6265SDimitry Andric template <typename RecordTy> 56181ad6265SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 56281ad6265SDimitry Andric serializeObject(Paren, "functionSignature", 56381ad6265SDimitry Andric serializeFunctionSignatureMixinImpl( 56481ad6265SDimitry Andric Record, has_function_signature<RecordTy>())); 56581ad6265SDimitry Andric } 56681ad6265SDimitry Andric 567*5f757f3fSDimitry Andric template <typename RecordTy> 568*5f757f3fSDimitry Andric std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, 569*5f757f3fSDimitry Andric std::true_type) { 570*5f757f3fSDimitry Andric const auto &AccessControl = Record.Access; 571*5f757f3fSDimitry Andric std::string Access; 572*5f757f3fSDimitry Andric if (AccessControl.empty()) 573*5f757f3fSDimitry Andric return std::nullopt; 574*5f757f3fSDimitry Andric Access = AccessControl.getAccess(); 575*5f757f3fSDimitry Andric return Access; 576*5f757f3fSDimitry Andric } 577*5f757f3fSDimitry Andric 578*5f757f3fSDimitry Andric template <typename RecordTy> 579*5f757f3fSDimitry Andric std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, 580*5f757f3fSDimitry Andric std::false_type) { 581*5f757f3fSDimitry Andric return std::nullopt; 582*5f757f3fSDimitry Andric } 583*5f757f3fSDimitry Andric 584*5f757f3fSDimitry Andric template <typename RecordTy> 585*5f757f3fSDimitry Andric void serializeAccessMixin(Object &Paren, const RecordTy &Record) { 586*5f757f3fSDimitry Andric auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>()); 587*5f757f3fSDimitry Andric if (!accessLevel.has_value()) 588*5f757f3fSDimitry Andric accessLevel = "public"; 589*5f757f3fSDimitry Andric serializeString(Paren, "accessLevel", accessLevel); 590*5f757f3fSDimitry Andric } 591*5f757f3fSDimitry Andric 592*5f757f3fSDimitry Andric template <typename RecordTy> 593*5f757f3fSDimitry Andric std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, 594*5f757f3fSDimitry Andric std::true_type) { 595*5f757f3fSDimitry Andric const auto &Template = Record.Templ; 596*5f757f3fSDimitry Andric if (Template.empty()) 597*5f757f3fSDimitry Andric return std::nullopt; 598*5f757f3fSDimitry Andric 599*5f757f3fSDimitry Andric Object Generics; 600*5f757f3fSDimitry Andric Array GenericParameters; 601*5f757f3fSDimitry Andric for (const auto &Param : Template.getParameters()) { 602*5f757f3fSDimitry Andric Object Parameter; 603*5f757f3fSDimitry Andric Parameter["name"] = Param.Name; 604*5f757f3fSDimitry Andric Parameter["index"] = Param.Index; 605*5f757f3fSDimitry Andric Parameter["depth"] = Param.Depth; 606*5f757f3fSDimitry Andric GenericParameters.emplace_back(std::move(Parameter)); 607*5f757f3fSDimitry Andric } 608*5f757f3fSDimitry Andric if (!GenericParameters.empty()) 609*5f757f3fSDimitry Andric Generics["parameters"] = std::move(GenericParameters); 610*5f757f3fSDimitry Andric 611*5f757f3fSDimitry Andric Array GenericConstraints; 612*5f757f3fSDimitry Andric for (const auto &Constr : Template.getConstraints()) { 613*5f757f3fSDimitry Andric Object Constraint; 614*5f757f3fSDimitry Andric Constraint["kind"] = Constr.Kind; 615*5f757f3fSDimitry Andric Constraint["lhs"] = Constr.LHS; 616*5f757f3fSDimitry Andric Constraint["rhs"] = Constr.RHS; 617*5f757f3fSDimitry Andric GenericConstraints.emplace_back(std::move(Constraint)); 618*5f757f3fSDimitry Andric } 619*5f757f3fSDimitry Andric 620*5f757f3fSDimitry Andric if (!GenericConstraints.empty()) 621*5f757f3fSDimitry Andric Generics["constraints"] = std::move(GenericConstraints); 622*5f757f3fSDimitry Andric 623*5f757f3fSDimitry Andric return Generics; 624*5f757f3fSDimitry Andric } 625*5f757f3fSDimitry Andric 626*5f757f3fSDimitry Andric template <typename RecordTy> 627*5f757f3fSDimitry Andric std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, 628*5f757f3fSDimitry Andric std::false_type) { 629*5f757f3fSDimitry Andric return std::nullopt; 630*5f757f3fSDimitry Andric } 631*5f757f3fSDimitry Andric 632*5f757f3fSDimitry Andric template <typename RecordTy> 633*5f757f3fSDimitry Andric void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { 634*5f757f3fSDimitry Andric serializeObject(Paren, "swiftGenerics", 635*5f757f3fSDimitry Andric serializeTemplateMixinImpl(Record, has_template<RecordTy>())); 636*5f757f3fSDimitry Andric } 637*5f757f3fSDimitry Andric 638bdd1243dSDimitry Andric struct PathComponent { 639bdd1243dSDimitry Andric StringRef USR; 640bdd1243dSDimitry Andric StringRef Name; 641bdd1243dSDimitry Andric APIRecord::RecordKind Kind; 642bdd1243dSDimitry Andric 643bdd1243dSDimitry Andric PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind) 644bdd1243dSDimitry Andric : USR(USR), Name(Name), Kind(Kind) {} 645bdd1243dSDimitry Andric }; 646bdd1243dSDimitry Andric 647bdd1243dSDimitry Andric template <typename RecordTy> 648bdd1243dSDimitry Andric bool generatePathComponents( 649bdd1243dSDimitry Andric const RecordTy &Record, const APISet &API, 650bdd1243dSDimitry Andric function_ref<void(const PathComponent &)> ComponentTransformer) { 651bdd1243dSDimitry Andric SmallVector<PathComponent, 4> ReverseComponenents; 652bdd1243dSDimitry Andric ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind()); 653bdd1243dSDimitry Andric const auto *CurrentParent = &Record.ParentInformation; 65406c3fb27SDimitry Andric bool FailedToFindParent = false; 655bdd1243dSDimitry Andric while (CurrentParent && !CurrentParent->empty()) { 656bdd1243dSDimitry Andric PathComponent CurrentParentComponent(CurrentParent->ParentUSR, 657bdd1243dSDimitry Andric CurrentParent->ParentName, 658bdd1243dSDimitry Andric CurrentParent->ParentKind); 659bdd1243dSDimitry Andric 660bdd1243dSDimitry Andric auto *ParentRecord = CurrentParent->ParentRecord; 661bdd1243dSDimitry Andric // Slow path if we don't have a direct reference to the ParentRecord 662bdd1243dSDimitry Andric if (!ParentRecord) 663bdd1243dSDimitry Andric ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); 664bdd1243dSDimitry Andric 665*5f757f3fSDimitry Andric // If the parent is a category extended from internal module then we need to 666*5f757f3fSDimitry Andric // pretend this belongs to the associated interface. 667bdd1243dSDimitry Andric if (auto *CategoryRecord = 668bdd1243dSDimitry Andric dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) { 669*5f757f3fSDimitry Andric if (!CategoryRecord->IsFromExternalModule) { 670bdd1243dSDimitry Andric ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); 671bdd1243dSDimitry Andric CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, 672bdd1243dSDimitry Andric CategoryRecord->Interface.Name, 673bdd1243dSDimitry Andric APIRecord::RK_ObjCInterface); 674bdd1243dSDimitry Andric } 675*5f757f3fSDimitry Andric } 676bdd1243dSDimitry Andric 677bdd1243dSDimitry Andric // The parent record doesn't exist which means the symbol shouldn't be 678bdd1243dSDimitry Andric // treated as part of the current product. 67906c3fb27SDimitry Andric if (!ParentRecord) { 68006c3fb27SDimitry Andric FailedToFindParent = true; 68106c3fb27SDimitry Andric break; 68206c3fb27SDimitry Andric } 683bdd1243dSDimitry Andric 684bdd1243dSDimitry Andric ReverseComponenents.push_back(std::move(CurrentParentComponent)); 685bdd1243dSDimitry Andric CurrentParent = &ParentRecord->ParentInformation; 686bdd1243dSDimitry Andric } 687bdd1243dSDimitry Andric 688bdd1243dSDimitry Andric for (const auto &PC : reverse(ReverseComponenents)) 689bdd1243dSDimitry Andric ComponentTransformer(PC); 690bdd1243dSDimitry Andric 69106c3fb27SDimitry Andric return FailedToFindParent; 692bdd1243dSDimitry Andric } 69306c3fb27SDimitry Andric 694bdd1243dSDimitry Andric Object serializeParentContext(const PathComponent &PC, Language Lang) { 695bdd1243dSDimitry Andric Object ParentContextElem; 696bdd1243dSDimitry Andric ParentContextElem["usr"] = PC.USR; 697bdd1243dSDimitry Andric ParentContextElem["name"] = PC.Name; 698bdd1243dSDimitry Andric ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"]; 699bdd1243dSDimitry Andric return ParentContextElem; 700bdd1243dSDimitry Andric } 701bdd1243dSDimitry Andric 702bdd1243dSDimitry Andric template <typename RecordTy> 703bdd1243dSDimitry Andric Array generateParentContexts(const RecordTy &Record, const APISet &API, 704bdd1243dSDimitry Andric Language Lang) { 705bdd1243dSDimitry Andric Array ParentContexts; 70606c3fb27SDimitry Andric generatePathComponents( 707bdd1243dSDimitry Andric Record, API, [Lang, &ParentContexts](const PathComponent &PC) { 708bdd1243dSDimitry Andric ParentContexts.push_back(serializeParentContext(PC, Lang)); 70906c3fb27SDimitry Andric }); 710bdd1243dSDimitry Andric 711bdd1243dSDimitry Andric return ParentContexts; 712bdd1243dSDimitry Andric } 71381ad6265SDimitry Andric } // namespace 71481ad6265SDimitry Andric 71581ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer. 71681ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 71781ad6265SDimitry Andric 71881ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const { 71981ad6265SDimitry Andric Object Metadata; 72081ad6265SDimitry Andric serializeObject(Metadata, "formatVersion", 72181ad6265SDimitry Andric serializeSemanticVersion(FormatVersion)); 72281ad6265SDimitry Andric Metadata["generator"] = clang::getClangFullVersion(); 72381ad6265SDimitry Andric return Metadata; 72481ad6265SDimitry Andric } 72581ad6265SDimitry Andric 72681ad6265SDimitry Andric Object SymbolGraphSerializer::serializeModule() const { 72781ad6265SDimitry Andric Object Module; 72881ad6265SDimitry Andric // The user is expected to always pass `--product-name=` on the command line 72981ad6265SDimitry Andric // to populate this field. 730bdd1243dSDimitry Andric Module["name"] = API.ProductName; 73181ad6265SDimitry Andric serializeObject(Module, "platform", serializePlatform(API.getTarget())); 73281ad6265SDimitry Andric return Module; 73381ad6265SDimitry Andric } 73481ad6265SDimitry Andric 73581ad6265SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { 736bdd1243dSDimitry Andric // Skip explicitly ignored symbols. 737bdd1243dSDimitry Andric if (IgnoresList.shouldIgnore(Record.Name)) 738bdd1243dSDimitry Andric return true; 739bdd1243dSDimitry Andric 74081ad6265SDimitry Andric // Skip unconditionally unavailable symbols 741bdd1243dSDimitry Andric if (Record.Availabilities.isUnconditionallyUnavailable()) 74281ad6265SDimitry Andric return true; 74381ad6265SDimitry Andric 74481ad6265SDimitry Andric // Filter out symbols prefixed with an underscored as they are understood to 74581ad6265SDimitry Andric // be symbols clients should not use. 746*5f757f3fSDimitry Andric if (Record.Name.starts_with("_")) 74781ad6265SDimitry Andric return true; 74881ad6265SDimitry Andric 74981ad6265SDimitry Andric return false; 75081ad6265SDimitry Andric } 75181ad6265SDimitry Andric 75281ad6265SDimitry Andric template <typename RecordTy> 753bdd1243dSDimitry Andric std::optional<Object> 75481ad6265SDimitry Andric SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { 75581ad6265SDimitry Andric if (shouldSkip(Record)) 756bdd1243dSDimitry Andric return std::nullopt; 75781ad6265SDimitry Andric 75881ad6265SDimitry Andric Object Obj; 75981ad6265SDimitry Andric serializeObject(Obj, "identifier", 76081ad6265SDimitry Andric serializeIdentifier(Record, API.getLanguage())); 76181ad6265SDimitry Andric serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); 76281ad6265SDimitry Andric serializeObject(Obj, "names", serializeNames(Record)); 76381ad6265SDimitry Andric serializeObject( 76481ad6265SDimitry Andric Obj, "location", 76581ad6265SDimitry Andric serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); 766bdd1243dSDimitry Andric serializeArray(Obj, "availability", 767bdd1243dSDimitry Andric serializeAvailability(Record.Availabilities)); 76881ad6265SDimitry Andric serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); 76981ad6265SDimitry Andric serializeArray(Obj, "declarationFragments", 77081ad6265SDimitry Andric serializeDeclarationFragments(Record.Declaration)); 771bdd1243dSDimitry Andric SmallVector<StringRef, 4> PathComponentsNames; 772bdd1243dSDimitry Andric // If this returns true it indicates that we couldn't find a symbol in the 773bdd1243dSDimitry Andric // hierarchy. 774bdd1243dSDimitry Andric if (generatePathComponents(Record, API, 775bdd1243dSDimitry Andric [&PathComponentsNames](const PathComponent &PC) { 776bdd1243dSDimitry Andric PathComponentsNames.push_back(PC.Name); 777bdd1243dSDimitry Andric })) 778bdd1243dSDimitry Andric return {}; 779bdd1243dSDimitry Andric 780bdd1243dSDimitry Andric serializeArray(Obj, "pathComponents", Array(PathComponentsNames)); 78181ad6265SDimitry Andric 78281ad6265SDimitry Andric serializeFunctionSignatureMixin(Obj, Record); 783*5f757f3fSDimitry Andric serializeAccessMixin(Obj, Record); 784*5f757f3fSDimitry Andric serializeTemplateMixin(Obj, Record); 78581ad6265SDimitry Andric 78681ad6265SDimitry Andric return Obj; 78781ad6265SDimitry Andric } 78881ad6265SDimitry Andric 78981ad6265SDimitry Andric template <typename MemberTy> 79081ad6265SDimitry Andric void SymbolGraphSerializer::serializeMembers( 79181ad6265SDimitry Andric const APIRecord &Record, 79281ad6265SDimitry Andric const SmallVector<std::unique_ptr<MemberTy>> &Members) { 793bdd1243dSDimitry Andric // Members should not be serialized if we aren't recursing. 794bdd1243dSDimitry Andric if (!ShouldRecurse) 795bdd1243dSDimitry Andric return; 79681ad6265SDimitry Andric for (const auto &Member : Members) { 79781ad6265SDimitry Andric auto MemberRecord = serializeAPIRecord(*Member); 79881ad6265SDimitry Andric if (!MemberRecord) 79981ad6265SDimitry Andric continue; 80081ad6265SDimitry Andric 80181ad6265SDimitry Andric Symbols.emplace_back(std::move(*MemberRecord)); 80281ad6265SDimitry Andric serializeRelationship(RelationshipKind::MemberOf, *Member, Record); 80381ad6265SDimitry Andric } 80481ad6265SDimitry Andric } 80581ad6265SDimitry Andric 80681ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 80781ad6265SDimitry Andric switch (Kind) { 80881ad6265SDimitry Andric case RelationshipKind::MemberOf: 80981ad6265SDimitry Andric return "memberOf"; 81081ad6265SDimitry Andric case RelationshipKind::InheritsFrom: 81181ad6265SDimitry Andric return "inheritsFrom"; 81281ad6265SDimitry Andric case RelationshipKind::ConformsTo: 81381ad6265SDimitry Andric return "conformsTo"; 814*5f757f3fSDimitry Andric case RelationshipKind::ExtensionTo: 815*5f757f3fSDimitry Andric return "extensionTo"; 81681ad6265SDimitry Andric } 81781ad6265SDimitry Andric llvm_unreachable("Unhandled relationship kind"); 81881ad6265SDimitry Andric } 81981ad6265SDimitry Andric 820*5f757f3fSDimitry Andric StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { 821*5f757f3fSDimitry Andric switch (Kind) { 822*5f757f3fSDimitry Andric case ConstraintKind::Conformance: 823*5f757f3fSDimitry Andric return "conformance"; 824*5f757f3fSDimitry Andric case ConstraintKind::ConditionalConformance: 825*5f757f3fSDimitry Andric return "conditionalConformance"; 826*5f757f3fSDimitry Andric } 827*5f757f3fSDimitry Andric llvm_unreachable("Unhandled constraint kind"); 828*5f757f3fSDimitry Andric } 829*5f757f3fSDimitry Andric 83081ad6265SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 83181ad6265SDimitry Andric SymbolReference Source, 83281ad6265SDimitry Andric SymbolReference Target) { 83381ad6265SDimitry Andric Object Relationship; 83481ad6265SDimitry Andric Relationship["source"] = Source.USR; 83581ad6265SDimitry Andric Relationship["target"] = Target.USR; 836bdd1243dSDimitry Andric Relationship["targetFallback"] = Target.Name; 83781ad6265SDimitry Andric Relationship["kind"] = getRelationshipString(Kind); 83881ad6265SDimitry Andric 83981ad6265SDimitry Andric Relationships.emplace_back(std::move(Relationship)); 84081ad6265SDimitry Andric } 84181ad6265SDimitry Andric 842*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitNamespaceRecord( 843*5f757f3fSDimitry Andric const NamespaceRecord &Record) { 844*5f757f3fSDimitry Andric auto Namespace = serializeAPIRecord(Record); 845*5f757f3fSDimitry Andric if (!Namespace) 846*5f757f3fSDimitry Andric return; 847*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Namespace)); 848*5f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 849*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 850*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 851*5f757f3fSDimitry Andric } 852*5f757f3fSDimitry Andric 85306c3fb27SDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionRecord( 85481ad6265SDimitry Andric const GlobalFunctionRecord &Record) { 85581ad6265SDimitry Andric auto Obj = serializeAPIRecord(Record); 85681ad6265SDimitry Andric if (!Obj) 85781ad6265SDimitry Andric return; 85881ad6265SDimitry Andric 85981ad6265SDimitry Andric Symbols.emplace_back(std::move(*Obj)); 86081ad6265SDimitry Andric } 86181ad6265SDimitry Andric 86206c3fb27SDimitry Andric void SymbolGraphSerializer::visitGlobalVariableRecord( 86381ad6265SDimitry Andric const GlobalVariableRecord &Record) { 86481ad6265SDimitry Andric auto Obj = serializeAPIRecord(Record); 86581ad6265SDimitry Andric if (!Obj) 86681ad6265SDimitry Andric return; 86781ad6265SDimitry Andric 86881ad6265SDimitry Andric Symbols.emplace_back(std::move(*Obj)); 86981ad6265SDimitry Andric } 87081ad6265SDimitry Andric 87106c3fb27SDimitry Andric void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) { 87281ad6265SDimitry Andric auto Enum = serializeAPIRecord(Record); 87381ad6265SDimitry Andric if (!Enum) 87481ad6265SDimitry Andric return; 87581ad6265SDimitry Andric 87681ad6265SDimitry Andric Symbols.emplace_back(std::move(*Enum)); 87781ad6265SDimitry Andric serializeMembers(Record, Record.Constants); 87881ad6265SDimitry Andric } 87981ad6265SDimitry Andric 88006c3fb27SDimitry Andric void SymbolGraphSerializer::visitStructRecord(const StructRecord &Record) { 88181ad6265SDimitry Andric auto Struct = serializeAPIRecord(Record); 88281ad6265SDimitry Andric if (!Struct) 88381ad6265SDimitry Andric return; 88481ad6265SDimitry Andric 88581ad6265SDimitry Andric Symbols.emplace_back(std::move(*Struct)); 88681ad6265SDimitry Andric serializeMembers(Record, Record.Fields); 88781ad6265SDimitry Andric } 88881ad6265SDimitry Andric 889*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitStaticFieldRecord( 890*5f757f3fSDimitry Andric const StaticFieldRecord &Record) { 891*5f757f3fSDimitry Andric auto StaticField = serializeAPIRecord(Record); 892*5f757f3fSDimitry Andric if (!StaticField) 893*5f757f3fSDimitry Andric return; 894*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*StaticField)); 895*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context); 896*5f757f3fSDimitry Andric } 897*5f757f3fSDimitry Andric 898*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) { 899*5f757f3fSDimitry Andric auto Class = serializeAPIRecord(Record); 900*5f757f3fSDimitry Andric if (!Class) 901*5f757f3fSDimitry Andric return; 902*5f757f3fSDimitry Andric 903*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Class)); 904*5f757f3fSDimitry Andric for (const auto &Base : Record.Bases) 905*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 906*5f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 907*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 908*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 909*5f757f3fSDimitry Andric } 910*5f757f3fSDimitry Andric 911*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplateRecord( 912*5f757f3fSDimitry Andric const ClassTemplateRecord &Record) { 913*5f757f3fSDimitry Andric auto Class = serializeAPIRecord(Record); 914*5f757f3fSDimitry Andric if (!Class) 915*5f757f3fSDimitry Andric return; 916*5f757f3fSDimitry Andric 917*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Class)); 918*5f757f3fSDimitry Andric for (const auto &Base : Record.Bases) 919*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 920*5f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 921*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 922*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 923*5f757f3fSDimitry Andric } 924*5f757f3fSDimitry Andric 925*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplateSpecializationRecord( 926*5f757f3fSDimitry Andric const ClassTemplateSpecializationRecord &Record) { 927*5f757f3fSDimitry Andric auto Class = serializeAPIRecord(Record); 928*5f757f3fSDimitry Andric if (!Class) 929*5f757f3fSDimitry Andric return; 930*5f757f3fSDimitry Andric 931*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Class)); 932*5f757f3fSDimitry Andric 933*5f757f3fSDimitry Andric for (const auto &Base : Record.Bases) 934*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 935*5f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 936*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 937*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 938*5f757f3fSDimitry Andric } 939*5f757f3fSDimitry Andric 940*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( 941*5f757f3fSDimitry Andric const ClassTemplatePartialSpecializationRecord &Record) { 942*5f757f3fSDimitry Andric auto Class = serializeAPIRecord(Record); 943*5f757f3fSDimitry Andric if (!Class) 944*5f757f3fSDimitry Andric return; 945*5f757f3fSDimitry Andric 946*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Class)); 947*5f757f3fSDimitry Andric 948*5f757f3fSDimitry Andric for (const auto &Base : Record.Bases) 949*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 950*5f757f3fSDimitry Andric if (!Record.ParentInformation.empty()) 951*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 952*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 953*5f757f3fSDimitry Andric } 954*5f757f3fSDimitry Andric 955*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXInstanceMethodRecord( 956*5f757f3fSDimitry Andric const CXXInstanceMethodRecord &Record) { 957*5f757f3fSDimitry Andric auto InstanceMethod = serializeAPIRecord(Record); 958*5f757f3fSDimitry Andric if (!InstanceMethod) 959*5f757f3fSDimitry Andric return; 960*5f757f3fSDimitry Andric 961*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*InstanceMethod)); 962*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 963*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 964*5f757f3fSDimitry Andric } 965*5f757f3fSDimitry Andric 966*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXStaticMethodRecord( 967*5f757f3fSDimitry Andric const CXXStaticMethodRecord &Record) { 968*5f757f3fSDimitry Andric auto StaticMethod = serializeAPIRecord(Record); 969*5f757f3fSDimitry Andric if (!StaticMethod) 970*5f757f3fSDimitry Andric return; 971*5f757f3fSDimitry Andric 972*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*StaticMethod)); 973*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 974*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 975*5f757f3fSDimitry Andric } 976*5f757f3fSDimitry Andric 977*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitMethodTemplateRecord( 978*5f757f3fSDimitry Andric const CXXMethodTemplateRecord &Record) { 979*5f757f3fSDimitry Andric if (!ShouldRecurse) 980*5f757f3fSDimitry Andric // Ignore child symbols 981*5f757f3fSDimitry Andric return; 982*5f757f3fSDimitry Andric auto MethodTemplate = serializeAPIRecord(Record); 983*5f757f3fSDimitry Andric if (!MethodTemplate) 984*5f757f3fSDimitry Andric return; 985*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*MethodTemplate)); 986*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 987*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 988*5f757f3fSDimitry Andric } 989*5f757f3fSDimitry Andric 990*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord( 991*5f757f3fSDimitry Andric const CXXMethodTemplateSpecializationRecord &Record) { 992*5f757f3fSDimitry Andric if (!ShouldRecurse) 993*5f757f3fSDimitry Andric // Ignore child symbols 994*5f757f3fSDimitry Andric return; 995*5f757f3fSDimitry Andric auto MethodTemplateSpecialization = serializeAPIRecord(Record); 996*5f757f3fSDimitry Andric if (!MethodTemplateSpecialization) 997*5f757f3fSDimitry Andric return; 998*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*MethodTemplateSpecialization)); 999*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 1000*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 1001*5f757f3fSDimitry Andric } 1002*5f757f3fSDimitry Andric 1003*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) { 1004*5f757f3fSDimitry Andric if (!ShouldRecurse) 1005*5f757f3fSDimitry Andric return; 1006*5f757f3fSDimitry Andric auto CXXField = serializeAPIRecord(Record); 1007*5f757f3fSDimitry Andric if (!CXXField) 1008*5f757f3fSDimitry Andric return; 1009*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*CXXField)); 1010*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 1011*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 1012*5f757f3fSDimitry Andric } 1013*5f757f3fSDimitry Andric 1014*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitCXXFieldTemplateRecord( 1015*5f757f3fSDimitry Andric const CXXFieldTemplateRecord &Record) { 1016*5f757f3fSDimitry Andric if (!ShouldRecurse) 1017*5f757f3fSDimitry Andric // Ignore child symbols 1018*5f757f3fSDimitry Andric return; 1019*5f757f3fSDimitry Andric auto CXXFieldTemplate = serializeAPIRecord(Record); 1020*5f757f3fSDimitry Andric if (!CXXFieldTemplate) 1021*5f757f3fSDimitry Andric return; 1022*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*CXXFieldTemplate)); 1023*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, Record, 1024*5f757f3fSDimitry Andric Record.ParentInformation.ParentRecord); 1025*5f757f3fSDimitry Andric } 1026*5f757f3fSDimitry Andric 1027*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { 1028*5f757f3fSDimitry Andric auto Concept = serializeAPIRecord(Record); 1029*5f757f3fSDimitry Andric if (!Concept) 1030*5f757f3fSDimitry Andric return; 1031*5f757f3fSDimitry Andric 1032*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*Concept)); 1033*5f757f3fSDimitry Andric } 1034*5f757f3fSDimitry Andric 1035*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( 1036*5f757f3fSDimitry Andric const GlobalVariableTemplateRecord &Record) { 1037*5f757f3fSDimitry Andric auto GlobalVariableTemplate = serializeAPIRecord(Record); 1038*5f757f3fSDimitry Andric if (!GlobalVariableTemplate) 1039*5f757f3fSDimitry Andric return; 1040*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalVariableTemplate)); 1041*5f757f3fSDimitry Andric } 1042*5f757f3fSDimitry Andric 1043*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord( 1044*5f757f3fSDimitry Andric const GlobalVariableTemplateSpecializationRecord &Record) { 1045*5f757f3fSDimitry Andric auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record); 1046*5f757f3fSDimitry Andric if (!GlobalVariableTemplateSpecialization) 1047*5f757f3fSDimitry Andric return; 1048*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization)); 1049*5f757f3fSDimitry Andric } 1050*5f757f3fSDimitry Andric 1051*5f757f3fSDimitry Andric void SymbolGraphSerializer:: 1052*5f757f3fSDimitry Andric visitGlobalVariableTemplatePartialSpecializationRecord( 1053*5f757f3fSDimitry Andric const GlobalVariableTemplatePartialSpecializationRecord &Record) { 1054*5f757f3fSDimitry Andric auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record); 1055*5f757f3fSDimitry Andric if (!GlobalVariableTemplatePartialSpecialization) 1056*5f757f3fSDimitry Andric return; 1057*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization)); 1058*5f757f3fSDimitry Andric } 1059*5f757f3fSDimitry Andric 1060*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( 1061*5f757f3fSDimitry Andric const GlobalFunctionTemplateRecord &Record) { 1062*5f757f3fSDimitry Andric auto GlobalFunctionTemplate = serializeAPIRecord(Record); 1063*5f757f3fSDimitry Andric if (!GlobalFunctionTemplate) 1064*5f757f3fSDimitry Andric return; 1065*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); 1066*5f757f3fSDimitry Andric } 1067*5f757f3fSDimitry Andric 1068*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord( 1069*5f757f3fSDimitry Andric const GlobalFunctionTemplateSpecializationRecord &Record) { 1070*5f757f3fSDimitry Andric auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record); 1071*5f757f3fSDimitry Andric if (!GlobalFunctionTemplateSpecialization) 1072*5f757f3fSDimitry Andric return; 1073*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization)); 1074*5f757f3fSDimitry Andric } 1075*5f757f3fSDimitry Andric 107606c3fb27SDimitry Andric void SymbolGraphSerializer::visitObjCContainerRecord( 107781ad6265SDimitry Andric const ObjCContainerRecord &Record) { 107881ad6265SDimitry Andric auto ObjCContainer = serializeAPIRecord(Record); 107981ad6265SDimitry Andric if (!ObjCContainer) 108081ad6265SDimitry Andric return; 108181ad6265SDimitry Andric 108281ad6265SDimitry Andric Symbols.emplace_back(std::move(*ObjCContainer)); 108381ad6265SDimitry Andric 108481ad6265SDimitry Andric serializeMembers(Record, Record.Ivars); 108581ad6265SDimitry Andric serializeMembers(Record, Record.Methods); 108681ad6265SDimitry Andric serializeMembers(Record, Record.Properties); 108781ad6265SDimitry Andric 108881ad6265SDimitry Andric for (const auto &Protocol : Record.Protocols) 108981ad6265SDimitry Andric // Record that Record conforms to Protocol. 109081ad6265SDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 109181ad6265SDimitry Andric 109281ad6265SDimitry Andric if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) { 109381ad6265SDimitry Andric if (!ObjCInterface->SuperClass.empty()) 109481ad6265SDimitry Andric // If Record is an Objective-C interface record and it has a super class, 109581ad6265SDimitry Andric // record that Record is inherited from SuperClass. 109681ad6265SDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, 109781ad6265SDimitry Andric ObjCInterface->SuperClass); 109881ad6265SDimitry Andric 109981ad6265SDimitry Andric // Members of categories extending an interface are serialized as members of 110081ad6265SDimitry Andric // the interface. 110181ad6265SDimitry Andric for (const auto *Category : ObjCInterface->Categories) { 110281ad6265SDimitry Andric serializeMembers(Record, Category->Ivars); 110381ad6265SDimitry Andric serializeMembers(Record, Category->Methods); 110481ad6265SDimitry Andric serializeMembers(Record, Category->Properties); 110581ad6265SDimitry Andric 1106bdd1243dSDimitry Andric // Surface the protocols of the category to the interface. 110781ad6265SDimitry Andric for (const auto &Protocol : Category->Protocols) 110881ad6265SDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 110981ad6265SDimitry Andric } 111081ad6265SDimitry Andric } 111181ad6265SDimitry Andric } 111281ad6265SDimitry Andric 1113*5f757f3fSDimitry Andric void SymbolGraphSerializer::visitObjCCategoryRecord( 1114*5f757f3fSDimitry Andric const ObjCCategoryRecord &Record) { 1115*5f757f3fSDimitry Andric if (!Record.IsFromExternalModule) 1116*5f757f3fSDimitry Andric return; 1117*5f757f3fSDimitry Andric 1118*5f757f3fSDimitry Andric // Check if the current Category' parent has been visited before, if so skip. 1119*5f757f3fSDimitry Andric if (!visitedCategories.contains(Record.Interface.Name)) { 1120*5f757f3fSDimitry Andric visitedCategories.insert(Record.Interface.Name); 1121*5f757f3fSDimitry Andric Object Obj; 1122*5f757f3fSDimitry Andric serializeObject(Obj, "identifier", 1123*5f757f3fSDimitry Andric serializeIdentifier(Record, API.getLanguage())); 1124*5f757f3fSDimitry Andric serializeObject(Obj, "kind", 1125*5f757f3fSDimitry Andric serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, 1126*5f757f3fSDimitry Andric API.getLanguage())); 1127*5f757f3fSDimitry Andric Obj["accessLevel"] = "public"; 1128*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(Obj)); 1129*5f757f3fSDimitry Andric } 1130*5f757f3fSDimitry Andric 1131*5f757f3fSDimitry Andric Object Relationship; 1132*5f757f3fSDimitry Andric Relationship["source"] = Record.USR; 1133*5f757f3fSDimitry Andric Relationship["target"] = Record.Interface.USR; 1134*5f757f3fSDimitry Andric Relationship["targetFallback"] = Record.Interface.Name; 1135*5f757f3fSDimitry Andric Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo); 1136*5f757f3fSDimitry Andric Relationships.emplace_back(std::move(Relationship)); 1137*5f757f3fSDimitry Andric 1138*5f757f3fSDimitry Andric auto ObjCCategory = serializeAPIRecord(Record); 1139*5f757f3fSDimitry Andric 1140*5f757f3fSDimitry Andric if (!ObjCCategory) 1141*5f757f3fSDimitry Andric return; 1142*5f757f3fSDimitry Andric 1143*5f757f3fSDimitry Andric Symbols.emplace_back(std::move(*ObjCCategory)); 1144*5f757f3fSDimitry Andric serializeMembers(Record, Record.Methods); 1145*5f757f3fSDimitry Andric serializeMembers(Record, Record.Properties); 1146*5f757f3fSDimitry Andric 1147*5f757f3fSDimitry Andric // Surface the protocols of the category to the interface. 1148*5f757f3fSDimitry Andric for (const auto &Protocol : Record.Protocols) 1149*5f757f3fSDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 1150*5f757f3fSDimitry Andric } 1151*5f757f3fSDimitry Andric 115206c3fb27SDimitry Andric void SymbolGraphSerializer::visitMacroDefinitionRecord( 115381ad6265SDimitry Andric const MacroDefinitionRecord &Record) { 115481ad6265SDimitry Andric auto Macro = serializeAPIRecord(Record); 115581ad6265SDimitry Andric 115681ad6265SDimitry Andric if (!Macro) 115781ad6265SDimitry Andric return; 115881ad6265SDimitry Andric 115981ad6265SDimitry Andric Symbols.emplace_back(std::move(*Macro)); 116081ad6265SDimitry Andric } 116181ad6265SDimitry Andric 1162bdd1243dSDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { 1163bdd1243dSDimitry Andric switch (Record->getKind()) { 1164bdd1243dSDimitry Andric case APIRecord::RK_Unknown: 1165bdd1243dSDimitry Andric llvm_unreachable("Records should have a known kind!"); 1166bdd1243dSDimitry Andric case APIRecord::RK_GlobalFunction: 116706c3fb27SDimitry Andric visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record)); 1168bdd1243dSDimitry Andric break; 1169bdd1243dSDimitry Andric case APIRecord::RK_GlobalVariable: 117006c3fb27SDimitry Andric visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record)); 1171bdd1243dSDimitry Andric break; 1172bdd1243dSDimitry Andric case APIRecord::RK_Enum: 117306c3fb27SDimitry Andric visitEnumRecord(*cast<EnumRecord>(Record)); 1174bdd1243dSDimitry Andric break; 1175bdd1243dSDimitry Andric case APIRecord::RK_Struct: 117606c3fb27SDimitry Andric visitStructRecord(*cast<StructRecord>(Record)); 1177bdd1243dSDimitry Andric break; 1178*5f757f3fSDimitry Andric case APIRecord::RK_StaticField: 1179*5f757f3fSDimitry Andric visitStaticFieldRecord(*cast<StaticFieldRecord>(Record)); 1180*5f757f3fSDimitry Andric break; 1181*5f757f3fSDimitry Andric case APIRecord::RK_CXXClass: 1182*5f757f3fSDimitry Andric visitCXXClassRecord(*cast<CXXClassRecord>(Record)); 1183*5f757f3fSDimitry 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; 1190*5f757f3fSDimitry Andric case APIRecord::RK_ObjCCategory: 1191*5f757f3fSDimitry Andric visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record)); 1192*5f757f3fSDimitry 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