1*81ad6265SDimitry Andric //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===// 2*81ad6265SDimitry Andric // 3*81ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*81ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*81ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*81ad6265SDimitry Andric // 7*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 8*81ad6265SDimitry Andric /// 9*81ad6265SDimitry Andric /// \file 10*81ad6265SDimitry Andric /// This file implements the SymbolGraphSerializer. 11*81ad6265SDimitry Andric /// 12*81ad6265SDimitry Andric //===----------------------------------------------------------------------===// 13*81ad6265SDimitry Andric 14*81ad6265SDimitry Andric #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 15*81ad6265SDimitry Andric #include "clang/Basic/Version.h" 16*81ad6265SDimitry Andric #include "clang/ExtractAPI/API.h" 17*81ad6265SDimitry Andric #include "clang/ExtractAPI/DeclarationFragments.h" 18*81ad6265SDimitry Andric #include "llvm/Support/JSON.h" 19*81ad6265SDimitry Andric #include "llvm/Support/Path.h" 20*81ad6265SDimitry Andric #include "llvm/Support/VersionTuple.h" 21*81ad6265SDimitry Andric #include <type_traits> 22*81ad6265SDimitry Andric 23*81ad6265SDimitry Andric using namespace clang; 24*81ad6265SDimitry Andric using namespace clang::extractapi; 25*81ad6265SDimitry Andric using namespace llvm; 26*81ad6265SDimitry Andric using namespace llvm::json; 27*81ad6265SDimitry Andric 28*81ad6265SDimitry Andric namespace { 29*81ad6265SDimitry Andric 30*81ad6265SDimitry Andric /// Helper function to inject a JSON object \p Obj into another object \p Paren 31*81ad6265SDimitry Andric /// at position \p Key. 32*81ad6265SDimitry Andric void serializeObject(Object &Paren, StringRef Key, Optional<Object> Obj) { 33*81ad6265SDimitry Andric if (Obj) 34*81ad6265SDimitry Andric Paren[Key] = std::move(Obj.getValue()); 35*81ad6265SDimitry Andric } 36*81ad6265SDimitry Andric 37*81ad6265SDimitry Andric /// Helper function to inject a JSON array \p Array into object \p Paren at 38*81ad6265SDimitry Andric /// position \p Key. 39*81ad6265SDimitry Andric void serializeArray(Object &Paren, StringRef Key, Optional<Array> Array) { 40*81ad6265SDimitry Andric if (Array) 41*81ad6265SDimitry Andric Paren[Key] = std::move(Array.getValue()); 42*81ad6265SDimitry Andric } 43*81ad6265SDimitry Andric 44*81ad6265SDimitry Andric /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 45*81ad6265SDimitry Andric /// format. 46*81ad6265SDimitry Andric /// 47*81ad6265SDimitry Andric /// A semantic version object contains three numeric fields, representing the 48*81ad6265SDimitry Andric /// \c major, \c minor, and \c patch parts of the version tuple. 49*81ad6265SDimitry Andric /// For example version tuple 1.0.3 is serialized as: 50*81ad6265SDimitry Andric /// \code 51*81ad6265SDimitry Andric /// { 52*81ad6265SDimitry Andric /// "major" : 1, 53*81ad6265SDimitry Andric /// "minor" : 0, 54*81ad6265SDimitry Andric /// "patch" : 3 55*81ad6265SDimitry Andric /// } 56*81ad6265SDimitry Andric /// \endcode 57*81ad6265SDimitry Andric /// 58*81ad6265SDimitry Andric /// \returns \c None if the version \p V is empty, or an \c Object containing 59*81ad6265SDimitry Andric /// the semantic version representation of \p V. 60*81ad6265SDimitry Andric Optional<Object> serializeSemanticVersion(const VersionTuple &V) { 61*81ad6265SDimitry Andric if (V.empty()) 62*81ad6265SDimitry Andric return None; 63*81ad6265SDimitry Andric 64*81ad6265SDimitry Andric Object Version; 65*81ad6265SDimitry Andric Version["major"] = V.getMajor(); 66*81ad6265SDimitry Andric Version["minor"] = V.getMinor().value_or(0); 67*81ad6265SDimitry Andric Version["patch"] = V.getSubminor().value_or(0); 68*81ad6265SDimitry Andric return Version; 69*81ad6265SDimitry Andric } 70*81ad6265SDimitry Andric 71*81ad6265SDimitry Andric /// Serialize the OS information in the Symbol Graph platform property. 72*81ad6265SDimitry Andric /// 73*81ad6265SDimitry Andric /// The OS information in Symbol Graph contains the \c name of the OS, and an 74*81ad6265SDimitry Andric /// optional \c minimumVersion semantic version field. 75*81ad6265SDimitry Andric Object serializeOperatingSystem(const Triple &T) { 76*81ad6265SDimitry Andric Object OS; 77*81ad6265SDimitry Andric OS["name"] = T.getOSTypeName(T.getOS()); 78*81ad6265SDimitry Andric serializeObject(OS, "minimumVersion", 79*81ad6265SDimitry Andric serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 80*81ad6265SDimitry Andric return OS; 81*81ad6265SDimitry Andric } 82*81ad6265SDimitry Andric 83*81ad6265SDimitry Andric /// Serialize the platform information in the Symbol Graph module section. 84*81ad6265SDimitry Andric /// 85*81ad6265SDimitry Andric /// The platform object describes a target platform triple in corresponding 86*81ad6265SDimitry Andric /// three fields: \c architecture, \c vendor, and \c operatingSystem. 87*81ad6265SDimitry Andric Object serializePlatform(const Triple &T) { 88*81ad6265SDimitry Andric Object Platform; 89*81ad6265SDimitry Andric Platform["architecture"] = T.getArchName(); 90*81ad6265SDimitry Andric Platform["vendor"] = T.getVendorName(); 91*81ad6265SDimitry Andric Platform["operatingSystem"] = serializeOperatingSystem(T); 92*81ad6265SDimitry Andric return Platform; 93*81ad6265SDimitry Andric } 94*81ad6265SDimitry Andric 95*81ad6265SDimitry Andric /// Serialize a source position. 96*81ad6265SDimitry Andric Object serializeSourcePosition(const PresumedLoc &Loc) { 97*81ad6265SDimitry Andric assert(Loc.isValid() && "invalid source position"); 98*81ad6265SDimitry Andric 99*81ad6265SDimitry Andric Object SourcePosition; 100*81ad6265SDimitry Andric SourcePosition["line"] = Loc.getLine(); 101*81ad6265SDimitry Andric SourcePosition["character"] = Loc.getColumn(); 102*81ad6265SDimitry Andric 103*81ad6265SDimitry Andric return SourcePosition; 104*81ad6265SDimitry Andric } 105*81ad6265SDimitry Andric 106*81ad6265SDimitry Andric /// Serialize a source location in file. 107*81ad6265SDimitry Andric /// 108*81ad6265SDimitry Andric /// \param Loc The presumed location to serialize. 109*81ad6265SDimitry Andric /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 110*81ad6265SDimitry Andric /// Defaults to false. 111*81ad6265SDimitry Andric Object serializeSourceLocation(const PresumedLoc &Loc, 112*81ad6265SDimitry Andric bool IncludeFileURI = false) { 113*81ad6265SDimitry Andric Object SourceLocation; 114*81ad6265SDimitry Andric serializeObject(SourceLocation, "position", serializeSourcePosition(Loc)); 115*81ad6265SDimitry Andric 116*81ad6265SDimitry Andric if (IncludeFileURI) { 117*81ad6265SDimitry Andric std::string FileURI = "file://"; 118*81ad6265SDimitry Andric // Normalize file path to use forward slashes for the URI. 119*81ad6265SDimitry Andric FileURI += sys::path::convert_to_slash(Loc.getFilename()); 120*81ad6265SDimitry Andric SourceLocation["uri"] = FileURI; 121*81ad6265SDimitry Andric } 122*81ad6265SDimitry Andric 123*81ad6265SDimitry Andric return SourceLocation; 124*81ad6265SDimitry Andric } 125*81ad6265SDimitry Andric 126*81ad6265SDimitry Andric /// Serialize a source range with begin and end locations. 127*81ad6265SDimitry Andric Object serializeSourceRange(const PresumedLoc &BeginLoc, 128*81ad6265SDimitry Andric const PresumedLoc &EndLoc) { 129*81ad6265SDimitry Andric Object SourceRange; 130*81ad6265SDimitry Andric serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 131*81ad6265SDimitry Andric serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 132*81ad6265SDimitry Andric return SourceRange; 133*81ad6265SDimitry Andric } 134*81ad6265SDimitry Andric 135*81ad6265SDimitry Andric /// Serialize the availability attributes of a symbol. 136*81ad6265SDimitry Andric /// 137*81ad6265SDimitry Andric /// Availability information contains the introduced, deprecated, and obsoleted 138*81ad6265SDimitry Andric /// versions of the symbol as semantic versions, if not default. 139*81ad6265SDimitry Andric /// Availability information also contains flags to indicate if the symbol is 140*81ad6265SDimitry Andric /// unconditionally unavailable or deprecated, 141*81ad6265SDimitry Andric /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). 142*81ad6265SDimitry Andric /// 143*81ad6265SDimitry Andric /// \returns \c None if the symbol has default availability attributes, or 144*81ad6265SDimitry Andric /// an \c Object containing the formatted availability information. 145*81ad6265SDimitry Andric Optional<Object> serializeAvailability(const AvailabilityInfo &Avail) { 146*81ad6265SDimitry Andric if (Avail.isDefault()) 147*81ad6265SDimitry Andric return None; 148*81ad6265SDimitry Andric 149*81ad6265SDimitry Andric Object Availbility; 150*81ad6265SDimitry Andric serializeObject(Availbility, "introducedVersion", 151*81ad6265SDimitry Andric serializeSemanticVersion(Avail.Introduced)); 152*81ad6265SDimitry Andric serializeObject(Availbility, "deprecatedVersion", 153*81ad6265SDimitry Andric serializeSemanticVersion(Avail.Deprecated)); 154*81ad6265SDimitry Andric serializeObject(Availbility, "obsoletedVersion", 155*81ad6265SDimitry Andric serializeSemanticVersion(Avail.Obsoleted)); 156*81ad6265SDimitry Andric if (Avail.isUnavailable()) 157*81ad6265SDimitry Andric Availbility["isUnconditionallyUnavailable"] = true; 158*81ad6265SDimitry Andric if (Avail.isUnconditionallyDeprecated()) 159*81ad6265SDimitry Andric Availbility["isUnconditionallyDeprecated"] = true; 160*81ad6265SDimitry Andric 161*81ad6265SDimitry Andric return Availbility; 162*81ad6265SDimitry Andric } 163*81ad6265SDimitry Andric 164*81ad6265SDimitry Andric /// Get the language name string for interface language references. 165*81ad6265SDimitry Andric StringRef getLanguageName(Language Lang) { 166*81ad6265SDimitry Andric switch (Lang) { 167*81ad6265SDimitry Andric case Language::C: 168*81ad6265SDimitry Andric return "c"; 169*81ad6265SDimitry Andric case Language::ObjC: 170*81ad6265SDimitry Andric return "objective-c"; 171*81ad6265SDimitry Andric 172*81ad6265SDimitry Andric // Unsupported language currently 173*81ad6265SDimitry Andric case Language::CXX: 174*81ad6265SDimitry Andric case Language::ObjCXX: 175*81ad6265SDimitry Andric case Language::OpenCL: 176*81ad6265SDimitry Andric case Language::OpenCLCXX: 177*81ad6265SDimitry Andric case Language::CUDA: 178*81ad6265SDimitry Andric case Language::RenderScript: 179*81ad6265SDimitry Andric case Language::HIP: 180*81ad6265SDimitry Andric case Language::HLSL: 181*81ad6265SDimitry Andric 182*81ad6265SDimitry Andric // Languages that the frontend cannot parse and compile 183*81ad6265SDimitry Andric case Language::Unknown: 184*81ad6265SDimitry Andric case Language::Asm: 185*81ad6265SDimitry Andric case Language::LLVM_IR: 186*81ad6265SDimitry Andric llvm_unreachable("Unsupported language kind"); 187*81ad6265SDimitry Andric } 188*81ad6265SDimitry Andric 189*81ad6265SDimitry Andric llvm_unreachable("Unhandled language kind"); 190*81ad6265SDimitry Andric } 191*81ad6265SDimitry Andric 192*81ad6265SDimitry Andric /// Serialize the identifier object as specified by the Symbol Graph format. 193*81ad6265SDimitry Andric /// 194*81ad6265SDimitry Andric /// The identifier property of a symbol contains the USR for precise and unique 195*81ad6265SDimitry Andric /// references, and the interface language name. 196*81ad6265SDimitry Andric Object serializeIdentifier(const APIRecord &Record, Language Lang) { 197*81ad6265SDimitry Andric Object Identifier; 198*81ad6265SDimitry Andric Identifier["precise"] = Record.USR; 199*81ad6265SDimitry Andric Identifier["interfaceLanguage"] = getLanguageName(Lang); 200*81ad6265SDimitry Andric 201*81ad6265SDimitry Andric return Identifier; 202*81ad6265SDimitry Andric } 203*81ad6265SDimitry Andric 204*81ad6265SDimitry Andric /// Serialize the documentation comments attached to a symbol, as specified by 205*81ad6265SDimitry Andric /// the Symbol Graph format. 206*81ad6265SDimitry Andric /// 207*81ad6265SDimitry Andric /// The Symbol Graph \c docComment object contains an array of lines. Each line 208*81ad6265SDimitry Andric /// represents one line of striped documentation comment, with source range 209*81ad6265SDimitry Andric /// information. 210*81ad6265SDimitry Andric /// e.g. 211*81ad6265SDimitry Andric /// \code 212*81ad6265SDimitry Andric /// /// This is a documentation comment 213*81ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 214*81ad6265SDimitry Andric /// /// with multiple lines. 215*81ad6265SDimitry Andric /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 216*81ad6265SDimitry Andric /// \endcode 217*81ad6265SDimitry Andric /// 218*81ad6265SDimitry Andric /// \returns \c None if \p Comment is empty, or an \c Object containing the 219*81ad6265SDimitry Andric /// formatted lines. 220*81ad6265SDimitry Andric Optional<Object> serializeDocComment(const DocComment &Comment) { 221*81ad6265SDimitry Andric if (Comment.empty()) 222*81ad6265SDimitry Andric return None; 223*81ad6265SDimitry Andric 224*81ad6265SDimitry Andric Object DocComment; 225*81ad6265SDimitry Andric Array LinesArray; 226*81ad6265SDimitry Andric for (const auto &CommentLine : Comment) { 227*81ad6265SDimitry Andric Object Line; 228*81ad6265SDimitry Andric Line["text"] = CommentLine.Text; 229*81ad6265SDimitry Andric serializeObject(Line, "range", 230*81ad6265SDimitry Andric serializeSourceRange(CommentLine.Begin, CommentLine.End)); 231*81ad6265SDimitry Andric LinesArray.emplace_back(std::move(Line)); 232*81ad6265SDimitry Andric } 233*81ad6265SDimitry Andric serializeArray(DocComment, "lines", LinesArray); 234*81ad6265SDimitry Andric 235*81ad6265SDimitry Andric return DocComment; 236*81ad6265SDimitry Andric } 237*81ad6265SDimitry Andric 238*81ad6265SDimitry Andric /// Serialize the declaration fragments of a symbol. 239*81ad6265SDimitry Andric /// 240*81ad6265SDimitry Andric /// The Symbol Graph declaration fragments is an array of tagged important 241*81ad6265SDimitry Andric /// parts of a symbol's declaration. The fragments sequence can be joined to 242*81ad6265SDimitry Andric /// form spans of declaration text, with attached information useful for 243*81ad6265SDimitry Andric /// purposes like syntax-highlighting etc. For example: 244*81ad6265SDimitry Andric /// \code 245*81ad6265SDimitry Andric /// const int pi; -> "declarationFragments" : [ 246*81ad6265SDimitry Andric /// { 247*81ad6265SDimitry Andric /// "kind" : "keyword", 248*81ad6265SDimitry Andric /// "spelling" : "const" 249*81ad6265SDimitry Andric /// }, 250*81ad6265SDimitry Andric /// { 251*81ad6265SDimitry Andric /// "kind" : "text", 252*81ad6265SDimitry Andric /// "spelling" : " " 253*81ad6265SDimitry Andric /// }, 254*81ad6265SDimitry Andric /// { 255*81ad6265SDimitry Andric /// "kind" : "typeIdentifier", 256*81ad6265SDimitry Andric /// "preciseIdentifier" : "c:I", 257*81ad6265SDimitry Andric /// "spelling" : "int" 258*81ad6265SDimitry Andric /// }, 259*81ad6265SDimitry Andric /// { 260*81ad6265SDimitry Andric /// "kind" : "text", 261*81ad6265SDimitry Andric /// "spelling" : " " 262*81ad6265SDimitry Andric /// }, 263*81ad6265SDimitry Andric /// { 264*81ad6265SDimitry Andric /// "kind" : "identifier", 265*81ad6265SDimitry Andric /// "spelling" : "pi" 266*81ad6265SDimitry Andric /// } 267*81ad6265SDimitry Andric /// ] 268*81ad6265SDimitry Andric /// \endcode 269*81ad6265SDimitry Andric /// 270*81ad6265SDimitry Andric /// \returns \c None if \p DF is empty, or an \c Array containing the formatted 271*81ad6265SDimitry Andric /// declaration fragments array. 272*81ad6265SDimitry Andric Optional<Array> serializeDeclarationFragments(const DeclarationFragments &DF) { 273*81ad6265SDimitry Andric if (DF.getFragments().empty()) 274*81ad6265SDimitry Andric return None; 275*81ad6265SDimitry Andric 276*81ad6265SDimitry Andric Array Fragments; 277*81ad6265SDimitry Andric for (const auto &F : DF.getFragments()) { 278*81ad6265SDimitry Andric Object Fragment; 279*81ad6265SDimitry Andric Fragment["spelling"] = F.Spelling; 280*81ad6265SDimitry Andric Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 281*81ad6265SDimitry Andric if (!F.PreciseIdentifier.empty()) 282*81ad6265SDimitry Andric Fragment["preciseIdentifier"] = F.PreciseIdentifier; 283*81ad6265SDimitry Andric Fragments.emplace_back(std::move(Fragment)); 284*81ad6265SDimitry Andric } 285*81ad6265SDimitry Andric 286*81ad6265SDimitry Andric return Fragments; 287*81ad6265SDimitry Andric } 288*81ad6265SDimitry Andric 289*81ad6265SDimitry Andric /// Serialize the \c names field of a symbol as specified by the Symbol Graph 290*81ad6265SDimitry Andric /// format. 291*81ad6265SDimitry Andric /// 292*81ad6265SDimitry Andric /// The Symbol Graph names field contains multiple representations of a symbol 293*81ad6265SDimitry Andric /// that can be used for different applications: 294*81ad6265SDimitry Andric /// - \c title : The simple declared name of the symbol; 295*81ad6265SDimitry Andric /// - \c subHeading : An array of declaration fragments that provides tags, 296*81ad6265SDimitry Andric /// and potentially more tokens (for example the \c +/- symbol for 297*81ad6265SDimitry Andric /// Objective-C methods). Can be used as sub-headings for documentation. 298*81ad6265SDimitry Andric Object serializeNames(const APIRecord &Record) { 299*81ad6265SDimitry Andric Object Names; 300*81ad6265SDimitry Andric Names["title"] = Record.Name; 301*81ad6265SDimitry Andric serializeArray(Names, "subHeading", 302*81ad6265SDimitry Andric serializeDeclarationFragments(Record.SubHeading)); 303*81ad6265SDimitry Andric DeclarationFragments NavigatorFragments; 304*81ad6265SDimitry Andric NavigatorFragments.append(Record.Name, 305*81ad6265SDimitry Andric DeclarationFragments::FragmentKind::Identifier, 306*81ad6265SDimitry Andric /*PreciseIdentifier*/ ""); 307*81ad6265SDimitry Andric serializeArray(Names, "navigator", 308*81ad6265SDimitry Andric serializeDeclarationFragments(NavigatorFragments)); 309*81ad6265SDimitry Andric 310*81ad6265SDimitry Andric return Names; 311*81ad6265SDimitry Andric } 312*81ad6265SDimitry Andric 313*81ad6265SDimitry Andric /// Serialize the symbol kind information. 314*81ad6265SDimitry Andric /// 315*81ad6265SDimitry Andric /// The Symbol Graph symbol kind property contains a shorthand \c identifier 316*81ad6265SDimitry Andric /// which is prefixed by the source language name, useful for tooling to parse 317*81ad6265SDimitry Andric /// the kind, and a \c displayName for rendering human-readable names. 318*81ad6265SDimitry Andric Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 319*81ad6265SDimitry Andric auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 320*81ad6265SDimitry Andric return (getLanguageName(Lang) + "." + S).str(); 321*81ad6265SDimitry Andric }; 322*81ad6265SDimitry Andric 323*81ad6265SDimitry Andric Object Kind; 324*81ad6265SDimitry Andric switch (Record.getKind()) { 325*81ad6265SDimitry Andric case APIRecord::RK_GlobalFunction: 326*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("func"); 327*81ad6265SDimitry Andric Kind["displayName"] = "Function"; 328*81ad6265SDimitry Andric break; 329*81ad6265SDimitry Andric case APIRecord::RK_GlobalVariable: 330*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("var"); 331*81ad6265SDimitry Andric Kind["displayName"] = "Global Variable"; 332*81ad6265SDimitry Andric break; 333*81ad6265SDimitry Andric case APIRecord::RK_EnumConstant: 334*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum.case"); 335*81ad6265SDimitry Andric Kind["displayName"] = "Enumeration Case"; 336*81ad6265SDimitry Andric break; 337*81ad6265SDimitry Andric case APIRecord::RK_Enum: 338*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("enum"); 339*81ad6265SDimitry Andric Kind["displayName"] = "Enumeration"; 340*81ad6265SDimitry Andric break; 341*81ad6265SDimitry Andric case APIRecord::RK_StructField: 342*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 343*81ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 344*81ad6265SDimitry Andric break; 345*81ad6265SDimitry Andric case APIRecord::RK_Struct: 346*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("struct"); 347*81ad6265SDimitry Andric Kind["displayName"] = "Structure"; 348*81ad6265SDimitry Andric break; 349*81ad6265SDimitry Andric case APIRecord::RK_ObjCIvar: 350*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("ivar"); 351*81ad6265SDimitry Andric Kind["displayName"] = "Instance Variable"; 352*81ad6265SDimitry Andric break; 353*81ad6265SDimitry Andric case APIRecord::RK_ObjCMethod: 354*81ad6265SDimitry Andric if (dyn_cast<ObjCMethodRecord>(&Record)->IsInstanceMethod) { 355*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("method"); 356*81ad6265SDimitry Andric Kind["displayName"] = "Instance Method"; 357*81ad6265SDimitry Andric } else { 358*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("type.method"); 359*81ad6265SDimitry Andric Kind["displayName"] = "Type Method"; 360*81ad6265SDimitry Andric } 361*81ad6265SDimitry Andric break; 362*81ad6265SDimitry Andric case APIRecord::RK_ObjCProperty: 363*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("property"); 364*81ad6265SDimitry Andric Kind["displayName"] = "Instance Property"; 365*81ad6265SDimitry Andric break; 366*81ad6265SDimitry Andric case APIRecord::RK_ObjCInterface: 367*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("class"); 368*81ad6265SDimitry Andric Kind["displayName"] = "Class"; 369*81ad6265SDimitry Andric break; 370*81ad6265SDimitry Andric case APIRecord::RK_ObjCCategory: 371*81ad6265SDimitry Andric // We don't serialize out standalone Objective-C category symbols yet. 372*81ad6265SDimitry Andric llvm_unreachable("Serializing standalone Objective-C category symbols is " 373*81ad6265SDimitry Andric "not supported."); 374*81ad6265SDimitry Andric break; 375*81ad6265SDimitry Andric case APIRecord::RK_ObjCProtocol: 376*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("protocol"); 377*81ad6265SDimitry Andric Kind["displayName"] = "Protocol"; 378*81ad6265SDimitry Andric break; 379*81ad6265SDimitry Andric case APIRecord::RK_MacroDefinition: 380*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("macro"); 381*81ad6265SDimitry Andric Kind["displayName"] = "Macro"; 382*81ad6265SDimitry Andric break; 383*81ad6265SDimitry Andric case APIRecord::RK_Typedef: 384*81ad6265SDimitry Andric Kind["identifier"] = AddLangPrefix("typealias"); 385*81ad6265SDimitry Andric Kind["displayName"] = "Type Alias"; 386*81ad6265SDimitry Andric break; 387*81ad6265SDimitry Andric } 388*81ad6265SDimitry Andric 389*81ad6265SDimitry Andric return Kind; 390*81ad6265SDimitry Andric } 391*81ad6265SDimitry Andric 392*81ad6265SDimitry Andric template <typename RecordTy> 393*81ad6265SDimitry Andric Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record, 394*81ad6265SDimitry Andric std::true_type) { 395*81ad6265SDimitry Andric const auto &FS = Record.Signature; 396*81ad6265SDimitry Andric if (FS.empty()) 397*81ad6265SDimitry Andric return None; 398*81ad6265SDimitry Andric 399*81ad6265SDimitry Andric Object Signature; 400*81ad6265SDimitry Andric serializeArray(Signature, "returns", 401*81ad6265SDimitry Andric serializeDeclarationFragments(FS.getReturnType())); 402*81ad6265SDimitry Andric 403*81ad6265SDimitry Andric Array Parameters; 404*81ad6265SDimitry Andric for (const auto &P : FS.getParameters()) { 405*81ad6265SDimitry Andric Object Parameter; 406*81ad6265SDimitry Andric Parameter["name"] = P.Name; 407*81ad6265SDimitry Andric serializeArray(Parameter, "declarationFragments", 408*81ad6265SDimitry Andric serializeDeclarationFragments(P.Fragments)); 409*81ad6265SDimitry Andric Parameters.emplace_back(std::move(Parameter)); 410*81ad6265SDimitry Andric } 411*81ad6265SDimitry Andric 412*81ad6265SDimitry Andric if (!Parameters.empty()) 413*81ad6265SDimitry Andric Signature["parameters"] = std::move(Parameters); 414*81ad6265SDimitry Andric 415*81ad6265SDimitry Andric return Signature; 416*81ad6265SDimitry Andric } 417*81ad6265SDimitry Andric 418*81ad6265SDimitry Andric template <typename RecordTy> 419*81ad6265SDimitry Andric Optional<Object> serializeFunctionSignatureMixinImpl(const RecordTy &Record, 420*81ad6265SDimitry Andric std::false_type) { 421*81ad6265SDimitry Andric return None; 422*81ad6265SDimitry Andric } 423*81ad6265SDimitry Andric 424*81ad6265SDimitry Andric /// Serialize the function signature field, as specified by the 425*81ad6265SDimitry Andric /// Symbol Graph format. 426*81ad6265SDimitry Andric /// 427*81ad6265SDimitry Andric /// The Symbol Graph function signature property contains two arrays. 428*81ad6265SDimitry Andric /// - The \c returns array is the declaration fragments of the return type; 429*81ad6265SDimitry Andric /// - The \c parameters array contains names and declaration fragments of the 430*81ad6265SDimitry Andric /// parameters. 431*81ad6265SDimitry Andric /// 432*81ad6265SDimitry Andric /// \returns \c None if \p FS is empty, or an \c Object containing the 433*81ad6265SDimitry Andric /// formatted function signature. 434*81ad6265SDimitry Andric template <typename RecordTy> 435*81ad6265SDimitry Andric void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 436*81ad6265SDimitry Andric serializeObject(Paren, "functionSignature", 437*81ad6265SDimitry Andric serializeFunctionSignatureMixinImpl( 438*81ad6265SDimitry Andric Record, has_function_signature<RecordTy>())); 439*81ad6265SDimitry Andric } 440*81ad6265SDimitry Andric 441*81ad6265SDimitry Andric } // namespace 442*81ad6265SDimitry Andric 443*81ad6265SDimitry Andric void SymbolGraphSerializer::anchor() {} 444*81ad6265SDimitry Andric 445*81ad6265SDimitry Andric /// Defines the format version emitted by SymbolGraphSerializer. 446*81ad6265SDimitry Andric const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 447*81ad6265SDimitry Andric 448*81ad6265SDimitry Andric Object SymbolGraphSerializer::serializeMetadata() const { 449*81ad6265SDimitry Andric Object Metadata; 450*81ad6265SDimitry Andric serializeObject(Metadata, "formatVersion", 451*81ad6265SDimitry Andric serializeSemanticVersion(FormatVersion)); 452*81ad6265SDimitry Andric Metadata["generator"] = clang::getClangFullVersion(); 453*81ad6265SDimitry Andric return Metadata; 454*81ad6265SDimitry Andric } 455*81ad6265SDimitry Andric 456*81ad6265SDimitry Andric Object SymbolGraphSerializer::serializeModule() const { 457*81ad6265SDimitry Andric Object Module; 458*81ad6265SDimitry Andric // The user is expected to always pass `--product-name=` on the command line 459*81ad6265SDimitry Andric // to populate this field. 460*81ad6265SDimitry Andric Module["name"] = ProductName; 461*81ad6265SDimitry Andric serializeObject(Module, "platform", serializePlatform(API.getTarget())); 462*81ad6265SDimitry Andric return Module; 463*81ad6265SDimitry Andric } 464*81ad6265SDimitry Andric 465*81ad6265SDimitry Andric bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { 466*81ad6265SDimitry Andric // Skip unconditionally unavailable symbols 467*81ad6265SDimitry Andric if (Record.Availability.isUnconditionallyUnavailable()) 468*81ad6265SDimitry Andric return true; 469*81ad6265SDimitry Andric 470*81ad6265SDimitry Andric // Filter out symbols prefixed with an underscored as they are understood to 471*81ad6265SDimitry Andric // be symbols clients should not use. 472*81ad6265SDimitry Andric if (Record.Name.startswith("_")) 473*81ad6265SDimitry Andric return true; 474*81ad6265SDimitry Andric 475*81ad6265SDimitry Andric return false; 476*81ad6265SDimitry Andric } 477*81ad6265SDimitry Andric 478*81ad6265SDimitry Andric template <typename RecordTy> 479*81ad6265SDimitry Andric Optional<Object> 480*81ad6265SDimitry Andric SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { 481*81ad6265SDimitry Andric if (shouldSkip(Record)) 482*81ad6265SDimitry Andric return None; 483*81ad6265SDimitry Andric 484*81ad6265SDimitry Andric Object Obj; 485*81ad6265SDimitry Andric serializeObject(Obj, "identifier", 486*81ad6265SDimitry Andric serializeIdentifier(Record, API.getLanguage())); 487*81ad6265SDimitry Andric serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); 488*81ad6265SDimitry Andric serializeObject(Obj, "names", serializeNames(Record)); 489*81ad6265SDimitry Andric serializeObject( 490*81ad6265SDimitry Andric Obj, "location", 491*81ad6265SDimitry Andric serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); 492*81ad6265SDimitry Andric serializeObject(Obj, "availbility", 493*81ad6265SDimitry Andric serializeAvailability(Record.Availability)); 494*81ad6265SDimitry Andric serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); 495*81ad6265SDimitry Andric serializeArray(Obj, "declarationFragments", 496*81ad6265SDimitry Andric serializeDeclarationFragments(Record.Declaration)); 497*81ad6265SDimitry Andric // TODO: Once we keep track of symbol access information serialize it 498*81ad6265SDimitry Andric // correctly here. 499*81ad6265SDimitry Andric Obj["accessLevel"] = "public"; 500*81ad6265SDimitry Andric serializeArray(Obj, "pathComponents", Array(PathComponents)); 501*81ad6265SDimitry Andric 502*81ad6265SDimitry Andric serializeFunctionSignatureMixin(Obj, Record); 503*81ad6265SDimitry Andric 504*81ad6265SDimitry Andric return Obj; 505*81ad6265SDimitry Andric } 506*81ad6265SDimitry Andric 507*81ad6265SDimitry Andric template <typename MemberTy> 508*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeMembers( 509*81ad6265SDimitry Andric const APIRecord &Record, 510*81ad6265SDimitry Andric const SmallVector<std::unique_ptr<MemberTy>> &Members) { 511*81ad6265SDimitry Andric for (const auto &Member : Members) { 512*81ad6265SDimitry Andric auto MemberPathComponentGuard = makePathComponentGuard(Member->Name); 513*81ad6265SDimitry Andric auto MemberRecord = serializeAPIRecord(*Member); 514*81ad6265SDimitry Andric if (!MemberRecord) 515*81ad6265SDimitry Andric continue; 516*81ad6265SDimitry Andric 517*81ad6265SDimitry Andric Symbols.emplace_back(std::move(*MemberRecord)); 518*81ad6265SDimitry Andric serializeRelationship(RelationshipKind::MemberOf, *Member, Record); 519*81ad6265SDimitry Andric } 520*81ad6265SDimitry Andric } 521*81ad6265SDimitry Andric 522*81ad6265SDimitry Andric StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 523*81ad6265SDimitry Andric switch (Kind) { 524*81ad6265SDimitry Andric case RelationshipKind::MemberOf: 525*81ad6265SDimitry Andric return "memberOf"; 526*81ad6265SDimitry Andric case RelationshipKind::InheritsFrom: 527*81ad6265SDimitry Andric return "inheritsFrom"; 528*81ad6265SDimitry Andric case RelationshipKind::ConformsTo: 529*81ad6265SDimitry Andric return "conformsTo"; 530*81ad6265SDimitry Andric } 531*81ad6265SDimitry Andric llvm_unreachable("Unhandled relationship kind"); 532*81ad6265SDimitry Andric } 533*81ad6265SDimitry Andric 534*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 535*81ad6265SDimitry Andric SymbolReference Source, 536*81ad6265SDimitry Andric SymbolReference Target) { 537*81ad6265SDimitry Andric Object Relationship; 538*81ad6265SDimitry Andric Relationship["source"] = Source.USR; 539*81ad6265SDimitry Andric Relationship["target"] = Target.USR; 540*81ad6265SDimitry Andric Relationship["kind"] = getRelationshipString(Kind); 541*81ad6265SDimitry Andric 542*81ad6265SDimitry Andric Relationships.emplace_back(std::move(Relationship)); 543*81ad6265SDimitry Andric } 544*81ad6265SDimitry Andric 545*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeGlobalFunctionRecord( 546*81ad6265SDimitry Andric const GlobalFunctionRecord &Record) { 547*81ad6265SDimitry Andric auto GlobalPathComponentGuard = makePathComponentGuard(Record.Name); 548*81ad6265SDimitry Andric 549*81ad6265SDimitry Andric auto Obj = serializeAPIRecord(Record); 550*81ad6265SDimitry Andric if (!Obj) 551*81ad6265SDimitry Andric return; 552*81ad6265SDimitry Andric 553*81ad6265SDimitry Andric Symbols.emplace_back(std::move(*Obj)); 554*81ad6265SDimitry Andric } 555*81ad6265SDimitry Andric 556*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeGlobalVariableRecord( 557*81ad6265SDimitry Andric const GlobalVariableRecord &Record) { 558*81ad6265SDimitry Andric auto GlobalPathComponentGuard = makePathComponentGuard(Record.Name); 559*81ad6265SDimitry Andric 560*81ad6265SDimitry Andric auto Obj = serializeAPIRecord(Record); 561*81ad6265SDimitry Andric if (!Obj) 562*81ad6265SDimitry Andric return; 563*81ad6265SDimitry Andric 564*81ad6265SDimitry Andric Symbols.emplace_back(std::move(*Obj)); 565*81ad6265SDimitry Andric } 566*81ad6265SDimitry Andric 567*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeEnumRecord(const EnumRecord &Record) { 568*81ad6265SDimitry Andric auto EnumPathComponentGuard = makePathComponentGuard(Record.Name); 569*81ad6265SDimitry Andric auto Enum = serializeAPIRecord(Record); 570*81ad6265SDimitry Andric if (!Enum) 571*81ad6265SDimitry Andric return; 572*81ad6265SDimitry Andric 573*81ad6265SDimitry Andric Symbols.emplace_back(std::move(*Enum)); 574*81ad6265SDimitry Andric serializeMembers(Record, Record.Constants); 575*81ad6265SDimitry Andric } 576*81ad6265SDimitry Andric 577*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeStructRecord(const StructRecord &Record) { 578*81ad6265SDimitry Andric auto StructPathComponentGuard = makePathComponentGuard(Record.Name); 579*81ad6265SDimitry Andric auto Struct = serializeAPIRecord(Record); 580*81ad6265SDimitry Andric if (!Struct) 581*81ad6265SDimitry Andric return; 582*81ad6265SDimitry Andric 583*81ad6265SDimitry Andric Symbols.emplace_back(std::move(*Struct)); 584*81ad6265SDimitry Andric serializeMembers(Record, Record.Fields); 585*81ad6265SDimitry Andric } 586*81ad6265SDimitry Andric 587*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeObjCContainerRecord( 588*81ad6265SDimitry Andric const ObjCContainerRecord &Record) { 589*81ad6265SDimitry Andric auto ObjCContainerPathComponentGuard = makePathComponentGuard(Record.Name); 590*81ad6265SDimitry Andric auto ObjCContainer = serializeAPIRecord(Record); 591*81ad6265SDimitry Andric if (!ObjCContainer) 592*81ad6265SDimitry Andric return; 593*81ad6265SDimitry Andric 594*81ad6265SDimitry Andric Symbols.emplace_back(std::move(*ObjCContainer)); 595*81ad6265SDimitry Andric 596*81ad6265SDimitry Andric serializeMembers(Record, Record.Ivars); 597*81ad6265SDimitry Andric serializeMembers(Record, Record.Methods); 598*81ad6265SDimitry Andric serializeMembers(Record, Record.Properties); 599*81ad6265SDimitry Andric 600*81ad6265SDimitry Andric for (const auto &Protocol : Record.Protocols) 601*81ad6265SDimitry Andric // Record that Record conforms to Protocol. 602*81ad6265SDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 603*81ad6265SDimitry Andric 604*81ad6265SDimitry Andric if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) { 605*81ad6265SDimitry Andric if (!ObjCInterface->SuperClass.empty()) 606*81ad6265SDimitry Andric // If Record is an Objective-C interface record and it has a super class, 607*81ad6265SDimitry Andric // record that Record is inherited from SuperClass. 608*81ad6265SDimitry Andric serializeRelationship(RelationshipKind::InheritsFrom, Record, 609*81ad6265SDimitry Andric ObjCInterface->SuperClass); 610*81ad6265SDimitry Andric 611*81ad6265SDimitry Andric // Members of categories extending an interface are serialized as members of 612*81ad6265SDimitry Andric // the interface. 613*81ad6265SDimitry Andric for (const auto *Category : ObjCInterface->Categories) { 614*81ad6265SDimitry Andric serializeMembers(Record, Category->Ivars); 615*81ad6265SDimitry Andric serializeMembers(Record, Category->Methods); 616*81ad6265SDimitry Andric serializeMembers(Record, Category->Properties); 617*81ad6265SDimitry Andric 618*81ad6265SDimitry Andric // Surface the protocols of the the category to the interface. 619*81ad6265SDimitry Andric for (const auto &Protocol : Category->Protocols) 620*81ad6265SDimitry Andric serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 621*81ad6265SDimitry Andric } 622*81ad6265SDimitry Andric } 623*81ad6265SDimitry Andric } 624*81ad6265SDimitry Andric 625*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeMacroDefinitionRecord( 626*81ad6265SDimitry Andric const MacroDefinitionRecord &Record) { 627*81ad6265SDimitry Andric auto MacroPathComponentGuard = makePathComponentGuard(Record.Name); 628*81ad6265SDimitry Andric auto Macro = serializeAPIRecord(Record); 629*81ad6265SDimitry Andric 630*81ad6265SDimitry Andric if (!Macro) 631*81ad6265SDimitry Andric return; 632*81ad6265SDimitry Andric 633*81ad6265SDimitry Andric Symbols.emplace_back(std::move(*Macro)); 634*81ad6265SDimitry Andric } 635*81ad6265SDimitry Andric 636*81ad6265SDimitry Andric void SymbolGraphSerializer::serializeTypedefRecord( 637*81ad6265SDimitry Andric const TypedefRecord &Record) { 638*81ad6265SDimitry Andric // Typedefs of anonymous types have their entries unified with the underlying 639*81ad6265SDimitry Andric // type. 640*81ad6265SDimitry Andric bool ShouldDrop = Record.UnderlyingType.Name.empty(); 641*81ad6265SDimitry Andric // enums declared with `NS_OPTION` have a named enum and a named typedef, with 642*81ad6265SDimitry Andric // the same name 643*81ad6265SDimitry Andric ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); 644*81ad6265SDimitry Andric if (ShouldDrop) 645*81ad6265SDimitry Andric return; 646*81ad6265SDimitry Andric 647*81ad6265SDimitry Andric auto TypedefPathComponentGuard = makePathComponentGuard(Record.Name); 648*81ad6265SDimitry Andric auto Typedef = serializeAPIRecord(Record); 649*81ad6265SDimitry Andric if (!Typedef) 650*81ad6265SDimitry Andric return; 651*81ad6265SDimitry Andric 652*81ad6265SDimitry Andric (*Typedef)["type"] = Record.UnderlyingType.USR; 653*81ad6265SDimitry Andric 654*81ad6265SDimitry Andric Symbols.emplace_back(std::move(*Typedef)); 655*81ad6265SDimitry Andric } 656*81ad6265SDimitry Andric 657*81ad6265SDimitry Andric SymbolGraphSerializer::PathComponentGuard 658*81ad6265SDimitry Andric SymbolGraphSerializer::makePathComponentGuard(StringRef Component) { 659*81ad6265SDimitry Andric return PathComponentGuard(PathComponents, Component); 660*81ad6265SDimitry Andric } 661*81ad6265SDimitry Andric 662*81ad6265SDimitry Andric Object SymbolGraphSerializer::serialize() { 663*81ad6265SDimitry Andric Object Root; 664*81ad6265SDimitry Andric serializeObject(Root, "metadata", serializeMetadata()); 665*81ad6265SDimitry Andric serializeObject(Root, "module", serializeModule()); 666*81ad6265SDimitry Andric 667*81ad6265SDimitry Andric // Serialize global variables in the API set. 668*81ad6265SDimitry Andric for (const auto &GlobalVar : API.getGlobalVariables()) 669*81ad6265SDimitry Andric serializeGlobalVariableRecord(*GlobalVar.second); 670*81ad6265SDimitry Andric 671*81ad6265SDimitry Andric for (const auto &GlobalFunction : API.getGlobalFunctions()) 672*81ad6265SDimitry Andric serializeGlobalFunctionRecord(*GlobalFunction.second); 673*81ad6265SDimitry Andric 674*81ad6265SDimitry Andric // Serialize enum records in the API set. 675*81ad6265SDimitry Andric for (const auto &Enum : API.getEnums()) 676*81ad6265SDimitry Andric serializeEnumRecord(*Enum.second); 677*81ad6265SDimitry Andric 678*81ad6265SDimitry Andric // Serialize struct records in the API set. 679*81ad6265SDimitry Andric for (const auto &Struct : API.getStructs()) 680*81ad6265SDimitry Andric serializeStructRecord(*Struct.second); 681*81ad6265SDimitry Andric 682*81ad6265SDimitry Andric // Serialize Objective-C interface records in the API set. 683*81ad6265SDimitry Andric for (const auto &ObjCInterface : API.getObjCInterfaces()) 684*81ad6265SDimitry Andric serializeObjCContainerRecord(*ObjCInterface.second); 685*81ad6265SDimitry Andric 686*81ad6265SDimitry Andric // Serialize Objective-C protocol records in the API set. 687*81ad6265SDimitry Andric for (const auto &ObjCProtocol : API.getObjCProtocols()) 688*81ad6265SDimitry Andric serializeObjCContainerRecord(*ObjCProtocol.second); 689*81ad6265SDimitry Andric 690*81ad6265SDimitry Andric for (const auto &Macro : API.getMacros()) 691*81ad6265SDimitry Andric serializeMacroDefinitionRecord(*Macro.second); 692*81ad6265SDimitry Andric 693*81ad6265SDimitry Andric for (const auto &Typedef : API.getTypedefs()) 694*81ad6265SDimitry Andric serializeTypedefRecord(*Typedef.second); 695*81ad6265SDimitry Andric 696*81ad6265SDimitry Andric Root["symbols"] = std::move(Symbols); 697*81ad6265SDimitry Andric Root["relationships"] = std::move(Relationships); 698*81ad6265SDimitry Andric 699*81ad6265SDimitry Andric return Root; 700*81ad6265SDimitry Andric } 701*81ad6265SDimitry Andric 702*81ad6265SDimitry Andric void SymbolGraphSerializer::serialize(raw_ostream &os) { 703*81ad6265SDimitry Andric Object root = serialize(); 704*81ad6265SDimitry Andric if (Options.Compact) 705*81ad6265SDimitry Andric os << formatv("{0}", Value(std::move(root))) << "\n"; 706*81ad6265SDimitry Andric else 707*81ad6265SDimitry Andric os << formatv("{0:2}", Value(std::move(root))) << "\n"; 708*81ad6265SDimitry Andric } 709