1 //===- ExtractAPI/Serialization/SymbolGraphSerializer.cpp -------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 /// 9 /// \file 10 /// This file implements the SymbolGraphSerializer. 11 /// 12 //===----------------------------------------------------------------------===// 13 14 #include "clang/ExtractAPI/Serialization/SymbolGraphSerializer.h" 15 #include "clang/Basic/SourceLocation.h" 16 #include "clang/Basic/Version.h" 17 #include "clang/ExtractAPI/DeclarationFragments.h" 18 #include "llvm/ADT/STLExtras.h" 19 #include "llvm/ADT/STLFunctionalExtras.h" 20 #include "llvm/Support/Casting.h" 21 #include "llvm/Support/Compiler.h" 22 #include "llvm/Support/Path.h" 23 #include "llvm/Support/VersionTuple.h" 24 #include <optional> 25 #include <type_traits> 26 27 using namespace clang; 28 using namespace clang::extractapi; 29 using namespace llvm; 30 using namespace llvm::json; 31 32 namespace { 33 34 /// Helper function to inject a JSON object \p Obj into another object \p Paren 35 /// at position \p Key. 36 void serializeObject(Object &Paren, StringRef Key, std::optional<Object> Obj) { 37 if (Obj) 38 Paren[Key] = std::move(*Obj); 39 } 40 41 /// Helper function to inject a StringRef \p String into an object \p Paren at 42 /// position \p Key 43 void serializeString(Object &Paren, StringRef Key, 44 std::optional<std::string> String) { 45 if (String) 46 Paren[Key] = std::move(*String); 47 } 48 49 /// Helper function to inject a JSON array \p Array into object \p Paren at 50 /// position \p Key. 51 void serializeArray(Object &Paren, StringRef Key, std::optional<Array> Array) { 52 if (Array) 53 Paren[Key] = std::move(*Array); 54 } 55 56 /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 57 /// format. 58 /// 59 /// A semantic version object contains three numeric fields, representing the 60 /// \c major, \c minor, and \c patch parts of the version tuple. 61 /// For example version tuple 1.0.3 is serialized as: 62 /// \code 63 /// { 64 /// "major" : 1, 65 /// "minor" : 0, 66 /// "patch" : 3 67 /// } 68 /// \endcode 69 /// 70 /// \returns \c std::nullopt if the version \p V is empty, or an \c Object 71 /// containing the semantic version representation of \p V. 72 std::optional<Object> serializeSemanticVersion(const VersionTuple &V) { 73 if (V.empty()) 74 return std::nullopt; 75 76 Object Version; 77 Version["major"] = V.getMajor(); 78 Version["minor"] = V.getMinor().value_or(0); 79 Version["patch"] = V.getSubminor().value_or(0); 80 return Version; 81 } 82 83 /// Serialize the OS information in the Symbol Graph platform property. 84 /// 85 /// The OS information in Symbol Graph contains the \c name of the OS, and an 86 /// optional \c minimumVersion semantic version field. 87 Object serializeOperatingSystem(const Triple &T) { 88 Object OS; 89 OS["name"] = T.getOSTypeName(T.getOS()); 90 serializeObject(OS, "minimumVersion", 91 serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 92 return OS; 93 } 94 95 /// Serialize the platform information in the Symbol Graph module section. 96 /// 97 /// The platform object describes a target platform triple in corresponding 98 /// three fields: \c architecture, \c vendor, and \c operatingSystem. 99 Object serializePlatform(const Triple &T) { 100 Object Platform; 101 Platform["architecture"] = T.getArchName(); 102 Platform["vendor"] = T.getVendorName(); 103 Platform["operatingSystem"] = serializeOperatingSystem(T); 104 return Platform; 105 } 106 107 /// Serialize a source position. 108 Object serializeSourcePosition(const PresumedLoc &Loc) { 109 assert(Loc.isValid() && "invalid source position"); 110 111 Object SourcePosition; 112 SourcePosition["line"] = Loc.getLine() - 1; 113 SourcePosition["character"] = Loc.getColumn() - 1; 114 115 return SourcePosition; 116 } 117 118 /// Serialize a source location in file. 119 /// 120 /// \param Loc The presumed location to serialize. 121 /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 122 /// Defaults to false. 123 Object serializeSourceLocation(const PresumedLoc &Loc, 124 bool IncludeFileURI = false) { 125 Object SourceLocation; 126 serializeObject(SourceLocation, "position", serializeSourcePosition(Loc)); 127 128 if (IncludeFileURI) { 129 std::string FileURI = "file://"; 130 // Normalize file path to use forward slashes for the URI. 131 FileURI += sys::path::convert_to_slash(Loc.getFilename()); 132 SourceLocation["uri"] = FileURI; 133 } 134 135 return SourceLocation; 136 } 137 138 /// Serialize a source range with begin and end locations. 139 Object serializeSourceRange(const PresumedLoc &BeginLoc, 140 const PresumedLoc &EndLoc) { 141 Object SourceRange; 142 serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 143 serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 144 return SourceRange; 145 } 146 147 /// Serialize the availability attributes of a symbol. 148 /// 149 /// Availability information contains the introduced, deprecated, and obsoleted 150 /// versions of the symbol for a given domain (roughly corresponds to a 151 /// platform) as semantic versions, if not default. Availability information 152 /// also contains flags to indicate if the symbol is unconditionally unavailable 153 /// or deprecated, i.e. \c __attribute__((unavailable)) and \c 154 /// __attribute__((deprecated)). 155 /// 156 /// \returns \c std::nullopt if the symbol has default availability attributes, 157 /// or an \c Array containing the formatted availability information. 158 std::optional<Array> 159 serializeAvailability(const AvailabilitySet &Availabilities) { 160 if (Availabilities.isDefault()) 161 return std::nullopt; 162 163 Array AvailabilityArray; 164 165 if (Availabilities.isUnconditionallyDeprecated()) { 166 Object UnconditionallyDeprecated; 167 UnconditionallyDeprecated["domain"] = "*"; 168 UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true; 169 AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated)); 170 } 171 172 // Note unconditionally unavailable records are skipped. 173 174 for (const auto &AvailInfo : Availabilities) { 175 Object Availability; 176 Availability["domain"] = AvailInfo.Domain; 177 if (AvailInfo.Unavailable) 178 Availability["isUnconditionallyUnavailable"] = true; 179 else { 180 serializeObject(Availability, "introduced", 181 serializeSemanticVersion(AvailInfo.Introduced)); 182 serializeObject(Availability, "deprecated", 183 serializeSemanticVersion(AvailInfo.Deprecated)); 184 serializeObject(Availability, "obsoleted", 185 serializeSemanticVersion(AvailInfo.Obsoleted)); 186 } 187 AvailabilityArray.emplace_back(std::move(Availability)); 188 } 189 190 return AvailabilityArray; 191 } 192 193 /// Get the language name string for interface language references. 194 StringRef getLanguageName(Language Lang) { 195 switch (Lang) { 196 case Language::C: 197 return "c"; 198 case Language::ObjC: 199 return "objective-c"; 200 case Language::CXX: 201 return "c++"; 202 case Language::ObjCXX: 203 return "objective-c++"; 204 205 // Unsupported language currently 206 case Language::OpenCL: 207 case Language::OpenCLCXX: 208 case Language::CUDA: 209 case Language::RenderScript: 210 case Language::HIP: 211 case Language::HLSL: 212 213 // Languages that the frontend cannot parse and compile 214 case Language::Unknown: 215 case Language::Asm: 216 case Language::LLVM_IR: 217 llvm_unreachable("Unsupported language kind"); 218 } 219 220 llvm_unreachable("Unhandled language kind"); 221 } 222 223 /// Serialize the identifier object as specified by the Symbol Graph format. 224 /// 225 /// The identifier property of a symbol contains the USR for precise and unique 226 /// references, and the interface language name. 227 Object serializeIdentifier(const APIRecord &Record, Language Lang) { 228 Object Identifier; 229 Identifier["precise"] = Record.USR; 230 Identifier["interfaceLanguage"] = getLanguageName(Lang); 231 232 return Identifier; 233 } 234 235 /// Serialize the documentation comments attached to a symbol, as specified by 236 /// the Symbol Graph format. 237 /// 238 /// The Symbol Graph \c docComment object contains an array of lines. Each line 239 /// represents one line of striped documentation comment, with source range 240 /// information. 241 /// e.g. 242 /// \code 243 /// /// This is a documentation comment 244 /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 245 /// /// with multiple lines. 246 /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 247 /// \endcode 248 /// 249 /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing 250 /// the formatted lines. 251 std::optional<Object> serializeDocComment(const DocComment &Comment) { 252 if (Comment.empty()) 253 return std::nullopt; 254 255 Object DocComment; 256 Array LinesArray; 257 for (const auto &CommentLine : Comment) { 258 Object Line; 259 Line["text"] = CommentLine.Text; 260 serializeObject(Line, "range", 261 serializeSourceRange(CommentLine.Begin, CommentLine.End)); 262 LinesArray.emplace_back(std::move(Line)); 263 } 264 serializeArray(DocComment, "lines", LinesArray); 265 266 return DocComment; 267 } 268 269 /// Serialize the declaration fragments of a symbol. 270 /// 271 /// The Symbol Graph declaration fragments is an array of tagged important 272 /// parts of a symbol's declaration. The fragments sequence can be joined to 273 /// form spans of declaration text, with attached information useful for 274 /// purposes like syntax-highlighting etc. For example: 275 /// \code 276 /// const int pi; -> "declarationFragments" : [ 277 /// { 278 /// "kind" : "keyword", 279 /// "spelling" : "const" 280 /// }, 281 /// { 282 /// "kind" : "text", 283 /// "spelling" : " " 284 /// }, 285 /// { 286 /// "kind" : "typeIdentifier", 287 /// "preciseIdentifier" : "c:I", 288 /// "spelling" : "int" 289 /// }, 290 /// { 291 /// "kind" : "text", 292 /// "spelling" : " " 293 /// }, 294 /// { 295 /// "kind" : "identifier", 296 /// "spelling" : "pi" 297 /// } 298 /// ] 299 /// \endcode 300 /// 301 /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the 302 /// formatted declaration fragments array. 303 std::optional<Array> 304 serializeDeclarationFragments(const DeclarationFragments &DF) { 305 if (DF.getFragments().empty()) 306 return std::nullopt; 307 308 Array Fragments; 309 for (const auto &F : DF.getFragments()) { 310 Object Fragment; 311 Fragment["spelling"] = F.Spelling; 312 Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 313 if (!F.PreciseIdentifier.empty()) 314 Fragment["preciseIdentifier"] = F.PreciseIdentifier; 315 Fragments.emplace_back(std::move(Fragment)); 316 } 317 318 return Fragments; 319 } 320 321 /// Serialize the \c names field of a symbol as specified by the Symbol Graph 322 /// format. 323 /// 324 /// The Symbol Graph names field contains multiple representations of a symbol 325 /// that can be used for different applications: 326 /// - \c title : The simple declared name of the symbol; 327 /// - \c subHeading : An array of declaration fragments that provides tags, 328 /// and potentially more tokens (for example the \c +/- symbol for 329 /// Objective-C methods). Can be used as sub-headings for documentation. 330 Object serializeNames(const APIRecord &Record) { 331 Object Names; 332 if (auto *CategoryRecord = 333 dyn_cast_or_null<const ObjCCategoryRecord>(&Record)) 334 Names["title"] = 335 (CategoryRecord->Interface.Name + " (" + Record.Name + ")").str(); 336 else 337 Names["title"] = Record.Name; 338 339 serializeArray(Names, "subHeading", 340 serializeDeclarationFragments(Record.SubHeading)); 341 DeclarationFragments NavigatorFragments; 342 NavigatorFragments.append(Record.Name, 343 DeclarationFragments::FragmentKind::Identifier, 344 /*PreciseIdentifier*/ ""); 345 serializeArray(Names, "navigator", 346 serializeDeclarationFragments(NavigatorFragments)); 347 348 return Names; 349 } 350 351 Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { 352 auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 353 return (getLanguageName(Lang) + "." + S).str(); 354 }; 355 356 Object Kind; 357 switch (RK) { 358 case APIRecord::RK_Unknown: 359 llvm_unreachable("Records should have an explicit kind"); 360 break; 361 case APIRecord::RK_Namespace: 362 Kind["identifier"] = AddLangPrefix("namespace"); 363 Kind["displayName"] = "Namespace"; 364 break; 365 case APIRecord::RK_GlobalFunction: 366 Kind["identifier"] = AddLangPrefix("func"); 367 Kind["displayName"] = "Function"; 368 break; 369 case APIRecord::RK_GlobalFunctionTemplate: 370 Kind["identifier"] = AddLangPrefix("func"); 371 Kind["displayName"] = "Function Template"; 372 break; 373 case APIRecord::RK_GlobalFunctionTemplateSpecialization: 374 Kind["identifier"] = AddLangPrefix("func"); 375 Kind["displayName"] = "Function Template Specialization"; 376 break; 377 case APIRecord::RK_GlobalVariableTemplate: 378 Kind["identifier"] = AddLangPrefix("var"); 379 Kind["displayName"] = "Global Variable Template"; 380 break; 381 case APIRecord::RK_GlobalVariableTemplateSpecialization: 382 Kind["identifier"] = AddLangPrefix("var"); 383 Kind["displayName"] = "Global Variable Template Specialization"; 384 break; 385 case APIRecord::RK_GlobalVariableTemplatePartialSpecialization: 386 Kind["identifier"] = AddLangPrefix("var"); 387 Kind["displayName"] = "Global Variable Template Partial Specialization"; 388 break; 389 case APIRecord::RK_GlobalVariable: 390 Kind["identifier"] = AddLangPrefix("var"); 391 Kind["displayName"] = "Global Variable"; 392 break; 393 case APIRecord::RK_EnumConstant: 394 Kind["identifier"] = AddLangPrefix("enum.case"); 395 Kind["displayName"] = "Enumeration Case"; 396 break; 397 case APIRecord::RK_Enum: 398 Kind["identifier"] = AddLangPrefix("enum"); 399 Kind["displayName"] = "Enumeration"; 400 break; 401 case APIRecord::RK_StructField: 402 Kind["identifier"] = AddLangPrefix("property"); 403 Kind["displayName"] = "Instance Property"; 404 break; 405 case APIRecord::RK_Struct: 406 Kind["identifier"] = AddLangPrefix("struct"); 407 Kind["displayName"] = "Structure"; 408 break; 409 case APIRecord::RK_CXXField: 410 Kind["identifier"] = AddLangPrefix("property"); 411 Kind["displayName"] = "Instance Property"; 412 break; 413 case APIRecord::RK_Union: 414 Kind["identifier"] = AddLangPrefix("union"); 415 Kind["displayName"] = "Union"; 416 break; 417 case APIRecord::RK_StaticField: 418 Kind["identifier"] = AddLangPrefix("type.property"); 419 Kind["displayName"] = "Type Property"; 420 break; 421 case APIRecord::RK_ClassTemplate: 422 case APIRecord::RK_ClassTemplateSpecialization: 423 case APIRecord::RK_ClassTemplatePartialSpecialization: 424 case APIRecord::RK_CXXClass: 425 Kind["identifier"] = AddLangPrefix("class"); 426 Kind["displayName"] = "Class"; 427 break; 428 case APIRecord::RK_CXXMethodTemplate: 429 Kind["identifier"] = AddLangPrefix("method"); 430 Kind["displayName"] = "Method Template"; 431 break; 432 case APIRecord::RK_CXXMethodTemplateSpecialization: 433 Kind["identifier"] = AddLangPrefix("method"); 434 Kind["displayName"] = "Method Template Specialization"; 435 break; 436 case APIRecord::RK_CXXFieldTemplate: 437 Kind["identifier"] = AddLangPrefix("property"); 438 Kind["displayName"] = "Template Property"; 439 break; 440 case APIRecord::RK_Concept: 441 Kind["identifier"] = AddLangPrefix("concept"); 442 Kind["displayName"] = "Concept"; 443 break; 444 case APIRecord::RK_CXXStaticMethod: 445 Kind["identifier"] = AddLangPrefix("type.method"); 446 Kind["displayName"] = "Static Method"; 447 break; 448 case APIRecord::RK_CXXInstanceMethod: 449 Kind["identifier"] = AddLangPrefix("method"); 450 Kind["displayName"] = "Instance Method"; 451 break; 452 case APIRecord::RK_CXXConstructorMethod: 453 Kind["identifier"] = AddLangPrefix("method"); 454 Kind["displayName"] = "Constructor"; 455 break; 456 case APIRecord::RK_CXXDestructorMethod: 457 Kind["identifier"] = AddLangPrefix("method"); 458 Kind["displayName"] = "Destructor"; 459 break; 460 case APIRecord::RK_ObjCIvar: 461 Kind["identifier"] = AddLangPrefix("ivar"); 462 Kind["displayName"] = "Instance Variable"; 463 break; 464 case APIRecord::RK_ObjCInstanceMethod: 465 Kind["identifier"] = AddLangPrefix("method"); 466 Kind["displayName"] = "Instance Method"; 467 break; 468 case APIRecord::RK_ObjCClassMethod: 469 Kind["identifier"] = AddLangPrefix("type.method"); 470 Kind["displayName"] = "Type Method"; 471 break; 472 case APIRecord::RK_ObjCInstanceProperty: 473 Kind["identifier"] = AddLangPrefix("property"); 474 Kind["displayName"] = "Instance Property"; 475 break; 476 case APIRecord::RK_ObjCClassProperty: 477 Kind["identifier"] = AddLangPrefix("type.property"); 478 Kind["displayName"] = "Type Property"; 479 break; 480 case APIRecord::RK_ObjCInterface: 481 Kind["identifier"] = AddLangPrefix("class"); 482 Kind["displayName"] = "Class"; 483 break; 484 case APIRecord::RK_ObjCCategory: 485 Kind["identifier"] = AddLangPrefix("class.extension"); 486 Kind["displayName"] = "Class Extension"; 487 break; 488 case APIRecord::RK_ObjCCategoryModule: 489 Kind["identifier"] = AddLangPrefix("module.extension"); 490 Kind["displayName"] = "Module Extension"; 491 break; 492 case APIRecord::RK_ObjCProtocol: 493 Kind["identifier"] = AddLangPrefix("protocol"); 494 Kind["displayName"] = "Protocol"; 495 break; 496 case APIRecord::RK_MacroDefinition: 497 Kind["identifier"] = AddLangPrefix("macro"); 498 Kind["displayName"] = "Macro"; 499 break; 500 case APIRecord::RK_Typedef: 501 Kind["identifier"] = AddLangPrefix("typealias"); 502 Kind["displayName"] = "Type Alias"; 503 break; 504 } 505 506 return Kind; 507 } 508 509 /// Serialize the symbol kind information. 510 /// 511 /// The Symbol Graph symbol kind property contains a shorthand \c identifier 512 /// which is prefixed by the source language name, useful for tooling to parse 513 /// the kind, and a \c displayName for rendering human-readable names. 514 Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 515 return serializeSymbolKind(Record.getKind(), Lang); 516 } 517 518 template <typename RecordTy> 519 std::optional<Object> 520 serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::true_type) { 521 const auto &FS = Record.Signature; 522 if (FS.empty()) 523 return std::nullopt; 524 525 Object Signature; 526 serializeArray(Signature, "returns", 527 serializeDeclarationFragments(FS.getReturnType())); 528 529 Array Parameters; 530 for (const auto &P : FS.getParameters()) { 531 Object Parameter; 532 Parameter["name"] = P.Name; 533 serializeArray(Parameter, "declarationFragments", 534 serializeDeclarationFragments(P.Fragments)); 535 Parameters.emplace_back(std::move(Parameter)); 536 } 537 538 if (!Parameters.empty()) 539 Signature["parameters"] = std::move(Parameters); 540 541 return Signature; 542 } 543 544 template <typename RecordTy> 545 std::optional<Object> 546 serializeFunctionSignatureMixinImpl(const RecordTy &Record, std::false_type) { 547 return std::nullopt; 548 } 549 550 /// Serialize the function signature field, as specified by the 551 /// Symbol Graph format. 552 /// 553 /// The Symbol Graph function signature property contains two arrays. 554 /// - The \c returns array is the declaration fragments of the return type; 555 /// - The \c parameters array contains names and declaration fragments of the 556 /// parameters. 557 /// 558 /// \returns \c std::nullopt if \p FS is empty, or an \c Object containing the 559 /// formatted function signature. 560 template <typename RecordTy> 561 void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 562 serializeObject(Paren, "functionSignature", 563 serializeFunctionSignatureMixinImpl( 564 Record, has_function_signature<RecordTy>())); 565 } 566 567 template <typename RecordTy> 568 std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, 569 std::true_type) { 570 const auto &AccessControl = Record.Access; 571 std::string Access; 572 if (AccessControl.empty()) 573 return std::nullopt; 574 Access = AccessControl.getAccess(); 575 return Access; 576 } 577 578 template <typename RecordTy> 579 std::optional<std::string> serializeAccessMixinImpl(const RecordTy &Record, 580 std::false_type) { 581 return std::nullopt; 582 } 583 584 template <typename RecordTy> 585 void serializeAccessMixin(Object &Paren, const RecordTy &Record) { 586 auto accessLevel = serializeAccessMixinImpl(Record, has_access<RecordTy>()); 587 if (!accessLevel.has_value()) 588 accessLevel = "public"; 589 serializeString(Paren, "accessLevel", accessLevel); 590 } 591 592 template <typename RecordTy> 593 std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, 594 std::true_type) { 595 const auto &Template = Record.Templ; 596 if (Template.empty()) 597 return std::nullopt; 598 599 Object Generics; 600 Array GenericParameters; 601 for (const auto &Param : Template.getParameters()) { 602 Object Parameter; 603 Parameter["name"] = Param.Name; 604 Parameter["index"] = Param.Index; 605 Parameter["depth"] = Param.Depth; 606 GenericParameters.emplace_back(std::move(Parameter)); 607 } 608 if (!GenericParameters.empty()) 609 Generics["parameters"] = std::move(GenericParameters); 610 611 Array GenericConstraints; 612 for (const auto &Constr : Template.getConstraints()) { 613 Object Constraint; 614 Constraint["kind"] = Constr.Kind; 615 Constraint["lhs"] = Constr.LHS; 616 Constraint["rhs"] = Constr.RHS; 617 GenericConstraints.emplace_back(std::move(Constraint)); 618 } 619 620 if (!GenericConstraints.empty()) 621 Generics["constraints"] = std::move(GenericConstraints); 622 623 return Generics; 624 } 625 626 template <typename RecordTy> 627 std::optional<Object> serializeTemplateMixinImpl(const RecordTy &Record, 628 std::false_type) { 629 return std::nullopt; 630 } 631 632 template <typename RecordTy> 633 void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { 634 serializeObject(Paren, "swiftGenerics", 635 serializeTemplateMixinImpl(Record, has_template<RecordTy>())); 636 } 637 638 struct PathComponent { 639 StringRef USR; 640 StringRef Name; 641 APIRecord::RecordKind Kind; 642 643 PathComponent(StringRef USR, StringRef Name, APIRecord::RecordKind Kind) 644 : USR(USR), Name(Name), Kind(Kind) {} 645 }; 646 647 template <typename RecordTy> 648 bool generatePathComponents( 649 const RecordTy &Record, const APISet &API, 650 function_ref<void(const PathComponent &)> ComponentTransformer) { 651 SmallVector<PathComponent, 4> ReverseComponenents; 652 ReverseComponenents.emplace_back(Record.USR, Record.Name, Record.getKind()); 653 const auto *CurrentParent = &Record.ParentInformation; 654 bool FailedToFindParent = false; 655 while (CurrentParent && !CurrentParent->empty()) { 656 PathComponent CurrentParentComponent(CurrentParent->ParentUSR, 657 CurrentParent->ParentName, 658 CurrentParent->ParentKind); 659 660 auto *ParentRecord = CurrentParent->ParentRecord; 661 // Slow path if we don't have a direct reference to the ParentRecord 662 if (!ParentRecord) 663 ParentRecord = API.findRecordForUSR(CurrentParent->ParentUSR); 664 665 // If the parent is a category extended from internal module then we need to 666 // pretend this belongs to the associated interface. 667 if (auto *CategoryRecord = 668 dyn_cast_or_null<ObjCCategoryRecord>(ParentRecord)) { 669 if (!CategoryRecord->IsFromExternalModule) { 670 ParentRecord = API.findRecordForUSR(CategoryRecord->Interface.USR); 671 CurrentParentComponent = PathComponent(CategoryRecord->Interface.USR, 672 CategoryRecord->Interface.Name, 673 APIRecord::RK_ObjCInterface); 674 } 675 } 676 677 // The parent record doesn't exist which means the symbol shouldn't be 678 // treated as part of the current product. 679 if (!ParentRecord) { 680 FailedToFindParent = true; 681 break; 682 } 683 684 ReverseComponenents.push_back(std::move(CurrentParentComponent)); 685 CurrentParent = &ParentRecord->ParentInformation; 686 } 687 688 for (const auto &PC : reverse(ReverseComponenents)) 689 ComponentTransformer(PC); 690 691 return FailedToFindParent; 692 } 693 694 Object serializeParentContext(const PathComponent &PC, Language Lang) { 695 Object ParentContextElem; 696 ParentContextElem["usr"] = PC.USR; 697 ParentContextElem["name"] = PC.Name; 698 ParentContextElem["kind"] = serializeSymbolKind(PC.Kind, Lang)["identifier"]; 699 return ParentContextElem; 700 } 701 702 template <typename RecordTy> 703 Array generateParentContexts(const RecordTy &Record, const APISet &API, 704 Language Lang) { 705 Array ParentContexts; 706 generatePathComponents( 707 Record, API, [Lang, &ParentContexts](const PathComponent &PC) { 708 ParentContexts.push_back(serializeParentContext(PC, Lang)); 709 }); 710 711 return ParentContexts; 712 } 713 } // namespace 714 715 /// Defines the format version emitted by SymbolGraphSerializer. 716 const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 717 718 Object SymbolGraphSerializer::serializeMetadata() const { 719 Object Metadata; 720 serializeObject(Metadata, "formatVersion", 721 serializeSemanticVersion(FormatVersion)); 722 Metadata["generator"] = clang::getClangFullVersion(); 723 return Metadata; 724 } 725 726 Object SymbolGraphSerializer::serializeModule() const { 727 Object Module; 728 // The user is expected to always pass `--product-name=` on the command line 729 // to populate this field. 730 Module["name"] = API.ProductName; 731 serializeObject(Module, "platform", serializePlatform(API.getTarget())); 732 return Module; 733 } 734 735 bool SymbolGraphSerializer::shouldSkip(const APIRecord &Record) const { 736 // Skip explicitly ignored symbols. 737 if (IgnoresList.shouldIgnore(Record.Name)) 738 return true; 739 740 // Skip unconditionally unavailable symbols 741 if (Record.Availabilities.isUnconditionallyUnavailable()) 742 return true; 743 744 // Filter out symbols prefixed with an underscored as they are understood to 745 // be symbols clients should not use. 746 if (Record.Name.starts_with("_")) 747 return true; 748 749 return false; 750 } 751 752 template <typename RecordTy> 753 std::optional<Object> 754 SymbolGraphSerializer::serializeAPIRecord(const RecordTy &Record) const { 755 if (shouldSkip(Record)) 756 return std::nullopt; 757 758 Object Obj; 759 serializeObject(Obj, "identifier", 760 serializeIdentifier(Record, API.getLanguage())); 761 serializeObject(Obj, "kind", serializeSymbolKind(Record, API.getLanguage())); 762 serializeObject(Obj, "names", serializeNames(Record)); 763 serializeObject( 764 Obj, "location", 765 serializeSourceLocation(Record.Location, /*IncludeFileURI=*/true)); 766 serializeArray(Obj, "availability", 767 serializeAvailability(Record.Availabilities)); 768 serializeObject(Obj, "docComment", serializeDocComment(Record.Comment)); 769 serializeArray(Obj, "declarationFragments", 770 serializeDeclarationFragments(Record.Declaration)); 771 SmallVector<StringRef, 4> PathComponentsNames; 772 // If this returns true it indicates that we couldn't find a symbol in the 773 // hierarchy. 774 if (generatePathComponents(Record, API, 775 [&PathComponentsNames](const PathComponent &PC) { 776 PathComponentsNames.push_back(PC.Name); 777 })) 778 return {}; 779 780 serializeArray(Obj, "pathComponents", Array(PathComponentsNames)); 781 782 serializeFunctionSignatureMixin(Obj, Record); 783 serializeAccessMixin(Obj, Record); 784 serializeTemplateMixin(Obj, Record); 785 786 return Obj; 787 } 788 789 template <typename MemberTy> 790 void SymbolGraphSerializer::serializeMembers( 791 const APIRecord &Record, 792 const SmallVector<std::unique_ptr<MemberTy>> &Members) { 793 // Members should not be serialized if we aren't recursing. 794 if (!ShouldRecurse) 795 return; 796 for (const auto &Member : Members) { 797 auto MemberRecord = serializeAPIRecord(*Member); 798 if (!MemberRecord) 799 continue; 800 801 Symbols.emplace_back(std::move(*MemberRecord)); 802 serializeRelationship(RelationshipKind::MemberOf, *Member, Record); 803 } 804 } 805 806 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 807 switch (Kind) { 808 case RelationshipKind::MemberOf: 809 return "memberOf"; 810 case RelationshipKind::InheritsFrom: 811 return "inheritsFrom"; 812 case RelationshipKind::ConformsTo: 813 return "conformsTo"; 814 case RelationshipKind::ExtensionTo: 815 return "extensionTo"; 816 } 817 llvm_unreachable("Unhandled relationship kind"); 818 } 819 820 StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { 821 switch (Kind) { 822 case ConstraintKind::Conformance: 823 return "conformance"; 824 case ConstraintKind::ConditionalConformance: 825 return "conditionalConformance"; 826 } 827 llvm_unreachable("Unhandled constraint kind"); 828 } 829 830 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 831 SymbolReference Source, 832 SymbolReference Target) { 833 Object Relationship; 834 Relationship["source"] = Source.USR; 835 Relationship["target"] = Target.USR; 836 Relationship["targetFallback"] = Target.Name; 837 Relationship["kind"] = getRelationshipString(Kind); 838 839 Relationships.emplace_back(std::move(Relationship)); 840 } 841 842 void SymbolGraphSerializer::visitNamespaceRecord( 843 const NamespaceRecord &Record) { 844 auto Namespace = serializeAPIRecord(Record); 845 if (!Namespace) 846 return; 847 Symbols.emplace_back(std::move(*Namespace)); 848 if (!Record.ParentInformation.empty()) 849 serializeRelationship(RelationshipKind::MemberOf, Record, 850 Record.ParentInformation.ParentRecord); 851 } 852 853 void SymbolGraphSerializer::visitGlobalFunctionRecord( 854 const GlobalFunctionRecord &Record) { 855 auto Obj = serializeAPIRecord(Record); 856 if (!Obj) 857 return; 858 859 Symbols.emplace_back(std::move(*Obj)); 860 } 861 862 void SymbolGraphSerializer::visitGlobalVariableRecord( 863 const GlobalVariableRecord &Record) { 864 auto Obj = serializeAPIRecord(Record); 865 if (!Obj) 866 return; 867 868 Symbols.emplace_back(std::move(*Obj)); 869 } 870 871 void SymbolGraphSerializer::visitEnumRecord(const EnumRecord &Record) { 872 auto Enum = serializeAPIRecord(Record); 873 if (!Enum) 874 return; 875 876 Symbols.emplace_back(std::move(*Enum)); 877 serializeMembers(Record, Record.Constants); 878 } 879 880 void SymbolGraphSerializer::visitStructRecord(const StructRecord &Record) { 881 auto Struct = serializeAPIRecord(Record); 882 if (!Struct) 883 return; 884 885 Symbols.emplace_back(std::move(*Struct)); 886 serializeMembers(Record, Record.Fields); 887 } 888 889 void SymbolGraphSerializer::visitStaticFieldRecord( 890 const StaticFieldRecord &Record) { 891 auto StaticField = serializeAPIRecord(Record); 892 if (!StaticField) 893 return; 894 Symbols.emplace_back(std::move(*StaticField)); 895 serializeRelationship(RelationshipKind::MemberOf, Record, Record.Context); 896 } 897 898 void SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord &Record) { 899 auto Class = serializeAPIRecord(Record); 900 if (!Class) 901 return; 902 903 Symbols.emplace_back(std::move(*Class)); 904 for (const auto &Base : Record.Bases) 905 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 906 if (!Record.ParentInformation.empty()) 907 serializeRelationship(RelationshipKind::MemberOf, Record, 908 Record.ParentInformation.ParentRecord); 909 } 910 911 void SymbolGraphSerializer::visitClassTemplateRecord( 912 const ClassTemplateRecord &Record) { 913 auto Class = serializeAPIRecord(Record); 914 if (!Class) 915 return; 916 917 Symbols.emplace_back(std::move(*Class)); 918 for (const auto &Base : Record.Bases) 919 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 920 if (!Record.ParentInformation.empty()) 921 serializeRelationship(RelationshipKind::MemberOf, Record, 922 Record.ParentInformation.ParentRecord); 923 } 924 925 void SymbolGraphSerializer::visitClassTemplateSpecializationRecord( 926 const ClassTemplateSpecializationRecord &Record) { 927 auto Class = serializeAPIRecord(Record); 928 if (!Class) 929 return; 930 931 Symbols.emplace_back(std::move(*Class)); 932 933 for (const auto &Base : Record.Bases) 934 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 935 if (!Record.ParentInformation.empty()) 936 serializeRelationship(RelationshipKind::MemberOf, Record, 937 Record.ParentInformation.ParentRecord); 938 } 939 940 void SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( 941 const ClassTemplatePartialSpecializationRecord &Record) { 942 auto Class = serializeAPIRecord(Record); 943 if (!Class) 944 return; 945 946 Symbols.emplace_back(std::move(*Class)); 947 948 for (const auto &Base : Record.Bases) 949 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base); 950 if (!Record.ParentInformation.empty()) 951 serializeRelationship(RelationshipKind::MemberOf, Record, 952 Record.ParentInformation.ParentRecord); 953 } 954 955 void SymbolGraphSerializer::visitCXXInstanceMethodRecord( 956 const CXXInstanceMethodRecord &Record) { 957 auto InstanceMethod = serializeAPIRecord(Record); 958 if (!InstanceMethod) 959 return; 960 961 Symbols.emplace_back(std::move(*InstanceMethod)); 962 serializeRelationship(RelationshipKind::MemberOf, Record, 963 Record.ParentInformation.ParentRecord); 964 } 965 966 void SymbolGraphSerializer::visitCXXStaticMethodRecord( 967 const CXXStaticMethodRecord &Record) { 968 auto StaticMethod = serializeAPIRecord(Record); 969 if (!StaticMethod) 970 return; 971 972 Symbols.emplace_back(std::move(*StaticMethod)); 973 serializeRelationship(RelationshipKind::MemberOf, Record, 974 Record.ParentInformation.ParentRecord); 975 } 976 977 void SymbolGraphSerializer::visitMethodTemplateRecord( 978 const CXXMethodTemplateRecord &Record) { 979 if (!ShouldRecurse) 980 // Ignore child symbols 981 return; 982 auto MethodTemplate = serializeAPIRecord(Record); 983 if (!MethodTemplate) 984 return; 985 Symbols.emplace_back(std::move(*MethodTemplate)); 986 serializeRelationship(RelationshipKind::MemberOf, Record, 987 Record.ParentInformation.ParentRecord); 988 } 989 990 void SymbolGraphSerializer::visitMethodTemplateSpecializationRecord( 991 const CXXMethodTemplateSpecializationRecord &Record) { 992 if (!ShouldRecurse) 993 // Ignore child symbols 994 return; 995 auto MethodTemplateSpecialization = serializeAPIRecord(Record); 996 if (!MethodTemplateSpecialization) 997 return; 998 Symbols.emplace_back(std::move(*MethodTemplateSpecialization)); 999 serializeRelationship(RelationshipKind::MemberOf, Record, 1000 Record.ParentInformation.ParentRecord); 1001 } 1002 1003 void SymbolGraphSerializer::visitCXXFieldRecord(const CXXFieldRecord &Record) { 1004 if (!ShouldRecurse) 1005 return; 1006 auto CXXField = serializeAPIRecord(Record); 1007 if (!CXXField) 1008 return; 1009 Symbols.emplace_back(std::move(*CXXField)); 1010 serializeRelationship(RelationshipKind::MemberOf, Record, 1011 Record.ParentInformation.ParentRecord); 1012 } 1013 1014 void SymbolGraphSerializer::visitCXXFieldTemplateRecord( 1015 const CXXFieldTemplateRecord &Record) { 1016 if (!ShouldRecurse) 1017 // Ignore child symbols 1018 return; 1019 auto CXXFieldTemplate = serializeAPIRecord(Record); 1020 if (!CXXFieldTemplate) 1021 return; 1022 Symbols.emplace_back(std::move(*CXXFieldTemplate)); 1023 serializeRelationship(RelationshipKind::MemberOf, Record, 1024 Record.ParentInformation.ParentRecord); 1025 } 1026 1027 void SymbolGraphSerializer::visitConceptRecord(const ConceptRecord &Record) { 1028 auto Concept = serializeAPIRecord(Record); 1029 if (!Concept) 1030 return; 1031 1032 Symbols.emplace_back(std::move(*Concept)); 1033 } 1034 1035 void SymbolGraphSerializer::visitGlobalVariableTemplateRecord( 1036 const GlobalVariableTemplateRecord &Record) { 1037 auto GlobalVariableTemplate = serializeAPIRecord(Record); 1038 if (!GlobalVariableTemplate) 1039 return; 1040 Symbols.emplace_back(std::move(*GlobalVariableTemplate)); 1041 } 1042 1043 void SymbolGraphSerializer::visitGlobalVariableTemplateSpecializationRecord( 1044 const GlobalVariableTemplateSpecializationRecord &Record) { 1045 auto GlobalVariableTemplateSpecialization = serializeAPIRecord(Record); 1046 if (!GlobalVariableTemplateSpecialization) 1047 return; 1048 Symbols.emplace_back(std::move(*GlobalVariableTemplateSpecialization)); 1049 } 1050 1051 void SymbolGraphSerializer:: 1052 visitGlobalVariableTemplatePartialSpecializationRecord( 1053 const GlobalVariableTemplatePartialSpecializationRecord &Record) { 1054 auto GlobalVariableTemplatePartialSpecialization = serializeAPIRecord(Record); 1055 if (!GlobalVariableTemplatePartialSpecialization) 1056 return; 1057 Symbols.emplace_back(std::move(*GlobalVariableTemplatePartialSpecialization)); 1058 } 1059 1060 void SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( 1061 const GlobalFunctionTemplateRecord &Record) { 1062 auto GlobalFunctionTemplate = serializeAPIRecord(Record); 1063 if (!GlobalFunctionTemplate) 1064 return; 1065 Symbols.emplace_back(std::move(*GlobalFunctionTemplate)); 1066 } 1067 1068 void SymbolGraphSerializer::visitGlobalFunctionTemplateSpecializationRecord( 1069 const GlobalFunctionTemplateSpecializationRecord &Record) { 1070 auto GlobalFunctionTemplateSpecialization = serializeAPIRecord(Record); 1071 if (!GlobalFunctionTemplateSpecialization) 1072 return; 1073 Symbols.emplace_back(std::move(*GlobalFunctionTemplateSpecialization)); 1074 } 1075 1076 void SymbolGraphSerializer::visitObjCContainerRecord( 1077 const ObjCContainerRecord &Record) { 1078 auto ObjCContainer = serializeAPIRecord(Record); 1079 if (!ObjCContainer) 1080 return; 1081 1082 Symbols.emplace_back(std::move(*ObjCContainer)); 1083 1084 serializeMembers(Record, Record.Ivars); 1085 serializeMembers(Record, Record.Methods); 1086 serializeMembers(Record, Record.Properties); 1087 1088 for (const auto &Protocol : Record.Protocols) 1089 // Record that Record conforms to Protocol. 1090 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 1091 1092 if (auto *ObjCInterface = dyn_cast<ObjCInterfaceRecord>(&Record)) { 1093 if (!ObjCInterface->SuperClass.empty()) 1094 // If Record is an Objective-C interface record and it has a super class, 1095 // record that Record is inherited from SuperClass. 1096 serializeRelationship(RelationshipKind::InheritsFrom, Record, 1097 ObjCInterface->SuperClass); 1098 1099 // Members of categories extending an interface are serialized as members of 1100 // the interface. 1101 for (const auto *Category : ObjCInterface->Categories) { 1102 serializeMembers(Record, Category->Ivars); 1103 serializeMembers(Record, Category->Methods); 1104 serializeMembers(Record, Category->Properties); 1105 1106 // Surface the protocols of the category to the interface. 1107 for (const auto &Protocol : Category->Protocols) 1108 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 1109 } 1110 } 1111 } 1112 1113 void SymbolGraphSerializer::visitObjCCategoryRecord( 1114 const ObjCCategoryRecord &Record) { 1115 if (!Record.IsFromExternalModule) 1116 return; 1117 1118 // Check if the current Category' parent has been visited before, if so skip. 1119 if (!visitedCategories.contains(Record.Interface.Name)) { 1120 visitedCategories.insert(Record.Interface.Name); 1121 Object Obj; 1122 serializeObject(Obj, "identifier", 1123 serializeIdentifier(Record, API.getLanguage())); 1124 serializeObject(Obj, "kind", 1125 serializeSymbolKind(APIRecord::RK_ObjCCategoryModule, 1126 API.getLanguage())); 1127 Obj["accessLevel"] = "public"; 1128 Symbols.emplace_back(std::move(Obj)); 1129 } 1130 1131 Object Relationship; 1132 Relationship["source"] = Record.USR; 1133 Relationship["target"] = Record.Interface.USR; 1134 Relationship["targetFallback"] = Record.Interface.Name; 1135 Relationship["kind"] = getRelationshipString(RelationshipKind::ExtensionTo); 1136 Relationships.emplace_back(std::move(Relationship)); 1137 1138 auto ObjCCategory = serializeAPIRecord(Record); 1139 1140 if (!ObjCCategory) 1141 return; 1142 1143 Symbols.emplace_back(std::move(*ObjCCategory)); 1144 serializeMembers(Record, Record.Methods); 1145 serializeMembers(Record, Record.Properties); 1146 1147 // Surface the protocols of the category to the interface. 1148 for (const auto &Protocol : Record.Protocols) 1149 serializeRelationship(RelationshipKind::ConformsTo, Record, Protocol); 1150 } 1151 1152 void SymbolGraphSerializer::visitMacroDefinitionRecord( 1153 const MacroDefinitionRecord &Record) { 1154 auto Macro = serializeAPIRecord(Record); 1155 1156 if (!Macro) 1157 return; 1158 1159 Symbols.emplace_back(std::move(*Macro)); 1160 } 1161 1162 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { 1163 switch (Record->getKind()) { 1164 case APIRecord::RK_Unknown: 1165 llvm_unreachable("Records should have a known kind!"); 1166 case APIRecord::RK_GlobalFunction: 1167 visitGlobalFunctionRecord(*cast<GlobalFunctionRecord>(Record)); 1168 break; 1169 case APIRecord::RK_GlobalVariable: 1170 visitGlobalVariableRecord(*cast<GlobalVariableRecord>(Record)); 1171 break; 1172 case APIRecord::RK_Enum: 1173 visitEnumRecord(*cast<EnumRecord>(Record)); 1174 break; 1175 case APIRecord::RK_Struct: 1176 visitStructRecord(*cast<StructRecord>(Record)); 1177 break; 1178 case APIRecord::RK_StaticField: 1179 visitStaticFieldRecord(*cast<StaticFieldRecord>(Record)); 1180 break; 1181 case APIRecord::RK_CXXClass: 1182 visitCXXClassRecord(*cast<CXXClassRecord>(Record)); 1183 break; 1184 case APIRecord::RK_ObjCInterface: 1185 visitObjCContainerRecord(*cast<ObjCInterfaceRecord>(Record)); 1186 break; 1187 case APIRecord::RK_ObjCProtocol: 1188 visitObjCContainerRecord(*cast<ObjCProtocolRecord>(Record)); 1189 break; 1190 case APIRecord::RK_ObjCCategory: 1191 visitObjCCategoryRecord(*cast<ObjCCategoryRecord>(Record)); 1192 break; 1193 case APIRecord::RK_MacroDefinition: 1194 visitMacroDefinitionRecord(*cast<MacroDefinitionRecord>(Record)); 1195 break; 1196 case APIRecord::RK_Typedef: 1197 visitTypedefRecord(*cast<TypedefRecord>(Record)); 1198 break; 1199 default: 1200 if (auto Obj = serializeAPIRecord(*Record)) { 1201 Symbols.emplace_back(std::move(*Obj)); 1202 auto &ParentInformation = Record->ParentInformation; 1203 if (!ParentInformation.empty()) 1204 serializeRelationship(RelationshipKind::MemberOf, *Record, 1205 *ParentInformation.ParentRecord); 1206 } 1207 break; 1208 } 1209 } 1210 1211 void SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord &Record) { 1212 // Typedefs of anonymous types have their entries unified with the underlying 1213 // type. 1214 bool ShouldDrop = Record.UnderlyingType.Name.empty(); 1215 // enums declared with `NS_OPTION` have a named enum and a named typedef, with 1216 // the same name 1217 ShouldDrop |= (Record.UnderlyingType.Name == Record.Name); 1218 if (ShouldDrop) 1219 return; 1220 1221 auto Typedef = serializeAPIRecord(Record); 1222 if (!Typedef) 1223 return; 1224 1225 (*Typedef)["type"] = Record.UnderlyingType.USR; 1226 1227 Symbols.emplace_back(std::move(*Typedef)); 1228 } 1229 1230 Object SymbolGraphSerializer::serialize() { 1231 traverseAPISet(); 1232 return serializeCurrentGraph(); 1233 } 1234 1235 Object SymbolGraphSerializer::serializeCurrentGraph() { 1236 Object Root; 1237 serializeObject(Root, "metadata", serializeMetadata()); 1238 serializeObject(Root, "module", serializeModule()); 1239 1240 Root["symbols"] = std::move(Symbols); 1241 Root["relationships"] = std::move(Relationships); 1242 1243 return Root; 1244 } 1245 1246 void SymbolGraphSerializer::serialize(raw_ostream &os) { 1247 Object root = serialize(); 1248 if (Options.Compact) 1249 os << formatv("{0}", Value(std::move(root))) << "\n"; 1250 else 1251 os << formatv("{0:2}", Value(std::move(root))) << "\n"; 1252 } 1253 1254 std::optional<Object> 1255 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, 1256 const APISet &API) { 1257 APIRecord *Record = API.findRecordForUSR(USR); 1258 if (!Record) 1259 return {}; 1260 1261 Object Root; 1262 APIIgnoresList EmptyIgnores; 1263 SymbolGraphSerializer Serializer(API, EmptyIgnores, 1264 /*Options.Compact*/ {true}, 1265 /*ShouldRecurse*/ false); 1266 Serializer.serializeSingleRecord(Record); 1267 serializeObject(Root, "symbolGraph", Serializer.serializeCurrentGraph()); 1268 1269 Language Lang = API.getLanguage(); 1270 serializeArray(Root, "parentContexts", 1271 generateParentContexts(*Record, API, Lang)); 1272 1273 Array RelatedSymbols; 1274 1275 for (const auto &Fragment : Record->Declaration.getFragments()) { 1276 // If we don't have a USR there isn't much we can do. 1277 if (Fragment.PreciseIdentifier.empty()) 1278 continue; 1279 1280 APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier); 1281 1282 // If we can't find the record let's skip. 1283 if (!RelatedRecord) 1284 continue; 1285 1286 Object RelatedSymbol; 1287 RelatedSymbol["usr"] = RelatedRecord->USR; 1288 RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); 1289 // TODO: once we record this properly let's serialize it right. 1290 RelatedSymbol["accessLevel"] = "public"; 1291 RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); 1292 RelatedSymbol["moduleName"] = API.ProductName; 1293 RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; 1294 1295 serializeArray(RelatedSymbol, "parentContexts", 1296 generateParentContexts(*RelatedRecord, API, Lang)); 1297 RelatedSymbols.push_back(std::move(RelatedSymbol)); 1298 } 1299 1300 serializeArray(Root, "relatedSymbols", RelatedSymbols); 1301 return Root; 1302 } 1303