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" 1789f6b26fSZixu Wang #include "llvm/Support/JSON.h" 1889f6b26fSZixu Wang #include "llvm/Support/Path.h" 1989f6b26fSZixu Wang #include "llvm/Support/VersionTuple.h" 2089f6b26fSZixu Wang 2189f6b26fSZixu Wang using namespace clang; 2289f6b26fSZixu Wang using namespace clang::extractapi; 2389f6b26fSZixu Wang using namespace llvm; 2489f6b26fSZixu Wang using namespace llvm::json; 2589f6b26fSZixu Wang 2689f6b26fSZixu Wang namespace { 2789f6b26fSZixu Wang 2889f6b26fSZixu Wang /// Helper function to inject a JSON object \p Obj into another object \p Paren 2989f6b26fSZixu Wang /// at position \p Key. 3089f6b26fSZixu Wang void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) { 3189f6b26fSZixu Wang if (Obj) 3289f6b26fSZixu Wang Paren[Key] = std::move(Obj.getValue()); 3389f6b26fSZixu Wang } 3489f6b26fSZixu Wang 3589f6b26fSZixu Wang /// Helper function to inject a JSON array \p Array into object \p Paren at 3689f6b26fSZixu Wang /// position \p Key. 3789f6b26fSZixu Wang void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) { 3889f6b26fSZixu Wang if (Array) 3989f6b26fSZixu Wang Paren[Key] = std::move(Array.getValue()); 4089f6b26fSZixu Wang } 4189f6b26fSZixu Wang 4289f6b26fSZixu Wang /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 4389f6b26fSZixu Wang /// format. 4489f6b26fSZixu Wang /// 4589f6b26fSZixu Wang /// A semantic version object contains three numeric fields, representing the 4689f6b26fSZixu Wang /// \c major, \c minor, and \c patch parts of the version tuple. 4789f6b26fSZixu Wang /// For example version tuple 1.0.3 is serialized as: 4889f6b26fSZixu Wang /// \code 4989f6b26fSZixu Wang /// { 5089f6b26fSZixu Wang /// "major" : 1, 5189f6b26fSZixu Wang /// "minor" : 0, 5289f6b26fSZixu Wang /// "patch" : 3 5389f6b26fSZixu Wang /// } 5489f6b26fSZixu Wang /// \endcode 5589f6b26fSZixu Wang /// 5689f6b26fSZixu Wang /// \returns \c None if the version \p V is empty, or an \c Object containing 5789f6b26fSZixu Wang /// the semantic version representation of \p V. 5889f6b26fSZixu Wang Optional<Object> serializeSemanticVersion(const VersionTuple &V) { 5989f6b26fSZixu Wang if (V.empty()) 6089f6b26fSZixu Wang return None; 6189f6b26fSZixu Wang 6289f6b26fSZixu Wang Object Version; 6389f6b26fSZixu Wang Version["major"] = V.getMajor(); 6489f6b26fSZixu Wang Version["minor"] = V.getMinor().getValueOr(0); 6589f6b26fSZixu Wang Version["patch"] = V.getSubminor().getValueOr(0); 6689f6b26fSZixu Wang return Version; 6789f6b26fSZixu Wang } 6889f6b26fSZixu Wang 6989f6b26fSZixu Wang /// Serialize the OS information in the Symbol Graph platform property. 7089f6b26fSZixu Wang /// 7189f6b26fSZixu Wang /// The OS information in Symbol Graph contains the \c name of the OS, and an 7289f6b26fSZixu Wang /// optional \c minimumVersion semantic version field. 7389f6b26fSZixu Wang Object serializeOperatingSystem(const Triple &T) { 7489f6b26fSZixu Wang Object OS; 7589f6b26fSZixu Wang OS["name"] = T.getOSTypeName(T.getOS()); 7689f6b26fSZixu Wang serializeObject(OS, "minimumVersion", 7789f6b26fSZixu Wang serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 7889f6b26fSZixu Wang return OS; 7989f6b26fSZixu Wang } 8089f6b26fSZixu Wang 8189f6b26fSZixu Wang /// Serialize the platform information in the Symbol Graph module section. 8289f6b26fSZixu Wang /// 8389f6b26fSZixu Wang /// The platform object describes a target platform triple in corresponding 8489f6b26fSZixu Wang /// three fields: \c architecture, \c vendor, and \c operatingSystem. 8589f6b26fSZixu Wang Object serializePlatform(const Triple &T) { 8689f6b26fSZixu Wang Object Platform; 8789f6b26fSZixu Wang Platform["architecture"] = T.getArchName(); 8889f6b26fSZixu Wang Platform["vendor"] = T.getVendorName(); 8989f6b26fSZixu Wang Platform["operatingSystem"] = serializeOperatingSystem(T); 9089f6b26fSZixu Wang return Platform; 9189f6b26fSZixu Wang } 9289f6b26fSZixu Wang 9389f6b26fSZixu Wang /// Serialize a source location in file. 9489f6b26fSZixu Wang /// 9589f6b26fSZixu Wang /// \param Loc The presumed location to serialize. 9689f6b26fSZixu Wang /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 9789f6b26fSZixu Wang /// Defaults to false. 9889f6b26fSZixu Wang Object serializeSourcePosition(const PresumedLoc &Loc, 9989f6b26fSZixu Wang bool IncludeFileURI = false) { 10089f6b26fSZixu Wang assert(Loc.isValid() && "invalid source position"); 10189f6b26fSZixu Wang 10289f6b26fSZixu Wang Object SourcePosition; 10389f6b26fSZixu Wang SourcePosition["line"] = Loc.getLine(); 10489f6b26fSZixu Wang SourcePosition["character"] = Loc.getColumn(); 10589f6b26fSZixu Wang 10689f6b26fSZixu Wang if (IncludeFileURI) { 10789f6b26fSZixu Wang std::string FileURI = "file://"; 10889f6b26fSZixu Wang // Normalize file path to use forward slashes for the URI. 10989f6b26fSZixu Wang FileURI += sys::path::convert_to_slash(Loc.getFilename()); 11089f6b26fSZixu Wang SourcePosition["uri"] = FileURI; 11189f6b26fSZixu Wang } 11289f6b26fSZixu Wang 11389f6b26fSZixu Wang return SourcePosition; 11489f6b26fSZixu Wang } 11589f6b26fSZixu Wang 11689f6b26fSZixu Wang /// Serialize a source range with begin and end locations. 11789f6b26fSZixu Wang Object serializeSourceRange(const PresumedLoc &BeginLoc, 11889f6b26fSZixu Wang const PresumedLoc &EndLoc) { 11989f6b26fSZixu Wang Object SourceRange; 12089f6b26fSZixu Wang serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 12189f6b26fSZixu Wang serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 12289f6b26fSZixu Wang return SourceRange; 12389f6b26fSZixu Wang } 12489f6b26fSZixu Wang 12589f6b26fSZixu Wang /// Serialize the availability attributes of a symbol. 12689f6b26fSZixu Wang /// 12789f6b26fSZixu Wang /// Availability information contains the introduced, deprecated, and obsoleted 12889f6b26fSZixu Wang /// versions of the symbol as semantic versions, if not default. 12989f6b26fSZixu Wang /// Availability information also contains flags to indicate if the symbol is 13089f6b26fSZixu Wang /// unconditionally unavailable or deprecated, 13189f6b26fSZixu Wang /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). 13289f6b26fSZixu Wang /// 13389f6b26fSZixu Wang /// \returns \c None if the symbol has default availability attributes, or 13489f6b26fSZixu Wang /// an \c Object containing the formatted availability information. 13589f6b26fSZixu Wang Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) { 13689f6b26fSZixu Wang if (Avail.isDefault()) 13789f6b26fSZixu Wang return None; 13889f6b26fSZixu Wang 13989f6b26fSZixu Wang Object Availbility; 14089f6b26fSZixu Wang serializeObject(Availbility, "introducedVersion", 14189f6b26fSZixu Wang serializeSemanticVersion(Avail.Introduced)); 14289f6b26fSZixu Wang serializeObject(Availbility, "deprecatedVersion", 14389f6b26fSZixu Wang serializeSemanticVersion(Avail.Deprecated)); 14489f6b26fSZixu Wang serializeObject(Availbility, "obsoletedVersion", 14589f6b26fSZixu Wang serializeSemanticVersion(Avail.Obsoleted)); 14689f6b26fSZixu Wang if (Avail.isUnavailable()) 14789f6b26fSZixu Wang Availbility["isUnconditionallyUnavailable"] = true; 14889f6b26fSZixu Wang if (Avail.isUnconditionallyDeprecated()) 14989f6b26fSZixu Wang Availbility["isUnconditionallyDeprecated"] = true; 15089f6b26fSZixu Wang 15189f6b26fSZixu Wang return Availbility; 15289f6b26fSZixu Wang } 15389f6b26fSZixu Wang 15415bf0e56SZixu Wang /// Get the language name string for interface language references. 15515bf0e56SZixu Wang StringRef getLanguageName(Language Lang) { 15615bf0e56SZixu Wang switch (Lang) { 15789f6b26fSZixu Wang case Language::C: 15889f6b26fSZixu Wang return "c"; 15989f6b26fSZixu Wang case Language::ObjC: 160b62d4021SZixu Wang return "objective-c"; 16189f6b26fSZixu Wang 16289f6b26fSZixu Wang // Unsupported language currently 16389f6b26fSZixu Wang case Language::CXX: 16489f6b26fSZixu Wang case Language::ObjCXX: 16589f6b26fSZixu Wang case Language::OpenCL: 16689f6b26fSZixu Wang case Language::OpenCLCXX: 16789f6b26fSZixu Wang case Language::CUDA: 16889f6b26fSZixu Wang case Language::RenderScript: 16989f6b26fSZixu Wang case Language::HIP: 170d394f9f8SChris Bieneman case Language::HLSL: 17189f6b26fSZixu Wang 17289f6b26fSZixu Wang // Languages that the frontend cannot parse and compile 17389f6b26fSZixu Wang case Language::Unknown: 17489f6b26fSZixu Wang case Language::Asm: 17589f6b26fSZixu Wang case Language::LLVM_IR: 17689f6b26fSZixu Wang llvm_unreachable("Unsupported language kind"); 17789f6b26fSZixu Wang } 17889f6b26fSZixu Wang 17989f6b26fSZixu Wang llvm_unreachable("Unhandled language kind"); 18089f6b26fSZixu Wang } 18189f6b26fSZixu Wang 18289f6b26fSZixu Wang /// Serialize the identifier object as specified by the Symbol Graph format. 18389f6b26fSZixu Wang /// 18489f6b26fSZixu Wang /// The identifier property of a symbol contains the USR for precise and unique 18589f6b26fSZixu Wang /// references, and the interface language name. 18615bf0e56SZixu Wang Object serializeIdentifier(const APIRecord &Record, Language Lang) { 18789f6b26fSZixu Wang Object Identifier; 18889f6b26fSZixu Wang Identifier["precise"] = Record.USR; 18915bf0e56SZixu Wang Identifier["interfaceLanguage"] = getLanguageName(Lang); 19089f6b26fSZixu Wang 19189f6b26fSZixu Wang return Identifier; 19289f6b26fSZixu Wang } 19389f6b26fSZixu Wang 19489f6b26fSZixu Wang /// Serialize the documentation comments attached to a symbol, as specified by 19589f6b26fSZixu Wang /// the Symbol Graph format. 19689f6b26fSZixu Wang /// 19789f6b26fSZixu Wang /// The Symbol Graph \c docComment object contains an array of lines. Each line 19889f6b26fSZixu Wang /// represents one line of striped documentation comment, with source range 19989f6b26fSZixu Wang /// information. 20089f6b26fSZixu Wang /// e.g. 20189f6b26fSZixu Wang /// \code 20289f6b26fSZixu Wang /// /// This is a documentation comment 20389f6b26fSZixu Wang /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 20489f6b26fSZixu Wang /// /// with multiple lines. 20589f6b26fSZixu Wang /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 20689f6b26fSZixu Wang /// \endcode 20789f6b26fSZixu Wang /// 20889f6b26fSZixu Wang /// \returns \c None if \p Comment is empty, or an \c Object containing the 20989f6b26fSZixu Wang /// formatted lines. 21089f6b26fSZixu Wang Optional<Object> serializeDocComment(const DocComment &Comment) { 21189f6b26fSZixu Wang if (Comment.empty()) 21289f6b26fSZixu Wang return None; 21389f6b26fSZixu Wang 21489f6b26fSZixu Wang Object DocComment; 21589f6b26fSZixu Wang Array LinesArray; 21689f6b26fSZixu Wang for (const auto &CommentLine : Comment) { 21789f6b26fSZixu Wang Object Line; 21889f6b26fSZixu Wang Line["text"] = CommentLine.Text; 21989f6b26fSZixu Wang serializeObject(Line, "range", 22089f6b26fSZixu Wang serializeSourceRange(CommentLine.Begin, CommentLine.End)); 22189f6b26fSZixu Wang LinesArray.emplace_back(std::move(Line)); 22289f6b26fSZixu Wang } 22389f6b26fSZixu Wang serializeArray(DocComment, "lines", LinesArray); 22489f6b26fSZixu Wang 22589f6b26fSZixu Wang return DocComment; 22689f6b26fSZixu Wang } 22789f6b26fSZixu Wang 22889f6b26fSZixu Wang /// Serialize the declaration fragments of a symbol. 22989f6b26fSZixu Wang /// 23089f6b26fSZixu Wang /// The Symbol Graph declaration fragments is an array of tagged important 23189f6b26fSZixu Wang /// parts of a symbol's declaration. The fragments sequence can be joined to 23289f6b26fSZixu Wang /// form spans of declaration text, with attached information useful for 23389f6b26fSZixu Wang /// purposes like syntax-highlighting etc. For example: 23489f6b26fSZixu Wang /// \code 23589f6b26fSZixu Wang /// const int pi; -> "declarationFragments" : [ 23689f6b26fSZixu Wang /// { 23789f6b26fSZixu Wang /// "kind" : "keyword", 23889f6b26fSZixu Wang /// "spelling" : "const" 23989f6b26fSZixu Wang /// }, 24089f6b26fSZixu Wang /// { 24189f6b26fSZixu Wang /// "kind" : "text", 24289f6b26fSZixu Wang /// "spelling" : " " 24389f6b26fSZixu Wang /// }, 24489f6b26fSZixu Wang /// { 24589f6b26fSZixu Wang /// "kind" : "typeIdentifier", 24689f6b26fSZixu Wang /// "preciseIdentifier" : "c:I", 24789f6b26fSZixu Wang /// "spelling" : "int" 24889f6b26fSZixu Wang /// }, 24989f6b26fSZixu Wang /// { 25089f6b26fSZixu Wang /// "kind" : "text", 25189f6b26fSZixu Wang /// "spelling" : " " 25289f6b26fSZixu Wang /// }, 25389f6b26fSZixu Wang /// { 25489f6b26fSZixu Wang /// "kind" : "identifier", 25589f6b26fSZixu Wang /// "spelling" : "pi" 25689f6b26fSZixu Wang /// } 25789f6b26fSZixu Wang /// ] 25889f6b26fSZixu Wang /// \endcode 25989f6b26fSZixu Wang /// 26089f6b26fSZixu Wang /// \returns \c None if \p DF is empty, or an \c Array containing the formatted 26189f6b26fSZixu Wang /// declaration fragments array. 26289f6b26fSZixu Wang Optional<Array> serializeDeclarationFragments(const DeclarationFragments &DF) { 26389f6b26fSZixu Wang if (DF.getFragments().empty()) 26489f6b26fSZixu Wang return None; 26589f6b26fSZixu Wang 26689f6b26fSZixu Wang Array Fragments; 26789f6b26fSZixu Wang for (const auto &F : DF.getFragments()) { 26889f6b26fSZixu Wang Object Fragment; 26989f6b26fSZixu Wang Fragment["spelling"] = F.Spelling; 27089f6b26fSZixu Wang Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 27189f6b26fSZixu Wang if (!F.PreciseIdentifier.empty()) 27289f6b26fSZixu Wang Fragment["preciseIdentifier"] = F.PreciseIdentifier; 27389f6b26fSZixu Wang Fragments.emplace_back(std::move(Fragment)); 27489f6b26fSZixu Wang } 27589f6b26fSZixu Wang 27689f6b26fSZixu Wang return Fragments; 27789f6b26fSZixu Wang } 27889f6b26fSZixu Wang 27989f6b26fSZixu Wang /// Serialize the function signature field of a function, as specified by the 28089f6b26fSZixu Wang /// Symbol Graph format. 28189f6b26fSZixu Wang /// 28289f6b26fSZixu Wang /// The Symbol Graph function signature property contains two arrays. 28389f6b26fSZixu Wang /// - The \c returns array is the declaration fragments of the return type; 28489f6b26fSZixu Wang /// - The \c parameters array contains names and declaration fragments of the 28589f6b26fSZixu Wang /// parameters. 28689f6b26fSZixu Wang /// 28789f6b26fSZixu Wang /// \returns \c None if \p FS is empty, or an \c Object containing the 28889f6b26fSZixu Wang /// formatted function signature. 28989f6b26fSZixu Wang Optional<Object> serializeFunctionSignature(const FunctionSignature &FS) { 29089f6b26fSZixu Wang if (FS.empty()) 29189f6b26fSZixu Wang return None; 29289f6b26fSZixu Wang 29389f6b26fSZixu Wang Object Signature; 29489f6b26fSZixu Wang serializeArray(Signature, "returns", 29589f6b26fSZixu Wang serializeDeclarationFragments(FS.getReturnType())); 29689f6b26fSZixu Wang 29789f6b26fSZixu Wang Array Parameters; 29889f6b26fSZixu Wang for (const auto &P : FS.getParameters()) { 29989f6b26fSZixu Wang Object Parameter; 30089f6b26fSZixu Wang Parameter["name"] = P.Name; 30189f6b26fSZixu Wang serializeArray(Parameter, "declarationFragments", 30289f6b26fSZixu Wang serializeDeclarationFragments(P.Fragments)); 30389f6b26fSZixu Wang Parameters.emplace_back(std::move(Parameter)); 30489f6b26fSZixu Wang } 30589f6b26fSZixu Wang 30689f6b26fSZixu Wang if (!Parameters.empty()) 30789f6b26fSZixu Wang Signature["parameters"] = std::move(Parameters); 30889f6b26fSZixu Wang 30989f6b26fSZixu Wang return Signature; 31089f6b26fSZixu Wang } 31189f6b26fSZixu Wang 31289f6b26fSZixu Wang /// Serialize the \c names field of a symbol as specified by the Symbol Graph 31389f6b26fSZixu Wang /// format. 31489f6b26fSZixu Wang /// 31589f6b26fSZixu Wang /// The Symbol Graph names field contains multiple representations of a symbol 31689f6b26fSZixu Wang /// that can be used for different applications: 31789f6b26fSZixu Wang /// - \c title : The simple declared name of the symbol; 31889f6b26fSZixu Wang /// - \c subHeading : An array of declaration fragments that provides tags, 31989f6b26fSZixu Wang /// and potentially more tokens (for example the \c +/- symbol for 32089f6b26fSZixu Wang /// Objective-C methods). Can be used as sub-headings for documentation. 32189f6b26fSZixu Wang Object serializeNames(const APIRecord &Record) { 32289f6b26fSZixu Wang Object Names; 32389f6b26fSZixu Wang Names["title"] = Record.Name; 32489f6b26fSZixu Wang serializeArray(Names, "subHeading", 32589f6b26fSZixu Wang serializeDeclarationFragments(Record.SubHeading)); 32689f6b26fSZixu Wang 32789f6b26fSZixu Wang return Names; 32889f6b26fSZixu Wang } 32989f6b26fSZixu Wang 33089f6b26fSZixu Wang /// Serialize the symbol kind information. 33189f6b26fSZixu Wang /// 33289f6b26fSZixu Wang /// The Symbol Graph symbol kind property contains a shorthand \c identifier 33389f6b26fSZixu Wang /// which is prefixed by the source language name, useful for tooling to parse 33489f6b26fSZixu Wang /// the kind, and a \c displayName for rendering human-readable names. 33515bf0e56SZixu Wang Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 33615bf0e56SZixu Wang auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 33715bf0e56SZixu Wang return (getLanguageName(Lang) + "." + S).str(); 33871b4c226SZixu Wang }; 33971b4c226SZixu Wang 34089f6b26fSZixu Wang Object Kind; 34189f6b26fSZixu Wang switch (Record.getKind()) { 34271b4c226SZixu Wang case APIRecord::RK_Global: { 34389f6b26fSZixu Wang auto *GR = dyn_cast<GlobalRecord>(&Record); 34489f6b26fSZixu Wang switch (GR->GlobalKind) { 34589f6b26fSZixu Wang case GVKind::Function: 34671b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("func"); 34789f6b26fSZixu Wang Kind["displayName"] = "Function"; 34889f6b26fSZixu Wang break; 34989f6b26fSZixu Wang case GVKind::Variable: 35071b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("var"); 35189f6b26fSZixu Wang Kind["displayName"] = "Global Variable"; 35289f6b26fSZixu Wang break; 35389f6b26fSZixu Wang case GVKind::Unknown: 35489f6b26fSZixu Wang // Unknown global kind 35589f6b26fSZixu Wang break; 35689f6b26fSZixu Wang } 35789f6b26fSZixu Wang break; 35889f6b26fSZixu Wang } 35971b4c226SZixu Wang case APIRecord::RK_EnumConstant: 36071b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("enum.case"); 36171b4c226SZixu Wang Kind["displayName"] = "Enumeration Case"; 36271b4c226SZixu Wang break; 36371b4c226SZixu Wang case APIRecord::RK_Enum: 36471b4c226SZixu Wang Kind["identifier"] = AddLangPrefix("enum"); 36571b4c226SZixu Wang Kind["displayName"] = "Enumeration"; 36671b4c226SZixu Wang break; 3675bb5704cSZixu Wang case APIRecord::RK_StructField: 3685bb5704cSZixu Wang Kind["identifier"] = AddLangPrefix("property"); 3695bb5704cSZixu Wang Kind["displayName"] = "Instance Property"; 3705bb5704cSZixu Wang break; 3715bb5704cSZixu Wang case APIRecord::RK_Struct: 3725bb5704cSZixu Wang Kind["identifier"] = AddLangPrefix("struct"); 3735bb5704cSZixu Wang Kind["displayName"] = "Structure"; 3745bb5704cSZixu Wang break; 3759b36e126SZixu Wang case APIRecord::RK_ObjCIvar: 3769b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("ivar"); 3779b36e126SZixu Wang Kind["displayName"] = "Instance Variable"; 3789b36e126SZixu Wang break; 3799b36e126SZixu Wang case APIRecord::RK_ObjCMethod: 3809b36e126SZixu Wang if (dyn_cast<ObjCMethodRecord>(&Record)->IsInstanceMethod) { 3819b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("method"); 3829b36e126SZixu Wang Kind["displayName"] = "Instance Method"; 3839b36e126SZixu Wang } else { 3849b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("type.method"); 3859b36e126SZixu Wang Kind["displayName"] = "Type Method"; 3869b36e126SZixu Wang } 3879b36e126SZixu Wang break; 3889b36e126SZixu Wang case APIRecord::RK_ObjCProperty: 3899b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("property"); 3909b36e126SZixu Wang Kind["displayName"] = "Instance Property"; 3919b36e126SZixu Wang break; 3929b36e126SZixu Wang case APIRecord::RK_ObjCInterface: 3939b36e126SZixu Wang Kind["identifier"] = AddLangPrefix("class"); 3949b36e126SZixu Wang Kind["displayName"] = "Class"; 3959b36e126SZixu Wang break; 396*d1d34bafSZixu Wang case APIRecord::RK_ObjCProtocol: 397*d1d34bafSZixu Wang Kind["identifier"] = AddLangPrefix("protocol"); 398*d1d34bafSZixu Wang Kind["displayName"] = "Protocol"; 399*d1d34bafSZixu Wang break; 40071b4c226SZixu Wang } 40189f6b26fSZixu Wang 40289f6b26fSZixu Wang return Kind; 40389f6b26fSZixu Wang } 40489f6b26fSZixu Wang 40589f6b26fSZixu Wang } // namespace 40689f6b26fSZixu Wang 40789f6b26fSZixu Wang void SymbolGraphSerializer::anchor() {} 40889f6b26fSZixu Wang 40989f6b26fSZixu Wang /// Defines the format version emitted by SymbolGraphSerializer. 41089f6b26fSZixu Wang const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 41189f6b26fSZixu Wang 41289f6b26fSZixu Wang Object SymbolGraphSerializer::serializeMetadata() const { 41389f6b26fSZixu Wang Object Metadata; 41489f6b26fSZixu Wang serializeObject(Metadata, "formatVersion", 41589f6b26fSZixu Wang serializeSemanticVersion(FormatVersion)); 41689f6b26fSZixu Wang Metadata["generator"] = clang::getClangFullVersion(); 41789f6b26fSZixu Wang return Metadata; 41889f6b26fSZixu Wang } 41989f6b26fSZixu Wang 42089f6b26fSZixu Wang Object SymbolGraphSerializer::serializeModule() const { 42189f6b26fSZixu Wang Object Module; 4225ef2ec7eSDaniel Grumberg // The user is expected to always pass `--product-name=` on the command line 4235ef2ec7eSDaniel Grumberg // to populate this field. 4245ef2ec7eSDaniel Grumberg Module["name"] = ProductName; 42589f6b26fSZixu Wang serializeObject(Module, "platform", serializePlatform(API.getTarget())); 42689f6b26fSZixu Wang return Module; 42789f6b26fSZixu Wang } 42889f6b26fSZixu Wang 42989f6b26fSZixu Wang bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { 43089f6b26fSZixu Wang // Skip unconditionally unavailable symbols 43189f6b26fSZixu Wang if (Record.Availability.isUnconditionallyUnavailable()) 43289f6b26fSZixu Wang return true; 43389f6b26fSZixu Wang 43489f6b26fSZixu Wang return false; 43589f6b26fSZixu Wang } 43689f6b26fSZixu Wang 43789f6b26fSZixu Wang Optional<Object> 43889f6b26fSZixu Wang SymbolGraphSerializer::serializeAPIRecord(const APIRecord &Record) const { 43989f6b26fSZixu Wang if (shouldSkip(Record)) 44089f6b26fSZixu Wang return None; 44189f6b26fSZixu Wang 44289f6b26fSZixu Wang Object Obj; 44389f6b26fSZixu Wang serializeObject(Obj, "identifier", 44415bf0e56SZixu Wang serializeIdentifier(Record, API.getLanguage())); 44515bf0e56SZixu Wang serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); 44689f6b26fSZixu Wang serializeObject(Obj, "names", serializeNames(Record)); 44789f6b26fSZixu Wang serializeObject( 44889f6b26fSZixu Wang Obj, "location", 44989f6b26fSZixu Wang serializeSourcePosition(Record.Location, /*IncludeFileURI=*/true)); 45089f6b26fSZixu Wang serializeObject(Obj, "availbility", 45189f6b26fSZixu Wang serializeAvailability(Record.Availability)); 45289f6b26fSZixu Wang serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); 45389f6b26fSZixu Wang serializeArray(Obj, "declarationFragments", 45489f6b26fSZixu Wang serializeDeclarationFragments(Record.Declaration)); 45589f6b26fSZixu Wang 45689f6b26fSZixu Wang return Obj; 45789f6b26fSZixu Wang } 45889f6b26fSZixu Wang 45971b4c226SZixu Wang StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 46071b4c226SZixu Wang switch (Kind) { 46171b4c226SZixu Wang case RelationshipKind::MemberOf: 46271b4c226SZixu Wang return "memberOf"; 4639b36e126SZixu Wang case RelationshipKind::InheritsFrom: 4649b36e126SZixu Wang return "inheritsFrom"; 4659b36e126SZixu Wang case RelationshipKind::ConformsTo: 4669b36e126SZixu Wang return "conformsTo"; 46771b4c226SZixu Wang } 46871b4c226SZixu Wang llvm_unreachable("Unhandled relationship kind"); 46971b4c226SZixu Wang } 47071b4c226SZixu Wang 47171b4c226SZixu Wang void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 4729b36e126SZixu Wang SymbolReference Source, 4739b36e126SZixu Wang SymbolReference Target) { 47471b4c226SZixu Wang Object Relationship; 47571b4c226SZixu Wang Relationship["source"] = Source.USR; 47671b4c226SZixu Wang Relationship["target"] = Target.USR; 47771b4c226SZixu Wang Relationship["kind"] = getRelationshipString(Kind); 47871b4c226SZixu Wang 47971b4c226SZixu Wang Relationships.emplace_back(std::move(Relationship)); 48071b4c226SZixu Wang } 48171b4c226SZixu Wang 48289f6b26fSZixu Wang void SymbolGraphSerializer::serializeGlobalRecord(const GlobalRecord &Record) { 48389f6b26fSZixu Wang auto Obj = serializeAPIRecord(Record); 48489f6b26fSZixu Wang if (!Obj) 48589f6b26fSZixu Wang return; 48689f6b26fSZixu Wang 48789f6b26fSZixu Wang if (Record.GlobalKind == GVKind::Function) 48889f6b26fSZixu Wang serializeObject(*Obj, "parameters", 48989f6b26fSZixu Wang serializeFunctionSignature(Record.Signature)); 49089f6b26fSZixu Wang 49189f6b26fSZixu Wang Symbols.emplace_back(std::move(*Obj)); 49289f6b26fSZixu Wang } 49389f6b26fSZixu Wang 49471b4c226SZixu Wang void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) { 49571b4c226SZixu Wang auto Enum = serializeAPIRecord(Record); 49671b4c226SZixu Wang if (!Enum) 49771b4c226SZixu Wang return; 49871b4c226SZixu Wang 49971b4c226SZixu Wang Symbols.emplace_back(std::move(*Enum)); 50071b4c226SZixu Wang 50171b4c226SZixu Wang for (const auto &Constant : Record.Constants) { 50271b4c226SZixu Wang auto EnumConstant = serializeAPIRecord(*Constant); 50371b4c226SZixu Wang if (!EnumConstant) 50471b4c226SZixu Wang continue; 50571b4c226SZixu Wang 50671b4c226SZixu Wang Symbols.emplace_back(std::move(*EnumConstant)); 50771b4c226SZixu Wang serializeRelationship(RelationshipKind::MemberOf, *Constant, Record); 50871b4c226SZixu Wang } 50971b4c226SZixu Wang } 51071b4c226SZixu Wang 5115bb5704cSZixu Wang void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) { 5125bb5704cSZixu Wang auto Struct = serializeAPIRecord(Record); 5135bb5704cSZixu Wang if (!Struct) 5145bb5704cSZixu Wang return; 5155bb5704cSZixu Wang 5165bb5704cSZixu Wang Symbols.emplace_back(std::move(*Struct)); 5175bb5704cSZixu Wang 5185bb5704cSZixu Wang for (const auto &Field : Record.Fields) { 5195bb5704cSZixu Wang auto StructField = serializeAPIRecord(*Field); 5205bb5704cSZixu Wang if (!StructField) 5215bb5704cSZixu Wang continue; 5225bb5704cSZixu Wang 5235bb5704cSZixu Wang Symbols.emplace_back(std::move(*StructField)); 5245bb5704cSZixu Wang serializeRelationship(RelationshipKind::MemberOf, *Field, Record); 5255bb5704cSZixu Wang } 5265bb5704cSZixu Wang } 5275bb5704cSZixu Wang 5289b36e126SZixu Wang void SymbolGraphSerializer::serializeObjCContainerRecord( 5299b36e126SZixu Wang const ObjCContainerRecord &Record) { 5309b36e126SZixu Wang auto ObjCContainer = serializeAPIRecord(Record); 5319b36e126SZixu Wang if (!ObjCContainer) 5329b36e126SZixu Wang return; 5339b36e126SZixu Wang 5349b36e126SZixu Wang Symbols.emplace_back(std::move(*ObjCContainer)); 5359b36e126SZixu Wang 5369b36e126SZixu Wang // Record instance variables and that the instance variables are members of 5379b36e126SZixu Wang // the container. 5389b36e126SZixu Wang for (const auto &Ivar : Record.Ivars) { 5399b36e126SZixu Wang auto ObjCIvar = serializeAPIRecord(*Ivar); 5409b36e126SZixu Wang if (!ObjCIvar) 5419b36e126SZixu Wang continue; 5429b36e126SZixu Wang 5439b36e126SZixu Wang Symbols.emplace_back(std::move(*ObjCIvar)); 5449b36e126SZixu Wang serializeRelationship(RelationshipKind::MemberOf, *Ivar, Record); 5459b36e126SZixu Wang } 5469b36e126SZixu Wang 5479b36e126SZixu Wang // Record methods and that the methods are members of the container. 5489b36e126SZixu Wang for (const auto &Method : Record.Methods) { 5499b36e126SZixu Wang auto ObjCMethod = serializeAPIRecord(*Method); 5509b36e126SZixu Wang if (!ObjCMethod) 5519b36e126SZixu Wang continue; 5529b36e126SZixu Wang 5539b36e126SZixu Wang Symbols.emplace_back(std::move(*ObjCMethod)); 5549b36e126SZixu Wang serializeRelationship(RelationshipKind::MemberOf, *Method, Record); 5559b36e126SZixu Wang } 5569b36e126SZixu Wang 5579b36e126SZixu Wang // Record properties and that the properties are members of the container. 5589b36e126SZixu Wang for (const auto &Property : Record.Properties) { 5599b36e126SZixu Wang auto ObjCProperty = serializeAPIRecord(*Property); 5609b36e126SZixu Wang if (!ObjCProperty) 5619b36e126SZixu Wang continue; 5629b36e126SZixu Wang 5639b36e126SZixu Wang Symbols.emplace_back(std::move(*ObjCProperty)); 5649b36e126SZixu Wang serializeRelationship(RelationshipKind::MemberOf, *Property, Record); 5659b36e126SZixu Wang } 5669b36e126SZixu Wang 5679b36e126SZixu Wang for (const auto &Protocol : Record.Protocols) 5689b36e126SZixu Wang // Record that Record conforms to Protocol. 5699b36e126SZixu Wang serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 5709b36e126SZixu Wang 5719b36e126SZixu Wang if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) 5729b36e126SZixu Wang if (!ObjCInterface->SuperClass.empty()) 5739b36e126SZixu Wang // If Record is an Objective-C interface record and it has a super class, 5749b36e126SZixu Wang // record that Record is inherited from SuperClass. 5759b36e126SZixu Wang serializeRelationship(RelationshipKind::InheritsFrom, Record, 5769b36e126SZixu Wang ObjCInterface->SuperClass); 5779b36e126SZixu Wang } 5789b36e126SZixu Wang 57989f6b26fSZixu Wang Object SymbolGraphSerializer::serialize() { 58089f6b26fSZixu Wang Object Root; 58189f6b26fSZixu Wang serializeObject(Root, "metadata", serializeMetadata()); 58289f6b26fSZixu Wang serializeObject(Root, "module", serializeModule()); 58389f6b26fSZixu Wang 58489f6b26fSZixu Wang // Serialize global records in the API set. 58589f6b26fSZixu Wang for (const auto &Global : API.getGlobals()) 58689f6b26fSZixu Wang serializeGlobalRecord(*Global.second); 58789f6b26fSZixu Wang 58871b4c226SZixu Wang // Serialize enum records in the API set. 58971b4c226SZixu Wang for (const auto &Enum : API.getEnums()) 59071b4c226SZixu Wang serializeEnumRecord(*Enum.second); 59171b4c226SZixu Wang 5925bb5704cSZixu Wang // Serialize struct records in the API set. 5935bb5704cSZixu Wang for (const auto &Struct : API.getStructs()) 5945bb5704cSZixu Wang serializeStructRecord(*Struct.second); 5955bb5704cSZixu Wang 5969b36e126SZixu Wang // Serialize Objective-C interface records in the API set. 5979b36e126SZixu Wang for (const auto &ObjCInterface : API.getObjCInterfaces()) 5989b36e126SZixu Wang serializeObjCContainerRecord(*ObjCInterface.second); 5999b36e126SZixu Wang 600*d1d34bafSZixu Wang // Serialize Objective-C protocol records in the API set. 601*d1d34bafSZixu Wang for (const auto &ObjCProtocol : API.getObjCProtocols()) 602*d1d34bafSZixu Wang serializeObjCContainerRecord(*ObjCProtocol.second); 603*d1d34bafSZixu Wang 60489f6b26fSZixu Wang Root["symbols"] = std::move(Symbols); 60589f6b26fSZixu Wang Root["relationhips"] = std::move(Relationships); 60689f6b26fSZixu Wang 60789f6b26fSZixu Wang return Root; 60889f6b26fSZixu Wang } 60989f6b26fSZixu Wang 61089f6b26fSZixu Wang void SymbolGraphSerializer::serialize(raw_ostream &os) { 61189f6b26fSZixu Wang Object root = serialize(); 61289f6b26fSZixu Wang if (Options.Compact) 61389f6b26fSZixu Wang os << formatv("{0}", Value(std::move(root))) << "\n"; 61489f6b26fSZixu Wang else 61589f6b26fSZixu Wang os << formatv("{0:2}", Value(std::move(root))) << "\n"; 61689f6b26fSZixu Wang } 617