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" 15*bdd1243dSDimitry Andric #include "clang/Basic/SourceLocation.h" 1681ad6265SDimitry Andric #include "clang/Basic/Version.h" 1781ad6265SDimitry Andric #include "clang/ExtractAPI/API.h" 18*bdd1243dSDimitry Andric #include "clang/ExtractAPI/APIIgnoresList.h" 1981ad6265SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h" 20*bdd1243dSDimitry Andric #include "clang/ExtractAPI/Serialization/SerializerBase.h" 21*bdd1243dSDimitry Andric #include "llvm/ADT/STLExtras.h" 22*bdd1243dSDimitry Andric #include "llvm/ADT/STLFunctionalExtras.h" 23*bdd1243dSDimitry Andric #include "llvm/ADT/SmallVector.h" 24*bdd1243dSDimitry Andric #include "llvm/Support/Casting.h" 25*bdd1243dSDimitry Andric #include "llvm/Support/Compiler.h" 2681ad6265SDimitry Andric #include "llvm/Support/JSON.h" 2781ad6265SDimitry Andric #include "llvm/Support/Path.h" 2881ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h" 29*bdd1243dSDimitry Andric #include <optional> 3081ad6265SDimitry Andric #include <type_traits> 3181ad6265SDimitry Andric 3281ad6265SDimitry Andric using namespace clang; 3381ad6265SDimitry Andric using namespace clang::extractapi; 3481ad6265SDimitry Andric using namespace llvm; 3581ad6265SDimitry Andric using namespace llvm::json; 3681ad6265SDimitry Andric 3781ad6265SDimitry Andric namespace { 3881ad6265SDimitry Andric 3981ad6265SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren 4081ad6265SDimitry Andric /// at position \p Key. 41*bdd1243dSDimitry Andric void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) { 4281ad6265SDimitry Andric if (Obj) 43*bdd1243dSDimitry Andric Paren[Key] = std::move(*Obj); 4481ad6265SDimitry Andric } 4581ad6265SDimitry Andric 4681ad6265SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at 4781ad6265SDimitry Andric /// position \p Key. 48*bdd1243dSDimitry Andric void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) { 4981ad6265SDimitry Andric if (Array) 50*bdd1243dSDimitry Andric Paren[Key] = std::move(*Array); 5181ad6265SDimitry Andric } 5281ad6265SDimitry Andric 5381ad6265SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 5481ad6265SDimitry Andric /// format. 5581ad6265SDimitry Andric /// 5681ad6265SDimitry Andric /// A semantic version object contains three numeric fields, representing the 5781ad6265SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple. 5881ad6265SDimitry Andric /// For example version tuple 1.0.3 is serialized as: 5981ad6265SDimitry Andric /// \code 6081ad6265SDimitry Andric /// { 6181ad6265SDimitry Andric /// "major" : 1, 6281ad6265SDimitry Andric /// "minor" : 0, 6381ad6265SDimitry Andric /// "patch" : 3 6481ad6265SDimitry Andric /// } 6581ad6265SDimitry Andric /// \endcode 6681ad6265SDimitry Andric /// 67*bdd1243dSDimitry Andric /// \returns \c std::nullopt if the version \p V is empty, or an \c Object 68*bdd1243dSDimitry Andric /// containing the semantic version representation of \p V. 69*bdd1243dSDimitry Andric std::optional<Object> serializeSemanticVersion(const VersionTuple &V) { 7081ad6265SDimitry Andric if (V.empty()) 71*bdd1243dSDimitry Andric return std::nullopt; 7281ad6265SDimitry Andric 7381ad6265SDimitry Andric Object Version; 7481ad6265SDimitry Andric Version["major"] = V.getMajor(); 7581ad6265SDimitry Andric Version["minor"] = V.getMinor().value_or(0); 7681ad6265SDimitry Andric Version["patch"] = V.getSubminor().value_or(0); 7781ad6265SDimitry Andric return Version; 7881ad6265SDimitry Andric } 7981ad6265SDimitry Andric 8081ad6265SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property. 8181ad6265SDimitry Andric /// 8281ad6265SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an 8381ad6265SDimitry Andric /// optional \c minimumVersion semantic version field. 8481ad6265SDimitry Andric Object serializeOperatingSystem(const Triple &T) { 8581ad6265SDimitry Andric Object OS; 8681ad6265SDimitry Andric OS["name"] = T.getOSTypeName(T.getOS()); 8781ad6265SDimitry Andric serializeObject(OS, "minimumVersion", 8881ad6265SDimitry Andric serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 8981ad6265SDimitry Andric return OS; 9081ad6265SDimitry Andric } 9181ad6265SDimitry Andric 9281ad6265SDimitry Andric /// Serialize the platform information in the Symbol Graph module section. 9381ad6265SDimitry Andric /// 9481ad6265SDimitry Andric /// The platform object describes a target platform triple in corresponding 9581ad6265SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem. 9681ad6265SDimitry Andric Object serializePlatform(const Triple &T) { 9781ad6265SDimitry Andric Object Platform; 9881ad6265SDimitry Andric Platform["architecture"] = T.getArchName(); 9981ad6265SDimitry Andric Platform["vendor"] = T.getVendorName(); 10081ad6265SDimitry Andric Platform["operatingSystem"] = serializeOperatingSystem(T); 10181ad6265SDimitry Andric return Platform; 10281ad6265SDimitry Andric } 10381ad6265SDimitry Andric 10481ad6265SDimitry Andric /// Serialize a source position. 10581ad6265SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) { 10681ad6265SDimitry Andric assert(Loc.isValid() && "invalid source position"); 10781ad6265SDimitry Andric 10881ad6265SDimitry Andric Object SourcePosition; 10981ad6265SDimitry Andric SourcePosition["line"] = Loc.getLine(); 11081ad6265SDimitry Andric SourcePosition["character"] = Loc.getColumn(); 11181ad6265SDimitry Andric 11281ad6265SDimitry Andric return SourcePosition; 11381ad6265SDimitry Andric } 11481ad6265SDimitry Andric 11581ad6265SDimitry Andric /// Serialize a source location in file. 11681ad6265SDimitry Andric /// 11781ad6265SDimitry Andric /// \param Loc The presumed location to serialize. 11881ad6265SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 11981ad6265SDimitry Andric /// Defaults to false. 12081ad6265SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc, 12181ad6265SDimitry Andric bool IncludeFileURI = false) { 12281ad6265SDimitry Andric Object SourceLocation; 12381ad6265SDimitry Andric serializeObject(SourceLocation, "position", serializeSourcePosition(Loc)); 12481ad6265SDimitry Andric 12581ad6265SDimitry Andric if (IncludeFileURI) { 12681ad6265SDimitry Andric std::string FileURI = "file://"; 12781ad6265SDimitry Andric // Normalize file path to use forward slashes for the URI. 12881ad6265SDimitry Andric FileURI += sys::path::convert_to_slash(Loc.getFilename()); 12981ad6265SDimitry Andric SourceLocation["uri"] = FileURI; 13081ad6265SDimitry Andric } 13181ad6265SDimitry Andric 13281ad6265SDimitry Andric return SourceLocation; 13381ad6265SDimitry Andric } 13481ad6265SDimitry Andric 13581ad6265SDimitry Andric /// Serialize a source range with begin and end locations. 13681ad6265SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc, 13781ad6265SDimitry Andric const PresumedLoc &EndLoc) { 13881ad6265SDimitry Andric Object SourceRange; 13981ad6265SDimitry Andric serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 14081ad6265SDimitry Andric serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 14181ad6265SDimitry Andric return SourceRange; 14281ad6265SDimitry Andric } 14381ad6265SDimitry Andric 14481ad6265SDimitry Andric /// Serialize the availability attributes of a symbol. 14581ad6265SDimitry Andric /// 14681ad6265SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted 147*bdd1243dSDimitry Andric /// versions of the symbol for a given domain (roughly corresponds to a 148*bdd1243dSDimitry Andric /// platform) as semantic versions, if not default. Availability information 149*bdd1243dSDimitry Andric /// also contains flags to indicate if the symbol is unconditionally unavailable 150*bdd1243dSDimitry Andric /// or deprecated, i.e. \c __attribute__((unavailable)) and \c 151*bdd1243dSDimitry Andric /// __attribute__((deprecated)). 15281ad6265SDimitry Andric /// 153*bdd1243dSDimitry Andric /// \returns \c std::nullopt if the symbol has default availability attributes, 154*bdd1243dSDimitry Andric /// or an \c Array containing the formatted availability information. 155*bdd1243dSDimitry Andric std::optional<Array> 156*bdd1243dSDimitry Andric serializeAvailability(const AvailabilitySet &Availabilities) { 157*bdd1243dSDimitry Andric if (Availabilities.isDefault()) 158*bdd1243dSDimitry Andric return std::nullopt; 15981ad6265SDimitry Andric 160*bdd1243dSDimitry Andric Array AvailabilityArray; 16181ad6265SDimitry Andric 162*bdd1243dSDimitry Andric if (Availabilities.isUnconditionallyDeprecated()) { 163*bdd1243dSDimitry Andric Object UnconditionallyDeprecated; 164*bdd1243dSDimitry Andric UnconditionallyDeprecated["domain"] = "*"; 165*bdd1243dSDimitry Andric UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true; 166*bdd1243dSDimitry Andric AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated)); 167*bdd1243dSDimitry Andric } 168*bdd1243dSDimitry Andric 169*bdd1243dSDimitry Andric // Note unconditionally unavailable records are skipped. 170*bdd1243dSDimitry Andric 171*bdd1243dSDimitry Andric for (const auto &AvailInfo : Availabilities) { 172*bdd1243dSDimitry Andric Object Availability; 173*bdd1243dSDimitry Andric Availability["domain"] = AvailInfo.Domain; 174*bdd1243dSDimitry Andric serializeObject(Availability, "introducedVersion", 175*bdd1243dSDimitry Andric serializeSemanticVersion(AvailInfo.Introduced)); 176*bdd1243dSDimitry Andric serializeObject(Availability, "deprecatedVersion", 177*bdd1243dSDimitry Andric serializeSemanticVersion(AvailInfo.Deprecated)); 178*bdd1243dSDimitry Andric serializeObject(Availability, "obsoletedVersion", 179*bdd1243dSDimitry Andric serializeSemanticVersion(AvailInfo.Obsoleted)); 180*bdd1243dSDimitry Andric AvailabilityArray.emplace_back(std::move(Availability)); 181*bdd1243dSDimitry Andric } 182*bdd1243dSDimitry Andric 183*bdd1243dSDimitry Andric return AvailabilityArray; 18481ad6265SDimitry Andric } 18581ad6265SDimitry Andric 18681ad6265SDimitry Andric /// Get the language name string for interface language references. 18781ad6265SDimitry Andric StringRef getLanguageName(Language Lang) { 18881ad6265SDimitry Andric switch (Lang) { 18981ad6265SDimitry Andric case Language::C: 19081ad6265SDimitry Andric return "c"; 19181ad6265SDimitry Andric case Language::ObjC: 19281ad6265SDimitry Andric return "objective-c"; 19381ad6265SDimitry Andric 19481ad6265SDimitry Andric // Unsupported language currently 19581ad6265SDimitry Andric case Language::CXX: 19681ad6265SDimitry Andric case Language::ObjCXX: 19781ad6265SDimitry Andric case Language::OpenCL: 19881ad6265SDimitry Andric case Language::OpenCLCXX: 19981ad6265SDimitry Andric case Language::CUDA: 20081ad6265SDimitry Andric case Language::RenderScript: 20181ad6265SDimitry Andric case Language::HIP: 20281ad6265SDimitry Andric case Language::HLSL: 20381ad6265SDimitry Andric 20481ad6265SDimitry Andric // Languages that the frontend cannot parse and compile 20581ad6265SDimitry Andric case Language::Unknown: 20681ad6265SDimitry Andric case Language::Asm: 20781ad6265SDimitry Andric case Language::LLVM_IR: 20881ad6265SDimitry Andric llvm_unreachable("Unsupported language kind"); 20981ad6265SDimitry Andric } 21081ad6265SDimitry Andric 21181ad6265SDimitry Andric llvm_unreachable("Unhandled language kind"); 21281ad6265SDimitry Andric } 21381ad6265SDimitry Andric 21481ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format. 21581ad6265SDimitry Andric /// 21681ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique 21781ad6265SDimitry Andric /// references, and the interface language name. 21881ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) { 21981ad6265SDimitry Andric Object Identifier; 22081ad6265SDimitry Andric Identifier["precise"] = Record.USR; 22181ad6265SDimitry Andric Identifier["interfaceLanguage"] = getLanguageName(Lang); 22281ad6265SDimitry Andric 22381ad6265SDimitry Andric return Identifier; 22481ad6265SDimitry Andric } 22581ad6265SDimitry Andric 22681ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by 22781ad6265SDimitry Andric /// the Symbol Graph format. 22881ad6265SDimitry Andric /// 22981ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line 23081ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range 23181ad6265SDimitry Andric /// information. 23281ad6265SDimitry Andric /// e.g. 23381ad6265SDimitry Andric /// \code 23481ad6265SDimitry Andric /// /// This is a documentation comment 23581ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 23681ad6265SDimitry Andric /// /// with multiple lines. 23781ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 23881ad6265SDimitry Andric /// \endcode 23981ad6265SDimitry Andric /// 240*bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing 241*bdd1243dSDimitry Andric /// the formatted lines. 242*bdd1243dSDimitry Andric std::optional<Object> serializeDocComment(const DocComment &Comment) { 24381ad6265SDimitry Andric if (Comment.empty()) 244*bdd1243dSDimitry Andric return std::nullopt; 24581ad6265SDimitry Andric 24681ad6265SDimitry Andric Object DocComment; 24781ad6265SDimitry Andric Array LinesArray; 24881ad6265SDimitry Andric for (const auto &CommentLine : Comment) { 24981ad6265SDimitry Andric Object Line; 25081ad6265SDimitry Andric Line["text"] = CommentLine.Text; 25181ad6265SDimitry Andric serializeObject(Line, "range", 25281ad6265SDimitry Andric serializeSourceRange(CommentLine.Begin, CommentLine.End)); 25381ad6265SDimitry Andric LinesArray.emplace_back(std::move(Line)); 25481ad6265SDimitry Andric } 25581ad6265SDimitry Andric serializeArray(DocComment, "lines", LinesArray); 25681ad6265SDimitry Andric 25781ad6265SDimitry Andric return DocComment; 25881ad6265SDimitry Andric } 25981ad6265SDimitry Andric 26081ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol. 26181ad6265SDimitry Andric /// 26281ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important 26381ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to 26481ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for 26581ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example: 26681ad6265SDimitry Andric /// \code 26781ad6265SDimitry Andric /// const int pi; -> "declarationFragments" : [ 26881ad6265SDimitry Andric /// { 26981ad6265SDimitry Andric /// "kind" : "keyword", 27081ad6265SDimitry Andric /// "spelling" : "const" 27181ad6265SDimitry Andric /// }, 27281ad6265SDimitry Andric /// { 27381ad6265SDimitry Andric /// "kind" : "text", 27481ad6265SDimitry Andric /// "spelling" : " " 27581ad6265SDimitry Andric /// }, 27681ad6265SDimitry Andric /// { 27781ad6265SDimitry Andric /// "kind" : "typeIdentifier", 27881ad6265SDimitry Andric /// "preciseIdentifier" : "c:I", 27981ad6265SDimitry Andric /// "spelling" : "int" 28081ad6265SDimitry Andric /// }, 28181ad6265SDimitry Andric /// { 28281ad6265SDimitry Andric /// "kind" : "text", 28381ad6265SDimitry Andric /// "spelling" : " " 28481ad6265SDimitry Andric /// }, 28581ad6265SDimitry Andric /// { 28681ad6265SDimitry Andric /// "kind" : "identifier", 28781ad6265SDimitry Andric /// "spelling" : "pi" 28881ad6265SDimitry Andric /// } 28981ad6265SDimitry Andric /// ] 29081ad6265SDimitry Andric /// \endcode 29181ad6265SDimitry Andric /// 292*bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the 293*bdd1243dSDimitry Andric /// formatted declaration fragments array. 294*bdd1243dSDimitry Andric std::optional<Array> 295*bdd1243dSDimitry Andric serializeDeclarationFragments(const DeclarationFragments &DF) { 29681ad6265SDimitry Andric if (DF.getFragments().empty()) 297*bdd1243dSDimitry Andric return std::nullopt; 29881ad6265SDimitry Andric 29981ad6265SDimitry Andric Array Fragments; 30081ad6265SDimitry Andric for (const auto &F : DF.getFragments()) { 30181ad6265SDimitry Andric Object Fragment; 30281ad6265SDimitry Andric Fragment["spelling"] = F.Spelling; 30381ad6265SDimitry Andric Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 30481ad6265SDimitry Andric if (!F.PreciseIdentifier.empty()) 30581ad6265SDimitry Andric Fragment["preciseIdentifier"] = F.PreciseIdentifier; 30681ad6265SDimitry Andric Fragments.emplace_back(std::move(Fragment)); 30781ad6265SDimitry Andric } 30881ad6265SDimitry Andric 30981ad6265SDimitry Andric return Fragments; 31081ad6265SDimitry Andric } 31181ad6265SDimitry Andric 31281ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph 31381ad6265SDimitry Andric /// format. 31481ad6265SDimitry Andric /// 31581ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol 31681ad6265SDimitry Andric /// that can be used for different applications: 31781ad6265SDimitry Andric /// - \c title : The simple declared name of the symbol; 31881ad6265SDimitry Andric /// - \c subHeading : An array of declaration fragments that provides tags, 31981ad6265SDimitry Andric /// and potentially more tokens (for example the \c +/- symbol for 32081ad6265SDimitry Andric /// Objective-C methods). Can be used as sub-headings for documentation. 32181ad6265SDimitry Andric Object serializeNames(const APIRecord &Record) { 32281ad6265SDimitry Andric Object Names; 32381ad6265SDimitry Andric Names["title"] = Record.Name; 32481ad6265SDimitry Andric serializeArray(Names, "subHeading", 32581ad6265SDimitry Andric serializeDeclarationFragments(Record.SubHeading)); 32681ad6265SDimitry Andric DeclarationFragments NavigatorFragments; 32781ad6265SDimitry Andric NavigatorFragments.append(Record.Name, 32881ad6265SDimitry Andric DeclarationFragments::FragmentKind::Identifier, 32981ad6265SDimitry Andric /*PreciseIdentifier*/ ""); 33081ad6265SDimitry Andric serializeArray(Names, "navigator", 33181ad6265SDimitry Andric serializeDeclarationFragments(NavigatorFragments)); 33281ad6265SDimitry Andric 33381ad6265SDimitry Andric return Names; 33481ad6265SDimitry Andric } 33581ad6265SDimitry Andric 336*bdd1243dSDimitry Andric Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { 33781ad6265SDimitry Andric auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 33881ad6265SDimitry Andric return (getLanguageName(Lang) + "." + S).str(); 33981ad6265SDimitry Andric }; 34081ad6265SDimitry Andric 34181ad6265SDimitry Andric Object Kind; 342*bdd1243dSDimitry Andric switch (RK) { 343*bdd1243dSDimitry Andric case APIRecord::RK_Unknown: 344*bdd1243dSDimitry Andric llvm_unreachable("Records should have an explicit kind"); 345*bdd1243dSDimitry Andric break; 34681ad6265SDimitry Andric case APIRecord::RK_GlobalFunction: 34781ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 34881ad6265SDimitry Andric Kind["displayName"] = "Function"; 34981ad6265SDimitry Andric break; 35081ad6265SDimitry Andric case APIRecord::RK_GlobalVariable: 35181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 35281ad6265SDimitry Andric Kind["displayName"] = "Global Variable"; 35381ad6265SDimitry Andric break; 35481ad6265SDimitry Andric case APIRecord::RK_EnumConstant: 35581ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum.case"); 35681ad6265SDimitry Andric Kind["displayName"] = "Enumeration Case"; 35781ad6265SDimitry Andric break; 35881ad6265SDimitry Andric case APIRecord::RK_Enum: 35981ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum"); 36081ad6265SDimitry Andric Kind["displayName"] = "Enumeration"; 36181ad6265SDimitry Andric break; 36281ad6265SDimitry Andric case APIRecord::RK_StructField: 36381ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 36481ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 36581ad6265SDimitry Andric break; 36681ad6265SDimitry Andric case APIRecord::RK_Struct: 36781ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("struct"); 36881ad6265SDimitry Andric Kind["displayName"] = "Structure"; 36981ad6265SDimitry Andric break; 37081ad6265SDimitry Andric case APIRecord::RK_ObjCIvar: 37181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("ivar"); 37281ad6265SDimitry Andric Kind["displayName"] = "Instance Variable"; 37381ad6265SDimitry Andric break; 374*bdd1243dSDimitry Andric case APIRecord::RK_ObjCInstanceMethod: 37581ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 37681ad6265SDimitry Andric Kind["displayName"] = "Instance Method"; 377*bdd1243dSDimitry Andric break; 378*bdd1243dSDimitry Andric case APIRecord::RK_ObjCClassMethod: 37981ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("type.method"); 38081ad6265SDimitry Andric Kind["displayName"] = "Type Method"; 38181ad6265SDimitry Andric break; 382*bdd1243dSDimitry Andric case APIRecord::RK_ObjCInstanceProperty: 38381ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 38481ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 38581ad6265SDimitry Andric break; 386*bdd1243dSDimitry Andric case APIRecord::RK_ObjCClassProperty: 387*bdd1243dSDimitry Andric Kind["identifier"] = AddLangPrefix("type.property"); 388*bdd1243dSDimitry Andric Kind["displayName"] = "Type Property"; 389*bdd1243dSDimitry Andric break; 39081ad6265SDimitry Andric case APIRecord::RK_ObjCInterface: 39181ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("class"); 39281ad6265SDimitry Andric Kind["displayName"] = "Class"; 39381ad6265SDimitry Andric break; 39481ad6265SDimitry Andric case APIRecord::RK_ObjCCategory: 39581ad6265SDimitry Andric // We don't serialize out standalone Objective-C category symbols yet. 39681ad6265SDimitry Andric llvm_unreachable("Serializing standalone Objective-C category symbols is " 39781ad6265SDimitry Andric "not supported."); 39881ad6265SDimitry Andric break; 39981ad6265SDimitry Andric case APIRecord::RK_ObjCProtocol: 40081ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("protocol"); 40181ad6265SDimitry Andric Kind["displayName"] = "Protocol"; 40281ad6265SDimitry Andric break; 40381ad6265SDimitry Andric case APIRecord::RK_MacroDefinition: 40481ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("macro"); 40581ad6265SDimitry Andric Kind["displayName"] = "Macro"; 40681ad6265SDimitry Andric break; 40781ad6265SDimitry Andric case APIRecord::RK_Typedef: 40881ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("typealias"); 40981ad6265SDimitry Andric Kind["displayName"] = "Type Alias"; 41081ad6265SDimitry Andric break; 41181ad6265SDimitry Andric } 41281ad6265SDimitry Andric 41381ad6265SDimitry Andric return Kind; 41481ad6265SDimitry Andric } 41581ad6265SDimitry Andric 416*bdd1243dSDimitry Andric /// Serialize the symbol kind information. 417*bdd1243dSDimitry Andric /// 418*bdd1243dSDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier 419*bdd1243dSDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse 420*bdd1243dSDimitry Andric /// the kind, and a \c displayName for rendering human-readable names. 421*bdd1243dSDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 422*bdd1243dSDimitry Andric return serializeSymbolKind(Record.getKind(), Lang); 423*bdd1243dSDimitry Andric } 424*bdd1243dSDimitry Andric 42581ad6265SDimitry Andric template <typename RecordTy> 426*bdd1243dSDimitry Andric std::optional<Object> 427*bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { 42881ad6265SDimitry Andric const auto &FS = Record.Signature; 42981ad6265SDimitry Andric if (FS.empty()) 430*bdd1243dSDimitry Andric return std::nullopt; 43181ad6265SDimitry Andric 43281ad6265SDimitry Andric Object Signature; 43381ad6265SDimitry Andric serializeArray(Signature, "returns", 43481ad6265SDimitry Andric serializeDeclarationFragments(FS.getReturnType())); 43581ad6265SDimitry Andric 43681ad6265SDimitry Andric Array Parameters; 43781ad6265SDimitry Andric for (const auto &P : FS.getParameters()) { 43881ad6265SDimitry Andric Object Parameter; 43981ad6265SDimitry Andric Parameter["name"] = P.Name; 44081ad6265SDimitry Andric serializeArray(Parameter, "declarationFragments", 44181ad6265SDimitry Andric serializeDeclarationFragments(P.Fragments)); 44281ad6265SDimitry Andric Parameters.emplace_back(std::move(Parameter)); 44381ad6265SDimitry Andric } 44481ad6265SDimitry Andric 44581ad6265SDimitry Andric if (!Parameters.empty()) 44681ad6265SDimitry Andric Signature["parameters"] = std::move(Parameters); 44781ad6265SDimitry Andric 44881ad6265SDimitry Andric return Signature; 44981ad6265SDimitry Andric } 45081ad6265SDimitry Andric 45181ad6265SDimitry Andric template <typename RecordTy> 452*bdd1243dSDimitry Andric std::optional<Object> 453*bdd1243dSDimitry Andric serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { 454*bdd1243dSDimitry Andric return std::nullopt; 45581ad6265SDimitry Andric } 45681ad6265SDimitry Andric 45781ad6265SDimitry Andric /// Serialize the function signature field, as specified by the 45881ad6265SDimitry Andric /// Symbol Graph format. 45981ad6265SDimitry Andric /// 46081ad6265SDimitry Andric /// The Symbol Graph function signature property contains two arrays. 46181ad6265SDimitry Andric /// - The \c returns array is the declaration fragments of the return type; 46281ad6265SDimitry Andric /// - The \c parameters array contains names and declaration fragments of the 46381ad6265SDimitry Andric /// parameters. 46481ad6265SDimitry Andric /// 465*bdd1243dSDimitry Andric /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the 46681ad6265SDimitry Andric /// formatted function signature. 46781ad6265SDimitry Andric template <typename RecordTy> 46881ad6265SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 46981ad6265SDimitry Andric serializeObject(Paren, "functionSignature", 47081ad6265SDimitry Andric serializeFunctionSignatureMixinImpl( 47181ad6265SDimitry Andric Record, has_function_signature<RecordTy>())); 47281ad6265SDimitry Andric } 47381ad6265SDimitry Andric 474*bdd1243dSDimitry Andric struct PathComponent { 475*bdd1243dSDimitry Andric StringRef USR; 476*bdd1243dSDimitry Andric StringRef Name; 477*bdd1243dSDimitry Andric APIRecord::RecordKind Kind; 478*bdd1243dSDimitry Andric 479*bdd1243dSDimitry Andric PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind) 480*bdd1243dSDimitry Andric : USR(USR), Name(Name), Kind(Kind) {} 481*bdd1243dSDimitry Andric }; 482*bdd1243dSDimitry Andric 483*bdd1243dSDimitry Andric template <typename RecordTy> 484*bdd1243dSDimitry Andric bool generatePathComponents( 485*bdd1243dSDimitry Andric const RecordTy &Record, const APISet &API, 486*bdd1243dSDimitry Andric function_ref<void(const PathComponent &)> ComponentTransformer) { 487*bdd1243dSDimitry Andric SmallVector<PathComponent, 4> ReverseComponenents; 488*bdd1243dSDimitry Andric ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind()); 489*bdd1243dSDimitry Andric const auto *CurrentParent = &Record.ParentInformation; 490*bdd1243dSDimitry Andric while (CurrentParent && !CurrentParent->empty()) { 491*bdd1243dSDimitry Andric PathComponent CurrentParentComponent(CurrentParent->ParentUSR, 492*bdd1243dSDimitry Andric CurrentParent->ParentName, 493*bdd1243dSDimitry Andric CurrentParent->ParentKind); 494*bdd1243dSDimitry Andric 495*bdd1243dSDimitry Andric auto *ParentRecord = CurrentParent->ParentRecord; 496*bdd1243dSDimitry Andric // Slow path if we don't have a direct reference to the ParentRecord 497*bdd1243dSDimitry Andric if (!ParentRecord) 498*bdd1243dSDimitry Andric ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); 499*bdd1243dSDimitry Andric 500*bdd1243dSDimitry Andric // If the parent is a category then we need to pretend this belongs to the 501*bdd1243dSDimitry Andric // associated interface. 502*bdd1243dSDimitry Andric if (auto *CategoryRecord = 503*bdd1243dSDimitry Andric dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) { 504*bdd1243dSDimitry Andric ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); 505*bdd1243dSDimitry Andric CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, 506*bdd1243dSDimitry Andric CategoryRecord->Interface.Name, 507*bdd1243dSDimitry Andric APIRecord::RK_ObjCInterface); 508*bdd1243dSDimitry Andric } 509*bdd1243dSDimitry Andric 510*bdd1243dSDimitry Andric // The parent record doesn't exist which means the symbol shouldn't be 511*bdd1243dSDimitry Andric // treated as part of the current product. 512*bdd1243dSDimitry Andric if (!ParentRecord) 513*bdd1243dSDimitry Andric return true; 514*bdd1243dSDimitry Andric 515*bdd1243dSDimitry Andric ReverseComponenents.push_back(std::move(CurrentParentComponent)); 516*bdd1243dSDimitry Andric CurrentParent = &ParentRecord->ParentInformation; 517*bdd1243dSDimitry Andric } 518*bdd1243dSDimitry Andric 519*bdd1243dSDimitry Andric for (const auto &PC : reverse(ReverseComponenents)) 520*bdd1243dSDimitry Andric ComponentTransformer(PC); 521*bdd1243dSDimitry Andric 522*bdd1243dSDimitry Andric return false; 523*bdd1243dSDimitry Andric } 524*bdd1243dSDimitry Andric Object serializeParentContext(const PathComponent &PC, Language Lang) { 525*bdd1243dSDimitry Andric Object ParentContextElem; 526*bdd1243dSDimitry Andric ParentContextElem["usr"] = PC.USR; 527*bdd1243dSDimitry Andric ParentContextElem["name"] = PC.Name; 528*bdd1243dSDimitry Andric ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"]; 529*bdd1243dSDimitry Andric return ParentContextElem; 530*bdd1243dSDimitry Andric } 531*bdd1243dSDimitry Andric 532*bdd1243dSDimitry Andric template <typename RecordTy> 533*bdd1243dSDimitry Andric Array generateParentContexts(const RecordTy &Record, const APISet &API, 534*bdd1243dSDimitry Andric Language Lang) { 535*bdd1243dSDimitry Andric Array ParentContexts; 536*bdd1243dSDimitry Andric if (generatePathComponents( 537*bdd1243dSDimitry Andric Record, API, [Lang, &ParentContexts](const PathComponent &PC) { 538*bdd1243dSDimitry Andric ParentContexts.push_back(serializeParentContext(PC, Lang)); 539*bdd1243dSDimitry Andric })) 540*bdd1243dSDimitry Andric ParentContexts.clear(); 541*bdd1243dSDimitry Andric ParentContexts.pop_back(); 542*bdd1243dSDimitry Andric 543*bdd1243dSDimitry Andric return ParentContexts; 544*bdd1243dSDimitry Andric } 545*bdd1243dSDimitry Andric 54681ad6265SDimitry Andric } // namespace 54781ad6265SDimitry Andric 54881ad6265SDimitry Andric void SymbolGraphSerializer::anchor() {} 54981ad6265SDimitry Andric 55081ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer. 55181ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 55281ad6265SDimitry Andric 55381ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const { 55481ad6265SDimitry Andric Object Metadata; 55581ad6265SDimitry Andric serializeObject(Metadata, "formatVersion", 55681ad6265SDimitry Andric serializeSemanticVersion(FormatVersion)); 55781ad6265SDimitry Andric Metadata["generator"] = clang::getClangFullVersion(); 55881ad6265SDimitry Andric return Metadata; 55981ad6265SDimitry Andric } 56081ad6265SDimitry Andric 56181ad6265SDimitry Andric Object SymbolGraphSerializer::serializeModule() const { 56281ad6265SDimitry Andric Object Module; 56381ad6265SDimitry Andric // The user is expected to always pass `--product-name=` on the command line 56481ad6265SDimitry Andric // to populate this field. 565*bdd1243dSDimitry Andric Module["name"] = API.ProductName; 56681ad6265SDimitry Andric serializeObject(Module, "platform", serializePlatform(API.getTarget())); 56781ad6265SDimitry Andric return Module; 56881ad6265SDimitry Andric } 56981ad6265SDimitry Andric 57081ad6265SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { 571*bdd1243dSDimitry Andric // Skip explicitly ignored symbols. 572*bdd1243dSDimitry Andric if (IgnoresList.shouldIgnore(Record.Name)) 573*bdd1243dSDimitry Andric return true; 574*bdd1243dSDimitry Andric 57581ad6265SDimitry Andric // Skip unconditionally unavailable symbols 576*bdd1243dSDimitry Andric if (Record.Availabilities.isUnconditionallyUnavailable()) 57781ad6265SDimitry Andric return true; 57881ad6265SDimitry Andric 57981ad6265SDimitry Andric // Filter out symbols prefixed with an underscored as they are understood to 58081ad6265SDimitry Andric // be symbols clients should not use. 58181ad6265SDimitry Andric if (Record.Name.startswith("_")) 58281ad6265SDimitry Andric return true; 58381ad6265SDimitry Andric 58481ad6265SDimitry Andric return false; 58581ad6265SDimitry Andric } 58681ad6265SDimitry Andric 58781ad6265SDimitry Andric template <typename RecordTy> 588*bdd1243dSDimitry Andric std::optional<Object> 58981ad6265SDimitry Andric SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { 59081ad6265SDimitry Andric if (shouldSkip(Record)) 591*bdd1243dSDimitry Andric return std::nullopt; 59281ad6265SDimitry Andric 59381ad6265SDimitry Andric Object Obj; 59481ad6265SDimitry Andric serializeObject(Obj, "identifier", 59581ad6265SDimitry Andric serializeIdentifier(Record, API.getLanguage())); 59681ad6265SDimitry Andric serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); 59781ad6265SDimitry Andric serializeObject(Obj, "names", serializeNames(Record)); 59881ad6265SDimitry Andric serializeObject( 59981ad6265SDimitry Andric Obj, "location", 60081ad6265SDimitry Andric serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); 601*bdd1243dSDimitry Andric serializeArray(Obj, "availability", 602*bdd1243dSDimitry Andric serializeAvailability(Record.Availabilities)); 60381ad6265SDimitry Andric serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); 60481ad6265SDimitry Andric serializeArray(Obj, "declarationFragments", 60581ad6265SDimitry Andric serializeDeclarationFragments(Record.Declaration)); 60681ad6265SDimitry Andric // TODO: Once we keep track of symbol access information serialize it 60781ad6265SDimitry Andric // correctly here. 60881ad6265SDimitry Andric Obj["accessLevel"] = "public"; 609*bdd1243dSDimitry Andric SmallVector<StringRef, 4> PathComponentsNames; 610*bdd1243dSDimitry Andric // If this returns true it indicates that we couldn't find a symbol in the 611*bdd1243dSDimitry Andric // hierarchy. 612*bdd1243dSDimitry Andric if (generatePathComponents(Record, API, 613*bdd1243dSDimitry Andric [&PathComponentsNames](const PathComponent &PC) { 614*bdd1243dSDimitry Andric PathComponentsNames.push_back(PC.Name); 615*bdd1243dSDimitry Andric })) 616*bdd1243dSDimitry Andric return {}; 617*bdd1243dSDimitry Andric 618*bdd1243dSDimitry Andric serializeArray(Obj, "pathComponents", Array(PathComponentsNames)); 61981ad6265SDimitry Andric 62081ad6265SDimitry Andric serializeFunctionSignatureMixin(Obj, Record); 62181ad6265SDimitry Andric 62281ad6265SDimitry Andric return Obj; 62381ad6265SDimitry Andric } 62481ad6265SDimitry Andric 62581ad6265SDimitry Andric template <typename MemberTy> 62681ad6265SDimitry Andric void SymbolGraphSerializer::serializeMembers( 62781ad6265SDimitry Andric const APIRecord &Record, 62881ad6265SDimitry Andric const SmallVector<std::unique_ptr<MemberTy>> &Members) { 629*bdd1243dSDimitry Andric // Members should not be serialized if we aren't recursing. 630*bdd1243dSDimitry Andric if (!ShouldRecurse) 631*bdd1243dSDimitry Andric return; 63281ad6265SDimitry Andric for (const auto &Member : Members) { 63381ad6265SDimitry Andric auto MemberRecord = serializeAPIRecord(*Member); 63481ad6265SDimitry Andric if (!MemberRecord) 63581ad6265SDimitry Andric continue; 63681ad6265SDimitry Andric 63781ad6265SDimitry Andric Symbols.emplace_back(std::move(*MemberRecord)); 63881ad6265SDimitry Andric serializeRelationship(RelationshipKind::MemberOf, *Member, Record); 63981ad6265SDimitry Andric } 64081ad6265SDimitry Andric } 64181ad6265SDimitry Andric 64281ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 64381ad6265SDimitry Andric switch (Kind) { 64481ad6265SDimitry Andric case RelationshipKind::MemberOf: 64581ad6265SDimitry Andric return "memberOf"; 64681ad6265SDimitry Andric case RelationshipKind::InheritsFrom: 64781ad6265SDimitry Andric return "inheritsFrom"; 64881ad6265SDimitry Andric case RelationshipKind::ConformsTo: 64981ad6265SDimitry Andric return "conformsTo"; 65081ad6265SDimitry Andric } 65181ad6265SDimitry Andric llvm_unreachable("Unhandled relationship kind"); 65281ad6265SDimitry Andric } 65381ad6265SDimitry Andric 65481ad6265SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 65581ad6265SDimitry Andric SymbolReference Source, 65681ad6265SDimitry Andric SymbolReference Target) { 65781ad6265SDimitry Andric Object Relationship; 65881ad6265SDimitry Andric Relationship["source"] = Source.USR; 65981ad6265SDimitry Andric Relationship["target"] = Target.USR; 660*bdd1243dSDimitry Andric Relationship["targetFallback"] = Target.Name; 66181ad6265SDimitry Andric Relationship["kind"] = getRelationshipString(Kind); 66281ad6265SDimitry Andric 66381ad6265SDimitry Andric Relationships.emplace_back(std::move(Relationship)); 66481ad6265SDimitry Andric } 66581ad6265SDimitry Andric 66681ad6265SDimitry Andric void SymbolGraphSerializer::serializeGlobalFunctionRecord( 66781ad6265SDimitry Andric const GlobalFunctionRecord &Record) { 66881ad6265SDimitry Andric auto Obj = serializeAPIRecord(Record); 66981ad6265SDimitry Andric if (!Obj) 67081ad6265SDimitry Andric return; 67181ad6265SDimitry Andric 67281ad6265SDimitry Andric Symbols.emplace_back(std::move(*Obj)); 67381ad6265SDimitry Andric } 67481ad6265SDimitry Andric 67581ad6265SDimitry Andric void SymbolGraphSerializer::serializeGlobalVariableRecord( 67681ad6265SDimitry Andric const GlobalVariableRecord &Record) { 67781ad6265SDimitry Andric auto Obj = serializeAPIRecord(Record); 67881ad6265SDimitry Andric if (!Obj) 67981ad6265SDimitry Andric return; 68081ad6265SDimitry Andric 68181ad6265SDimitry Andric Symbols.emplace_back(std::move(*Obj)); 68281ad6265SDimitry Andric } 68381ad6265SDimitry Andric 68481ad6265SDimitry Andric void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) { 68581ad6265SDimitry Andric auto Enum = serializeAPIRecord(Record); 68681ad6265SDimitry Andric if (!Enum) 68781ad6265SDimitry Andric return; 68881ad6265SDimitry Andric 68981ad6265SDimitry Andric Symbols.emplace_back(std::move(*Enum)); 69081ad6265SDimitry Andric serializeMembers(Record, Record.Constants); 69181ad6265SDimitry Andric } 69281ad6265SDimitry Andric 69381ad6265SDimitry Andric void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) { 69481ad6265SDimitry Andric auto Struct = serializeAPIRecord(Record); 69581ad6265SDimitry Andric if (!Struct) 69681ad6265SDimitry Andric return; 69781ad6265SDimitry Andric 69881ad6265SDimitry Andric Symbols.emplace_back(std::move(*Struct)); 69981ad6265SDimitry Andric serializeMembers(Record, Record.Fields); 70081ad6265SDimitry Andric } 70181ad6265SDimitry Andric 70281ad6265SDimitry Andric void SymbolGraphSerializer::serializeObjCContainerRecord( 70381ad6265SDimitry Andric const ObjCContainerRecord &Record) { 70481ad6265SDimitry Andric auto ObjCContainer = serializeAPIRecord(Record); 70581ad6265SDimitry Andric if (!ObjCContainer) 70681ad6265SDimitry Andric return; 70781ad6265SDimitry Andric 70881ad6265SDimitry Andric Symbols.emplace_back(std::move(*ObjCContainer)); 70981ad6265SDimitry Andric 71081ad6265SDimitry Andric serializeMembers(Record, Record.Ivars); 71181ad6265SDimitry Andric serializeMembers(Record, Record.Methods); 71281ad6265SDimitry Andric serializeMembers(Record, Record.Properties); 71381ad6265SDimitry Andric 71481ad6265SDimitry Andric for (const auto &Protocol : Record.Protocols) 71581ad6265SDimitry Andric // Record that Record conforms to Protocol. 71681ad6265SDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 71781ad6265SDimitry Andric 71881ad6265SDimitry Andric if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) { 71981ad6265SDimitry Andric if (!ObjCInterface->SuperClass.empty()) 72081ad6265SDimitry Andric // If Record is an Objective-C interface record and it has a super class, 72181ad6265SDimitry Andric // record that Record is inherited from SuperClass. 72281ad6265SDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, 72381ad6265SDimitry Andric ObjCInterface->SuperClass); 72481ad6265SDimitry Andric 72581ad6265SDimitry Andric // Members of categories extending an interface are serialized as members of 72681ad6265SDimitry Andric // the interface. 72781ad6265SDimitry Andric for (const auto *Category : ObjCInterface->Categories) { 72881ad6265SDimitry Andric serializeMembers(Record, Category->Ivars); 72981ad6265SDimitry Andric serializeMembers(Record, Category->Methods); 73081ad6265SDimitry Andric serializeMembers(Record, Category->Properties); 73181ad6265SDimitry Andric 732*bdd1243dSDimitry Andric // Surface the protocols of the category to the interface. 73381ad6265SDimitry Andric for (const auto &Protocol : Category->Protocols) 73481ad6265SDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 73581ad6265SDimitry Andric } 73681ad6265SDimitry Andric } 73781ad6265SDimitry Andric } 73881ad6265SDimitry Andric 73981ad6265SDimitry Andric void SymbolGraphSerializer::serializeMacroDefinitionRecord( 74081ad6265SDimitry Andric const MacroDefinitionRecord &Record) { 74181ad6265SDimitry Andric auto Macro = serializeAPIRecord(Record); 74281ad6265SDimitry Andric 74381ad6265SDimitry Andric if (!Macro) 74481ad6265SDimitry Andric return; 74581ad6265SDimitry Andric 74681ad6265SDimitry Andric Symbols.emplace_back(std::move(*Macro)); 74781ad6265SDimitry Andric } 74881ad6265SDimitry Andric 749*bdd1243dSDimitry Andric void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { 750*bdd1243dSDimitry Andric switch (Record->getKind()) { 751*bdd1243dSDimitry Andric case APIRecord::RK_Unknown: 752*bdd1243dSDimitry Andric llvm_unreachable("Records should have a known kind!"); 753*bdd1243dSDimitry Andric case APIRecord::RK_GlobalFunction: 754*bdd1243dSDimitry Andric serializeGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record)); 755*bdd1243dSDimitry Andric break; 756*bdd1243dSDimitry Andric case APIRecord::RK_GlobalVariable: 757*bdd1243dSDimitry Andric serializeGlobalVariableRecord(*cast<GlobalVariableRecord>(Record)); 758*bdd1243dSDimitry Andric break; 759*bdd1243dSDimitry Andric case APIRecord::RK_Enum: 760*bdd1243dSDimitry Andric serializeEnumRecord(*cast<EnumRecord>(Record)); 761*bdd1243dSDimitry Andric break; 762*bdd1243dSDimitry Andric case APIRecord::RK_Struct: 763*bdd1243dSDimitry Andric serializeStructRecord(*cast<StructRecord>(Record)); 764*bdd1243dSDimitry Andric break; 765*bdd1243dSDimitry Andric case APIRecord::RK_ObjCInterface: 766*bdd1243dSDimitry Andric serializeObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record)); 767*bdd1243dSDimitry Andric break; 768*bdd1243dSDimitry Andric case APIRecord::RK_ObjCProtocol: 769*bdd1243dSDimitry Andric serializeObjCContainerRecord(*cast<ObjCProtocolRecord>(Record)); 770*bdd1243dSDimitry Andric break; 771*bdd1243dSDimitry Andric case APIRecord::RK_MacroDefinition: 772*bdd1243dSDimitry Andric serializeMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record)); 773*bdd1243dSDimitry Andric break; 774*bdd1243dSDimitry Andric case APIRecord::RK_Typedef: 775*bdd1243dSDimitry Andric serializeTypedefRecord(*cast<TypedefRecord>(Record)); 776*bdd1243dSDimitry Andric break; 777*bdd1243dSDimitry Andric default: 778*bdd1243dSDimitry Andric if (auto Obj = serializeAPIRecord(*Record)) { 779*bdd1243dSDimitry Andric Symbols.emplace_back(std::move(*Obj)); 780*bdd1243dSDimitry Andric auto &ParentInformation = Record->ParentInformation; 781*bdd1243dSDimitry Andric if (!ParentInformation.empty()) 782*bdd1243dSDimitry Andric serializeRelationship(RelationshipKind::MemberOf, *Record, 783*bdd1243dSDimitry Andric *ParentInformation.ParentRecord); 784*bdd1243dSDimitry Andric } 785*bdd1243dSDimitry Andric break; 786*bdd1243dSDimitry Andric } 787*bdd1243dSDimitry Andric } 788*bdd1243dSDimitry Andric 78981ad6265SDimitry Andric void SymbolGraphSerializer::serializeTypedefRecord( 79081ad6265SDimitry Andric const TypedefRecord &Record) { 79181ad6265SDimitry Andric // Typedefs of anonymous types have their entries unified with the underlying 79281ad6265SDimitry Andric // type. 79381ad6265SDimitry Andric bool ShouldDrop = Record.UnderlyingType.Name.empty(); 79481ad6265SDimitry Andric // enums declared with `NS_OPTION` have a named enum and a named typedef, with 79581ad6265SDimitry Andric // the same name 79681ad6265SDimitry Andric ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); 79781ad6265SDimitry Andric if (ShouldDrop) 79881ad6265SDimitry Andric return; 79981ad6265SDimitry Andric 80081ad6265SDimitry Andric auto Typedef = serializeAPIRecord(Record); 80181ad6265SDimitry Andric if (!Typedef) 80281ad6265SDimitry Andric return; 80381ad6265SDimitry Andric 80481ad6265SDimitry Andric (*Typedef)["type"] = Record.UnderlyingType.USR; 80581ad6265SDimitry Andric 80681ad6265SDimitry Andric Symbols.emplace_back(std::move(*Typedef)); 80781ad6265SDimitry Andric } 80881ad6265SDimitry Andric 80981ad6265SDimitry Andric Object SymbolGraphSerializer::serialize() { 81081ad6265SDimitry Andric // Serialize global variables in the API set. 81181ad6265SDimitry Andric for (const auto &GlobalVar : API.getGlobalVariables()) 81281ad6265SDimitry Andric serializeGlobalVariableRecord(*GlobalVar.second); 81381ad6265SDimitry Andric 81481ad6265SDimitry Andric for (const auto &GlobalFunction : API.getGlobalFunctions()) 81581ad6265SDimitry Andric serializeGlobalFunctionRecord(*GlobalFunction.second); 81681ad6265SDimitry Andric 81781ad6265SDimitry Andric // Serialize enum records in the API set. 81881ad6265SDimitry Andric for (const auto &Enum : API.getEnums()) 81981ad6265SDimitry Andric serializeEnumRecord(*Enum.second); 82081ad6265SDimitry Andric 82181ad6265SDimitry Andric // Serialize struct records in the API set. 82281ad6265SDimitry Andric for (const auto &Struct : API.getStructs()) 82381ad6265SDimitry Andric serializeStructRecord(*Struct.second); 82481ad6265SDimitry Andric 82581ad6265SDimitry Andric // Serialize Objective-C interface records in the API set. 82681ad6265SDimitry Andric for (const auto &ObjCInterface : API.getObjCInterfaces()) 82781ad6265SDimitry Andric serializeObjCContainerRecord(*ObjCInterface.second); 82881ad6265SDimitry Andric 82981ad6265SDimitry Andric // Serialize Objective-C protocol records in the API set. 83081ad6265SDimitry Andric for (const auto &ObjCProtocol : API.getObjCProtocols()) 83181ad6265SDimitry Andric serializeObjCContainerRecord(*ObjCProtocol.second); 83281ad6265SDimitry Andric 83381ad6265SDimitry Andric for (const auto &Macro : API.getMacros()) 83481ad6265SDimitry Andric serializeMacroDefinitionRecord(*Macro.second); 83581ad6265SDimitry Andric 83681ad6265SDimitry Andric for (const auto &Typedef : API.getTypedefs()) 83781ad6265SDimitry Andric serializeTypedefRecord(*Typedef.second); 83881ad6265SDimitry Andric 839*bdd1243dSDimitry Andric return serializeCurrentGraph(); 840*bdd1243dSDimitry Andric } 841*bdd1243dSDimitry Andric 842*bdd1243dSDimitry Andric Object SymbolGraphSerializer::serializeCurrentGraph() { 843*bdd1243dSDimitry Andric Object Root; 844*bdd1243dSDimitry Andric serializeObject(Root, "metadata", serializeMetadata()); 845*bdd1243dSDimitry Andric serializeObject(Root, "module", serializeModule()); 846*bdd1243dSDimitry Andric 84781ad6265SDimitry Andric Root["symbols"] = std::move(Symbols); 84881ad6265SDimitry Andric Root["relationships"] = std::move(Relationships); 84981ad6265SDimitry Andric 85081ad6265SDimitry Andric return Root; 85181ad6265SDimitry Andric } 85281ad6265SDimitry Andric 85381ad6265SDimitry Andric void SymbolGraphSerializer::serialize(raw_ostream &os) { 85481ad6265SDimitry Andric Object root = serialize(); 85581ad6265SDimitry Andric if (Options.Compact) 85681ad6265SDimitry Andric os << formatv("{0}", Value(std::move(root))) << "\n"; 85781ad6265SDimitry Andric else 85881ad6265SDimitry Andric os << formatv("{0:2}", Value(std::move(root))) << "\n"; 85981ad6265SDimitry Andric } 860*bdd1243dSDimitry Andric 861*bdd1243dSDimitry Andric std::optional<Object> 862*bdd1243dSDimitry Andric SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, 863*bdd1243dSDimitry Andric const APISet &API) { 864*bdd1243dSDimitry Andric APIRecord *Record = API.findRecordForUSR(USR); 865*bdd1243dSDimitry Andric if (!Record) 866*bdd1243dSDimitry Andric return {}; 867*bdd1243dSDimitry Andric 868*bdd1243dSDimitry Andric Object Root; 869*bdd1243dSDimitry Andric APIIgnoresList EmptyIgnores; 870*bdd1243dSDimitry Andric SymbolGraphSerializer Serializer(API, EmptyIgnores, 871*bdd1243dSDimitry Andric /*Options.Compact*/ {true}, 872*bdd1243dSDimitry Andric /*ShouldRecurse*/ false); 873*bdd1243dSDimitry Andric Serializer.serializeSingleRecord(Record); 874*bdd1243dSDimitry Andric serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph()); 875*bdd1243dSDimitry Andric 876*bdd1243dSDimitry Andric Language Lang = API.getLanguage(); 877*bdd1243dSDimitry Andric serializeArray(Root, "parentContexts", 878*bdd1243dSDimitry Andric generateParentContexts(*Record, API, Lang)); 879*bdd1243dSDimitry Andric 880*bdd1243dSDimitry Andric Array RelatedSymbols; 881*bdd1243dSDimitry Andric 882*bdd1243dSDimitry Andric for (const auto &Fragment : Record->Declaration.getFragments()) { 883*bdd1243dSDimitry Andric // If we don't have a USR there isn't much we can do. 884*bdd1243dSDimitry Andric if (Fragment.PreciseIdentifier.empty()) 885*bdd1243dSDimitry Andric continue; 886*bdd1243dSDimitry Andric 887*bdd1243dSDimitry Andric APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier); 888*bdd1243dSDimitry Andric 889*bdd1243dSDimitry Andric // If we can't find the record let's skip. 890*bdd1243dSDimitry Andric if (!RelatedRecord) 891*bdd1243dSDimitry Andric continue; 892*bdd1243dSDimitry Andric 893*bdd1243dSDimitry Andric Object RelatedSymbol; 894*bdd1243dSDimitry Andric RelatedSymbol["usr"] = RelatedRecord->USR; 895*bdd1243dSDimitry Andric RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); 896*bdd1243dSDimitry Andric // TODO: once we record this properly let's serialize it right. 897*bdd1243dSDimitry Andric RelatedSymbol["accessLevel"] = "public"; 898*bdd1243dSDimitry Andric RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); 899*bdd1243dSDimitry Andric RelatedSymbol["moduleName"] = API.ProductName; 900*bdd1243dSDimitry Andric RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; 901*bdd1243dSDimitry Andric 902*bdd1243dSDimitry Andric serializeArray(RelatedSymbol, "parentContexts", 903*bdd1243dSDimitry Andric generateParentContexts(*RelatedRecord, API, Lang)); 904*bdd1243dSDimitry Andric RelatedSymbols.push_back(std::move(RelatedSymbol)); 905*bdd1243dSDimitry Andric } 906*bdd1243dSDimitry Andric 907*bdd1243dSDimitry Andric serializeArray(Root, "relatedSymbols", RelatedSymbols); 908*bdd1243dSDimitry Andric return Root; 909*bdd1243dSDimitry Andric } 910