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" 17*0fca6ea1SDimitry Andric #include "clang/ExtractAPI/API.h" 1881ad6265SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h" 19bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 20bdd1243dSDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h" 21*0fca6ea1SDimitry Andric #include "llvm/ADT/SmallVector.h" 22bdd1243dSDimitry Andric #include "llvm/Support/Casting.h" 23bdd1243dSDimitry Andric #include "llvm/Support/Compiler.h" 2481ad6265SDimitry Andric #include "llvm/Support/Path.h" 2581ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h" 26*0fca6ea1SDimitry Andric #include "llvm/Support/raw_ostream.h" 27*0fca6ea1SDimitry Andric #include <iterator> 28bdd1243dSDimitry Andric #include <optional> 2981ad6265SDimitry Andric #include <type_traits> 3081ad6265SDimitry Andric 3181ad6265SDimitry Andric using namespace clang; 3281ad6265SDimitry Andric using namespace clang::extractapi; 3381ad6265SDimitry Andric using namespace llvm; 3481ad6265SDimitry Andric 3581ad6265SDimitry Andric namespace { 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren 3881ad6265SDimitry Andric /// at position \p Key. 39*0fca6ea1SDimitry Andric void serializeObject(Object &Paren, StringRef Key, 40*0fca6ea1SDimitry Andric std::optional<Object> &&Obj) { 4181ad6265SDimitry Andric if (Obj) 42bdd1243dSDimitry Andric Paren[Key] = std::move(*Obj); 4381ad6265SDimitry Andric } 4481ad6265SDimitry Andric 4581ad6265SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at 4681ad6265SDimitry Andric /// position \p Key. 47*0fca6ea1SDimitry Andric void serializeArray(Object &Paren, StringRef Key, 48*0fca6ea1SDimitry Andric std::optional<Array> &&Array) { 4981ad6265SDimitry Andric if (Array) 50bdd1243dSDimitry Andric Paren[Key] = std::move(*Array); 5181ad6265SDimitry Andric } 5281ad6265SDimitry Andric 53*0fca6ea1SDimitry Andric /// Helper function to inject a JSON array composed of the values in \p C into 54*0fca6ea1SDimitry Andric /// object \p Paren at position \p Key. 55*0fca6ea1SDimitry Andric template <typename ContainerTy> 56*0fca6ea1SDimitry Andric void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) { 57*0fca6ea1SDimitry Andric Paren[Key] = Array(C); 58*0fca6ea1SDimitry Andric } 59*0fca6ea1SDimitry Andric 6081ad6265SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 6181ad6265SDimitry Andric /// format. 6281ad6265SDimitry Andric /// 6381ad6265SDimitry Andric /// A semantic version object contains three numeric fields, representing the 6481ad6265SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple. 6581ad6265SDimitry Andric /// For example version tuple 1.0.3 is serialized as: 6681ad6265SDimitry Andric /// \code 6781ad6265SDimitry Andric /// { 6881ad6265SDimitry Andric /// "major" : 1, 6981ad6265SDimitry Andric /// "minor" : 0, 7081ad6265SDimitry Andric /// "patch" : 3 7181ad6265SDimitry Andric /// } 7281ad6265SDimitry Andric /// \endcode 7381ad6265SDimitry Andric /// 74bdd1243dSDimitry Andric /// \returns \c std::nullopt if the version \p V is empty, or an \c Object 75bdd1243dSDimitry Andric /// containing the semantic version representation of \p V. 76bdd1243dSDimitry Andric std::optional<Object> serializeSemanticVersion(const VersionTuple &V) { 7781ad6265SDimitry Andric if (V.empty()) 78bdd1243dSDimitry Andric return std::nullopt; 7981ad6265SDimitry Andric 8081ad6265SDimitry Andric Object Version; 8181ad6265SDimitry Andric Version["major"] = V.getMajor(); 8281ad6265SDimitry Andric Version["minor"] = V.getMinor().value_or(0); 8381ad6265SDimitry Andric Version["patch"] = V.getSubminor().value_or(0); 8481ad6265SDimitry Andric return Version; 8581ad6265SDimitry Andric } 8681ad6265SDimitry Andric 8781ad6265SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property. 8881ad6265SDimitry Andric /// 8981ad6265SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an 9081ad6265SDimitry Andric /// optional \c minimumVersion semantic version field. 9181ad6265SDimitry Andric Object serializeOperatingSystem(const Triple &T) { 9281ad6265SDimitry Andric Object OS; 9381ad6265SDimitry Andric OS["name"] = T.getOSTypeName(T.getOS()); 9481ad6265SDimitry Andric serializeObject(OS, "minimumVersion", 9581ad6265SDimitry Andric serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 9681ad6265SDimitry Andric return OS; 9781ad6265SDimitry Andric } 9881ad6265SDimitry Andric 9981ad6265SDimitry Andric /// Serialize the platform information in the Symbol Graph module section. 10081ad6265SDimitry Andric /// 10181ad6265SDimitry Andric /// The platform object describes a target platform triple in corresponding 10281ad6265SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem. 10381ad6265SDimitry Andric Object serializePlatform(const Triple &T) { 10481ad6265SDimitry Andric Object Platform; 10581ad6265SDimitry Andric Platform["architecture"] = T.getArchName(); 10681ad6265SDimitry Andric Platform["vendor"] = T.getVendorName(); 10781ad6265SDimitry Andric Platform["operatingSystem"] = serializeOperatingSystem(T); 10881ad6265SDimitry Andric return Platform; 10981ad6265SDimitry Andric } 11081ad6265SDimitry Andric 11181ad6265SDimitry Andric /// Serialize a source position. 11281ad6265SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) { 11381ad6265SDimitry Andric assert(Loc.isValid() && "invalid source position"); 11481ad6265SDimitry Andric 11581ad6265SDimitry Andric Object SourcePosition; 1165f757f3fSDimitry Andric SourcePosition["line"] = Loc.getLine() - 1; 1175f757f3fSDimitry Andric SourcePosition["character"] = Loc.getColumn() - 1; 11881ad6265SDimitry Andric 11981ad6265SDimitry Andric return SourcePosition; 12081ad6265SDimitry Andric } 12181ad6265SDimitry Andric 12281ad6265SDimitry Andric /// Serialize a source location in file. 12381ad6265SDimitry Andric /// 12481ad6265SDimitry Andric /// \param Loc The presumed location to serialize. 12581ad6265SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 12681ad6265SDimitry Andric /// Defaults to false. 12781ad6265SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc, 12881ad6265SDimitry Andric bool IncludeFileURI = false) { 12981ad6265SDimitry Andric Object SourceLocation; 13081ad6265SDimitry Andric serializeObject(SourceLocation, "position", serializeSourcePosition(Loc)); 13181ad6265SDimitry Andric 13281ad6265SDimitry Andric if (IncludeFileURI) { 13381ad6265SDimitry Andric std::string FileURI = "file://"; 13481ad6265SDimitry Andric // Normalize file path to use forward slashes for the URI. 13581ad6265SDimitry Andric FileURI += sys::path::convert_to_slash(Loc.getFilename()); 13681ad6265SDimitry Andric SourceLocation["uri"] = FileURI; 13781ad6265SDimitry Andric } 13881ad6265SDimitry Andric 13981ad6265SDimitry Andric return SourceLocation; 14081ad6265SDimitry Andric } 14181ad6265SDimitry Andric 14281ad6265SDimitry Andric /// Serialize a source range with begin and end locations. 14381ad6265SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc, 14481ad6265SDimitry Andric const PresumedLoc &EndLoc) { 14581ad6265SDimitry Andric Object SourceRange; 14681ad6265SDimitry Andric serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 14781ad6265SDimitry Andric serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 14881ad6265SDimitry Andric return SourceRange; 14981ad6265SDimitry Andric } 15081ad6265SDimitry Andric 15181ad6265SDimitry Andric /// Serialize the availability attributes of a symbol. 15281ad6265SDimitry Andric /// 15381ad6265SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted 1547a6dacacSDimitry Andric /// versions of the symbol as semantic versions, if not default. 1557a6dacacSDimitry Andric /// Availability information also contains flags to indicate if the symbol is 1567a6dacacSDimitry Andric /// unconditionally unavailable or deprecated, 1577a6dacacSDimitry Andric /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). 15881ad6265SDimitry Andric /// 159bdd1243dSDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes, 1607a6dacacSDimitry Andric /// or an \c Array containing an object with the formatted availability 1617a6dacacSDimitry Andric /// information. 1627a6dacacSDimitry Andric std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) { 1637a6dacacSDimitry Andric if (Avail.isDefault()) 164bdd1243dSDimitry Andric return std::nullopt; 16581ad6265SDimitry Andric 166bdd1243dSDimitry Andric Array AvailabilityArray; 167*0fca6ea1SDimitry Andric 1687a6dacacSDimitry Andric if (Avail.isUnconditionallyDeprecated()) { 169bdd1243dSDimitry Andric Object UnconditionallyDeprecated; 170bdd1243dSDimitry Andric UnconditionallyDeprecated["domain"] = "*"; 171bdd1243dSDimitry Andric UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true; 172bdd1243dSDimitry Andric AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated)); 173bdd1243dSDimitry Andric } 174*0fca6ea1SDimitry Andric Object Availability; 175*0fca6ea1SDimitry Andric 176*0fca6ea1SDimitry Andric Availability["domain"] = Avail.Domain; 177*0fca6ea1SDimitry Andric 178*0fca6ea1SDimitry Andric if (Avail.isUnavailable()) { 179*0fca6ea1SDimitry Andric Availability["isUnconditionallyUnavailable"] = true; 180*0fca6ea1SDimitry Andric } else { 181*0fca6ea1SDimitry Andric serializeObject(Availability, "introduced", 182*0fca6ea1SDimitry Andric serializeSemanticVersion(Avail.Introduced)); 183*0fca6ea1SDimitry Andric serializeObject(Availability, "deprecated", 184*0fca6ea1SDimitry Andric serializeSemanticVersion(Avail.Deprecated)); 185*0fca6ea1SDimitry Andric serializeObject(Availability, "obsoleted", 186*0fca6ea1SDimitry Andric serializeSemanticVersion(Avail.Obsoleted)); 18706c3fb27SDimitry Andric } 188*0fca6ea1SDimitry Andric 189bdd1243dSDimitry Andric AvailabilityArray.emplace_back(std::move(Availability)); 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"; 2005f757f3fSDimitry Andric case Language::CXX: 2015f757f3fSDimitry Andric return "c++"; 2025f757f3fSDimitry Andric case Language::ObjCXX: 2035f757f3fSDimitry 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: 217*0fca6ea1SDimitry Andric case Language::CIR: 21881ad6265SDimitry Andric llvm_unreachable("Unsupported language kind"); 21981ad6265SDimitry Andric } 22081ad6265SDimitry Andric 22181ad6265SDimitry Andric llvm_unreachable("Unhandled language kind"); 22281ad6265SDimitry Andric } 22381ad6265SDimitry Andric 22481ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format. 22581ad6265SDimitry Andric /// 22681ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique 22781ad6265SDimitry Andric /// references, and the interface language name. 22881ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) { 22981ad6265SDimitry Andric Object Identifier; 23081ad6265SDimitry Andric Identifier["precise"] = Record.USR; 23181ad6265SDimitry Andric Identifier["interfaceLanguage"] = getLanguageName(Lang); 23281ad6265SDimitry Andric 23381ad6265SDimitry Andric return Identifier; 23481ad6265SDimitry Andric } 23581ad6265SDimitry Andric 23681ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by 23781ad6265SDimitry Andric /// the Symbol Graph format. 23881ad6265SDimitry Andric /// 23981ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line 24081ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range 24181ad6265SDimitry Andric /// information. 24281ad6265SDimitry Andric /// e.g. 24381ad6265SDimitry Andric /// \code 24481ad6265SDimitry Andric /// /// This is a documentation comment 24581ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 24681ad6265SDimitry Andric /// /// with multiple lines. 24781ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 24881ad6265SDimitry Andric /// \endcode 24981ad6265SDimitry Andric /// 250bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing 251bdd1243dSDimitry Andric /// the formatted lines. 252bdd1243dSDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) { 25381ad6265SDimitry Andric if (Comment.empty()) 254bdd1243dSDimitry Andric return std::nullopt; 25581ad6265SDimitry Andric 25681ad6265SDimitry Andric Object DocComment; 257*0fca6ea1SDimitry Andric 25881ad6265SDimitry Andric Array LinesArray; 25981ad6265SDimitry Andric for (const auto &CommentLine : Comment) { 26081ad6265SDimitry Andric Object Line; 26181ad6265SDimitry Andric Line["text"] = CommentLine.Text; 26281ad6265SDimitry Andric serializeObject(Line, "range", 26381ad6265SDimitry Andric serializeSourceRange(CommentLine.Begin, CommentLine.End)); 26481ad6265SDimitry Andric LinesArray.emplace_back(std::move(Line)); 26581ad6265SDimitry Andric } 266*0fca6ea1SDimitry Andric 267*0fca6ea1SDimitry Andric serializeArray(DocComment, "lines", std::move(LinesArray)); 26881ad6265SDimitry Andric 26981ad6265SDimitry Andric return DocComment; 27081ad6265SDimitry Andric } 27181ad6265SDimitry Andric 27281ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol. 27381ad6265SDimitry Andric /// 27481ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important 27581ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to 27681ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for 27781ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example: 27881ad6265SDimitry Andric /// \code 27981ad6265SDimitry Andric /// const int pi; -> "declarationFragments" : [ 28081ad6265SDimitry Andric /// { 28181ad6265SDimitry Andric /// "kind" : "keyword", 28281ad6265SDimitry Andric /// "spelling" : "const" 28381ad6265SDimitry Andric /// }, 28481ad6265SDimitry Andric /// { 28581ad6265SDimitry Andric /// "kind" : "text", 28681ad6265SDimitry Andric /// "spelling" : " " 28781ad6265SDimitry Andric /// }, 28881ad6265SDimitry Andric /// { 28981ad6265SDimitry Andric /// "kind" : "typeIdentifier", 29081ad6265SDimitry Andric /// "preciseIdentifier" : "c:I", 29181ad6265SDimitry Andric /// "spelling" : "int" 29281ad6265SDimitry Andric /// }, 29381ad6265SDimitry Andric /// { 29481ad6265SDimitry Andric /// "kind" : "text", 29581ad6265SDimitry Andric /// "spelling" : " " 29681ad6265SDimitry Andric /// }, 29781ad6265SDimitry Andric /// { 29881ad6265SDimitry Andric /// "kind" : "identifier", 29981ad6265SDimitry Andric /// "spelling" : "pi" 30081ad6265SDimitry Andric /// } 30181ad6265SDimitry Andric /// ] 30281ad6265SDimitry Andric /// \endcode 30381ad6265SDimitry Andric /// 304bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the 305bdd1243dSDimitry Andric /// formatted declaration fragments array. 306bdd1243dSDimitry Andric std::optional<Array> 307bdd1243dSDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) { 30881ad6265SDimitry Andric if (DF.getFragments().empty()) 309bdd1243dSDimitry Andric return std::nullopt; 31081ad6265SDimitry Andric 31181ad6265SDimitry Andric Array Fragments; 31281ad6265SDimitry Andric for (const auto &F : DF.getFragments()) { 31381ad6265SDimitry Andric Object Fragment; 31481ad6265SDimitry Andric Fragment["spelling"] = F.Spelling; 31581ad6265SDimitry Andric Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 31681ad6265SDimitry Andric if (!F.PreciseIdentifier.empty()) 31781ad6265SDimitry Andric Fragment["preciseIdentifier"] = F.PreciseIdentifier; 31881ad6265SDimitry Andric Fragments.emplace_back(std::move(Fragment)); 31981ad6265SDimitry Andric } 32081ad6265SDimitry Andric 32181ad6265SDimitry Andric return Fragments; 32281ad6265SDimitry Andric } 32381ad6265SDimitry Andric 32481ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph 32581ad6265SDimitry Andric /// format. 32681ad6265SDimitry Andric /// 32781ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol 32881ad6265SDimitry Andric /// that can be used for different applications: 32981ad6265SDimitry Andric /// - \c title : The simple declared name of the symbol; 33081ad6265SDimitry Andric /// - \c subHeading : An array of declaration fragments that provides tags, 33181ad6265SDimitry Andric /// and potentially more tokens (for example the \c +/- symbol for 33281ad6265SDimitry Andric /// Objective-C methods). Can be used as sub-headings for documentation. 333*0fca6ea1SDimitry Andric Object serializeNames(const APIRecord *Record) { 33481ad6265SDimitry Andric Object Names; 335*0fca6ea1SDimitry Andric Names["title"] = Record->Name; 3365f757f3fSDimitry Andric 33781ad6265SDimitry Andric serializeArray(Names, "subHeading", 338*0fca6ea1SDimitry Andric serializeDeclarationFragments(Record->SubHeading)); 33981ad6265SDimitry Andric DeclarationFragments NavigatorFragments; 340*0fca6ea1SDimitry Andric NavigatorFragments.append(Record->Name, 34181ad6265SDimitry Andric DeclarationFragments::FragmentKind::Identifier, 34281ad6265SDimitry Andric /*PreciseIdentifier*/ ""); 34381ad6265SDimitry Andric serializeArray(Names, "navigator", 34481ad6265SDimitry Andric serializeDeclarationFragments(NavigatorFragments)); 34581ad6265SDimitry Andric 34681ad6265SDimitry Andric return Names; 34781ad6265SDimitry Andric } 34881ad6265SDimitry Andric 349bdd1243dSDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { 35081ad6265SDimitry Andric auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 35181ad6265SDimitry Andric return (getLanguageName(Lang) + "." + S).str(); 35281ad6265SDimitry Andric }; 35381ad6265SDimitry Andric 35481ad6265SDimitry Andric Object Kind; 355bdd1243dSDimitry Andric switch (RK) { 356bdd1243dSDimitry Andric case APIRecord::RK_Unknown: 357*0fca6ea1SDimitry Andric Kind["identifier"] = AddLangPrefix("unknown"); 358*0fca6ea1SDimitry Andric Kind["displayName"] = "Unknown"; 359bdd1243dSDimitry Andric break; 3605f757f3fSDimitry Andric case APIRecord::RK_Namespace: 3615f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("namespace"); 3625f757f3fSDimitry Andric Kind["displayName"] = "Namespace"; 3635f757f3fSDimitry Andric break; 36481ad6265SDimitry Andric case APIRecord::RK_GlobalFunction: 36581ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 36681ad6265SDimitry Andric Kind["displayName"] = "Function"; 36781ad6265SDimitry Andric break; 3685f757f3fSDimitry Andric case APIRecord::RK_GlobalFunctionTemplate: 3695f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 3705f757f3fSDimitry Andric Kind["displayName"] = "Function Template"; 3715f757f3fSDimitry Andric break; 3725f757f3fSDimitry Andric case APIRecord::RK_GlobalFunctionTemplateSpecialization: 3735f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 3745f757f3fSDimitry Andric Kind["displayName"] = "Function Template Specialization"; 3755f757f3fSDimitry Andric break; 3765f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplate: 3775f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 3785f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template"; 3795f757f3fSDimitry Andric break; 3805f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplateSpecialization: 3815f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 3825f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template Specialization"; 3835f757f3fSDimitry Andric break; 3845f757f3fSDimitry Andric case APIRecord::RK_GlobalVariableTemplatePartialSpecialization: 3855f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 3865f757f3fSDimitry Andric Kind["displayName"] = "Global Variable Template Partial Specialization"; 3875f757f3fSDimitry Andric break; 38881ad6265SDimitry Andric case APIRecord::RK_GlobalVariable: 38981ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 39081ad6265SDimitry Andric Kind["displayName"] = "Global Variable"; 39181ad6265SDimitry Andric break; 39281ad6265SDimitry Andric case APIRecord::RK_EnumConstant: 39381ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum.case"); 39481ad6265SDimitry Andric Kind["displayName"] = "Enumeration Case"; 39581ad6265SDimitry Andric break; 39681ad6265SDimitry Andric case APIRecord::RK_Enum: 39781ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum"); 39881ad6265SDimitry Andric Kind["displayName"] = "Enumeration"; 39981ad6265SDimitry Andric break; 40081ad6265SDimitry Andric case APIRecord::RK_StructField: 40181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 40281ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 40381ad6265SDimitry Andric break; 40481ad6265SDimitry Andric case APIRecord::RK_Struct: 40581ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("struct"); 40681ad6265SDimitry Andric Kind["displayName"] = "Structure"; 40781ad6265SDimitry Andric break; 4087a6dacacSDimitry Andric case APIRecord::RK_UnionField: 4095f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 4105f757f3fSDimitry Andric Kind["displayName"] = "Instance Property"; 4115f757f3fSDimitry Andric break; 4125f757f3fSDimitry Andric case APIRecord::RK_Union: 4135f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("union"); 4145f757f3fSDimitry Andric Kind["displayName"] = "Union"; 4155f757f3fSDimitry Andric break; 4167a6dacacSDimitry Andric case APIRecord::RK_CXXField: 4177a6dacacSDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 4187a6dacacSDimitry Andric Kind["displayName"] = "Instance Property"; 4197a6dacacSDimitry Andric break; 4205f757f3fSDimitry Andric case APIRecord::RK_StaticField: 4215f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("type.property"); 4225f757f3fSDimitry Andric Kind["displayName"] = "Type Property"; 4235f757f3fSDimitry Andric break; 4245f757f3fSDimitry Andric case APIRecord::RK_ClassTemplate: 4255f757f3fSDimitry Andric case APIRecord::RK_ClassTemplateSpecialization: 4265f757f3fSDimitry Andric case APIRecord::RK_ClassTemplatePartialSpecialization: 4275f757f3fSDimitry Andric case APIRecord::RK_CXXClass: 4285f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("class"); 4295f757f3fSDimitry Andric Kind["displayName"] = "Class"; 4305f757f3fSDimitry Andric break; 4315f757f3fSDimitry Andric case APIRecord::RK_CXXMethodTemplate: 4325f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4335f757f3fSDimitry Andric Kind["displayName"] = "Method Template"; 4345f757f3fSDimitry Andric break; 4355f757f3fSDimitry Andric case APIRecord::RK_CXXMethodTemplateSpecialization: 4365f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4375f757f3fSDimitry Andric Kind["displayName"] = "Method Template Specialization"; 4385f757f3fSDimitry Andric break; 4395f757f3fSDimitry Andric case APIRecord::RK_CXXFieldTemplate: 4405f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 4415f757f3fSDimitry Andric Kind["displayName"] = "Template Property"; 4425f757f3fSDimitry Andric break; 4435f757f3fSDimitry Andric case APIRecord::RK_Concept: 4445f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("concept"); 4455f757f3fSDimitry Andric Kind["displayName"] = "Concept"; 4465f757f3fSDimitry Andric break; 4475f757f3fSDimitry Andric case APIRecord::RK_CXXStaticMethod: 4485f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("type.method"); 4495f757f3fSDimitry Andric Kind["displayName"] = "Static Method"; 4505f757f3fSDimitry Andric break; 4515f757f3fSDimitry Andric case APIRecord::RK_CXXInstanceMethod: 4525f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4535f757f3fSDimitry Andric Kind["displayName"] = "Instance Method"; 4545f757f3fSDimitry Andric break; 4555f757f3fSDimitry Andric case APIRecord::RK_CXXConstructorMethod: 4565f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4575f757f3fSDimitry Andric Kind["displayName"] = "Constructor"; 4585f757f3fSDimitry Andric break; 4595f757f3fSDimitry Andric case APIRecord::RK_CXXDestructorMethod: 4605f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 4615f757f3fSDimitry Andric Kind["displayName"] = "Destructor"; 4625f757f3fSDimitry Andric break; 46381ad6265SDimitry Andric case APIRecord::RK_ObjCIvar: 46481ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("ivar"); 46581ad6265SDimitry Andric Kind["displayName"] = "Instance Variable"; 46681ad6265SDimitry Andric break; 467bdd1243dSDimitry Andric case APIRecord::RK_ObjCInstanceMethod: 46881ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 46981ad6265SDimitry Andric Kind["displayName"] = "Instance Method"; 470bdd1243dSDimitry Andric break; 471bdd1243dSDimitry Andric case APIRecord::RK_ObjCClassMethod: 47281ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("type.method"); 47381ad6265SDimitry Andric Kind["displayName"] = "Type Method"; 47481ad6265SDimitry Andric break; 475bdd1243dSDimitry Andric case APIRecord::RK_ObjCInstanceProperty: 47681ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 47781ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 47881ad6265SDimitry Andric break; 479bdd1243dSDimitry Andric case APIRecord::RK_ObjCClassProperty: 480bdd1243dSDimitry Andric Kind["identifier"] = AddLangPrefix("type.property"); 481bdd1243dSDimitry Andric Kind["displayName"] = "Type Property"; 482bdd1243dSDimitry Andric break; 48381ad6265SDimitry Andric case APIRecord::RK_ObjCInterface: 48481ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("class"); 48581ad6265SDimitry Andric Kind["displayName"] = "Class"; 48681ad6265SDimitry Andric break; 48781ad6265SDimitry Andric case APIRecord::RK_ObjCCategory: 4885f757f3fSDimitry Andric Kind["identifier"] = AddLangPrefix("class.extension"); 4895f757f3fSDimitry Andric Kind["displayName"] = "Class Extension"; 4905f757f3fSDimitry Andric break; 49181ad6265SDimitry Andric case APIRecord::RK_ObjCProtocol: 49281ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("protocol"); 49381ad6265SDimitry Andric Kind["displayName"] = "Protocol"; 49481ad6265SDimitry Andric break; 49581ad6265SDimitry Andric case APIRecord::RK_MacroDefinition: 49681ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("macro"); 49781ad6265SDimitry Andric Kind["displayName"] = "Macro"; 49881ad6265SDimitry Andric break; 49981ad6265SDimitry Andric case APIRecord::RK_Typedef: 50081ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("typealias"); 50181ad6265SDimitry Andric Kind["displayName"] = "Type Alias"; 50281ad6265SDimitry Andric break; 503*0fca6ea1SDimitry Andric default: 504*0fca6ea1SDimitry Andric llvm_unreachable("API Record with uninstantiable kind"); 50581ad6265SDimitry Andric } 50681ad6265SDimitry Andric 50781ad6265SDimitry Andric return Kind; 50881ad6265SDimitry Andric } 50981ad6265SDimitry Andric 510bdd1243dSDimitry Andric /// Serialize the symbol kind information. 511bdd1243dSDimitry Andric /// 512bdd1243dSDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier 513bdd1243dSDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse 514bdd1243dSDimitry Andric /// the kind, and a \c displayName for rendering human-readable names. 515bdd1243dSDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 516*0fca6ea1SDimitry Andric return serializeSymbolKind(Record.KindForDisplay, Lang); 517bdd1243dSDimitry Andric } 518bdd1243dSDimitry Andric 519*0fca6ea1SDimitry Andric /// Serialize the function signature field, as specified by the 520*0fca6ea1SDimitry Andric /// Symbol Graph format. 521*0fca6ea1SDimitry Andric /// 522*0fca6ea1SDimitry Andric /// The Symbol Graph function signature property contains two arrays. 523*0fca6ea1SDimitry Andric /// - The \c returns array is the declaration fragments of the return type; 524*0fca6ea1SDimitry Andric /// - The \c parameters array contains names and declaration fragments of the 525*0fca6ea1SDimitry Andric /// parameters. 52681ad6265SDimitry Andric template <typename RecordTy> 527*0fca6ea1SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 52881ad6265SDimitry Andric const auto &FS = Record.Signature; 52981ad6265SDimitry Andric if (FS.empty()) 530*0fca6ea1SDimitry Andric return; 53181ad6265SDimitry Andric 53281ad6265SDimitry Andric Object Signature; 53381ad6265SDimitry Andric serializeArray(Signature, "returns", 53481ad6265SDimitry Andric serializeDeclarationFragments(FS.getReturnType())); 53581ad6265SDimitry Andric 53681ad6265SDimitry Andric Array Parameters; 53781ad6265SDimitry Andric for (const auto &P : FS.getParameters()) { 53881ad6265SDimitry Andric Object Parameter; 53981ad6265SDimitry Andric Parameter["name"] = P.Name; 54081ad6265SDimitry Andric serializeArray(Parameter, "declarationFragments", 54181ad6265SDimitry Andric serializeDeclarationFragments(P.Fragments)); 54281ad6265SDimitry Andric Parameters.emplace_back(std::move(Parameter)); 54381ad6265SDimitry Andric } 54481ad6265SDimitry Andric 54581ad6265SDimitry Andric if (!Parameters.empty()) 54681ad6265SDimitry Andric Signature["parameters"] = std::move(Parameters); 54781ad6265SDimitry Andric 548*0fca6ea1SDimitry Andric serializeObject(Paren, "functionSignature", std::move(Signature)); 54981ad6265SDimitry Andric } 55081ad6265SDimitry Andric 55181ad6265SDimitry Andric template <typename RecordTy> 552*0fca6ea1SDimitry Andric void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { 5535f757f3fSDimitry Andric const auto &Template = Record.Templ; 5545f757f3fSDimitry Andric if (Template.empty()) 555*0fca6ea1SDimitry Andric return; 5565f757f3fSDimitry Andric 5575f757f3fSDimitry Andric Object Generics; 5585f757f3fSDimitry Andric Array GenericParameters; 5595f757f3fSDimitry Andric for (const auto &Param : Template.getParameters()) { 5605f757f3fSDimitry Andric Object Parameter; 5615f757f3fSDimitry Andric Parameter["name"] = Param.Name; 5625f757f3fSDimitry Andric Parameter["index"] = Param.Index; 5635f757f3fSDimitry Andric Parameter["depth"] = Param.Depth; 5645f757f3fSDimitry Andric GenericParameters.emplace_back(std::move(Parameter)); 5655f757f3fSDimitry Andric } 5665f757f3fSDimitry Andric if (!GenericParameters.empty()) 5675f757f3fSDimitry Andric Generics["parameters"] = std::move(GenericParameters); 5685f757f3fSDimitry Andric 5695f757f3fSDimitry Andric Array GenericConstraints; 5705f757f3fSDimitry Andric for (const auto &Constr : Template.getConstraints()) { 5715f757f3fSDimitry Andric Object Constraint; 5725f757f3fSDimitry Andric Constraint["kind"] = Constr.Kind; 5735f757f3fSDimitry Andric Constraint["lhs"] = Constr.LHS; 5745f757f3fSDimitry Andric Constraint["rhs"] = Constr.RHS; 5755f757f3fSDimitry Andric GenericConstraints.emplace_back(std::move(Constraint)); 5765f757f3fSDimitry Andric } 5775f757f3fSDimitry Andric 5785f757f3fSDimitry Andric if (!GenericConstraints.empty()) 5795f757f3fSDimitry Andric Generics["constraints"] = std::move(GenericConstraints); 5805f757f3fSDimitry Andric 581*0fca6ea1SDimitry Andric serializeObject(Paren, "swiftGenerics", Generics); 5825f757f3fSDimitry Andric } 5835f757f3fSDimitry Andric 584*0fca6ea1SDimitry Andric Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents, 585bdd1243dSDimitry Andric Language Lang) { 586bdd1243dSDimitry Andric Array ParentContexts; 587*0fca6ea1SDimitry Andric 588*0fca6ea1SDimitry Andric for (const auto &Parent : Parents) { 589*0fca6ea1SDimitry Andric Object Elem; 590*0fca6ea1SDimitry Andric Elem["usr"] = Parent.USR; 591*0fca6ea1SDimitry Andric Elem["name"] = Parent.Name; 592*0fca6ea1SDimitry Andric if (Parent.Record) 593*0fca6ea1SDimitry Andric Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay, 594*0fca6ea1SDimitry Andric Lang)["identifier"]; 595*0fca6ea1SDimitry Andric else 596*0fca6ea1SDimitry Andric Elem["kind"] = 597*0fca6ea1SDimitry Andric serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"]; 598*0fca6ea1SDimitry Andric ParentContexts.emplace_back(std::move(Elem)); 599*0fca6ea1SDimitry Andric } 600bdd1243dSDimitry Andric 601bdd1243dSDimitry Andric return ParentContexts; 602bdd1243dSDimitry Andric } 603*0fca6ea1SDimitry Andric 604*0fca6ea1SDimitry Andric /// Walk the records parent information in reverse to generate a hierarchy 605*0fca6ea1SDimitry Andric /// suitable for serialization. 606*0fca6ea1SDimitry Andric SmallVector<SymbolReference, 8> 607*0fca6ea1SDimitry Andric generateHierarchyFromRecord(const APIRecord *Record) { 608*0fca6ea1SDimitry Andric SmallVector<SymbolReference, 8> ReverseHierarchy; 609*0fca6ea1SDimitry Andric for (const auto *Current = Record; Current != nullptr; 610*0fca6ea1SDimitry Andric Current = Current->Parent.Record) 611*0fca6ea1SDimitry Andric ReverseHierarchy.emplace_back(Current); 612*0fca6ea1SDimitry Andric 613*0fca6ea1SDimitry Andric return SmallVector<SymbolReference, 8>( 614*0fca6ea1SDimitry Andric std::make_move_iterator(ReverseHierarchy.rbegin()), 615*0fca6ea1SDimitry Andric std::make_move_iterator(ReverseHierarchy.rend())); 616*0fca6ea1SDimitry Andric } 617*0fca6ea1SDimitry Andric 618*0fca6ea1SDimitry Andric SymbolReference getHierarchyReference(const APIRecord *Record, 619*0fca6ea1SDimitry Andric const APISet &API) { 620*0fca6ea1SDimitry Andric // If the parent is a category extended from internal module then we need to 621*0fca6ea1SDimitry Andric // pretend this belongs to the associated interface. 622*0fca6ea1SDimitry Andric if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) { 623*0fca6ea1SDimitry Andric return CategoryRecord->Interface; 624*0fca6ea1SDimitry Andric // FIXME: TODO generate path components correctly for categories extending 625*0fca6ea1SDimitry Andric // an external module. 626*0fca6ea1SDimitry Andric } 627*0fca6ea1SDimitry Andric 628*0fca6ea1SDimitry Andric return SymbolReference(Record); 629*0fca6ea1SDimitry Andric } 630*0fca6ea1SDimitry Andric 63181ad6265SDimitry Andric } // namespace 63281ad6265SDimitry Andric 633*0fca6ea1SDimitry Andric Object *ExtendedModule::addSymbol(Object &&Symbol) { 634*0fca6ea1SDimitry Andric Symbols.emplace_back(std::move(Symbol)); 635*0fca6ea1SDimitry Andric return Symbols.back().getAsObject(); 636*0fca6ea1SDimitry Andric } 637*0fca6ea1SDimitry Andric 638*0fca6ea1SDimitry Andric void ExtendedModule::addRelationship(Object &&Relationship) { 639*0fca6ea1SDimitry Andric Relationships.emplace_back(std::move(Relationship)); 640*0fca6ea1SDimitry Andric } 641*0fca6ea1SDimitry Andric 64281ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer. 64381ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 64481ad6265SDimitry Andric 64581ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const { 64681ad6265SDimitry Andric Object Metadata; 64781ad6265SDimitry Andric serializeObject(Metadata, "formatVersion", 64881ad6265SDimitry Andric serializeSemanticVersion(FormatVersion)); 64981ad6265SDimitry Andric Metadata["generator"] = clang::getClangFullVersion(); 65081ad6265SDimitry Andric return Metadata; 65181ad6265SDimitry Andric } 65281ad6265SDimitry Andric 653*0fca6ea1SDimitry Andric Object 654*0fca6ea1SDimitry Andric SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const { 65581ad6265SDimitry Andric Object Module; 656*0fca6ea1SDimitry Andric Module["name"] = ModuleName; 65781ad6265SDimitry Andric serializeObject(Module, "platform", serializePlatform(API.getTarget())); 65881ad6265SDimitry Andric return Module; 65981ad6265SDimitry Andric } 66081ad6265SDimitry Andric 661*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const { 662*0fca6ea1SDimitry Andric if (!Record) 663bdd1243dSDimitry Andric return true; 664bdd1243dSDimitry Andric 66581ad6265SDimitry Andric // Skip unconditionally unavailable symbols 666*0fca6ea1SDimitry Andric if (Record->Availability.isUnconditionallyUnavailable()) 66781ad6265SDimitry Andric return true; 66881ad6265SDimitry Andric 669*0fca6ea1SDimitry Andric // Filter out symbols without a name as we can generate correct symbol graphs 670*0fca6ea1SDimitry Andric // for them. In practice these are anonymous record types that aren't attached 671*0fca6ea1SDimitry Andric // to a declaration. 672*0fca6ea1SDimitry Andric if (auto *Tag = dyn_cast<TagRecord>(Record)) { 673*0fca6ea1SDimitry Andric if (Tag->IsEmbeddedInVarDeclarator) 674*0fca6ea1SDimitry Andric return true; 675*0fca6ea1SDimitry Andric } 676*0fca6ea1SDimitry Andric 67781ad6265SDimitry Andric // Filter out symbols prefixed with an underscored as they are understood to 67881ad6265SDimitry Andric // be symbols clients should not use. 679*0fca6ea1SDimitry Andric if (Record->Name.starts_with("_")) 680*0fca6ea1SDimitry Andric return true; 681*0fca6ea1SDimitry Andric 682*0fca6ea1SDimitry Andric // Skip explicitly ignored symbols. 683*0fca6ea1SDimitry Andric if (IgnoresList.shouldIgnore(Record->Name)) 68481ad6265SDimitry Andric return true; 68581ad6265SDimitry Andric 68681ad6265SDimitry Andric return false; 68781ad6265SDimitry Andric } 68881ad6265SDimitry Andric 689*0fca6ea1SDimitry Andric ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() { 690*0fca6ea1SDimitry Andric if (!ForceEmitToMainModule && ModuleForCurrentSymbol) 691*0fca6ea1SDimitry Andric return *ModuleForCurrentSymbol; 69281ad6265SDimitry Andric 693*0fca6ea1SDimitry Andric return MainModule; 69481ad6265SDimitry Andric } 69581ad6265SDimitry Andric 696*0fca6ea1SDimitry Andric Array SymbolGraphSerializer::serializePathComponents( 697*0fca6ea1SDimitry Andric const APIRecord *Record) const { 698*0fca6ea1SDimitry Andric return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; })); 69981ad6265SDimitry Andric } 70081ad6265SDimitry Andric 70181ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 70281ad6265SDimitry Andric switch (Kind) { 70381ad6265SDimitry Andric case RelationshipKind::MemberOf: 70481ad6265SDimitry Andric return "memberOf"; 70581ad6265SDimitry Andric case RelationshipKind::InheritsFrom: 70681ad6265SDimitry Andric return "inheritsFrom"; 70781ad6265SDimitry Andric case RelationshipKind::ConformsTo: 70881ad6265SDimitry Andric return "conformsTo"; 7095f757f3fSDimitry Andric case RelationshipKind::ExtensionTo: 7105f757f3fSDimitry Andric return "extensionTo"; 71181ad6265SDimitry Andric } 71281ad6265SDimitry Andric llvm_unreachable("Unhandled relationship kind"); 71381ad6265SDimitry Andric } 71481ad6265SDimitry Andric 715*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 716*0fca6ea1SDimitry Andric const SymbolReference &Source, 717*0fca6ea1SDimitry Andric const SymbolReference &Target, 718*0fca6ea1SDimitry Andric ExtendedModule &Into) { 719*0fca6ea1SDimitry Andric Object Relationship; 720*0fca6ea1SDimitry Andric SmallString<64> TestRelLabel; 721*0fca6ea1SDimitry Andric if (EmitSymbolLabelsForTesting) { 722*0fca6ea1SDimitry Andric llvm::raw_svector_ostream OS(TestRelLabel); 723*0fca6ea1SDimitry Andric OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ " 724*0fca6ea1SDimitry Andric << Source.USR << " $ "; 725*0fca6ea1SDimitry Andric if (Target.USR.empty()) 726*0fca6ea1SDimitry Andric OS << Target.Name; 727*0fca6ea1SDimitry Andric else 728*0fca6ea1SDimitry Andric OS << Target.USR; 729*0fca6ea1SDimitry Andric Relationship["!testRelLabel"] = TestRelLabel; 730*0fca6ea1SDimitry Andric } 731*0fca6ea1SDimitry Andric Relationship["source"] = Source.USR; 732*0fca6ea1SDimitry Andric Relationship["target"] = Target.USR; 733*0fca6ea1SDimitry Andric Relationship["targetFallback"] = Target.Name; 734*0fca6ea1SDimitry Andric Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind); 735*0fca6ea1SDimitry Andric 736*0fca6ea1SDimitry Andric if (ForceEmitToMainModule) 737*0fca6ea1SDimitry Andric MainModule.addRelationship(std::move(Relationship)); 738*0fca6ea1SDimitry Andric else 739*0fca6ea1SDimitry Andric Into.addRelationship(std::move(Relationship)); 740*0fca6ea1SDimitry Andric } 741*0fca6ea1SDimitry Andric 7425f757f3fSDimitry Andric StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { 7435f757f3fSDimitry Andric switch (Kind) { 7445f757f3fSDimitry Andric case ConstraintKind::Conformance: 7455f757f3fSDimitry Andric return "conformance"; 7465f757f3fSDimitry Andric case ConstraintKind::ConditionalConformance: 7475f757f3fSDimitry Andric return "conditionalConformance"; 7485f757f3fSDimitry Andric } 7495f757f3fSDimitry Andric llvm_unreachable("Unhandled constraint kind"); 7505f757f3fSDimitry Andric } 7515f757f3fSDimitry Andric 752*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) { 7535f757f3fSDimitry Andric Object Obj; 754*0fca6ea1SDimitry Andric 755*0fca6ea1SDimitry Andric // If we need symbol labels for testing emit the USR as the value and the key 756*0fca6ea1SDimitry Andric // starts with '!'' to ensure it ends up at the top of the object. 757*0fca6ea1SDimitry Andric if (EmitSymbolLabelsForTesting) 758*0fca6ea1SDimitry Andric Obj["!testLabel"] = Record->USR; 759*0fca6ea1SDimitry Andric 7605f757f3fSDimitry Andric serializeObject(Obj, "identifier", 761*0fca6ea1SDimitry Andric serializeIdentifier(*Record, API.getLanguage())); 762*0fca6ea1SDimitry Andric serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage())); 763*0fca6ea1SDimitry Andric serializeObject(Obj, "names", serializeNames(Record)); 764*0fca6ea1SDimitry Andric serializeObject( 765*0fca6ea1SDimitry Andric Obj, "location", 766*0fca6ea1SDimitry Andric serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true)); 767*0fca6ea1SDimitry Andric serializeArray(Obj, "availability", 768*0fca6ea1SDimitry Andric serializeAvailability(Record->Availability)); 769*0fca6ea1SDimitry Andric serializeObject(Obj, "docComment", serializeDocComment(Record->Comment)); 770*0fca6ea1SDimitry Andric serializeArray(Obj, "declarationFragments", 771*0fca6ea1SDimitry Andric serializeDeclarationFragments(Record->Declaration)); 772*0fca6ea1SDimitry Andric 773*0fca6ea1SDimitry Andric Obj["pathComponents"] = serializePathComponents(Record); 774*0fca6ea1SDimitry Andric Obj["accessLevel"] = Record->Access.getAccess(); 775*0fca6ea1SDimitry Andric 776*0fca6ea1SDimitry Andric ExtendedModule &Module = getModuleForCurrentSymbol(); 777*0fca6ea1SDimitry Andric // If the hierarchy has at least one parent and child. 778*0fca6ea1SDimitry Andric if (Hierarchy.size() >= 2) 779*0fca6ea1SDimitry Andric serializeRelationship(MemberOf, Hierarchy.back(), 780*0fca6ea1SDimitry Andric Hierarchy[Hierarchy.size() - 2], Module); 781*0fca6ea1SDimitry Andric 782*0fca6ea1SDimitry Andric CurrentSymbol = Module.addSymbol(std::move(Obj)); 7835f757f3fSDimitry Andric } 7845f757f3fSDimitry Andric 785*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) { 786*0fca6ea1SDimitry Andric if (!Record) 787*0fca6ea1SDimitry Andric return true; 788*0fca6ea1SDimitry Andric if (shouldSkip(Record)) 789*0fca6ea1SDimitry Andric return true; 790*0fca6ea1SDimitry Andric Hierarchy.push_back(getHierarchyReference(Record, API)); 791*0fca6ea1SDimitry Andric // Defer traversal mechanics to APISetVisitor base implementation 792*0fca6ea1SDimitry Andric auto RetVal = Base::traverseAPIRecord(Record); 793*0fca6ea1SDimitry Andric Hierarchy.pop_back(); 794*0fca6ea1SDimitry Andric return RetVal; 7955f757f3fSDimitry Andric } 7965f757f3fSDimitry Andric 797*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) { 798*0fca6ea1SDimitry Andric serializeAPIRecord(Record); 799*0fca6ea1SDimitry Andric return true; 800*0fca6ea1SDimitry Andric } 80181ad6265SDimitry Andric 802*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitGlobalFunctionRecord( 803*0fca6ea1SDimitry Andric const GlobalFunctionRecord *Record) { 804*0fca6ea1SDimitry Andric if (!CurrentSymbol) 805*0fca6ea1SDimitry Andric return true; 80681ad6265SDimitry Andric 807*0fca6ea1SDimitry Andric serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 808*0fca6ea1SDimitry Andric return true; 809*0fca6ea1SDimitry Andric } 810*0fca6ea1SDimitry Andric 811*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) { 812*0fca6ea1SDimitry Andric if (!CurrentSymbol) 813*0fca6ea1SDimitry Andric return true; 814*0fca6ea1SDimitry Andric 815*0fca6ea1SDimitry Andric for (const auto &Base : Record->Bases) 816*0fca6ea1SDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, Base, 817*0fca6ea1SDimitry Andric getModuleForCurrentSymbol()); 818*0fca6ea1SDimitry Andric return true; 819*0fca6ea1SDimitry Andric } 820*0fca6ea1SDimitry Andric 821*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitClassTemplateRecord( 822*0fca6ea1SDimitry Andric const ClassTemplateRecord *Record) { 823*0fca6ea1SDimitry Andric if (!CurrentSymbol) 824*0fca6ea1SDimitry Andric return true; 825*0fca6ea1SDimitry Andric 826*0fca6ea1SDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record); 827*0fca6ea1SDimitry Andric return true; 828*0fca6ea1SDimitry Andric } 829*0fca6ea1SDimitry Andric 830*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( 831*0fca6ea1SDimitry Andric const ClassTemplatePartialSpecializationRecord *Record) { 832*0fca6ea1SDimitry Andric if (!CurrentSymbol) 833*0fca6ea1SDimitry Andric return true; 834*0fca6ea1SDimitry Andric 835*0fca6ea1SDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record); 836*0fca6ea1SDimitry Andric return true; 837*0fca6ea1SDimitry Andric } 838*0fca6ea1SDimitry Andric 839*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitCXXMethodRecord( 840*0fca6ea1SDimitry Andric const CXXMethodRecord *Record) { 841*0fca6ea1SDimitry Andric if (!CurrentSymbol) 842*0fca6ea1SDimitry Andric return true; 843*0fca6ea1SDimitry Andric 844*0fca6ea1SDimitry Andric serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 845*0fca6ea1SDimitry Andric return true; 846*0fca6ea1SDimitry Andric } 847*0fca6ea1SDimitry Andric 848*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitCXXMethodTemplateRecord( 849*0fca6ea1SDimitry Andric const CXXMethodTemplateRecord *Record) { 850*0fca6ea1SDimitry Andric if (!CurrentSymbol) 851*0fca6ea1SDimitry Andric return true; 852*0fca6ea1SDimitry Andric 853*0fca6ea1SDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record); 854*0fca6ea1SDimitry Andric return true; 855*0fca6ea1SDimitry Andric } 856*0fca6ea1SDimitry Andric 857*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitCXXFieldTemplateRecord( 858*0fca6ea1SDimitry Andric const CXXFieldTemplateRecord *Record) { 859*0fca6ea1SDimitry Andric if (!CurrentSymbol) 860*0fca6ea1SDimitry Andric return true; 861*0fca6ea1SDimitry Andric 862*0fca6ea1SDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record); 863*0fca6ea1SDimitry Andric return true; 864*0fca6ea1SDimitry Andric } 865*0fca6ea1SDimitry Andric 866*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) { 867*0fca6ea1SDimitry Andric if (!CurrentSymbol) 868*0fca6ea1SDimitry Andric return true; 869*0fca6ea1SDimitry Andric 870*0fca6ea1SDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record); 871*0fca6ea1SDimitry Andric return true; 872*0fca6ea1SDimitry Andric } 873*0fca6ea1SDimitry Andric 874*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord( 875*0fca6ea1SDimitry Andric const GlobalVariableTemplateRecord *Record) { 876*0fca6ea1SDimitry Andric if (!CurrentSymbol) 877*0fca6ea1SDimitry Andric return true; 878*0fca6ea1SDimitry Andric 879*0fca6ea1SDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record); 880*0fca6ea1SDimitry Andric return true; 881*0fca6ea1SDimitry Andric } 882*0fca6ea1SDimitry Andric 883*0fca6ea1SDimitry Andric bool SymbolGraphSerializer:: 884*0fca6ea1SDimitry Andric visitGlobalVariableTemplatePartialSpecializationRecord( 885*0fca6ea1SDimitry Andric const GlobalVariableTemplatePartialSpecializationRecord *Record) { 886*0fca6ea1SDimitry Andric if (!CurrentSymbol) 887*0fca6ea1SDimitry Andric return true; 888*0fca6ea1SDimitry Andric 889*0fca6ea1SDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record); 890*0fca6ea1SDimitry Andric return true; 891*0fca6ea1SDimitry Andric } 892*0fca6ea1SDimitry Andric 893*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( 894*0fca6ea1SDimitry Andric const GlobalFunctionTemplateRecord *Record) { 895*0fca6ea1SDimitry Andric if (!CurrentSymbol) 896*0fca6ea1SDimitry Andric return true; 897*0fca6ea1SDimitry Andric 898*0fca6ea1SDimitry Andric serializeTemplateMixin(*CurrentSymbol, *Record); 899*0fca6ea1SDimitry Andric return true; 900*0fca6ea1SDimitry Andric } 901*0fca6ea1SDimitry Andric 902*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCContainerRecord( 903*0fca6ea1SDimitry Andric const ObjCContainerRecord *Record) { 904*0fca6ea1SDimitry Andric if (!CurrentSymbol) 905*0fca6ea1SDimitry Andric return true; 906*0fca6ea1SDimitry Andric 907*0fca6ea1SDimitry Andric for (const auto &Protocol : Record->Protocols) 908*0fca6ea1SDimitry Andric serializeRelationship(ConformsTo, Record, Protocol, 909*0fca6ea1SDimitry Andric getModuleForCurrentSymbol()); 910*0fca6ea1SDimitry Andric 911*0fca6ea1SDimitry Andric return true; 912*0fca6ea1SDimitry Andric } 913*0fca6ea1SDimitry Andric 914*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCInterfaceRecord( 915*0fca6ea1SDimitry Andric const ObjCInterfaceRecord *Record) { 916*0fca6ea1SDimitry Andric if (!CurrentSymbol) 917*0fca6ea1SDimitry Andric return true; 918*0fca6ea1SDimitry Andric 919*0fca6ea1SDimitry Andric if (!Record->SuperClass.empty()) 920*0fca6ea1SDimitry Andric serializeRelationship(InheritsFrom, Record, Record->SuperClass, 921*0fca6ea1SDimitry Andric getModuleForCurrentSymbol()); 922*0fca6ea1SDimitry Andric return true; 923*0fca6ea1SDimitry Andric } 924*0fca6ea1SDimitry Andric 925*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::traverseObjCCategoryRecord( 926*0fca6ea1SDimitry Andric const ObjCCategoryRecord *Record) { 927*0fca6ea1SDimitry Andric if (SkipSymbolsInCategoriesToExternalTypes && 928*0fca6ea1SDimitry Andric !API.findRecordForUSR(Record->Interface.USR)) 929*0fca6ea1SDimitry Andric return true; 930*0fca6ea1SDimitry Andric 931*0fca6ea1SDimitry Andric auto *CurrentModule = ModuleForCurrentSymbol; 932*0fca6ea1SDimitry Andric if (Record->isExtendingExternalModule()) 933*0fca6ea1SDimitry Andric ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source]; 934*0fca6ea1SDimitry Andric 935*0fca6ea1SDimitry Andric if (!walkUpFromObjCCategoryRecord(Record)) 936*0fca6ea1SDimitry Andric return false; 937*0fca6ea1SDimitry Andric 938*0fca6ea1SDimitry Andric bool RetVal = traverseRecordContext(Record); 939*0fca6ea1SDimitry Andric ModuleForCurrentSymbol = CurrentModule; 940*0fca6ea1SDimitry Andric return RetVal; 941*0fca6ea1SDimitry Andric } 942*0fca6ea1SDimitry Andric 943*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord( 944*0fca6ea1SDimitry Andric const ObjCCategoryRecord *Record) { 945*0fca6ea1SDimitry Andric return visitObjCCategoryRecord(Record); 946*0fca6ea1SDimitry Andric } 947*0fca6ea1SDimitry Andric 948*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCCategoryRecord( 949*0fca6ea1SDimitry Andric const ObjCCategoryRecord *Record) { 950*0fca6ea1SDimitry Andric // If we need to create a record for the category in the future do so here, 951*0fca6ea1SDimitry Andric // otherwise everything is set up to pretend that the category is in fact the 952*0fca6ea1SDimitry Andric // interface it extends. 953*0fca6ea1SDimitry Andric for (const auto &Protocol : Record->Protocols) 954*0fca6ea1SDimitry Andric serializeRelationship(ConformsTo, Record->Interface, Protocol, 955*0fca6ea1SDimitry Andric getModuleForCurrentSymbol()); 956*0fca6ea1SDimitry Andric 957*0fca6ea1SDimitry Andric return true; 958*0fca6ea1SDimitry Andric } 959*0fca6ea1SDimitry Andric 960*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCMethodRecord( 961*0fca6ea1SDimitry Andric const ObjCMethodRecord *Record) { 962*0fca6ea1SDimitry Andric if (!CurrentSymbol) 963*0fca6ea1SDimitry Andric return true; 964*0fca6ea1SDimitry Andric 965*0fca6ea1SDimitry Andric serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 966*0fca6ea1SDimitry Andric return true; 967*0fca6ea1SDimitry Andric } 968*0fca6ea1SDimitry Andric 969*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitObjCInstanceVariableRecord( 970*0fca6ea1SDimitry Andric const ObjCInstanceVariableRecord *Record) { 971*0fca6ea1SDimitry Andric // FIXME: serialize ivar access control here. 972*0fca6ea1SDimitry Andric return true; 973*0fca6ea1SDimitry Andric } 974*0fca6ea1SDimitry Andric 975*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::walkUpFromTypedefRecord( 976*0fca6ea1SDimitry Andric const TypedefRecord *Record) { 977*0fca6ea1SDimitry Andric // Short-circuit walking up the class hierarchy and handle creating typedef 978*0fca6ea1SDimitry Andric // symbol objects manually as there are additional symbol dropping rules to 979*0fca6ea1SDimitry Andric // respect. 980*0fca6ea1SDimitry Andric return visitTypedefRecord(Record); 981*0fca6ea1SDimitry Andric } 982*0fca6ea1SDimitry Andric 983*0fca6ea1SDimitry Andric bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) { 984*0fca6ea1SDimitry Andric // Typedefs of anonymous types have their entries unified with the underlying 985*0fca6ea1SDimitry Andric // type. 986*0fca6ea1SDimitry Andric bool ShouldDrop = Record->UnderlyingType.Name.empty(); 987*0fca6ea1SDimitry Andric // enums declared with `NS_OPTION` have a named enum and a named typedef, with 988*0fca6ea1SDimitry Andric // the same name 989*0fca6ea1SDimitry Andric ShouldDrop |= (Record->UnderlyingType.Name == Record->Name); 990*0fca6ea1SDimitry Andric if (ShouldDrop) 991*0fca6ea1SDimitry Andric return true; 992*0fca6ea1SDimitry Andric 993*0fca6ea1SDimitry Andric // Create the symbol record if the other symbol droppping rules permit it. 994*0fca6ea1SDimitry Andric serializeAPIRecord(Record); 995*0fca6ea1SDimitry Andric if (!CurrentSymbol) 996*0fca6ea1SDimitry Andric return true; 997*0fca6ea1SDimitry Andric 998*0fca6ea1SDimitry Andric (*CurrentSymbol)["type"] = Record->UnderlyingType.USR; 999*0fca6ea1SDimitry Andric 1000*0fca6ea1SDimitry Andric return true; 100181ad6265SDimitry Andric } 100281ad6265SDimitry Andric 1003bdd1243dSDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { 1004bdd1243dSDimitry Andric switch (Record->getKind()) { 1005*0fca6ea1SDimitry Andric // dispatch to the relevant walkUpFromMethod 1006*0fca6ea1SDimitry Andric #define CONCRETE_RECORD(CLASS, BASE, KIND) \ 1007*0fca6ea1SDimitry Andric case APIRecord::KIND: { \ 1008*0fca6ea1SDimitry Andric walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \ 1009*0fca6ea1SDimitry Andric break; \ 1010*0fca6ea1SDimitry Andric } 1011*0fca6ea1SDimitry Andric #include "clang/ExtractAPI/APIRecords.inc" 1012*0fca6ea1SDimitry Andric // otherwise fallback on the only behavior we can implement safely. 1013bdd1243dSDimitry Andric case APIRecord::RK_Unknown: 1014*0fca6ea1SDimitry Andric visitAPIRecord(Record); 1015bdd1243dSDimitry Andric break; 1016bdd1243dSDimitry Andric default: 1017*0fca6ea1SDimitry Andric llvm_unreachable("API Record with uninstantiable kind"); 1018bdd1243dSDimitry Andric } 1019bdd1243dSDimitry Andric } 1020bdd1243dSDimitry Andric 1021*0fca6ea1SDimitry Andric Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName, 1022*0fca6ea1SDimitry Andric ExtendedModule &&EM) { 1023bdd1243dSDimitry Andric Object Root; 1024bdd1243dSDimitry Andric serializeObject(Root, "metadata", serializeMetadata()); 1025*0fca6ea1SDimitry Andric serializeObject(Root, "module", serializeModuleObject(ModuleName)); 1026bdd1243dSDimitry Andric 1027*0fca6ea1SDimitry Andric Root["symbols"] = std::move(EM.Symbols); 1028*0fca6ea1SDimitry Andric Root["relationships"] = std::move(EM.Relationships); 102981ad6265SDimitry Andric 103081ad6265SDimitry Andric return Root; 103181ad6265SDimitry Andric } 103281ad6265SDimitry Andric 1033*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeGraphToStream( 1034*0fca6ea1SDimitry Andric raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName, 1035*0fca6ea1SDimitry Andric ExtendedModule &&EM) { 1036*0fca6ea1SDimitry Andric Object Root = serializeGraph(ModuleName, std::move(EM)); 103781ad6265SDimitry Andric if (Options.Compact) 1038*0fca6ea1SDimitry Andric OS << formatv("{0}", json::Value(std::move(Root))) << "\n"; 103981ad6265SDimitry Andric else 1040*0fca6ea1SDimitry Andric OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n"; 1041*0fca6ea1SDimitry Andric } 1042*0fca6ea1SDimitry Andric 1043*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeMainSymbolGraph( 1044*0fca6ea1SDimitry Andric raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, 1045*0fca6ea1SDimitry Andric SymbolGraphSerializerOption Options) { 1046*0fca6ea1SDimitry Andric SymbolGraphSerializer Serializer( 1047*0fca6ea1SDimitry Andric API, IgnoresList, Options.EmitSymbolLabelsForTesting, 1048*0fca6ea1SDimitry Andric /*ForceEmitToMainModule=*/true, 1049*0fca6ea1SDimitry Andric /*SkipSymbolsInCategoriesToExternalTypes=*/true); 1050*0fca6ea1SDimitry Andric 1051*0fca6ea1SDimitry Andric Serializer.traverseAPISet(); 1052*0fca6ea1SDimitry Andric Serializer.serializeGraphToStream(OS, Options, API.ProductName, 1053*0fca6ea1SDimitry Andric std::move(Serializer.MainModule)); 1054*0fca6ea1SDimitry Andric // FIXME: TODO handle extended modules here 1055*0fca6ea1SDimitry Andric } 1056*0fca6ea1SDimitry Andric 1057*0fca6ea1SDimitry Andric void SymbolGraphSerializer::serializeWithExtensionGraphs( 1058*0fca6ea1SDimitry Andric raw_ostream &MainOutput, const APISet &API, 1059*0fca6ea1SDimitry Andric const APIIgnoresList &IgnoresList, 1060*0fca6ea1SDimitry Andric llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)> 1061*0fca6ea1SDimitry Andric CreateOutputStream, 1062*0fca6ea1SDimitry Andric SymbolGraphSerializerOption Options) { 1063*0fca6ea1SDimitry Andric SymbolGraphSerializer Serializer(API, IgnoresList, 1064*0fca6ea1SDimitry Andric Options.EmitSymbolLabelsForTesting); 1065*0fca6ea1SDimitry Andric Serializer.traverseAPISet(); 1066*0fca6ea1SDimitry Andric 1067*0fca6ea1SDimitry Andric Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName, 1068*0fca6ea1SDimitry Andric std::move(Serializer.MainModule)); 1069*0fca6ea1SDimitry Andric 1070*0fca6ea1SDimitry Andric for (auto &ExtensionSGF : Serializer.ExtendedModules) { 1071*0fca6ea1SDimitry Andric if (auto ExtensionOS = 1072*0fca6ea1SDimitry Andric CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName)) 1073*0fca6ea1SDimitry Andric Serializer.serializeGraphToStream(*ExtensionOS, Options, 1074*0fca6ea1SDimitry Andric ExtensionSGF.getKey(), 1075*0fca6ea1SDimitry Andric std::move(ExtensionSGF.getValue())); 1076*0fca6ea1SDimitry Andric } 107781ad6265SDimitry Andric } 1078bdd1243dSDimitry Andric 1079bdd1243dSDimitry Andric std::optional<Object> 1080bdd1243dSDimitry Andric SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, 1081bdd1243dSDimitry Andric const APISet &API) { 1082bdd1243dSDimitry Andric APIRecord *Record = API.findRecordForUSR(USR); 1083bdd1243dSDimitry Andric if (!Record) 1084bdd1243dSDimitry Andric return {}; 1085bdd1243dSDimitry Andric 1086bdd1243dSDimitry Andric Object Root; 1087bdd1243dSDimitry Andric APIIgnoresList EmptyIgnores; 1088bdd1243dSDimitry Andric SymbolGraphSerializer Serializer(API, EmptyIgnores, 1089*0fca6ea1SDimitry Andric /*EmitSymbolLabelsForTesting*/ false, 1090*0fca6ea1SDimitry Andric /*ForceEmitToMainModule*/ true); 1091*0fca6ea1SDimitry Andric 1092*0fca6ea1SDimitry Andric // Set up serializer parent chain 1093*0fca6ea1SDimitry Andric Serializer.Hierarchy = generateHierarchyFromRecord(Record); 1094*0fca6ea1SDimitry Andric 1095bdd1243dSDimitry Andric Serializer.serializeSingleRecord(Record); 1096*0fca6ea1SDimitry Andric serializeObject(Root, "symbolGraph", 1097*0fca6ea1SDimitry Andric Serializer.serializeGraph(API.ProductName, 1098*0fca6ea1SDimitry Andric std::move(Serializer.MainModule))); 1099bdd1243dSDimitry Andric 1100bdd1243dSDimitry Andric Language Lang = API.getLanguage(); 1101bdd1243dSDimitry Andric serializeArray(Root, "parentContexts", 1102*0fca6ea1SDimitry Andric generateParentContexts(Serializer.Hierarchy, Lang)); 1103bdd1243dSDimitry Andric 1104bdd1243dSDimitry Andric Array RelatedSymbols; 1105bdd1243dSDimitry Andric 1106bdd1243dSDimitry Andric for (const auto &Fragment : Record->Declaration.getFragments()) { 1107bdd1243dSDimitry Andric // If we don't have a USR there isn't much we can do. 1108bdd1243dSDimitry Andric if (Fragment.PreciseIdentifier.empty()) 1109bdd1243dSDimitry Andric continue; 1110bdd1243dSDimitry Andric 1111bdd1243dSDimitry Andric APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier); 1112bdd1243dSDimitry Andric 1113bdd1243dSDimitry Andric // If we can't find the record let's skip. 1114bdd1243dSDimitry Andric if (!RelatedRecord) 1115bdd1243dSDimitry Andric continue; 1116bdd1243dSDimitry Andric 1117bdd1243dSDimitry Andric Object RelatedSymbol; 1118bdd1243dSDimitry Andric RelatedSymbol["usr"] = RelatedRecord->USR; 1119bdd1243dSDimitry Andric RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); 1120*0fca6ea1SDimitry Andric RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess(); 1121bdd1243dSDimitry Andric RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); 1122bdd1243dSDimitry Andric RelatedSymbol["moduleName"] = API.ProductName; 1123bdd1243dSDimitry Andric RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; 1124bdd1243dSDimitry Andric 1125bdd1243dSDimitry Andric serializeArray(RelatedSymbol, "parentContexts", 1126*0fca6ea1SDimitry Andric generateParentContexts( 1127*0fca6ea1SDimitry Andric generateHierarchyFromRecord(RelatedRecord), Lang)); 1128*0fca6ea1SDimitry Andric 1129bdd1243dSDimitry Andric RelatedSymbols.push_back(std::move(RelatedSymbol)); 1130bdd1243dSDimitry Andric } 1131bdd1243dSDimitry Andric 1132bdd1243dSDimitry Andric serializeArray(Root, "relatedSymbols", RelatedSymbols); 1133bdd1243dSDimitry Andric return Root; 1134bdd1243dSDimitry Andric } 1135