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" 1589f6b26fSZixu Wang #include "clang/Basic/Version.h" 1689f6b26fSZixu Wang #include "clang/ExtractAPI/API.h" 1780ae3665SDaniel Grumberg #include "clang/ExtractAPI/DeclarationFragments.h" 1889f6b26fSZixu Wang #include "llvm/Support/JSON.h" 1989f6b26fSZixu Wang #include "llvm/Support/Path.h" 2089f6b26fSZixu Wang #include "llvm/Support/VersionTuple.h" 21236b6a0eSDaniel Grumberg #include <type_traits> 2289f6b26fSZixu Wang 2389f6b26fSZixu Wang using namespace clang; 2489f6b26fSZixu Wang using namespace clang::extractapi; 2589f6b26fSZixu Wang using namespace llvm; 2689f6b26fSZixu Wang using namespace llvm::json; 2789f6b26fSZixu Wang 2889f6b26fSZixu Wang namespace { 2989f6b26fSZixu Wang 3089f6b26fSZixu Wang /// Helper function to inject a JSON object \p Obj into another object \p Paren 3189f6b26fSZixu Wang /// at position \p Key. 3289f6b26fSZixu Wang void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) { 3389f6b26fSZixu Wang if (Obj) 3489f6b26fSZixu Wang Paren[Key] = std::move(Obj.getValue()); 3589f6b26fSZixu Wang } 3689f6b26fSZixu Wang 3789f6b26fSZixu Wang /// Helper function to inject a JSON array \p Array into object \p Paren at 3889f6b26fSZixu Wang /// position \p Key. 3989f6b26fSZixu Wang void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) { 4089f6b26fSZixu Wang if (Array) 4189f6b26fSZixu Wang Paren[Key] = std::move(Array.getValue()); 4289f6b26fSZixu Wang } 4389f6b26fSZixu Wang 4489f6b26fSZixu Wang /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 4589f6b26fSZixu Wang /// format. 4689f6b26fSZixu Wang /// 4789f6b26fSZixu Wang /// A semantic version object contains three numeric fields, representing the 4889f6b26fSZixu Wang /// \c major, \c minor, and \c patch parts of the version tuple. 4989f6b26fSZixu Wang /// For example version tuple 1.0.3 is serialized as: 5089f6b26fSZixu Wang /// \code 5189f6b26fSZixu Wang /// { 5289f6b26fSZixu Wang /// "major" : 1, 5389f6b26fSZixu Wang /// "minor" : 0, 5489f6b26fSZixu Wang /// "patch" : 3 5589f6b26fSZixu Wang /// } 5689f6b26fSZixu Wang /// \endcode 5789f6b26fSZixu Wang /// 5889f6b26fSZixu Wang /// \returns \c None if the version \p V is empty, or an \c Object containing 5989f6b26fSZixu Wang /// the semantic version representation of \p V. 6089f6b26fSZixu Wang Optional<Object> serializeSemanticVersion(const VersionTuple &V) { 6189f6b26fSZixu Wang if (V.empty()) 6289f6b26fSZixu Wang return None; 6389f6b26fSZixu Wang 6489f6b26fSZixu Wang Object Version; 6589f6b26fSZixu Wang Version["major"] = V.getMajor(); 66*06decd0bSKazu Hirata Version["minor"] = V.getMinor().value_or(0); 67*06decd0bSKazu Hirata Version["patch"] = V.getSubminor().value_or(0); 6889f6b26fSZixu Wang return Version; 6989f6b26fSZixu Wang } 7089f6b26fSZixu Wang 7189f6b26fSZixu Wang /// Serialize the OS information in the Symbol Graph platform property. 7289f6b26fSZixu Wang /// 7389f6b26fSZixu Wang /// The OS information in Symbol Graph contains the \c name of the OS, and an 7489f6b26fSZixu Wang /// optional \c minimumVersion semantic version field. 7589f6b26fSZixu Wang Object serializeOperatingSystem(const Triple &T) { 7689f6b26fSZixu Wang Object OS; 7789f6b26fSZixu Wang OS["name"] = T.getOSTypeName(T.getOS()); 7889f6b26fSZixu Wang serializeObject(OS, "minimumVersion", 7989f6b26fSZixu Wang serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 8089f6b26fSZixu Wang return OS; 8189f6b26fSZixu Wang } 8289f6b26fSZixu Wang 8389f6b26fSZixu Wang /// Serialize the platform information in the Symbol Graph module section. 8489f6b26fSZixu Wang /// 8589f6b26fSZixu Wang /// The platform object describes a target platform triple in corresponding 8689f6b26fSZixu Wang /// three fields: \c architecture, \c vendor, and \c operatingSystem. 8789f6b26fSZixu Wang Object serializePlatform(const Triple &T) { 8889f6b26fSZixu Wang Object Platform; 8989f6b26fSZixu Wang Platform["architecture"] = T.getArchName(); 9089f6b26fSZixu Wang Platform["vendor"] = T.getVendorName(); 9189f6b26fSZixu Wang Platform["operatingSystem"] = serializeOperatingSystem(T); 9289f6b26fSZixu Wang return Platform; 9389f6b26fSZixu Wang } 9489f6b26fSZixu Wang 9528d79314SDaniel Grumberg /// Serialize a source position. 9628d79314SDaniel Grumberg Object serializeSourcePosition(const PresumedLoc &Loc) { 9789f6b26fSZixu Wang assert(Loc.isValid() && "invalid source position"); 9889f6b26fSZixu Wang 9989f6b26fSZixu Wang Object SourcePosition; 10089f6b26fSZixu Wang SourcePosition["line"] = Loc.getLine(); 10189f6b26fSZixu Wang SourcePosition["character"] = Loc.getColumn(); 10289f6b26fSZixu Wang 10328d79314SDaniel Grumberg return SourcePosition; 10428d79314SDaniel Grumberg } 10528d79314SDaniel Grumberg 10628d79314SDaniel Grumberg /// Serialize a source location in file. 10728d79314SDaniel Grumberg /// 10828d79314SDaniel Grumberg /// \param Loc The presumed location to serialize. 10928d79314SDaniel Grumberg /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 11028d79314SDaniel Grumberg /// Defaults to false. 11128d79314SDaniel Grumberg Object serializeSourceLocation(const PresumedLoc &Loc, 11228d79314SDaniel Grumberg bool IncludeFileURI = false) { 11328d79314SDaniel Grumberg Object SourceLocation; 11428d79314SDaniel Grumberg serializeObject(SourceLocation, "position", serializeSourcePosition(Loc)); 11528d79314SDaniel Grumberg 11689f6b26fSZixu Wang if (IncludeFileURI) { 11789f6b26fSZixu Wang std::string FileURI = "file://"; 11889f6b26fSZixu Wang // Normalize file path to use forward slashes for the URI. 11989f6b26fSZixu Wang FileURI += sys::path::convert_to_slash(Loc.getFilename()); 12028d79314SDaniel Grumberg SourceLocation["uri"] = FileURI; 12189f6b26fSZixu Wang } 12289f6b26fSZixu Wang 12328d79314SDaniel Grumberg return SourceLocation; 12489f6b26fSZixu Wang } 12589f6b26fSZixu Wang 12689f6b26fSZixu Wang /// Serialize a source range with begin and end locations. 12789f6b26fSZixu Wang Object serializeSourceRange(const PresumedLoc &BeginLoc, 12889f6b26fSZixu Wang const PresumedLoc &EndLoc) { 12989f6b26fSZixu Wang Object SourceRange; 13089f6b26fSZixu Wang serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 13189f6b26fSZixu Wang serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 13289f6b26fSZixu Wang return SourceRange; 13389f6b26fSZixu Wang } 13489f6b26fSZixu Wang 13589f6b26fSZixu Wang /// Serialize the availability attributes of a symbol. 13689f6b26fSZixu Wang /// 13789f6b26fSZixu Wang /// Availability information contains the introduced, deprecated, and obsoleted 13889f6b26fSZixu Wang /// versions of the symbol as semantic versions, if not default. 13989f6b26fSZixu Wang /// Availability information also contains flags to indicate if the symbol is 14089f6b26fSZixu Wang /// unconditionally unavailable or deprecated, 14189f6b26fSZixu Wang /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). 14289f6b26fSZixu Wang /// 14389f6b26fSZixu Wang /// \returns \c None if the symbol has default availability attributes, or 14489f6b26fSZixu Wang /// an \c Object containing the formatted availability information. 14589f6b26fSZixu Wang Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) { 14689f6b26fSZixu Wang if (Avail.isDefault()) 14789f6b26fSZixu Wang return None; 14889f6b26fSZixu Wang 14989f6b26fSZixu Wang Object Availbility; 15089f6b26fSZixu Wang serializeObject(Availbility, "introducedVersion", 15189f6b26fSZixu Wang serializeSemanticVersion(Avail.Introduced)); 15289f6b26fSZixu Wang serializeObject(Availbility, "deprecatedVersion", 15389f6b26fSZixu Wang serializeSemanticVersion(Avail.Deprecated)); 15489f6b26fSZixu Wang serializeObject(Availbility, "obsoletedVersion", 15589f6b26fSZixu Wang serializeSemanticVersion(Avail.Obsoleted)); 15689f6b26fSZixu Wang if (Avail.isUnavailable()) 15789f6b26fSZixu Wang Availbility["isUnconditionallyUnavailable"] = true; 15889f6b26fSZixu Wang if (Avail.isUnconditionallyDeprecated()) 15989f6b26fSZixu Wang Availbility["isUnconditionallyDeprecated"] = true; 16089f6b26fSZixu Wang 16189f6b26fSZixu Wang return Availbility; 16289f6b26fSZixu Wang } 16389f6b26fSZixu Wang 16415bf0e56SZixu Wang /// Get the language name string for interface language references. 16515bf0e56SZixu Wang StringRef getLanguageName(Language Lang) { 16615bf0e56SZixu Wang switch (Lang) { 16789f6b26fSZixu Wang case Language::C: 16889f6b26fSZixu Wang return "c"; 16989f6b26fSZixu Wang case Language::ObjC: 170b62d4021SZixu Wang return "objective-c"; 17189f6b26fSZixu Wang 17289f6b26fSZixu Wang // Unsupported language currently 17389f6b26fSZixu Wang case Language::CXX: 17489f6b26fSZixu Wang case Language::ObjCXX: 17589f6b26fSZixu Wang case Language::OpenCL: 17689f6b26fSZixu Wang case Language::OpenCLCXX: 17789f6b26fSZixu Wang case Language::CUDA: 17889f6b26fSZixu Wang case Language::RenderScript: 17989f6b26fSZixu Wang case Language::HIP: 180d394f9f8SChris Bieneman case Language::HLSL: 18189f6b26fSZixu Wang 18289f6b26fSZixu Wang // Languages that the frontend cannot parse and compile 18389f6b26fSZixu Wang case Language::Unknown: 18489f6b26fSZixu Wang case Language::Asm: 18589f6b26fSZixu Wang case Language::LLVM_IR: 18689f6b26fSZixu Wang llvm_unreachable("Unsupported language kind"); 18789f6b26fSZixu Wang } 18889f6b26fSZixu Wang 18989f6b26fSZixu Wang llvm_unreachable("Unhandled language kind"); 19089f6b26fSZixu Wang } 19189f6b26fSZixu Wang 19289f6b26fSZixu Wang /// Serialize the identifier object as specified by the Symbol Graph format. 19389f6b26fSZixu Wang /// 19489f6b26fSZixu Wang /// The identifier property of a symbol contains the USR for precise and unique 19589f6b26fSZixu Wang /// references, and the interface language name. 19615bf0e56SZixu Wang Object serializeIdentifier(const APIRecord &Record, Language Lang) { 19789f6b26fSZixu Wang Object Identifier; 19889f6b26fSZixu Wang Identifier["precise"] = Record.USR; 19915bf0e56SZixu Wang Identifier["interfaceLanguage"] = getLanguageName(Lang); 20089f6b26fSZixu Wang 20189f6b26fSZixu Wang return Identifier; 20289f6b26fSZixu Wang } 20389f6b26fSZixu Wang 20489f6b26fSZixu Wang /// Serialize the documentation comments attached to a symbol, as specified by 20589f6b26fSZixu Wang /// the Symbol Graph format. 20689f6b26fSZixu Wang /// 20789f6b26fSZixu Wang /// The Symbol Graph \c docComment object contains an array of lines. Each line 20889f6b26fSZixu Wang /// represents one line of striped documentation comment, with source range 20989f6b26fSZixu Wang /// information. 21089f6b26fSZixu Wang /// e.g. 21189f6b26fSZixu Wang /// \code 21289f6b26fSZixu Wang /// /// This is a documentation comment 21389f6b26fSZixu Wang /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 21489f6b26fSZixu Wang /// /// with multiple lines. 21589f6b26fSZixu Wang /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 21689f6b26fSZixu Wang /// \endcode 21789f6b26fSZixu Wang /// 21889f6b26fSZixu Wang /// \returns \c None if \p Comment is empty, or an \c Object containing the 21989f6b26fSZixu Wang /// formatted lines. 22089f6b26fSZixu Wang Optional<Object> serializeDocComment(const DocComment &Comment) { 22189f6b26fSZixu Wang if (Comment.empty()) 22289f6b26fSZixu Wang return None; 22389f6b26fSZixu Wang 22489f6b26fSZixu Wang Object DocComment; 22589f6b26fSZixu Wang Array LinesArray; 22689f6b26fSZixu Wang for (const auto &CommentLine : Comment) { 22789f6b26fSZixu Wang Object Line; 22889f6b26fSZixu Wang Line["text"] = CommentLine.Text; 22989f6b26fSZixu Wang serializeObject(Line, "range", 23089f6b26fSZixu Wang serializeSourceRange(CommentLine.Begin, CommentLine.End)); 23189f6b26fSZixu Wang LinesArray.emplace_back(std::move(Line)); 23289f6b26fSZixu Wang } 23389f6b26fSZixu Wang serializeArray(DocComment, "lines", LinesArray); 23489f6b26fSZixu Wang 23589f6b26fSZixu Wang return DocComment; 23689f6b26fSZixu Wang } 23789f6b26fSZixu Wang 23889f6b26fSZixu Wang /// Serialize the declaration fragments of a symbol. 23989f6b26fSZixu Wang /// 24089f6b26fSZixu Wang /// The Symbol Graph declaration fragments is an array of tagged important 24189f6b26fSZixu Wang /// parts of a symbol's declaration. The fragments sequence can be joined to 24289f6b26fSZixu Wang /// form spans of declaration text, with attached information useful for 24389f6b26fSZixu Wang /// purposes like syntax-highlighting etc. For example: 24489f6b26fSZixu Wang /// \code 24589f6b26fSZixu Wang /// const int pi; -> "declarationFragments" : [ 24689f6b26fSZixu Wang /// { 24789f6b26fSZixu Wang /// "kind" : "keyword", 24889f6b26fSZixu Wang /// "spelling" : "const" 24989f6b26fSZixu Wang /// }, 25089f6b26fSZixu Wang /// { 25189f6b26fSZixu Wang /// "kind" : "text", 25289f6b26fSZixu Wang /// "spelling" : " " 25389f6b26fSZixu Wang /// }, 25489f6b26fSZixu Wang /// { 25589f6b26fSZixu Wang /// "kind" : "typeIdentifier", 25689f6b26fSZixu Wang /// "preciseIdentifier" : "c:I", 25789f6b26fSZixu Wang /// "spelling" : "int" 25889f6b26fSZixu Wang /// }, 25989f6b26fSZixu Wang /// { 26089f6b26fSZixu Wang /// "kind" : "text", 26189f6b26fSZixu Wang /// "spelling" : " " 26289f6b26fSZixu Wang /// }, 26389f6b26fSZixu Wang /// { 26489f6b26fSZixu Wang /// "kind" : "identifier", 26589f6b26fSZixu Wang /// "spelling" : "pi" 26689f6b26fSZixu Wang /// } 26789f6b26fSZixu Wang /// ] 26889f6b26fSZixu Wang /// \endcode 26989f6b26fSZixu Wang /// 27089f6b26fSZixu Wang /// \returns \c None if \p DF is empty, or an \c Array containing the formatted 27189f6b26fSZixu Wang /// declaration fragments array. 27289f6b26fSZixu Wang Optional<Array> serializeDeclarationFragments(const DeclarationFragments &DF) { 27389f6b26fSZixu Wang if (DF.getFragments().empty()) 27489f6b26fSZixu Wang return None; 27589f6b26fSZixu Wang 27689f6b26fSZixu Wang Array Fragments; 27789f6b26fSZixu Wang for (const auto &F : DF.getFragments()) { 27889f6b26fSZixu Wang Object Fragment; 27989f6b26fSZixu Wang Fragment["spelling"] = F.Spelling; 28089f6b26fSZixu Wang Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 28189f6b26fSZixu Wang if (!F.PreciseIdentifier.empty()) 28289f6b26fSZixu Wang Fragment["preciseIdentifier"] = F.PreciseIdentifier; 28389f6b26fSZixu Wang Fragments.emplace_back(std::move(Fragment)); 28489f6b26fSZixu Wang } 28589f6b26fSZixu Wang 28689f6b26fSZixu Wang return Fragments; 28789f6b26fSZixu Wang } 28889f6b26fSZixu Wang 28989f6b26fSZixu Wang /// Serialize the \c names field of a symbol as specified by the Symbol Graph 29089f6b26fSZixu Wang /// format. 29189f6b26fSZixu Wang /// 29289f6b26fSZixu Wang /// The Symbol Graph names field contains multiple representations of a symbol 29389f6b26fSZixu Wang /// that can be used for different applications: 29489f6b26fSZixu Wang /// - \c title : The simple declared name of the symbol; 29589f6b26fSZixu Wang /// - \c subHeading : An array of declaration fragments that provides tags, 29689f6b26fSZixu Wang /// and potentially more tokens (for example the \c +/- symbol for 29789f6b26fSZixu Wang /// Objective-C methods). Can be used as sub-headings for documentation. 29889f6b26fSZixu Wang Object serializeNames(const APIRecord &Record) { 29989f6b26fSZixu Wang Object Names; 30089f6b26fSZixu Wang Names["title"] = Record.Name; 30189f6b26fSZixu Wang serializeArray(Names, "subHeading", 30289f6b26fSZixu Wang serializeDeclarationFragments(Record.SubHeading)); 30380ae3665SDaniel Grumberg DeclarationFragments NavigatorFragments; 30480ae3665SDaniel Grumberg NavigatorFragments.append(Record.Name, 30580ae3665SDaniel Grumberg DeclarationFragments::FragmentKind::Identifier, 30680ae3665SDaniel Grumberg /*PreciseIdentifier*/ ""); 30780ae3665SDaniel Grumberg serializeArray(Names, "navigator", 30880ae3665SDaniel Grumberg serializeDeclarationFragments(NavigatorFragments)); 30989f6b26fSZixu Wang 31089f6b26fSZixu Wang return Names; 31189f6b26fSZixu Wang } 31289f6b26fSZixu Wang 31389f6b26fSZixu Wang /// Serialize the symbol kind information. 31489f6b26fSZixu Wang /// 31589f6b26fSZixu Wang /// The Symbol Graph symbol kind property contains a shorthand \c identifier 31689f6b26fSZixu Wang /// which is prefixed by the source language name, useful for tooling to parse 31789f6b26fSZixu Wang /// the kind, and a \c displayName for rendering human-readable names. 31815bf0e56SZixu Wang Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 31915bf0e56SZixu Wang auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 32015bf0e56SZixu Wang return (getLanguageName(Lang) + "." + S).str(); 32171b4c226SZixu Wang }; 32271b4c226SZixu Wang 32389f6b26fSZixu Wang Object Kind; 32489f6b26fSZixu Wang switch (Record.getKind()) { 325236b6a0eSDaniel Grumberg case APIRecord::RK_GlobalFunction: 32671b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("func"); 32789f6b26fSZixu Wang Kind["displayName"] = "Function"; 32889f6b26fSZixu Wang break; 329236b6a0eSDaniel Grumberg case APIRecord::RK_GlobalVariable: 33071b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("var"); 33189f6b26fSZixu Wang Kind["displayName"] = "Global Variable"; 33289f6b26fSZixu Wang break; 33371b4c226SZixu Wang case APIRecord::RK_EnumConstant: 33471b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("enum.case"); 33571b4c226SZixu Wang Kind["displayName"] = "Enumeration Case"; 33671b4c226SZixu Wang break; 33771b4c226SZixu Wang case APIRecord::RK_Enum: 33871b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("enum"); 33971b4c226SZixu Wang Kind["displayName"] = "Enumeration"; 34071b4c226SZixu Wang break; 3415bb5704cSZixu Wang case APIRecord::RK_StructField: 3425bb5704cSZixu Wang Kind["identifier"] = AddLangPrefix("property"); 3435bb5704cSZixu Wang Kind["displayName"] = "Instance Property"; 3445bb5704cSZixu Wang break; 3455bb5704cSZixu Wang case APIRecord::RK_Struct: 3465bb5704cSZixu Wang Kind["identifier"] = AddLangPrefix("struct"); 3475bb5704cSZixu Wang Kind["displayName"] = "Structure"; 3485bb5704cSZixu Wang break; 3499b36e126SZixu Wang case APIRecord::RK_ObjCIvar: 3509b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("ivar"); 3519b36e126SZixu Wang Kind["displayName"] = "Instance Variable"; 3529b36e126SZixu Wang break; 3539b36e126SZixu Wang case APIRecord::RK_ObjCMethod: 3549b36e126SZixu Wang if (dyn_cast<ObjCMethodRecord>(&Record)->IsInstanceMethod) { 3559b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("method"); 3569b36e126SZixu Wang Kind["displayName"] = "Instance Method"; 3579b36e126SZixu Wang } else { 3589b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("type.method"); 3599b36e126SZixu Wang Kind["displayName"] = "Type Method"; 3609b36e126SZixu Wang } 3619b36e126SZixu Wang break; 3629b36e126SZixu Wang case APIRecord::RK_ObjCProperty: 3639b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("property"); 3649b36e126SZixu Wang Kind["displayName"] = "Instance Property"; 3659b36e126SZixu Wang break; 3669b36e126SZixu Wang case APIRecord::RK_ObjCInterface: 3679b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("class"); 3689b36e126SZixu Wang Kind["displayName"] = "Class"; 3699b36e126SZixu Wang break; 370178aad9bSZixu Wang case APIRecord::RK_ObjCCategory: 371178aad9bSZixu Wang // We don't serialize out standalone Objective-C category symbols yet. 372178aad9bSZixu Wang llvm_unreachable("Serializing standalone Objective-C category symbols is " 373178aad9bSZixu Wang "not supported."); 374178aad9bSZixu Wang break; 375d1d34bafSZixu Wang case APIRecord::RK_ObjCProtocol: 376d1d34bafSZixu Wang Kind["identifier"] = AddLangPrefix("protocol"); 377d1d34bafSZixu Wang Kind["displayName"] = "Protocol"; 378d1d34bafSZixu Wang break; 379529a0570SDaniel Grumberg case APIRecord::RK_MacroDefinition: 380529a0570SDaniel Grumberg Kind["identifier"] = AddLangPrefix("macro"); 381529a0570SDaniel Grumberg Kind["displayName"] = "Macro"; 3829fc45ca0SDaniel Grumberg break; 3839fc45ca0SDaniel Grumberg case APIRecord::RK_Typedef: 3849fc45ca0SDaniel Grumberg Kind["identifier"] = AddLangPrefix("typealias"); 3859fc45ca0SDaniel Grumberg Kind["displayName"] = "Type Alias"; 3869fc45ca0SDaniel Grumberg break; 38771b4c226SZixu Wang } 38889f6b26fSZixu Wang 38989f6b26fSZixu Wang return Kind; 39089f6b26fSZixu Wang } 39189f6b26fSZixu Wang 392236b6a0eSDaniel Grumberg template <typename RecordTy> 393236b6a0eSDaniel Grumberg Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record, 394236b6a0eSDaniel Grumberg std::true_type) { 395236b6a0eSDaniel Grumberg const auto &FS = Record.Signature; 396236b6a0eSDaniel Grumberg if (FS.empty()) 397236b6a0eSDaniel Grumberg return None; 398236b6a0eSDaniel Grumberg 399236b6a0eSDaniel Grumberg Object Signature; 400236b6a0eSDaniel Grumberg serializeArray(Signature, "returns", 401236b6a0eSDaniel Grumberg serializeDeclarationFragments(FS.getReturnType())); 402236b6a0eSDaniel Grumberg 403236b6a0eSDaniel Grumberg Array Parameters; 404236b6a0eSDaniel Grumberg for (const auto &P : FS.getParameters()) { 405236b6a0eSDaniel Grumberg Object Parameter; 406236b6a0eSDaniel Grumberg Parameter["name"] = P.Name; 407236b6a0eSDaniel Grumberg serializeArray(Parameter, "declarationFragments", 408236b6a0eSDaniel Grumberg serializeDeclarationFragments(P.Fragments)); 409236b6a0eSDaniel Grumberg Parameters.emplace_back(std::move(Parameter)); 410236b6a0eSDaniel Grumberg } 411236b6a0eSDaniel Grumberg 412236b6a0eSDaniel Grumberg if (!Parameters.empty()) 413236b6a0eSDaniel Grumberg Signature["parameters"] = std::move(Parameters); 414236b6a0eSDaniel Grumberg 415236b6a0eSDaniel Grumberg return Signature; 416236b6a0eSDaniel Grumberg } 417236b6a0eSDaniel Grumberg 418236b6a0eSDaniel Grumberg template <typename RecordTy> 419236b6a0eSDaniel Grumberg Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record, 420236b6a0eSDaniel Grumberg std::false_type) { 421236b6a0eSDaniel Grumberg return None; 422236b6a0eSDaniel Grumberg } 423236b6a0eSDaniel Grumberg 424236b6a0eSDaniel Grumberg /// Serialize the function signature field, as specified by the 425236b6a0eSDaniel Grumberg /// Symbol Graph format. 426236b6a0eSDaniel Grumberg /// 427236b6a0eSDaniel Grumberg /// The Symbol Graph function signature property contains two arrays. 428236b6a0eSDaniel Grumberg /// - The \c returns array is the declaration fragments of the return type; 429236b6a0eSDaniel Grumberg /// - The \c parameters array contains names and declaration fragments of the 430236b6a0eSDaniel Grumberg /// parameters. 431236b6a0eSDaniel Grumberg /// 432236b6a0eSDaniel Grumberg /// \returns \c None if \p FS is empty, or an \c Object containing the 433236b6a0eSDaniel Grumberg /// formatted function signature. 434236b6a0eSDaniel Grumberg template <typename RecordTy> 435236b6a0eSDaniel Grumberg void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 436236b6a0eSDaniel Grumberg serializeObject(Paren, "functionSignature", 437236b6a0eSDaniel Grumberg serializeFunctionSignatureMixinImpl( 438236b6a0eSDaniel Grumberg Record, has_function_signature<RecordTy>())); 439236b6a0eSDaniel Grumberg } 440236b6a0eSDaniel Grumberg 44189f6b26fSZixu Wang } // namespace 44289f6b26fSZixu Wang 44389f6b26fSZixu Wang void SymbolGraphSerializer::anchor() {} 44489f6b26fSZixu Wang 44589f6b26fSZixu Wang /// Defines the format version emitted by SymbolGraphSerializer. 44689f6b26fSZixu Wang const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 44789f6b26fSZixu Wang 44889f6b26fSZixu Wang Object SymbolGraphSerializer::serializeMetadata() const { 44989f6b26fSZixu Wang Object Metadata; 45089f6b26fSZixu Wang serializeObject(Metadata, "formatVersion", 45189f6b26fSZixu Wang serializeSemanticVersion(FormatVersion)); 45289f6b26fSZixu Wang Metadata["generator"] = clang::getClangFullVersion(); 45389f6b26fSZixu Wang return Metadata; 45489f6b26fSZixu Wang } 45589f6b26fSZixu Wang 45689f6b26fSZixu Wang Object SymbolGraphSerializer::serializeModule() const { 45789f6b26fSZixu Wang Object Module; 4585ef2ec7eSDaniel Grumberg // The user is expected to always pass `--product-name=` on the command line 4595ef2ec7eSDaniel Grumberg // to populate this field. 4605ef2ec7eSDaniel Grumberg Module["name"] = ProductName; 46189f6b26fSZixu Wang serializeObject(Module, "platform", serializePlatform(API.getTarget())); 46289f6b26fSZixu Wang return Module; 46389f6b26fSZixu Wang } 46489f6b26fSZixu Wang 46589f6b26fSZixu Wang bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { 46689f6b26fSZixu Wang // Skip unconditionally unavailable symbols 46789f6b26fSZixu Wang if (Record.Availability.isUnconditionallyUnavailable()) 46889f6b26fSZixu Wang return true; 46989f6b26fSZixu Wang 470504736ceSDaniel Grumberg // Filter out symbols prefixed with an underscored as they are understood to 471504736ceSDaniel Grumberg // be symbols clients should not use. 472504736ceSDaniel Grumberg if (Record.Name.startswith("_")) 473504736ceSDaniel Grumberg return true; 474504736ceSDaniel Grumberg 47589f6b26fSZixu Wang return false; 47689f6b26fSZixu Wang } 47789f6b26fSZixu Wang 478236b6a0eSDaniel Grumberg template <typename RecordTy> 47989f6b26fSZixu Wang Optional<Object> 480236b6a0eSDaniel Grumberg SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { 48189f6b26fSZixu Wang if (shouldSkip(Record)) 48289f6b26fSZixu Wang return None; 48389f6b26fSZixu Wang 48489f6b26fSZixu Wang Object Obj; 48589f6b26fSZixu Wang serializeObject(Obj, "identifier", 48615bf0e56SZixu Wang serializeIdentifier(Record, API.getLanguage())); 48715bf0e56SZixu Wang serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); 48889f6b26fSZixu Wang serializeObject(Obj, "names", serializeNames(Record)); 48989f6b26fSZixu Wang serializeObject( 49089f6b26fSZixu Wang Obj, "location", 49128d79314SDaniel Grumberg serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); 49289f6b26fSZixu Wang serializeObject(Obj, "availbility", 49389f6b26fSZixu Wang serializeAvailability(Record.Availability)); 49489f6b26fSZixu Wang serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); 49589f6b26fSZixu Wang serializeArray(Obj, "declarationFragments", 49689f6b26fSZixu Wang serializeDeclarationFragments(Record.Declaration)); 49728d79314SDaniel Grumberg // TODO: Once we keep track of symbol access information serialize it 49828d79314SDaniel Grumberg // correctly here. 49928d79314SDaniel Grumberg Obj["accessLevel"] = "public"; 50028d79314SDaniel Grumberg serializeArray(Obj, "pathComponents", Array(PathComponents)); 50189f6b26fSZixu Wang 502236b6a0eSDaniel Grumberg serializeFunctionSignatureMixin(Obj, Record); 503236b6a0eSDaniel Grumberg 50489f6b26fSZixu Wang return Obj; 50589f6b26fSZixu Wang } 50689f6b26fSZixu Wang 507178aad9bSZixu Wang template <typename MemberTy> 508178aad9bSZixu Wang void SymbolGraphSerializer::serializeMembers( 509178aad9bSZixu Wang const APIRecord &Record, 510178aad9bSZixu Wang const SmallVector<std::unique_ptr<MemberTy>> &Members) { 511178aad9bSZixu Wang for (const auto &Member : Members) { 512178aad9bSZixu Wang auto MemberPathComponentGuard = makePathComponentGuard(Member->Name); 513178aad9bSZixu Wang auto MemberRecord = serializeAPIRecord(*Member); 514178aad9bSZixu Wang if (!MemberRecord) 515178aad9bSZixu Wang continue; 516178aad9bSZixu Wang 517178aad9bSZixu Wang Symbols.emplace_back(std::move(*MemberRecord)); 518178aad9bSZixu Wang serializeRelationship(RelationshipKind::MemberOf, *Member, Record); 519178aad9bSZixu Wang } 520178aad9bSZixu Wang } 521178aad9bSZixu Wang 52271b4c226SZixu Wang StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 52371b4c226SZixu Wang switch (Kind) { 52471b4c226SZixu Wang case RelationshipKind::MemberOf: 52571b4c226SZixu Wang return "memberOf"; 5269b36e126SZixu Wang case RelationshipKind::InheritsFrom: 5279b36e126SZixu Wang return "inheritsFrom"; 5289b36e126SZixu Wang case RelationshipKind::ConformsTo: 5299b36e126SZixu Wang return "conformsTo"; 53071b4c226SZixu Wang } 53171b4c226SZixu Wang llvm_unreachable("Unhandled relationship kind"); 53271b4c226SZixu Wang } 53371b4c226SZixu Wang 53471b4c226SZixu Wang void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 5359b36e126SZixu Wang SymbolReference Source, 5369b36e126SZixu Wang SymbolReference Target) { 53771b4c226SZixu Wang Object Relationship; 53871b4c226SZixu Wang Relationship["source"] = Source.USR; 53971b4c226SZixu Wang Relationship["target"] = Target.USR; 54071b4c226SZixu Wang Relationship["kind"] = getRelationshipString(Kind); 54171b4c226SZixu Wang 54271b4c226SZixu Wang Relationships.emplace_back(std::move(Relationship)); 54371b4c226SZixu Wang } 54471b4c226SZixu Wang 545236b6a0eSDaniel Grumberg void SymbolGraphSerializer::serializeGlobalFunctionRecord( 546236b6a0eSDaniel Grumberg const GlobalFunctionRecord &Record) { 54728d79314SDaniel Grumberg auto GlobalPathComponentGuard = makePathComponentGuard(Record.Name); 54828d79314SDaniel Grumberg 54989f6b26fSZixu Wang auto Obj = serializeAPIRecord(Record); 55089f6b26fSZixu Wang if (!Obj) 55189f6b26fSZixu Wang return; 55289f6b26fSZixu Wang 553236b6a0eSDaniel Grumberg Symbols.emplace_back(std::move(*Obj)); 554236b6a0eSDaniel Grumberg } 555236b6a0eSDaniel Grumberg 556236b6a0eSDaniel Grumberg void SymbolGraphSerializer::serializeGlobalVariableRecord( 557236b6a0eSDaniel Grumberg const GlobalVariableRecord &Record) { 558236b6a0eSDaniel Grumberg auto GlobalPathComponentGuard = makePathComponentGuard(Record.Name); 559236b6a0eSDaniel Grumberg 560236b6a0eSDaniel Grumberg auto Obj = serializeAPIRecord(Record); 561236b6a0eSDaniel Grumberg if (!Obj) 562236b6a0eSDaniel Grumberg return; 56389f6b26fSZixu Wang 56489f6b26fSZixu Wang Symbols.emplace_back(std::move(*Obj)); 56589f6b26fSZixu Wang } 56689f6b26fSZixu Wang 56771b4c226SZixu Wang void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) { 56828d79314SDaniel Grumberg auto EnumPathComponentGuard = makePathComponentGuard(Record.Name); 56971b4c226SZixu Wang auto Enum = serializeAPIRecord(Record); 57071b4c226SZixu Wang if (!Enum) 57171b4c226SZixu Wang return; 57271b4c226SZixu Wang 57371b4c226SZixu Wang Symbols.emplace_back(std::move(*Enum)); 574178aad9bSZixu Wang serializeMembers(Record, Record.Constants); 57571b4c226SZixu Wang } 57671b4c226SZixu Wang 5775bb5704cSZixu Wang void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) { 57828d79314SDaniel Grumberg auto StructPathComponentGuard = makePathComponentGuard(Record.Name); 5795bb5704cSZixu Wang auto Struct = serializeAPIRecord(Record); 5805bb5704cSZixu Wang if (!Struct) 5815bb5704cSZixu Wang return; 5825bb5704cSZixu Wang 5835bb5704cSZixu Wang Symbols.emplace_back(std::move(*Struct)); 584178aad9bSZixu Wang serializeMembers(Record, Record.Fields); 5855bb5704cSZixu Wang } 5865bb5704cSZixu Wang 5879b36e126SZixu Wang void SymbolGraphSerializer::serializeObjCContainerRecord( 5889b36e126SZixu Wang const ObjCContainerRecord &Record) { 58928d79314SDaniel Grumberg auto ObjCContainerPathComponentGuard = makePathComponentGuard(Record.Name); 5909b36e126SZixu Wang auto ObjCContainer = serializeAPIRecord(Record); 5919b36e126SZixu Wang if (!ObjCContainer) 5929b36e126SZixu Wang return; 5939b36e126SZixu Wang 5949b36e126SZixu Wang Symbols.emplace_back(std::move(*ObjCContainer)); 5959b36e126SZixu Wang 596178aad9bSZixu Wang serializeMembers(Record, Record.Ivars); 597178aad9bSZixu Wang serializeMembers(Record, Record.Methods); 598178aad9bSZixu Wang serializeMembers(Record, Record.Properties); 5999b36e126SZixu Wang 6009b36e126SZixu Wang for (const auto &Protocol : Record.Protocols) 6019b36e126SZixu Wang // Record that Record conforms to Protocol. 6029b36e126SZixu Wang serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 6039b36e126SZixu Wang 604178aad9bSZixu Wang if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) { 6059b36e126SZixu Wang if (!ObjCInterface->SuperClass.empty()) 6069b36e126SZixu Wang // If Record is an Objective-C interface record and it has a super class, 6079b36e126SZixu Wang // record that Record is inherited from SuperClass. 6089b36e126SZixu Wang serializeRelationship(RelationshipKind::InheritsFrom, Record, 6099b36e126SZixu Wang ObjCInterface->SuperClass); 610178aad9bSZixu Wang 611178aad9bSZixu Wang // Members of categories extending an interface are serialized as members of 612178aad9bSZixu Wang // the interface. 613178aad9bSZixu Wang for (const auto *Category : ObjCInterface->Categories) { 614178aad9bSZixu Wang serializeMembers(Record, Category->Ivars); 615178aad9bSZixu Wang serializeMembers(Record, Category->Methods); 616178aad9bSZixu Wang serializeMembers(Record, Category->Properties); 617178aad9bSZixu Wang 618178aad9bSZixu Wang // Surface the protocols of the the category to the interface. 619178aad9bSZixu Wang for (const auto &Protocol : Category->Protocols) 620178aad9bSZixu Wang serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 621178aad9bSZixu Wang } 622178aad9bSZixu Wang } 6239b36e126SZixu Wang } 6249b36e126SZixu Wang 625529a0570SDaniel Grumberg void SymbolGraphSerializer::serializeMacroDefinitionRecord( 626529a0570SDaniel Grumberg const MacroDefinitionRecord &Record) { 62728d79314SDaniel Grumberg auto MacroPathComponentGuard = makePathComponentGuard(Record.Name); 628529a0570SDaniel Grumberg auto Macro = serializeAPIRecord(Record); 62928d79314SDaniel Grumberg 630529a0570SDaniel Grumberg if (!Macro) 631529a0570SDaniel Grumberg return; 632529a0570SDaniel Grumberg 633529a0570SDaniel Grumberg Symbols.emplace_back(std::move(*Macro)); 634529a0570SDaniel Grumberg } 635529a0570SDaniel Grumberg 6369fc45ca0SDaniel Grumberg void SymbolGraphSerializer::serializeTypedefRecord( 6379fc45ca0SDaniel Grumberg const TypedefRecord &Record) { 6389fc45ca0SDaniel Grumberg // Typedefs of anonymous types have their entries unified with the underlying 6399fc45ca0SDaniel Grumberg // type. 6409fc45ca0SDaniel Grumberg bool ShouldDrop = Record.UnderlyingType.Name.empty(); 6419fc45ca0SDaniel Grumberg // enums declared with `NS_OPTION` have a named enum and a named typedef, with 6429fc45ca0SDaniel Grumberg // the same name 6439fc45ca0SDaniel Grumberg ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); 6449fc45ca0SDaniel Grumberg if (ShouldDrop) 6459fc45ca0SDaniel Grumberg return; 6469fc45ca0SDaniel Grumberg 6479fc45ca0SDaniel Grumberg auto TypedefPathComponentGuard = makePathComponentGuard(Record.Name); 6489fc45ca0SDaniel Grumberg auto Typedef = serializeAPIRecord(Record); 6499fc45ca0SDaniel Grumberg if (!Typedef) 6509fc45ca0SDaniel Grumberg return; 6519fc45ca0SDaniel Grumberg 6529fc45ca0SDaniel Grumberg (*Typedef)["type"] = Record.UnderlyingType.USR; 6539fc45ca0SDaniel Grumberg 6549fc45ca0SDaniel Grumberg Symbols.emplace_back(std::move(*Typedef)); 6559fc45ca0SDaniel Grumberg } 6569fc45ca0SDaniel Grumberg 65728d79314SDaniel Grumberg SymbolGraphSerializer::PathComponentGuard 65828d79314SDaniel Grumberg SymbolGraphSerializer::makePathComponentGuard(StringRef Component) { 65928d79314SDaniel Grumberg return PathComponentGuard(PathComponents, Component); 66028d79314SDaniel Grumberg } 66128d79314SDaniel Grumberg 66289f6b26fSZixu Wang Object SymbolGraphSerializer::serialize() { 66389f6b26fSZixu Wang Object Root; 66489f6b26fSZixu Wang serializeObject(Root, "metadata", serializeMetadata()); 66589f6b26fSZixu Wang serializeObject(Root, "module", serializeModule()); 66689f6b26fSZixu Wang 667236b6a0eSDaniel Grumberg // Serialize global variables in the API set. 668236b6a0eSDaniel Grumberg for (const auto &GlobalVar : API.getGlobalVariables()) 669236b6a0eSDaniel Grumberg serializeGlobalVariableRecord(*GlobalVar.second); 670236b6a0eSDaniel Grumberg 671236b6a0eSDaniel Grumberg for (const auto &GlobalFunction : API.getGlobalFunctions()) 672236b6a0eSDaniel Grumberg serializeGlobalFunctionRecord(*GlobalFunction.second); 67389f6b26fSZixu Wang 67471b4c226SZixu Wang // Serialize enum records in the API set. 67571b4c226SZixu Wang for (const auto &Enum : API.getEnums()) 67671b4c226SZixu Wang serializeEnumRecord(*Enum.second); 67771b4c226SZixu Wang 6785bb5704cSZixu Wang // Serialize struct records in the API set. 6795bb5704cSZixu Wang for (const auto &Struct : API.getStructs()) 6805bb5704cSZixu Wang serializeStructRecord(*Struct.second); 6815bb5704cSZixu Wang 6829b36e126SZixu Wang // Serialize Objective-C interface records in the API set. 6839b36e126SZixu Wang for (const auto &ObjCInterface : API.getObjCInterfaces()) 6849b36e126SZixu Wang serializeObjCContainerRecord(*ObjCInterface.second); 6859b36e126SZixu Wang 686d1d34bafSZixu Wang // Serialize Objective-C protocol records in the API set. 687d1d34bafSZixu Wang for (const auto &ObjCProtocol : API.getObjCProtocols()) 688d1d34bafSZixu Wang serializeObjCContainerRecord(*ObjCProtocol.second); 689d1d34bafSZixu Wang 690529a0570SDaniel Grumberg for (const auto &Macro : API.getMacros()) 691529a0570SDaniel Grumberg serializeMacroDefinitionRecord(*Macro.second); 692529a0570SDaniel Grumberg 6939fc45ca0SDaniel Grumberg for (const auto &Typedef : API.getTypedefs()) 6949fc45ca0SDaniel Grumberg serializeTypedefRecord(*Typedef.second); 6959fc45ca0SDaniel Grumberg 69689f6b26fSZixu Wang Root["symbols"] = std::move(Symbols); 69728d79314SDaniel Grumberg Root["relationships"] = std::move(Relationships); 69889f6b26fSZixu Wang 69989f6b26fSZixu Wang return Root; 70089f6b26fSZixu Wang } 70189f6b26fSZixu Wang 70289f6b26fSZixu Wang void SymbolGraphSerializer::serialize(raw_ostream &os) { 70389f6b26fSZixu Wang Object root = serialize(); 70489f6b26fSZixu Wang if (Options.Compact) 70589f6b26fSZixu Wang os << formatv("{0}", Value(std::move(root))) << "\n"; 70689f6b26fSZixu Wang else 70789f6b26fSZixu Wang os << formatv("{0:2}", Value(std::move(root))) << "\n"; 70889f6b26fSZixu Wang } 709