189f6b26fSZixu Wang //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===// 289f6b26fSZixu Wang // 389f6b26fSZixu Wang // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 489f6b26fSZixu Wang // See https://llvm.org/LICENSE.txt for license information. 589f6b26fSZixu Wang // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 689f6b26fSZixu Wang // 789f6b26fSZixu Wang //===----------------------------------------------------------------------===// 889f6b26fSZixu Wang /// 989f6b26fSZixu Wang /// \file 1089f6b26fSZixu Wang /// This file implements the SymbolGraphSerializer. 1189f6b26fSZixu Wang /// 1289f6b26fSZixu Wang //===----------------------------------------------------------------------===// 1389f6b26fSZixu Wang 1489f6b26fSZixu Wang #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 157a851921SDaniel Grumberg #include "clang/Basic/SourceLocation.h" 1689f6b26fSZixu Wang #include "clang/Basic/Version.h" 17e05c1b46SDaniel Grumberg #include "clang/ExtractAPI/API.h" 1880ae3665SDaniel Grumberg #include "clang/ExtractAPI/DeclarationFragments.h" 197a851921SDaniel Grumberg #include "llvm/ADT/STLExtras.h" 207a851921SDaniel Grumberg #include "llvm/ADT/STLFunctionalExtras.h" 21e05c1b46SDaniel Grumberg #include "llvm/ADT/SmallVector.h" 227a851921SDaniel Grumberg #include "llvm/Support/Casting.h" 237a851921SDaniel Grumberg #include "llvm/Support/Compiler.h" 2489f6b26fSZixu Wang #include "llvm/Support/Path.h" 2589f6b26fSZixu Wang #include "llvm/Support/VersionTuple.h" 26e05c1b46SDaniel Grumberg #include "llvm/Support/raw_ostream.h" 27e05c1b46SDaniel Grumberg #include <iterator> 28a1580d7bSKazu Hirata #include <optional> 29236b6a0eSDaniel Grumberg #include <type_traits> 3089f6b26fSZixu Wang 3189f6b26fSZixu Wang using namespace clang; 3289f6b26fSZixu Wang using namespace clang::extractapi; 3389f6b26fSZixu Wang using namespace llvm; 3489f6b26fSZixu Wang 3589f6b26fSZixu Wang namespace { 3689f6b26fSZixu Wang 3789f6b26fSZixu Wang /// Helper function to inject a JSON object \p Obj into another object \p Paren 3889f6b26fSZixu Wang /// at position \p Key. 39e05c1b46SDaniel Grumberg void serializeObject(Object &Paren, StringRef Key, 40e05c1b46SDaniel Grumberg std::optional<Object> &&Obj) { 4189f6b26fSZixu Wang if (Obj) 4253e5cd4dSFangrui Song Paren[Key] = std::move(*Obj); 4389f6b26fSZixu Wang } 4489f6b26fSZixu Wang 45209a1e8dSDaniel Grumberg /// Helper function to inject a JSON array \p Array into object \p Paren at 46209a1e8dSDaniel Grumberg /// position \p Key. 47e05c1b46SDaniel Grumberg void serializeArray(Object &Paren, StringRef Key, 48e05c1b46SDaniel Grumberg std::optional<Array> &&Array) { 49209a1e8dSDaniel Grumberg if (Array) 50209a1e8dSDaniel Grumberg Paren[Key] = std::move(*Array); 51b31414bfSDaniel Grumberg } 52b31414bfSDaniel Grumberg 53e05c1b46SDaniel Grumberg /// Helper function to inject a JSON array composed of the values in \p C into 54e05c1b46SDaniel Grumberg /// object \p Paren at position \p Key. 55e05c1b46SDaniel Grumberg template <typename ContainerTy> 56e05c1b46SDaniel Grumberg void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) { 57e05c1b46SDaniel Grumberg Paren[Key] = Array(C); 58e05c1b46SDaniel Grumberg } 59e05c1b46SDaniel Grumberg 6089f6b26fSZixu Wang /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 6189f6b26fSZixu Wang /// format. 6289f6b26fSZixu Wang /// 6389f6b26fSZixu Wang /// A semantic version object contains three numeric fields, representing the 6489f6b26fSZixu Wang /// \c major, \c minor, and \c patch parts of the version tuple. 6589f6b26fSZixu Wang /// For example version tuple 1.0.3 is serialized as: 6689f6b26fSZixu Wang /// \code 6789f6b26fSZixu Wang /// { 6889f6b26fSZixu Wang /// "major" : 1, 6989f6b26fSZixu Wang /// "minor" : 0, 7089f6b26fSZixu Wang /// "patch" : 3 7189f6b26fSZixu Wang /// } 7289f6b26fSZixu Wang /// \endcode 7389f6b26fSZixu Wang /// 7437a3e98cSKazu Hirata /// \returns \c std::nullopt if the version \p V is empty, or an \c Object 7537a3e98cSKazu Hirata /// containing the semantic version representation of \p V. 766ad0788cSKazu Hirata std::optional<Object> serializeSemanticVersion(const VersionTuple &V) { 7789f6b26fSZixu Wang if (V.empty()) 785891420eSKazu Hirata return std::nullopt; 7989f6b26fSZixu Wang 8089f6b26fSZixu Wang Object Version; 8189f6b26fSZixu Wang Version["major"] = V.getMajor(); 8206decd0bSKazu Hirata Version["minor"] = V.getMinor().value_or(0); 8306decd0bSKazu Hirata Version["patch"] = V.getSubminor().value_or(0); 8489f6b26fSZixu Wang return Version; 8589f6b26fSZixu Wang } 8689f6b26fSZixu Wang 8789f6b26fSZixu Wang /// Serialize the OS information in the Symbol Graph platform property. 8889f6b26fSZixu Wang /// 8989f6b26fSZixu Wang /// The OS information in Symbol Graph contains the \c name of the OS, and an 9089f6b26fSZixu Wang /// optional \c minimumVersion semantic version field. 9189f6b26fSZixu Wang Object serializeOperatingSystem(const Triple &T) { 9289f6b26fSZixu Wang Object OS; 9389f6b26fSZixu Wang OS["name"] = T.getOSTypeName(T.getOS()); 9489f6b26fSZixu Wang serializeObject(OS, "minimumVersion", 9589f6b26fSZixu Wang serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 9689f6b26fSZixu Wang return OS; 9789f6b26fSZixu Wang } 9889f6b26fSZixu Wang 9989f6b26fSZixu Wang /// Serialize the platform information in the Symbol Graph module section. 10089f6b26fSZixu Wang /// 10189f6b26fSZixu Wang /// The platform object describes a target platform triple in corresponding 10289f6b26fSZixu Wang /// three fields: \c architecture, \c vendor, and \c operatingSystem. 10389f6b26fSZixu Wang Object serializePlatform(const Triple &T) { 10489f6b26fSZixu Wang Object Platform; 10589f6b26fSZixu Wang Platform["architecture"] = T.getArchName(); 10689f6b26fSZixu Wang Platform["vendor"] = T.getVendorName(); 10757abd4e4SDaniel Grumberg 10857abd4e4SDaniel Grumberg if (!T.getEnvironmentName().empty()) 10957abd4e4SDaniel Grumberg Platform["environment"] = T.getEnvironmentName(); 11057abd4e4SDaniel Grumberg 11189f6b26fSZixu Wang Platform["operatingSystem"] = serializeOperatingSystem(T); 11289f6b26fSZixu Wang return Platform; 11389f6b26fSZixu Wang } 11489f6b26fSZixu Wang 11528d79314SDaniel Grumberg /// Serialize a source position. 11628d79314SDaniel Grumberg Object serializeSourcePosition(const PresumedLoc &Loc) { 11789f6b26fSZixu Wang assert(Loc.isValid() && "invalid source position"); 11889f6b26fSZixu Wang 11989f6b26fSZixu Wang Object SourcePosition; 12063537872SQuietMisdreavus SourcePosition["line"] = Loc.getLine() - 1; 12163537872SQuietMisdreavus SourcePosition["character"] = Loc.getColumn() - 1; 12289f6b26fSZixu Wang 12328d79314SDaniel Grumberg return SourcePosition; 12428d79314SDaniel Grumberg } 12528d79314SDaniel Grumberg 12628d79314SDaniel Grumberg /// Serialize a source location in file. 12728d79314SDaniel Grumberg /// 12828d79314SDaniel Grumberg /// \param Loc The presumed location to serialize. 12928d79314SDaniel Grumberg /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 13028d79314SDaniel Grumberg /// Defaults to false. 13128d79314SDaniel Grumberg Object serializeSourceLocation(const PresumedLoc &Loc, 13228d79314SDaniel Grumberg bool IncludeFileURI = false) { 13328d79314SDaniel Grumberg Object SourceLocation; 13428d79314SDaniel Grumberg serializeObject(SourceLocation, "position", serializeSourcePosition(Loc)); 13528d79314SDaniel Grumberg 13689f6b26fSZixu Wang if (IncludeFileURI) { 13789f6b26fSZixu Wang std::string FileURI = "file://"; 13889f6b26fSZixu Wang // Normalize file path to use forward slashes for the URI. 13989f6b26fSZixu Wang FileURI += sys::path::convert_to_slash(Loc.getFilename()); 14028d79314SDaniel Grumberg SourceLocation["uri"] = FileURI; 14189f6b26fSZixu Wang } 14289f6b26fSZixu Wang 14328d79314SDaniel Grumberg return SourceLocation; 14489f6b26fSZixu Wang } 14589f6b26fSZixu Wang 14689f6b26fSZixu Wang /// Serialize a source range with begin and end locations. 14789f6b26fSZixu Wang Object serializeSourceRange(const PresumedLoc &BeginLoc, 14889f6b26fSZixu Wang const PresumedLoc &EndLoc) { 14989f6b26fSZixu Wang Object SourceRange; 15089f6b26fSZixu Wang serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 15189f6b26fSZixu Wang serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 15289f6b26fSZixu Wang return SourceRange; 15389f6b26fSZixu Wang } 15489f6b26fSZixu Wang 15589f6b26fSZixu Wang /// Serialize the availability attributes of a symbol. 15689f6b26fSZixu Wang /// 15789f6b26fSZixu Wang /// Availability information contains the introduced, deprecated, and obsoleted 1583d4128f7SSofía Rodríguez /// versions of the symbol as semantic versions, if not default. 1593d4128f7SSofía Rodríguez /// Availability information also contains flags to indicate if the symbol is 1603d4128f7SSofía Rodríguez /// unconditionally unavailable or deprecated, 1613d4128f7SSofía Rodríguez /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). 16289f6b26fSZixu Wang /// 16337a3e98cSKazu Hirata /// \returns \c std::nullopt if the symbol has default availability attributes, 1643d4128f7SSofía Rodríguez /// or an \c Array containing an object with the formatted availability 1653d4128f7SSofía Rodríguez /// information. 1663d4128f7SSofía Rodríguez std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) { 1673d4128f7SSofía Rodríguez if (Avail.isDefault()) 1685891420eSKazu Hirata return std::nullopt; 16989f6b26fSZixu Wang 17057c9780dSDaniel Grumberg Array AvailabilityArray; 17105c1447bSDaniel Grumberg 1723d4128f7SSofía Rodríguez if (Avail.isUnconditionallyDeprecated()) { 17357c9780dSDaniel Grumberg Object UnconditionallyDeprecated; 17457c9780dSDaniel Grumberg UnconditionallyDeprecated["domain"] = "*"; 17557c9780dSDaniel Grumberg UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true; 17657c9780dSDaniel Grumberg AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated)); 17757c9780dSDaniel Grumberg } 17805c1447bSDaniel Grumberg 179026d963cSDaniel Grumberg if (Avail.Domain.str() != "") { 180026d963cSDaniel Grumberg Object Availability; 18105c1447bSDaniel Grumberg Availability["domain"] = Avail.Domain; 18205c1447bSDaniel Grumberg 18305c1447bSDaniel Grumberg if (Avail.isUnavailable()) { 18405c1447bSDaniel Grumberg Availability["isUnconditionallyUnavailable"] = true; 18505c1447bSDaniel Grumberg } else { 18605c1447bSDaniel Grumberg serializeObject(Availability, "introduced", 18705c1447bSDaniel Grumberg serializeSemanticVersion(Avail.Introduced)); 18805c1447bSDaniel Grumberg serializeObject(Availability, "deprecated", 18905c1447bSDaniel Grumberg serializeSemanticVersion(Avail.Deprecated)); 19005c1447bSDaniel Grumberg serializeObject(Availability, "obsoleted", 19105c1447bSDaniel Grumberg serializeSemanticVersion(Avail.Obsoleted)); 19265f7a84cSAnkur } 19305c1447bSDaniel Grumberg 19457c9780dSDaniel Grumberg AvailabilityArray.emplace_back(std::move(Availability)); 195026d963cSDaniel Grumberg } 196026d963cSDaniel Grumberg 19757c9780dSDaniel Grumberg return AvailabilityArray; 19889f6b26fSZixu Wang } 19989f6b26fSZixu Wang 20015bf0e56SZixu Wang /// Get the language name string for interface language references. 20115bf0e56SZixu Wang StringRef getLanguageName(Language Lang) { 20215bf0e56SZixu Wang switch (Lang) { 20389f6b26fSZixu Wang case Language::C: 20489f6b26fSZixu Wang return "c"; 20589f6b26fSZixu Wang case Language::ObjC: 206b62d4021SZixu Wang return "objective-c"; 20775f55eb3SErick Velez case Language::CXX: 20875f55eb3SErick Velez return "c++"; 209789a5bbbSDaniel Grumberg case Language::ObjCXX: 210789a5bbbSDaniel Grumberg return "objective-c++"; 21189f6b26fSZixu Wang 21289f6b26fSZixu Wang // Unsupported language currently 21389f6b26fSZixu Wang case Language::OpenCL: 21489f6b26fSZixu Wang case Language::OpenCLCXX: 21589f6b26fSZixu Wang case Language::CUDA: 21689f6b26fSZixu Wang case Language::HIP: 217d394f9f8SChris Bieneman case Language::HLSL: 21889f6b26fSZixu Wang 21989f6b26fSZixu Wang // Languages that the frontend cannot parse and compile 22089f6b26fSZixu Wang case Language::Unknown: 22189f6b26fSZixu Wang case Language::Asm: 22289f6b26fSZixu Wang case Language::LLVM_IR: 223e66b670fSNathan Lanza case Language::CIR: 22489f6b26fSZixu Wang llvm_unreachable("Unsupported language kind"); 22589f6b26fSZixu Wang } 22689f6b26fSZixu Wang 22789f6b26fSZixu Wang llvm_unreachable("Unhandled language kind"); 22889f6b26fSZixu Wang } 22989f6b26fSZixu Wang 23089f6b26fSZixu Wang /// Serialize the identifier object as specified by the Symbol Graph format. 23189f6b26fSZixu Wang /// 23289f6b26fSZixu Wang /// The identifier property of a symbol contains the USR for precise and unique 23389f6b26fSZixu Wang /// references, and the interface language name. 23415bf0e56SZixu Wang Object serializeIdentifier(const APIRecord &Record, Language Lang) { 23589f6b26fSZixu Wang Object Identifier; 23689f6b26fSZixu Wang Identifier["precise"] = Record.USR; 23715bf0e56SZixu Wang Identifier["interfaceLanguage"] = getLanguageName(Lang); 23889f6b26fSZixu Wang 23989f6b26fSZixu Wang return Identifier; 24089f6b26fSZixu Wang } 24189f6b26fSZixu Wang 24289f6b26fSZixu Wang /// Serialize the documentation comments attached to a symbol, as specified by 24389f6b26fSZixu Wang /// the Symbol Graph format. 24489f6b26fSZixu Wang /// 24589f6b26fSZixu Wang /// The Symbol Graph \c docComment object contains an array of lines. Each line 24689f6b26fSZixu Wang /// represents one line of striped documentation comment, with source range 24789f6b26fSZixu Wang /// information. 24889f6b26fSZixu Wang /// e.g. 24989f6b26fSZixu Wang /// \code 25089f6b26fSZixu Wang /// /// This is a documentation comment 25189f6b26fSZixu Wang /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 25289f6b26fSZixu Wang /// /// with multiple lines. 25389f6b26fSZixu Wang /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 25489f6b26fSZixu Wang /// \endcode 25589f6b26fSZixu Wang /// 25637a3e98cSKazu Hirata /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing 25737a3e98cSKazu Hirata /// the formatted lines. 2586ad0788cSKazu Hirata std::optional<Object> serializeDocComment(const DocComment &Comment) { 25989f6b26fSZixu Wang if (Comment.empty()) 2605891420eSKazu Hirata return std::nullopt; 26189f6b26fSZixu Wang 26289f6b26fSZixu Wang Object DocComment; 263e05c1b46SDaniel Grumberg 26489f6b26fSZixu Wang Array LinesArray; 26589f6b26fSZixu Wang for (const auto &CommentLine : Comment) { 26689f6b26fSZixu Wang Object Line; 26789f6b26fSZixu Wang Line["text"] = CommentLine.Text; 26889f6b26fSZixu Wang serializeObject(Line, "range", 26989f6b26fSZixu Wang serializeSourceRange(CommentLine.Begin, CommentLine.End)); 27089f6b26fSZixu Wang LinesArray.emplace_back(std::move(Line)); 27189f6b26fSZixu Wang } 272e05c1b46SDaniel Grumberg 273e05c1b46SDaniel Grumberg serializeArray(DocComment, "lines", std::move(LinesArray)); 27489f6b26fSZixu Wang 27589f6b26fSZixu Wang return DocComment; 27689f6b26fSZixu Wang } 27789f6b26fSZixu Wang 27889f6b26fSZixu Wang /// Serialize the declaration fragments of a symbol. 27989f6b26fSZixu Wang /// 28089f6b26fSZixu Wang /// The Symbol Graph declaration fragments is an array of tagged important 28189f6b26fSZixu Wang /// parts of a symbol's declaration. The fragments sequence can be joined to 28289f6b26fSZixu Wang /// form spans of declaration text, with attached information useful for 28389f6b26fSZixu Wang /// purposes like syntax-highlighting etc. For example: 28489f6b26fSZixu Wang /// \code 28589f6b26fSZixu Wang /// const int pi; -> "declarationFragments" : [ 28689f6b26fSZixu Wang /// { 28789f6b26fSZixu Wang /// "kind" : "keyword", 28889f6b26fSZixu Wang /// "spelling" : "const" 28989f6b26fSZixu Wang /// }, 29089f6b26fSZixu Wang /// { 29189f6b26fSZixu Wang /// "kind" : "text", 29289f6b26fSZixu Wang /// "spelling" : " " 29389f6b26fSZixu Wang /// }, 29489f6b26fSZixu Wang /// { 29589f6b26fSZixu Wang /// "kind" : "typeIdentifier", 29689f6b26fSZixu Wang /// "preciseIdentifier" : "c:I", 29789f6b26fSZixu Wang /// "spelling" : "int" 29889f6b26fSZixu Wang /// }, 29989f6b26fSZixu Wang /// { 30089f6b26fSZixu Wang /// "kind" : "text", 30189f6b26fSZixu Wang /// "spelling" : " " 30289f6b26fSZixu Wang /// }, 30389f6b26fSZixu Wang /// { 30489f6b26fSZixu Wang /// "kind" : "identifier", 30589f6b26fSZixu Wang /// "spelling" : "pi" 30689f6b26fSZixu Wang /// } 30789f6b26fSZixu Wang /// ] 30889f6b26fSZixu Wang /// \endcode 30989f6b26fSZixu Wang /// 31037a3e98cSKazu Hirata /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the 31137a3e98cSKazu Hirata /// formatted declaration fragments array. 3126ad0788cSKazu Hirata std::optional<Array> 3136ad0788cSKazu Hirata serializeDeclarationFragments(const DeclarationFragments &DF) { 31489f6b26fSZixu Wang if (DF.getFragments().empty()) 3155891420eSKazu Hirata return std::nullopt; 31689f6b26fSZixu Wang 31789f6b26fSZixu Wang Array Fragments; 31889f6b26fSZixu Wang for (const auto &F : DF.getFragments()) { 31989f6b26fSZixu Wang Object Fragment; 32089f6b26fSZixu Wang Fragment["spelling"] = F.Spelling; 32189f6b26fSZixu Wang Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 32289f6b26fSZixu Wang if (!F.PreciseIdentifier.empty()) 32389f6b26fSZixu Wang Fragment["preciseIdentifier"] = F.PreciseIdentifier; 32489f6b26fSZixu Wang Fragments.emplace_back(std::move(Fragment)); 32589f6b26fSZixu Wang } 32689f6b26fSZixu Wang 32789f6b26fSZixu Wang return Fragments; 32889f6b26fSZixu Wang } 32989f6b26fSZixu Wang 33089f6b26fSZixu Wang /// Serialize the \c names field of a symbol as specified by the Symbol Graph 33189f6b26fSZixu Wang /// format. 33289f6b26fSZixu Wang /// 33389f6b26fSZixu Wang /// The Symbol Graph names field contains multiple representations of a symbol 33489f6b26fSZixu Wang /// that can be used for different applications: 33589f6b26fSZixu Wang /// - \c title : The simple declared name of the symbol; 33689f6b26fSZixu Wang /// - \c subHeading : An array of declaration fragments that provides tags, 33789f6b26fSZixu Wang /// and potentially more tokens (for example the \c +/- symbol for 33889f6b26fSZixu Wang /// Objective-C methods). Can be used as sub-headings for documentation. 339e05c1b46SDaniel Grumberg Object serializeNames(const APIRecord *Record) { 34089f6b26fSZixu Wang Object Names; 341e05c1b46SDaniel Grumberg Names["title"] = Record->Name; 34218493185Sruturaj4 34389f6b26fSZixu Wang serializeArray(Names, "subHeading", 344e05c1b46SDaniel Grumberg serializeDeclarationFragments(Record->SubHeading)); 34580ae3665SDaniel Grumberg DeclarationFragments NavigatorFragments; 346e05c1b46SDaniel Grumberg NavigatorFragments.append(Record->Name, 34780ae3665SDaniel Grumberg DeclarationFragments::FragmentKind::Identifier, 34880ae3665SDaniel Grumberg /*PreciseIdentifier*/ ""); 34980ae3665SDaniel Grumberg serializeArray(Names, "navigator", 35080ae3665SDaniel Grumberg serializeDeclarationFragments(NavigatorFragments)); 35189f6b26fSZixu Wang 35289f6b26fSZixu Wang return Names; 35389f6b26fSZixu Wang } 35489f6b26fSZixu Wang 3557a851921SDaniel Grumberg Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { 35615bf0e56SZixu Wang auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 35715bf0e56SZixu Wang return (getLanguageName(Lang) + "." + S).str(); 35871b4c226SZixu Wang }; 35971b4c226SZixu Wang 36089f6b26fSZixu Wang Object Kind; 3617a851921SDaniel Grumberg switch (RK) { 3627a851921SDaniel Grumberg case APIRecord::RK_Unknown: 363e05c1b46SDaniel Grumberg Kind["identifier"] = AddLangPrefix("unknown"); 364e05c1b46SDaniel Grumberg Kind["displayName"] = "Unknown"; 3657a851921SDaniel Grumberg break; 36608f034f9SErick Velez case APIRecord::RK_Namespace: 36708f034f9SErick Velez Kind["identifier"] = AddLangPrefix("namespace"); 36808f034f9SErick Velez Kind["displayName"] = "Namespace"; 36908f034f9SErick Velez break; 370236b6a0eSDaniel Grumberg case APIRecord::RK_GlobalFunction: 37171b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("func"); 37289f6b26fSZixu Wang Kind["displayName"] = "Function"; 37389f6b26fSZixu Wang break; 37480b787e8SErick Velez case APIRecord::RK_GlobalFunctionTemplate: 37580b787e8SErick Velez Kind["identifier"] = AddLangPrefix("func"); 37680b787e8SErick Velez Kind["displayName"] = "Function Template"; 37780b787e8SErick Velez break; 37880b787e8SErick Velez case APIRecord::RK_GlobalFunctionTemplateSpecialization: 37980b787e8SErick Velez Kind["identifier"] = AddLangPrefix("func"); 38080b787e8SErick Velez Kind["displayName"] = "Function Template Specialization"; 38180b787e8SErick Velez break; 3828d8c8981SErick Velez case APIRecord::RK_GlobalVariableTemplate: 3838d8c8981SErick Velez Kind["identifier"] = AddLangPrefix("var"); 3848d8c8981SErick Velez Kind["displayName"] = "Global Variable Template"; 3858d8c8981SErick Velez break; 3868d8c8981SErick Velez case APIRecord::RK_GlobalVariableTemplateSpecialization: 3878d8c8981SErick Velez Kind["identifier"] = AddLangPrefix("var"); 3888d8c8981SErick Velez Kind["displayName"] = "Global Variable Template Specialization"; 3898d8c8981SErick Velez break; 3908d8c8981SErick Velez case APIRecord::RK_GlobalVariableTemplatePartialSpecialization: 3918d8c8981SErick Velez Kind["identifier"] = AddLangPrefix("var"); 3928d8c8981SErick Velez Kind["displayName"] = "Global Variable Template Partial Specialization"; 3938d8c8981SErick Velez break; 394236b6a0eSDaniel Grumberg case APIRecord::RK_GlobalVariable: 39571b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("var"); 39689f6b26fSZixu Wang Kind["displayName"] = "Global Variable"; 39789f6b26fSZixu Wang break; 39871b4c226SZixu Wang case APIRecord::RK_EnumConstant: 39971b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("enum.case"); 40071b4c226SZixu Wang Kind["displayName"] = "Enumeration Case"; 40171b4c226SZixu Wang break; 40271b4c226SZixu Wang case APIRecord::RK_Enum: 40371b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("enum"); 40471b4c226SZixu Wang Kind["displayName"] = "Enumeration"; 40571b4c226SZixu Wang break; 4065bb5704cSZixu Wang case APIRecord::RK_StructField: 4075bb5704cSZixu Wang Kind["identifier"] = AddLangPrefix("property"); 4085bb5704cSZixu Wang Kind["displayName"] = "Instance Property"; 4095bb5704cSZixu Wang break; 4105bb5704cSZixu Wang case APIRecord::RK_Struct: 4115bb5704cSZixu Wang Kind["identifier"] = AddLangPrefix("struct"); 4125bb5704cSZixu Wang Kind["displayName"] = "Structure"; 4135bb5704cSZixu Wang break; 41469fedaf8SDaniel Grumberg case APIRecord::RK_UnionField: 41575f55eb3SErick Velez Kind["identifier"] = AddLangPrefix("property"); 41675f55eb3SErick Velez Kind["displayName"] = "Instance Property"; 41775f55eb3SErick Velez break; 41875f55eb3SErick Velez case APIRecord::RK_Union: 41975f55eb3SErick Velez Kind["identifier"] = AddLangPrefix("union"); 42075f55eb3SErick Velez Kind["displayName"] = "Union"; 42175f55eb3SErick Velez break; 42269fedaf8SDaniel Grumberg case APIRecord::RK_CXXField: 42369fedaf8SDaniel Grumberg Kind["identifier"] = AddLangPrefix("property"); 42469fedaf8SDaniel Grumberg Kind["displayName"] = "Instance Property"; 42569fedaf8SDaniel Grumberg break; 42675f55eb3SErick Velez case APIRecord::RK_StaticField: 42775f55eb3SErick Velez Kind["identifier"] = AddLangPrefix("type.property"); 42875f55eb3SErick Velez Kind["displayName"] = "Type Property"; 42975f55eb3SErick Velez break; 4307ba37f4eSErick Velez case APIRecord::RK_ClassTemplate: 4317ba37f4eSErick Velez case APIRecord::RK_ClassTemplateSpecialization: 4327ba37f4eSErick Velez case APIRecord::RK_ClassTemplatePartialSpecialization: 43375f55eb3SErick Velez case APIRecord::RK_CXXClass: 43475f55eb3SErick Velez Kind["identifier"] = AddLangPrefix("class"); 43575f55eb3SErick Velez Kind["displayName"] = "Class"; 43675f55eb3SErick Velez break; 437d8e9c5d9SErick Velez case APIRecord::RK_CXXMethodTemplate: 438d8e9c5d9SErick Velez Kind["identifier"] = AddLangPrefix("method"); 439d8e9c5d9SErick Velez Kind["displayName"] = "Method Template"; 440d8e9c5d9SErick Velez break; 441d8e9c5d9SErick Velez case APIRecord::RK_CXXMethodTemplateSpecialization: 442d8e9c5d9SErick Velez Kind["identifier"] = AddLangPrefix("method"); 443d8e9c5d9SErick Velez Kind["displayName"] = "Method Template Specialization"; 444d8e9c5d9SErick Velez break; 445634b2fd2SErick Velez case APIRecord::RK_CXXFieldTemplate: 446634b2fd2SErick Velez Kind["identifier"] = AddLangPrefix("property"); 447634b2fd2SErick Velez Kind["displayName"] = "Template Property"; 448634b2fd2SErick Velez break; 4497ba37f4eSErick Velez case APIRecord::RK_Concept: 4507ba37f4eSErick Velez Kind["identifier"] = AddLangPrefix("concept"); 4517ba37f4eSErick Velez Kind["displayName"] = "Concept"; 4527ba37f4eSErick Velez break; 45375f55eb3SErick Velez case APIRecord::RK_CXXStaticMethod: 45475f55eb3SErick Velez Kind["identifier"] = AddLangPrefix("type.method"); 45575f55eb3SErick Velez Kind["displayName"] = "Static Method"; 45675f55eb3SErick Velez break; 45775f55eb3SErick Velez case APIRecord::RK_CXXInstanceMethod: 45875f55eb3SErick Velez Kind["identifier"] = AddLangPrefix("method"); 45975f55eb3SErick Velez Kind["displayName"] = "Instance Method"; 46075f55eb3SErick Velez break; 46175f55eb3SErick Velez case APIRecord::RK_CXXConstructorMethod: 46275f55eb3SErick Velez Kind["identifier"] = AddLangPrefix("method"); 46375f55eb3SErick Velez Kind["displayName"] = "Constructor"; 46475f55eb3SErick Velez break; 46575f55eb3SErick Velez case APIRecord::RK_CXXDestructorMethod: 46675f55eb3SErick Velez Kind["identifier"] = AddLangPrefix("method"); 46775f55eb3SErick Velez Kind["displayName"] = "Destructor"; 46875f55eb3SErick Velez break; 4699b36e126SZixu Wang case APIRecord::RK_ObjCIvar: 4709b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("ivar"); 4719b36e126SZixu Wang Kind["displayName"] = "Instance Variable"; 4729b36e126SZixu Wang break; 4737a851921SDaniel Grumberg case APIRecord::RK_ObjCInstanceMethod: 4749b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("method"); 4759b36e126SZixu Wang Kind["displayName"] = "Instance Method"; 4767a851921SDaniel Grumberg break; 4777a851921SDaniel Grumberg case APIRecord::RK_ObjCClassMethod: 4789b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("type.method"); 4799b36e126SZixu Wang Kind["displayName"] = "Type Method"; 4809b36e126SZixu Wang break; 4817a851921SDaniel Grumberg case APIRecord::RK_ObjCInstanceProperty: 4829b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("property"); 4839b36e126SZixu Wang Kind["displayName"] = "Instance Property"; 4847a851921SDaniel Grumberg break; 4857a851921SDaniel Grumberg case APIRecord::RK_ObjCClassProperty: 4867a851921SDaniel Grumberg Kind["identifier"] = AddLangPrefix("type.property"); 4877a851921SDaniel Grumberg Kind["displayName"] = "Type Property"; 4889b36e126SZixu Wang break; 4899b36e126SZixu Wang case APIRecord::RK_ObjCInterface: 4909b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("class"); 4919b36e126SZixu Wang Kind["displayName"] = "Class"; 4929b36e126SZixu Wang break; 493178aad9bSZixu Wang case APIRecord::RK_ObjCCategory: 49418493185Sruturaj4 Kind["identifier"] = AddLangPrefix("class.extension"); 49518493185Sruturaj4 Kind["displayName"] = "Class Extension"; 49618493185Sruturaj4 break; 497d1d34bafSZixu Wang case APIRecord::RK_ObjCProtocol: 498d1d34bafSZixu Wang Kind["identifier"] = AddLangPrefix("protocol"); 499d1d34bafSZixu Wang Kind["displayName"] = "Protocol"; 500d1d34bafSZixu Wang break; 501529a0570SDaniel Grumberg case APIRecord::RK_MacroDefinition: 502529a0570SDaniel Grumberg Kind["identifier"] = AddLangPrefix("macro"); 503529a0570SDaniel Grumberg Kind["displayName"] = "Macro"; 5049fc45ca0SDaniel Grumberg break; 5059fc45ca0SDaniel Grumberg case APIRecord::RK_Typedef: 5069fc45ca0SDaniel Grumberg Kind["identifier"] = AddLangPrefix("typealias"); 5079fc45ca0SDaniel Grumberg Kind["displayName"] = "Type Alias"; 5089fc45ca0SDaniel Grumberg break; 509e05c1b46SDaniel Grumberg default: 510e05c1b46SDaniel Grumberg llvm_unreachable("API Record with uninstantiable kind"); 51171b4c226SZixu Wang } 51289f6b26fSZixu Wang 51389f6b26fSZixu Wang return Kind; 51489f6b26fSZixu Wang } 51589f6b26fSZixu Wang 5167a851921SDaniel Grumberg /// Serialize the symbol kind information. 5177a851921SDaniel Grumberg /// 5187a851921SDaniel Grumberg /// The Symbol Graph symbol kind property contains a shorthand \c identifier 5197a851921SDaniel Grumberg /// which is prefixed by the source language name, useful for tooling to parse 5207a851921SDaniel Grumberg /// the kind, and a \c displayName for rendering human-readable names. 5217a851921SDaniel Grumberg Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 52261d4ca87SDaniel Grumberg return serializeSymbolKind(Record.KindForDisplay, Lang); 5237a851921SDaniel Grumberg } 5247a851921SDaniel Grumberg 525e05c1b46SDaniel Grumberg /// Serialize the function signature field, as specified by the 526e05c1b46SDaniel Grumberg /// Symbol Graph format. 527e05c1b46SDaniel Grumberg /// 528e05c1b46SDaniel Grumberg /// The Symbol Graph function signature property contains two arrays. 529e05c1b46SDaniel Grumberg /// - The \c returns array is the declaration fragments of the return type; 530e05c1b46SDaniel Grumberg /// - The \c parameters array contains names and declaration fragments of the 531e05c1b46SDaniel Grumberg /// parameters. 532236b6a0eSDaniel Grumberg template <typename RecordTy> 533e05c1b46SDaniel Grumberg void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 534236b6a0eSDaniel Grumberg const auto &FS = Record.Signature; 535236b6a0eSDaniel Grumberg if (FS.empty()) 536e05c1b46SDaniel Grumberg return; 537236b6a0eSDaniel Grumberg 538236b6a0eSDaniel Grumberg Object Signature; 539236b6a0eSDaniel Grumberg serializeArray(Signature, "returns", 540236b6a0eSDaniel Grumberg serializeDeclarationFragments(FS.getReturnType())); 541236b6a0eSDaniel Grumberg 542236b6a0eSDaniel Grumberg Array Parameters; 543236b6a0eSDaniel Grumberg for (const auto &P : FS.getParameters()) { 544236b6a0eSDaniel Grumberg Object Parameter; 545236b6a0eSDaniel Grumberg Parameter["name"] = P.Name; 546236b6a0eSDaniel Grumberg serializeArray(Parameter, "declarationFragments", 547236b6a0eSDaniel Grumberg serializeDeclarationFragments(P.Fragments)); 548236b6a0eSDaniel Grumberg Parameters.emplace_back(std::move(Parameter)); 549236b6a0eSDaniel Grumberg } 550236b6a0eSDaniel Grumberg 551236b6a0eSDaniel Grumberg if (!Parameters.empty()) 552236b6a0eSDaniel Grumberg Signature["parameters"] = std::move(Parameters); 553236b6a0eSDaniel Grumberg 554e05c1b46SDaniel Grumberg serializeObject(Paren, "functionSignature", std::move(Signature)); 555236b6a0eSDaniel Grumberg } 556236b6a0eSDaniel Grumberg 557236b6a0eSDaniel Grumberg template <typename RecordTy> 558e05c1b46SDaniel Grumberg void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { 5597ba37f4eSErick Velez const auto &Template = Record.Templ; 5607ba37f4eSErick Velez if (Template.empty()) 561e05c1b46SDaniel Grumberg return; 5627ba37f4eSErick Velez 5637ba37f4eSErick Velez Object Generics; 5647ba37f4eSErick Velez Array GenericParameters; 565ffb8434fSAntonio Frighetto for (const auto &Param : Template.getParameters()) { 5667ba37f4eSErick Velez Object Parameter; 5677ba37f4eSErick Velez Parameter["name"] = Param.Name; 5687ba37f4eSErick Velez Parameter["index"] = Param.Index; 5697ba37f4eSErick Velez Parameter["depth"] = Param.Depth; 5707ba37f4eSErick Velez GenericParameters.emplace_back(std::move(Parameter)); 5717ba37f4eSErick Velez } 5727ba37f4eSErick Velez if (!GenericParameters.empty()) 5737ba37f4eSErick Velez Generics["parameters"] = std::move(GenericParameters); 5747ba37f4eSErick Velez 5757ba37f4eSErick Velez Array GenericConstraints; 576ffb8434fSAntonio Frighetto for (const auto &Constr : Template.getConstraints()) { 5777ba37f4eSErick Velez Object Constraint; 5787ba37f4eSErick Velez Constraint["kind"] = Constr.Kind; 5797ba37f4eSErick Velez Constraint["lhs"] = Constr.LHS; 5807ba37f4eSErick Velez Constraint["rhs"] = Constr.RHS; 5817ba37f4eSErick Velez GenericConstraints.emplace_back(std::move(Constraint)); 5827ba37f4eSErick Velez } 5837ba37f4eSErick Velez 5847ba37f4eSErick Velez if (!GenericConstraints.empty()) 5857ba37f4eSErick Velez Generics["constraints"] = std::move(GenericConstraints); 5867ba37f4eSErick Velez 587e05c1b46SDaniel Grumberg serializeObject(Paren, "swiftGenerics", Generics); 5887ba37f4eSErick Velez } 5897ba37f4eSErick Velez 590e05c1b46SDaniel Grumberg Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents, 5917a851921SDaniel Grumberg Language Lang) { 5927a851921SDaniel Grumberg Array ParentContexts; 593e05c1b46SDaniel Grumberg 594e05c1b46SDaniel Grumberg for (const auto &Parent : Parents) { 595e05c1b46SDaniel Grumberg Object Elem; 596e05c1b46SDaniel Grumberg Elem["usr"] = Parent.USR; 597e05c1b46SDaniel Grumberg Elem["name"] = Parent.Name; 598e05c1b46SDaniel Grumberg if (Parent.Record) 59961d4ca87SDaniel Grumberg Elem["kind"] = serializeSymbolKind(Parent.Record->KindForDisplay, 60061d4ca87SDaniel Grumberg Lang)["identifier"]; 601e05c1b46SDaniel Grumberg else 602e05c1b46SDaniel Grumberg Elem["kind"] = 603e05c1b46SDaniel Grumberg serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"]; 604e05c1b46SDaniel Grumberg ParentContexts.emplace_back(std::move(Elem)); 605e05c1b46SDaniel Grumberg } 6067da2d644SDaniel Grumberg 6077a851921SDaniel Grumberg return ParentContexts; 6087a851921SDaniel Grumberg } 609e05c1b46SDaniel Grumberg 610e05c1b46SDaniel Grumberg /// Walk the records parent information in reverse to generate a hierarchy 611e05c1b46SDaniel Grumberg /// suitable for serialization. 612e05c1b46SDaniel Grumberg SmallVector<SymbolReference, 8> 613e05c1b46SDaniel Grumberg generateHierarchyFromRecord(const APIRecord *Record) { 614e05c1b46SDaniel Grumberg SmallVector<SymbolReference, 8> ReverseHierarchy; 615e05c1b46SDaniel Grumberg for (const auto *Current = Record; Current != nullptr; 616e05c1b46SDaniel Grumberg Current = Current->Parent.Record) 617e05c1b46SDaniel Grumberg ReverseHierarchy.emplace_back(Current); 618e05c1b46SDaniel Grumberg 619e05c1b46SDaniel Grumberg return SmallVector<SymbolReference, 8>( 620e05c1b46SDaniel Grumberg std::make_move_iterator(ReverseHierarchy.rbegin()), 621e05c1b46SDaniel Grumberg std::make_move_iterator(ReverseHierarchy.rend())); 622e05c1b46SDaniel Grumberg } 623e05c1b46SDaniel Grumberg 624e05c1b46SDaniel Grumberg SymbolReference getHierarchyReference(const APIRecord *Record, 625e05c1b46SDaniel Grumberg const APISet &API) { 626e05c1b46SDaniel Grumberg // If the parent is a category extended from internal module then we need to 627e05c1b46SDaniel Grumberg // pretend this belongs to the associated interface. 628e05c1b46SDaniel Grumberg if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) { 629e05c1b46SDaniel Grumberg return CategoryRecord->Interface; 630e05c1b46SDaniel Grumberg // FIXME: TODO generate path components correctly for categories extending 631e05c1b46SDaniel Grumberg // an external module. 632e05c1b46SDaniel Grumberg } 633e05c1b46SDaniel Grumberg 634e05c1b46SDaniel Grumberg return SymbolReference(Record); 635e05c1b46SDaniel Grumberg } 636e05c1b46SDaniel Grumberg 63789f6b26fSZixu Wang } // namespace 63889f6b26fSZixu Wang 639e05c1b46SDaniel Grumberg Object *ExtendedModule::addSymbol(Object &&Symbol) { 640e05c1b46SDaniel Grumberg Symbols.emplace_back(std::move(Symbol)); 641e05c1b46SDaniel Grumberg return Symbols.back().getAsObject(); 642e05c1b46SDaniel Grumberg } 643e05c1b46SDaniel Grumberg 644e05c1b46SDaniel Grumberg void ExtendedModule::addRelationship(Object &&Relationship) { 645e05c1b46SDaniel Grumberg Relationships.emplace_back(std::move(Relationship)); 646e05c1b46SDaniel Grumberg } 647e05c1b46SDaniel Grumberg 64889f6b26fSZixu Wang /// Defines the format version emitted by SymbolGraphSerializer. 64989f6b26fSZixu Wang const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 65089f6b26fSZixu Wang 65189f6b26fSZixu Wang Object SymbolGraphSerializer::serializeMetadata() const { 65289f6b26fSZixu Wang Object Metadata; 65389f6b26fSZixu Wang serializeObject(Metadata, "formatVersion", 65489f6b26fSZixu Wang serializeSemanticVersion(FormatVersion)); 65589f6b26fSZixu Wang Metadata["generator"] = clang::getClangFullVersion(); 65689f6b26fSZixu Wang return Metadata; 65789f6b26fSZixu Wang } 65889f6b26fSZixu Wang 659e05c1b46SDaniel Grumberg Object 660e05c1b46SDaniel Grumberg SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const { 66189f6b26fSZixu Wang Object Module; 662e05c1b46SDaniel Grumberg Module["name"] = ModuleName; 66389f6b26fSZixu Wang serializeObject(Module, "platform", serializePlatform(API.getTarget())); 66489f6b26fSZixu Wang return Module; 66589f6b26fSZixu Wang } 66689f6b26fSZixu Wang 667e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const { 668e05c1b46SDaniel Grumberg if (!Record) 669791fe26dSDaniel Grumberg return true; 670791fe26dSDaniel Grumberg 67189f6b26fSZixu Wang // Skip unconditionally unavailable symbols 672e05c1b46SDaniel Grumberg if (Record->Availability.isUnconditionallyUnavailable()) 67389f6b26fSZixu Wang return true; 67489f6b26fSZixu Wang 675504736ceSDaniel Grumberg // Filter out symbols prefixed with an underscored as they are understood to 676504736ceSDaniel Grumberg // be symbols clients should not use. 677e05c1b46SDaniel Grumberg if (Record->Name.starts_with("_")) 678e05c1b46SDaniel Grumberg return true; 679e05c1b46SDaniel Grumberg 680e05c1b46SDaniel Grumberg // Skip explicitly ignored symbols. 681e05c1b46SDaniel Grumberg if (IgnoresList.shouldIgnore(Record->Name)) 682504736ceSDaniel Grumberg return true; 683504736ceSDaniel Grumberg 68489f6b26fSZixu Wang return false; 68589f6b26fSZixu Wang } 68689f6b26fSZixu Wang 687e05c1b46SDaniel Grumberg ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() { 688e05c1b46SDaniel Grumberg if (!ForceEmitToMainModule && ModuleForCurrentSymbol) 689e05c1b46SDaniel Grumberg return *ModuleForCurrentSymbol; 69089f6b26fSZixu Wang 691e05c1b46SDaniel Grumberg return MainModule; 69289f6b26fSZixu Wang } 69389f6b26fSZixu Wang 694e05c1b46SDaniel Grumberg Array SymbolGraphSerializer::serializePathComponents( 695e05c1b46SDaniel Grumberg const APIRecord *Record) const { 696e05c1b46SDaniel Grumberg return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; })); 697178aad9bSZixu Wang } 698178aad9bSZixu Wang 69971b4c226SZixu Wang StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 70071b4c226SZixu Wang switch (Kind) { 70171b4c226SZixu Wang case RelationshipKind::MemberOf: 70271b4c226SZixu Wang return "memberOf"; 7039b36e126SZixu Wang case RelationshipKind::InheritsFrom: 7049b36e126SZixu Wang return "inheritsFrom"; 7059b36e126SZixu Wang case RelationshipKind::ConformsTo: 7069b36e126SZixu Wang return "conformsTo"; 70718493185Sruturaj4 case RelationshipKind::ExtensionTo: 70818493185Sruturaj4 return "extensionTo"; 70971b4c226SZixu Wang } 71071b4c226SZixu Wang llvm_unreachable("Unhandled relationship kind"); 71171b4c226SZixu Wang } 71271b4c226SZixu Wang 713e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 714e05c1b46SDaniel Grumberg const SymbolReference &Source, 715e05c1b46SDaniel Grumberg const SymbolReference &Target, 716e05c1b46SDaniel Grumberg ExtendedModule &Into) { 717e05c1b46SDaniel Grumberg Object Relationship; 718e05c1b46SDaniel Grumberg SmallString<64> TestRelLabel; 719e05c1b46SDaniel Grumberg if (EmitSymbolLabelsForTesting) { 720e05c1b46SDaniel Grumberg llvm::raw_svector_ostream OS(TestRelLabel); 721e05c1b46SDaniel Grumberg OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ " 722e05c1b46SDaniel Grumberg << Source.USR << " $ "; 723e05c1b46SDaniel Grumberg if (Target.USR.empty()) 724e05c1b46SDaniel Grumberg OS << Target.Name; 725e05c1b46SDaniel Grumberg else 726e05c1b46SDaniel Grumberg OS << Target.USR; 727e05c1b46SDaniel Grumberg Relationship["!testRelLabel"] = TestRelLabel; 728e05c1b46SDaniel Grumberg } 729e05c1b46SDaniel Grumberg Relationship["source"] = Source.USR; 730e05c1b46SDaniel Grumberg Relationship["target"] = Target.USR; 731e05c1b46SDaniel Grumberg Relationship["targetFallback"] = Target.Name; 732e05c1b46SDaniel Grumberg Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind); 733e05c1b46SDaniel Grumberg 734e05c1b46SDaniel Grumberg if (ForceEmitToMainModule) 735e05c1b46SDaniel Grumberg MainModule.addRelationship(std::move(Relationship)); 736e05c1b46SDaniel Grumberg else 737e05c1b46SDaniel Grumberg Into.addRelationship(std::move(Relationship)); 738e05c1b46SDaniel Grumberg } 739e05c1b46SDaniel Grumberg 7407ba37f4eSErick Velez StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { 7417ba37f4eSErick Velez switch (Kind) { 7427ba37f4eSErick Velez case ConstraintKind::Conformance: 7437ba37f4eSErick Velez return "conformance"; 7447ba37f4eSErick Velez case ConstraintKind::ConditionalConformance: 7457ba37f4eSErick Velez return "conditionalConformance"; 7467ba37f4eSErick Velez } 7477ba37f4eSErick Velez llvm_unreachable("Unhandled constraint kind"); 7487ba37f4eSErick Velez } 7497ba37f4eSErick Velez 750e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) { 751209a1e8dSDaniel Grumberg Object Obj; 752e05c1b46SDaniel Grumberg 753e05c1b46SDaniel Grumberg // If we need symbol labels for testing emit the USR as the value and the key 754e05c1b46SDaniel Grumberg // starts with '!'' to ensure it ends up at the top of the object. 755e05c1b46SDaniel Grumberg if (EmitSymbolLabelsForTesting) 756e05c1b46SDaniel Grumberg Obj["!testLabel"] = Record->USR; 757e05c1b46SDaniel Grumberg 758209a1e8dSDaniel Grumberg serializeObject(Obj, "identifier", 759e05c1b46SDaniel Grumberg serializeIdentifier(*Record, API.getLanguage())); 760e05c1b46SDaniel Grumberg serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage())); 761e05c1b46SDaniel Grumberg serializeObject(Obj, "names", serializeNames(Record)); 762e05c1b46SDaniel Grumberg serializeObject( 763e05c1b46SDaniel Grumberg Obj, "location", 764e05c1b46SDaniel Grumberg serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true)); 765e05c1b46SDaniel Grumberg serializeArray(Obj, "availability", 766e05c1b46SDaniel Grumberg serializeAvailability(Record->Availability)); 767e05c1b46SDaniel Grumberg serializeObject(Obj, "docComment", serializeDocComment(Record->Comment)); 768e05c1b46SDaniel Grumberg serializeArray(Obj, "declarationFragments", 769e05c1b46SDaniel Grumberg serializeDeclarationFragments(Record->Declaration)); 770e05c1b46SDaniel Grumberg 771e05c1b46SDaniel Grumberg Obj["pathComponents"] = serializePathComponents(Record); 772e05c1b46SDaniel Grumberg Obj["accessLevel"] = Record->Access.getAccess(); 773e05c1b46SDaniel Grumberg 774e05c1b46SDaniel Grumberg ExtendedModule &Module = getModuleForCurrentSymbol(); 775e05c1b46SDaniel Grumberg // If the hierarchy has at least one parent and child. 776e05c1b46SDaniel Grumberg if (Hierarchy.size() >= 2) 777e05c1b46SDaniel Grumberg serializeRelationship(MemberOf, Hierarchy.back(), 778e05c1b46SDaniel Grumberg Hierarchy[Hierarchy.size() - 2], Module); 779e05c1b46SDaniel Grumberg 780e05c1b46SDaniel Grumberg CurrentSymbol = Module.addSymbol(std::move(Obj)); 781b31414bfSDaniel Grumberg } 782b31414bfSDaniel Grumberg 783e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) { 784e05c1b46SDaniel Grumberg if (!Record) 785e05c1b46SDaniel Grumberg return true; 786e05c1b46SDaniel Grumberg if (shouldSkip(Record)) 787e05c1b46SDaniel Grumberg return true; 788e05c1b46SDaniel Grumberg Hierarchy.push_back(getHierarchyReference(Record, API)); 789e05c1b46SDaniel Grumberg // Defer traversal mechanics to APISetVisitor base implementation 790e05c1b46SDaniel Grumberg auto RetVal = Base::traverseAPIRecord(Record); 791e05c1b46SDaniel Grumberg Hierarchy.pop_back(); 792e05c1b46SDaniel Grumberg return RetVal; 793b31414bfSDaniel Grumberg } 794b31414bfSDaniel Grumberg 795e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) { 796e05c1b46SDaniel Grumberg serializeAPIRecord(Record); 797e05c1b46SDaniel Grumberg return true; 798e05c1b46SDaniel Grumberg } 799b31414bfSDaniel Grumberg 800e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitGlobalFunctionRecord( 801e05c1b46SDaniel Grumberg const GlobalFunctionRecord *Record) { 802e05c1b46SDaniel Grumberg if (!CurrentSymbol) 803e05c1b46SDaniel Grumberg return true; 804b31414bfSDaniel Grumberg 805e05c1b46SDaniel Grumberg serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 806e05c1b46SDaniel Grumberg return true; 807e05c1b46SDaniel Grumberg } 808e05c1b46SDaniel Grumberg 809e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) { 810e05c1b46SDaniel Grumberg if (!CurrentSymbol) 811e05c1b46SDaniel Grumberg return true; 812e05c1b46SDaniel Grumberg 813e05c1b46SDaniel Grumberg for (const auto &Base : Record->Bases) 814e05c1b46SDaniel Grumberg serializeRelationship(RelationshipKind::InheritsFrom, Record, Base, 815e05c1b46SDaniel Grumberg getModuleForCurrentSymbol()); 816e05c1b46SDaniel Grumberg return true; 817e05c1b46SDaniel Grumberg } 818e05c1b46SDaniel Grumberg 819e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitClassTemplateRecord( 820e05c1b46SDaniel Grumberg const ClassTemplateRecord *Record) { 821e05c1b46SDaniel Grumberg if (!CurrentSymbol) 822e05c1b46SDaniel Grumberg return true; 823e05c1b46SDaniel Grumberg 824e05c1b46SDaniel Grumberg serializeTemplateMixin(*CurrentSymbol, *Record); 825e05c1b46SDaniel Grumberg return true; 826e05c1b46SDaniel Grumberg } 827e05c1b46SDaniel Grumberg 828e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( 829e05c1b46SDaniel Grumberg const ClassTemplatePartialSpecializationRecord *Record) { 830e05c1b46SDaniel Grumberg if (!CurrentSymbol) 831e05c1b46SDaniel Grumberg return true; 832e05c1b46SDaniel Grumberg 833e05c1b46SDaniel Grumberg serializeTemplateMixin(*CurrentSymbol, *Record); 834e05c1b46SDaniel Grumberg return true; 835e05c1b46SDaniel Grumberg } 836e05c1b46SDaniel Grumberg 837e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitCXXMethodRecord( 838e05c1b46SDaniel Grumberg const CXXMethodRecord *Record) { 839e05c1b46SDaniel Grumberg if (!CurrentSymbol) 840e05c1b46SDaniel Grumberg return true; 841e05c1b46SDaniel Grumberg 842e05c1b46SDaniel Grumberg serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 843e05c1b46SDaniel Grumberg return true; 844e05c1b46SDaniel Grumberg } 845e05c1b46SDaniel Grumberg 846e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitCXXMethodTemplateRecord( 847e05c1b46SDaniel Grumberg const CXXMethodTemplateRecord *Record) { 848e05c1b46SDaniel Grumberg if (!CurrentSymbol) 849e05c1b46SDaniel Grumberg return true; 850e05c1b46SDaniel Grumberg 851e05c1b46SDaniel Grumberg serializeTemplateMixin(*CurrentSymbol, *Record); 852e05c1b46SDaniel Grumberg return true; 853e05c1b46SDaniel Grumberg } 854e05c1b46SDaniel Grumberg 855e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitCXXFieldTemplateRecord( 856e05c1b46SDaniel Grumberg const CXXFieldTemplateRecord *Record) { 857e05c1b46SDaniel Grumberg if (!CurrentSymbol) 858e05c1b46SDaniel Grumberg return true; 859e05c1b46SDaniel Grumberg 860e05c1b46SDaniel Grumberg serializeTemplateMixin(*CurrentSymbol, *Record); 861e05c1b46SDaniel Grumberg return true; 862e05c1b46SDaniel Grumberg } 863e05c1b46SDaniel Grumberg 864e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) { 865e05c1b46SDaniel Grumberg if (!CurrentSymbol) 866e05c1b46SDaniel Grumberg return true; 867e05c1b46SDaniel Grumberg 868e05c1b46SDaniel Grumberg serializeTemplateMixin(*CurrentSymbol, *Record); 869e05c1b46SDaniel Grumberg return true; 870e05c1b46SDaniel Grumberg } 871e05c1b46SDaniel Grumberg 872e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord( 873e05c1b46SDaniel Grumberg const GlobalVariableTemplateRecord *Record) { 874e05c1b46SDaniel Grumberg if (!CurrentSymbol) 875e05c1b46SDaniel Grumberg return true; 876e05c1b46SDaniel Grumberg 877e05c1b46SDaniel Grumberg serializeTemplateMixin(*CurrentSymbol, *Record); 878e05c1b46SDaniel Grumberg return true; 879e05c1b46SDaniel Grumberg } 880e05c1b46SDaniel Grumberg 881e05c1b46SDaniel Grumberg bool SymbolGraphSerializer:: 882e05c1b46SDaniel Grumberg visitGlobalVariableTemplatePartialSpecializationRecord( 883e05c1b46SDaniel Grumberg const GlobalVariableTemplatePartialSpecializationRecord *Record) { 884e05c1b46SDaniel Grumberg if (!CurrentSymbol) 885e05c1b46SDaniel Grumberg return true; 886e05c1b46SDaniel Grumberg 887e05c1b46SDaniel Grumberg serializeTemplateMixin(*CurrentSymbol, *Record); 888e05c1b46SDaniel Grumberg return true; 889e05c1b46SDaniel Grumberg } 890e05c1b46SDaniel Grumberg 891e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( 892e05c1b46SDaniel Grumberg const GlobalFunctionTemplateRecord *Record) { 893e05c1b46SDaniel Grumberg if (!CurrentSymbol) 894e05c1b46SDaniel Grumberg return true; 895e05c1b46SDaniel Grumberg 896e05c1b46SDaniel Grumberg serializeTemplateMixin(*CurrentSymbol, *Record); 897e05c1b46SDaniel Grumberg return true; 898e05c1b46SDaniel Grumberg } 899e05c1b46SDaniel Grumberg 900e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCContainerRecord( 901e05c1b46SDaniel Grumberg const ObjCContainerRecord *Record) { 902e05c1b46SDaniel Grumberg if (!CurrentSymbol) 903e05c1b46SDaniel Grumberg return true; 904e05c1b46SDaniel Grumberg 905e05c1b46SDaniel Grumberg for (const auto &Protocol : Record->Protocols) 906e05c1b46SDaniel Grumberg serializeRelationship(ConformsTo, Record, Protocol, 907e05c1b46SDaniel Grumberg getModuleForCurrentSymbol()); 908e05c1b46SDaniel Grumberg 909e05c1b46SDaniel Grumberg return true; 910e05c1b46SDaniel Grumberg } 911e05c1b46SDaniel Grumberg 912e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCInterfaceRecord( 913e05c1b46SDaniel Grumberg const ObjCInterfaceRecord *Record) { 914e05c1b46SDaniel Grumberg if (!CurrentSymbol) 915e05c1b46SDaniel Grumberg return true; 916e05c1b46SDaniel Grumberg 917e05c1b46SDaniel Grumberg if (!Record->SuperClass.empty()) 918e05c1b46SDaniel Grumberg serializeRelationship(InheritsFrom, Record, Record->SuperClass, 919e05c1b46SDaniel Grumberg getModuleForCurrentSymbol()); 920e05c1b46SDaniel Grumberg return true; 921e05c1b46SDaniel Grumberg } 922e05c1b46SDaniel Grumberg 923e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::traverseObjCCategoryRecord( 924e05c1b46SDaniel Grumberg const ObjCCategoryRecord *Record) { 92550b2bd4aSDaniel Grumberg if (SkipSymbolsInCategoriesToExternalTypes && 92650b2bd4aSDaniel Grumberg !API.findRecordForUSR(Record->Interface.USR)) 92750b2bd4aSDaniel Grumberg return true; 92850b2bd4aSDaniel Grumberg 929e05c1b46SDaniel Grumberg auto *CurrentModule = ModuleForCurrentSymbol; 930b1b24d75SDaniel Grumberg if (auto ModuleExtendedByRecord = Record->getExtendedExternalModule()) 931b1b24d75SDaniel Grumberg ModuleForCurrentSymbol = &ExtendedModules[*ModuleExtendedByRecord]; 932e05c1b46SDaniel Grumberg 933e05c1b46SDaniel Grumberg if (!walkUpFromObjCCategoryRecord(Record)) 934e05c1b46SDaniel Grumberg return false; 935e05c1b46SDaniel Grumberg 936e05c1b46SDaniel Grumberg bool RetVal = traverseRecordContext(Record); 937e05c1b46SDaniel Grumberg ModuleForCurrentSymbol = CurrentModule; 938e05c1b46SDaniel Grumberg return RetVal; 939e05c1b46SDaniel Grumberg } 940e05c1b46SDaniel Grumberg 941e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord( 942e05c1b46SDaniel Grumberg const ObjCCategoryRecord *Record) { 943e05c1b46SDaniel Grumberg return visitObjCCategoryRecord(Record); 944e05c1b46SDaniel Grumberg } 945e05c1b46SDaniel Grumberg 946e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCCategoryRecord( 947e05c1b46SDaniel Grumberg const ObjCCategoryRecord *Record) { 948e05c1b46SDaniel Grumberg // If we need to create a record for the category in the future do so here, 949e05c1b46SDaniel Grumberg // otherwise everything is set up to pretend that the category is in fact the 950e05c1b46SDaniel Grumberg // interface it extends. 951e05c1b46SDaniel Grumberg for (const auto &Protocol : Record->Protocols) 952e05c1b46SDaniel Grumberg serializeRelationship(ConformsTo, Record->Interface, Protocol, 953e05c1b46SDaniel Grumberg getModuleForCurrentSymbol()); 954e05c1b46SDaniel Grumberg 955e05c1b46SDaniel Grumberg return true; 956e05c1b46SDaniel Grumberg } 957e05c1b46SDaniel Grumberg 958e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCMethodRecord( 959e05c1b46SDaniel Grumberg const ObjCMethodRecord *Record) { 960e05c1b46SDaniel Grumberg if (!CurrentSymbol) 961e05c1b46SDaniel Grumberg return true; 962e05c1b46SDaniel Grumberg 963e05c1b46SDaniel Grumberg serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 964e05c1b46SDaniel Grumberg return true; 965e05c1b46SDaniel Grumberg } 966e05c1b46SDaniel Grumberg 967e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitObjCInstanceVariableRecord( 968e05c1b46SDaniel Grumberg const ObjCInstanceVariableRecord *Record) { 969e05c1b46SDaniel Grumberg // FIXME: serialize ivar access control here. 970e05c1b46SDaniel Grumberg return true; 971e05c1b46SDaniel Grumberg } 972e05c1b46SDaniel Grumberg 973e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::walkUpFromTypedefRecord( 974e05c1b46SDaniel Grumberg const TypedefRecord *Record) { 975e05c1b46SDaniel Grumberg // Short-circuit walking up the class hierarchy and handle creating typedef 976e05c1b46SDaniel Grumberg // symbol objects manually as there are additional symbol dropping rules to 977e05c1b46SDaniel Grumberg // respect. 978e05c1b46SDaniel Grumberg return visitTypedefRecord(Record); 979e05c1b46SDaniel Grumberg } 980e05c1b46SDaniel Grumberg 981e05c1b46SDaniel Grumberg bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) { 982e05c1b46SDaniel Grumberg // Typedefs of anonymous types have their entries unified with the underlying 983e05c1b46SDaniel Grumberg // type. 984e05c1b46SDaniel Grumberg bool ShouldDrop = Record->UnderlyingType.Name.empty(); 985e05c1b46SDaniel Grumberg // enums declared with `NS_OPTION` have a named enum and a named typedef, with 986e05c1b46SDaniel Grumberg // the same name 987e05c1b46SDaniel Grumberg ShouldDrop |= (Record->UnderlyingType.Name == Record->Name); 988e05c1b46SDaniel Grumberg if (ShouldDrop) 989e05c1b46SDaniel Grumberg return true; 990e05c1b46SDaniel Grumberg 991e05c1b46SDaniel Grumberg // Create the symbol record if the other symbol droppping rules permit it. 992e05c1b46SDaniel Grumberg serializeAPIRecord(Record); 993e05c1b46SDaniel Grumberg if (!CurrentSymbol) 994e05c1b46SDaniel Grumberg return true; 995e05c1b46SDaniel Grumberg 996e05c1b46SDaniel Grumberg (*CurrentSymbol)["type"] = Record->UnderlyingType.USR; 997e05c1b46SDaniel Grumberg 998e05c1b46SDaniel Grumberg return true; 999529a0570SDaniel Grumberg } 1000529a0570SDaniel Grumberg 10017a851921SDaniel Grumberg void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { 10027a851921SDaniel Grumberg switch (Record->getKind()) { 1003e05c1b46SDaniel Grumberg // dispatch to the relevant walkUpFromMethod 1004e05c1b46SDaniel Grumberg #define CONCRETE_RECORD(CLASS, BASE, KIND) \ 1005e05c1b46SDaniel Grumberg case APIRecord::KIND: { \ 1006e05c1b46SDaniel Grumberg walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \ 1007e05c1b46SDaniel Grumberg break; \ 1008e05c1b46SDaniel Grumberg } 1009e05c1b46SDaniel Grumberg #include "clang/ExtractAPI/APIRecords.inc" 1010e05c1b46SDaniel Grumberg // otherwise fallback on the only behavior we can implement safely. 10117a851921SDaniel Grumberg case APIRecord::RK_Unknown: 1012e05c1b46SDaniel Grumberg visitAPIRecord(Record); 10137a851921SDaniel Grumberg break; 10147a851921SDaniel Grumberg default: 1015e05c1b46SDaniel Grumberg llvm_unreachable("API Record with uninstantiable kind"); 10167a851921SDaniel Grumberg } 10177a851921SDaniel Grumberg } 10187a851921SDaniel Grumberg 1019e05c1b46SDaniel Grumberg Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName, 1020e05c1b46SDaniel Grumberg ExtendedModule &&EM) { 10217a851921SDaniel Grumberg Object Root; 10227a851921SDaniel Grumberg serializeObject(Root, "metadata", serializeMetadata()); 1023e05c1b46SDaniel Grumberg serializeObject(Root, "module", serializeModuleObject(ModuleName)); 10247a851921SDaniel Grumberg 1025e05c1b46SDaniel Grumberg Root["symbols"] = std::move(EM.Symbols); 1026e05c1b46SDaniel Grumberg Root["relationships"] = std::move(EM.Relationships); 102789f6b26fSZixu Wang 102889f6b26fSZixu Wang return Root; 102989f6b26fSZixu Wang } 103089f6b26fSZixu Wang 1031e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeGraphToStream( 1032e05c1b46SDaniel Grumberg raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName, 1033e05c1b46SDaniel Grumberg ExtendedModule &&EM) { 1034e05c1b46SDaniel Grumberg Object Root = serializeGraph(ModuleName, std::move(EM)); 103589f6b26fSZixu Wang if (Options.Compact) 1036f0785484SYuxuan Chen OS << formatv("{0}", json::Value(std::move(Root))) << "\n"; 103789f6b26fSZixu Wang else 1038f0785484SYuxuan Chen OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n"; 1039e05c1b46SDaniel Grumberg } 1040e05c1b46SDaniel Grumberg 1041e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeMainSymbolGraph( 1042e05c1b46SDaniel Grumberg raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, 1043e05c1b46SDaniel Grumberg SymbolGraphSerializerOption Options) { 104450b2bd4aSDaniel Grumberg SymbolGraphSerializer Serializer( 104550b2bd4aSDaniel Grumberg API, IgnoresList, Options.EmitSymbolLabelsForTesting, 104650b2bd4aSDaniel Grumberg /*ForceEmitToMainModule=*/true, 104750b2bd4aSDaniel Grumberg /*SkipSymbolsInCategoriesToExternalTypes=*/true); 104850b2bd4aSDaniel Grumberg 1049e05c1b46SDaniel Grumberg Serializer.traverseAPISet(); 1050e05c1b46SDaniel Grumberg Serializer.serializeGraphToStream(OS, Options, API.ProductName, 1051e05c1b46SDaniel Grumberg std::move(Serializer.MainModule)); 1052e05c1b46SDaniel Grumberg // FIXME: TODO handle extended modules here 1053e05c1b46SDaniel Grumberg } 1054e05c1b46SDaniel Grumberg 1055e05c1b46SDaniel Grumberg void SymbolGraphSerializer::serializeWithExtensionGraphs( 1056e05c1b46SDaniel Grumberg raw_ostream &MainOutput, const APISet &API, 1057e05c1b46SDaniel Grumberg const APIIgnoresList &IgnoresList, 1058e05c1b46SDaniel Grumberg llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)> 1059e05c1b46SDaniel Grumberg CreateOutputStream, 1060e05c1b46SDaniel Grumberg SymbolGraphSerializerOption Options) { 1061e05c1b46SDaniel Grumberg SymbolGraphSerializer Serializer(API, IgnoresList, 1062e05c1b46SDaniel Grumberg Options.EmitSymbolLabelsForTesting); 1063e05c1b46SDaniel Grumberg Serializer.traverseAPISet(); 1064e05c1b46SDaniel Grumberg 1065e05c1b46SDaniel Grumberg Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName, 1066e05c1b46SDaniel Grumberg std::move(Serializer.MainModule)); 1067e05c1b46SDaniel Grumberg 1068e05c1b46SDaniel Grumberg for (auto &ExtensionSGF : Serializer.ExtendedModules) { 1069e05c1b46SDaniel Grumberg if (auto ExtensionOS = 1070*1be4a674SQuietMisdreavus CreateOutputStream(API.ProductName + "@" + ExtensionSGF.getKey())) 1071*1be4a674SQuietMisdreavus Serializer.serializeGraphToStream(*ExtensionOS, Options, API.ProductName, 1072e05c1b46SDaniel Grumberg std::move(ExtensionSGF.getValue())); 1073e05c1b46SDaniel Grumberg } 107489f6b26fSZixu Wang } 10757a851921SDaniel Grumberg 10766ad0788cSKazu Hirata std::optional<Object> 10777a851921SDaniel Grumberg SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, 10787a851921SDaniel Grumberg const APISet &API) { 10797a851921SDaniel Grumberg APIRecord *Record = API.findRecordForUSR(USR); 10807a851921SDaniel Grumberg if (!Record) 10817a851921SDaniel Grumberg return {}; 10827a851921SDaniel Grumberg 10837a851921SDaniel Grumberg Object Root; 10847a851921SDaniel Grumberg APIIgnoresList EmptyIgnores; 10857a851921SDaniel Grumberg SymbolGraphSerializer Serializer(API, EmptyIgnores, 1086e05c1b46SDaniel Grumberg /*EmitSymbolLabelsForTesting*/ false, 1087e05c1b46SDaniel Grumberg /*ForceEmitToMainModule*/ true); 1088e05c1b46SDaniel Grumberg 1089e05c1b46SDaniel Grumberg // Set up serializer parent chain 1090e05c1b46SDaniel Grumberg Serializer.Hierarchy = generateHierarchyFromRecord(Record); 1091e05c1b46SDaniel Grumberg 10927a851921SDaniel Grumberg Serializer.serializeSingleRecord(Record); 1093e05c1b46SDaniel Grumberg serializeObject(Root, "symbolGraph", 1094e05c1b46SDaniel Grumberg Serializer.serializeGraph(API.ProductName, 1095e05c1b46SDaniel Grumberg std::move(Serializer.MainModule))); 10967a851921SDaniel Grumberg 10977a851921SDaniel Grumberg Language Lang = API.getLanguage(); 10987a851921SDaniel Grumberg serializeArray(Root, "parentContexts", 1099e05c1b46SDaniel Grumberg generateParentContexts(Serializer.Hierarchy, Lang)); 11007a851921SDaniel Grumberg 11017a851921SDaniel Grumberg Array RelatedSymbols; 11027a851921SDaniel Grumberg 11037a851921SDaniel Grumberg for (const auto &Fragment : Record->Declaration.getFragments()) { 11047a851921SDaniel Grumberg // If we don't have a USR there isn't much we can do. 11057a851921SDaniel Grumberg if (Fragment.PreciseIdentifier.empty()) 11067a851921SDaniel Grumberg continue; 11077a851921SDaniel Grumberg 11087a851921SDaniel Grumberg APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier); 11097a851921SDaniel Grumberg 11107a851921SDaniel Grumberg // If we can't find the record let's skip. 11117a851921SDaniel Grumberg if (!RelatedRecord) 11127a851921SDaniel Grumberg continue; 11137a851921SDaniel Grumberg 11147a851921SDaniel Grumberg Object RelatedSymbol; 11157a851921SDaniel Grumberg RelatedSymbol["usr"] = RelatedRecord->USR; 11167a851921SDaniel Grumberg RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); 1117e05c1b46SDaniel Grumberg RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess(); 11187a851921SDaniel Grumberg RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); 11197a851921SDaniel Grumberg RelatedSymbol["moduleName"] = API.ProductName; 11207a851921SDaniel Grumberg RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; 11217a851921SDaniel Grumberg 11227a851921SDaniel Grumberg serializeArray(RelatedSymbol, "parentContexts", 1123e05c1b46SDaniel Grumberg generateParentContexts( 1124e05c1b46SDaniel Grumberg generateHierarchyFromRecord(RelatedRecord), Lang)); 1125e05c1b46SDaniel Grumberg 11267a851921SDaniel Grumberg RelatedSymbols.push_back(std::move(RelatedSymbol)); 11277a851921SDaniel Grumberg } 11287a851921SDaniel Grumberg 11297a851921SDaniel Grumberg serializeArray(Root, "relatedSymbols", RelatedSymbols); 11307a851921SDaniel Grumberg return Root; 11317a851921SDaniel Grumberg } 1132