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/API.h" 18 #include "clang/ExtractAPI/DeclarationFragments.h" 19 #include "llvm/ADT/STLExtras.h" 20 #include "llvm/ADT/STLFunctionalExtras.h" 21 #include "llvm/ADT/SmallVector.h" 22 #include "llvm/Support/Casting.h" 23 #include "llvm/Support/Compiler.h" 24 #include "llvm/Support/Path.h" 25 #include "llvm/Support/VersionTuple.h" 26 #include "llvm/Support/raw_ostream.h" 27 #include <iterator> 28 #include <optional> 29 #include <type_traits> 30 31 using namespace clang; 32 using namespace clang::extractapi; 33 using namespace llvm; 34 using namespace llvm::json; 35 36 namespace { 37 38 /// Helper function to inject a JSON object \p Obj into another object \p Paren 39 /// at position \p Key. 40 void serializeObject(Object &Paren, StringRef Key, 41 std::optional<Object> &&Obj) { 42 if (Obj) 43 Paren[Key] = std::move(*Obj); 44 } 45 46 /// Helper function to inject a JSON array \p Array into object \p Paren at 47 /// position \p Key. 48 void serializeArray(Object &Paren, StringRef Key, 49 std::optional<Array> &&Array) { 50 if (Array) 51 Paren[Key] = std::move(*Array); 52 } 53 54 /// Helper function to inject a JSON array composed of the values in \p C into 55 /// object \p Paren at position \p Key. 56 template <typename ContainerTy> 57 void serializeArray(Object &Paren, StringRef Key, ContainerTy &&C) { 58 Paren[Key] = Array(C); 59 } 60 61 /// Serialize a \c VersionTuple \p V with the Symbol Graph semantic version 62 /// format. 63 /// 64 /// A semantic version object contains three numeric fields, representing the 65 /// \c major, \c minor, and \c patch parts of the version tuple. 66 /// For example version tuple 1.0.3 is serialized as: 67 /// \code 68 /// { 69 /// "major" : 1, 70 /// "minor" : 0, 71 /// "patch" : 3 72 /// } 73 /// \endcode 74 /// 75 /// \returns \c std::nullopt if the version \p V is empty, or an \c Object 76 /// containing the semantic version representation of \p V. 77 std::optional<Object> serializeSemanticVersion(const VersionTuple &V) { 78 if (V.empty()) 79 return std::nullopt; 80 81 Object Version; 82 Version["major"] = V.getMajor(); 83 Version["minor"] = V.getMinor().value_or(0); 84 Version["patch"] = V.getSubminor().value_or(0); 85 return Version; 86 } 87 88 /// Serialize the OS information in the Symbol Graph platform property. 89 /// 90 /// The OS information in Symbol Graph contains the \c name of the OS, and an 91 /// optional \c minimumVersion semantic version field. 92 Object serializeOperatingSystem(const Triple &T) { 93 Object OS; 94 OS["name"] = T.getOSTypeName(T.getOS()); 95 serializeObject(OS, "minimumVersion", 96 serializeSemanticVersion(T.getMinimumSupportedOSVersion())); 97 return OS; 98 } 99 100 /// Serialize the platform information in the Symbol Graph module section. 101 /// 102 /// The platform object describes a target platform triple in corresponding 103 /// three fields: \c architecture, \c vendor, and \c operatingSystem. 104 Object serializePlatform(const Triple &T) { 105 Object Platform; 106 Platform["architecture"] = T.getArchName(); 107 Platform["vendor"] = T.getVendorName(); 108 Platform["operatingSystem"] = serializeOperatingSystem(T); 109 return Platform; 110 } 111 112 /// Serialize a source position. 113 Object serializeSourcePosition(const PresumedLoc &Loc) { 114 assert(Loc.isValid() && "invalid source position"); 115 116 Object SourcePosition; 117 SourcePosition["line"] = Loc.getLine() - 1; 118 SourcePosition["character"] = Loc.getColumn() - 1; 119 120 return SourcePosition; 121 } 122 123 /// Serialize a source location in file. 124 /// 125 /// \param Loc The presumed location to serialize. 126 /// \param IncludeFileURI If true, include the file path of \p Loc as a URI. 127 /// Defaults to false. 128 Object serializeSourceLocation(const PresumedLoc &Loc, 129 bool IncludeFileURI = false) { 130 Object SourceLocation; 131 serializeObject(SourceLocation, "position", serializeSourcePosition(Loc)); 132 133 if (IncludeFileURI) { 134 std::string FileURI = "file://"; 135 // Normalize file path to use forward slashes for the URI. 136 FileURI += sys::path::convert_to_slash(Loc.getFilename()); 137 SourceLocation["uri"] = FileURI; 138 } 139 140 return SourceLocation; 141 } 142 143 /// Serialize a source range with begin and end locations. 144 Object serializeSourceRange(const PresumedLoc &BeginLoc, 145 const PresumedLoc &EndLoc) { 146 Object SourceRange; 147 serializeObject(SourceRange, "start", serializeSourcePosition(BeginLoc)); 148 serializeObject(SourceRange, "end", serializeSourcePosition(EndLoc)); 149 return SourceRange; 150 } 151 152 /// Serialize the availability attributes of a symbol. 153 /// 154 /// Availability information contains the introduced, deprecated, and obsoleted 155 /// versions of the symbol as semantic versions, if not default. 156 /// Availability information also contains flags to indicate if the symbol is 157 /// unconditionally unavailable or deprecated, 158 /// i.e. \c __attribute__((unavailable)) and \c __attribute__((deprecated)). 159 /// 160 /// \returns \c std::nullopt if the symbol has default availability attributes, 161 /// or an \c Array containing an object with the formatted availability 162 /// information. 163 std::optional<Array> serializeAvailability(const AvailabilityInfo &Avail) { 164 if (Avail.isDefault()) 165 return std::nullopt; 166 167 Array AvailabilityArray; 168 169 if (Avail.isUnconditionallyDeprecated()) { 170 Object UnconditionallyDeprecated; 171 UnconditionallyDeprecated["domain"] = "*"; 172 UnconditionallyDeprecated["isUnconditionallyDeprecated"] = true; 173 AvailabilityArray.emplace_back(std::move(UnconditionallyDeprecated)); 174 } 175 Object Availability; 176 177 Availability["domain"] = Avail.Domain; 178 179 if (Avail.isUnavailable()) { 180 Availability["isUnconditionallyUnavailable"] = true; 181 } else { 182 serializeObject(Availability, "introduced", 183 serializeSemanticVersion(Avail.Introduced)); 184 serializeObject(Availability, "deprecated", 185 serializeSemanticVersion(Avail.Deprecated)); 186 serializeObject(Availability, "obsoleted", 187 serializeSemanticVersion(Avail.Obsoleted)); 188 } 189 190 AvailabilityArray.emplace_back(std::move(Availability)); 191 return AvailabilityArray; 192 } 193 194 /// Get the language name string for interface language references. 195 StringRef getLanguageName(Language Lang) { 196 switch (Lang) { 197 case Language::C: 198 return "c"; 199 case Language::ObjC: 200 return "objective-c"; 201 case Language::CXX: 202 return "c++"; 203 case Language::ObjCXX: 204 return "objective-c++"; 205 206 // Unsupported language currently 207 case Language::OpenCL: 208 case Language::OpenCLCXX: 209 case Language::CUDA: 210 case Language::RenderScript: 211 case Language::HIP: 212 case Language::HLSL: 213 214 // Languages that the frontend cannot parse and compile 215 case Language::Unknown: 216 case Language::Asm: 217 case Language::LLVM_IR: 218 case Language::CIR: 219 llvm_unreachable("Unsupported language kind"); 220 } 221 222 llvm_unreachable("Unhandled language kind"); 223 } 224 225 /// Serialize the identifier object as specified by the Symbol Graph format. 226 /// 227 /// The identifier property of a symbol contains the USR for precise and unique 228 /// references, and the interface language name. 229 Object serializeIdentifier(const APIRecord &Record, Language Lang) { 230 Object Identifier; 231 Identifier["precise"] = Record.USR; 232 Identifier["interfaceLanguage"] = getLanguageName(Lang); 233 234 return Identifier; 235 } 236 237 /// Serialize the documentation comments attached to a symbol, as specified by 238 /// the Symbol Graph format. 239 /// 240 /// The Symbol Graph \c docComment object contains an array of lines. Each line 241 /// represents one line of striped documentation comment, with source range 242 /// information. 243 /// e.g. 244 /// \code 245 /// /// This is a documentation comment 246 /// ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~' First line. 247 /// /// with multiple lines. 248 /// ^~~~~~~~~~~~~~~~~~~~~~~' Second line. 249 /// \endcode 250 /// 251 /// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing 252 /// the formatted lines. 253 std::optional<Object> serializeDocComment(const DocComment &Comment) { 254 if (Comment.empty()) 255 return std::nullopt; 256 257 Object DocComment; 258 259 Array LinesArray; 260 for (const auto &CommentLine : Comment) { 261 Object Line; 262 Line["text"] = CommentLine.Text; 263 serializeObject(Line, "range", 264 serializeSourceRange(CommentLine.Begin, CommentLine.End)); 265 LinesArray.emplace_back(std::move(Line)); 266 } 267 268 serializeArray(DocComment, "lines", std::move(LinesArray)); 269 270 return DocComment; 271 } 272 273 /// Serialize the declaration fragments of a symbol. 274 /// 275 /// The Symbol Graph declaration fragments is an array of tagged important 276 /// parts of a symbol's declaration. The fragments sequence can be joined to 277 /// form spans of declaration text, with attached information useful for 278 /// purposes like syntax-highlighting etc. For example: 279 /// \code 280 /// const int pi; -> "declarationFragments" : [ 281 /// { 282 /// "kind" : "keyword", 283 /// "spelling" : "const" 284 /// }, 285 /// { 286 /// "kind" : "text", 287 /// "spelling" : " " 288 /// }, 289 /// { 290 /// "kind" : "typeIdentifier", 291 /// "preciseIdentifier" : "c:I", 292 /// "spelling" : "int" 293 /// }, 294 /// { 295 /// "kind" : "text", 296 /// "spelling" : " " 297 /// }, 298 /// { 299 /// "kind" : "identifier", 300 /// "spelling" : "pi" 301 /// } 302 /// ] 303 /// \endcode 304 /// 305 /// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the 306 /// formatted declaration fragments array. 307 std::optional<Array> 308 serializeDeclarationFragments(const DeclarationFragments &DF) { 309 if (DF.getFragments().empty()) 310 return std::nullopt; 311 312 Array Fragments; 313 for (const auto &F : DF.getFragments()) { 314 Object Fragment; 315 Fragment["spelling"] = F.Spelling; 316 Fragment["kind"] = DeclarationFragments::getFragmentKindString(F.Kind); 317 if (!F.PreciseIdentifier.empty()) 318 Fragment["preciseIdentifier"] = F.PreciseIdentifier; 319 Fragments.emplace_back(std::move(Fragment)); 320 } 321 322 return Fragments; 323 } 324 325 /// Serialize the \c names field of a symbol as specified by the Symbol Graph 326 /// format. 327 /// 328 /// The Symbol Graph names field contains multiple representations of a symbol 329 /// that can be used for different applications: 330 /// - \c title : The simple declared name of the symbol; 331 /// - \c subHeading : An array of declaration fragments that provides tags, 332 /// and potentially more tokens (for example the \c +/- symbol for 333 /// Objective-C methods). Can be used as sub-headings for documentation. 334 Object serializeNames(const APIRecord *Record) { 335 Object Names; 336 Names["title"] = Record->Name; 337 338 serializeArray(Names, "subHeading", 339 serializeDeclarationFragments(Record->SubHeading)); 340 DeclarationFragments NavigatorFragments; 341 NavigatorFragments.append(Record->Name, 342 DeclarationFragments::FragmentKind::Identifier, 343 /*PreciseIdentifier*/ ""); 344 serializeArray(Names, "navigator", 345 serializeDeclarationFragments(NavigatorFragments)); 346 347 return Names; 348 } 349 350 Object serializeSymbolKind(APIRecord::RecordKind RK, Language Lang) { 351 auto AddLangPrefix = [&Lang](StringRef S) -> std::string { 352 return (getLanguageName(Lang) + "." + S).str(); 353 }; 354 355 Object Kind; 356 switch (RK) { 357 case APIRecord::RK_Unknown: 358 Kind["identifier"] = AddLangPrefix("unknown"); 359 Kind["displayName"] = "Unknown"; 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_UnionField: 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_CXXField: 418 Kind["identifier"] = AddLangPrefix("property"); 419 Kind["displayName"] = "Instance Property"; 420 break; 421 case APIRecord::RK_StaticField: 422 Kind["identifier"] = AddLangPrefix("type.property"); 423 Kind["displayName"] = "Type Property"; 424 break; 425 case APIRecord::RK_ClassTemplate: 426 case APIRecord::RK_ClassTemplateSpecialization: 427 case APIRecord::RK_ClassTemplatePartialSpecialization: 428 case APIRecord::RK_CXXClass: 429 Kind["identifier"] = AddLangPrefix("class"); 430 Kind["displayName"] = "Class"; 431 break; 432 case APIRecord::RK_CXXMethodTemplate: 433 Kind["identifier"] = AddLangPrefix("method"); 434 Kind["displayName"] = "Method Template"; 435 break; 436 case APIRecord::RK_CXXMethodTemplateSpecialization: 437 Kind["identifier"] = AddLangPrefix("method"); 438 Kind["displayName"] = "Method Template Specialization"; 439 break; 440 case APIRecord::RK_CXXFieldTemplate: 441 Kind["identifier"] = AddLangPrefix("property"); 442 Kind["displayName"] = "Template Property"; 443 break; 444 case APIRecord::RK_Concept: 445 Kind["identifier"] = AddLangPrefix("concept"); 446 Kind["displayName"] = "Concept"; 447 break; 448 case APIRecord::RK_CXXStaticMethod: 449 Kind["identifier"] = AddLangPrefix("type.method"); 450 Kind["displayName"] = "Static Method"; 451 break; 452 case APIRecord::RK_CXXInstanceMethod: 453 Kind["identifier"] = AddLangPrefix("method"); 454 Kind["displayName"] = "Instance Method"; 455 break; 456 case APIRecord::RK_CXXConstructorMethod: 457 Kind["identifier"] = AddLangPrefix("method"); 458 Kind["displayName"] = "Constructor"; 459 break; 460 case APIRecord::RK_CXXDestructorMethod: 461 Kind["identifier"] = AddLangPrefix("method"); 462 Kind["displayName"] = "Destructor"; 463 break; 464 case APIRecord::RK_ObjCIvar: 465 Kind["identifier"] = AddLangPrefix("ivar"); 466 Kind["displayName"] = "Instance Variable"; 467 break; 468 case APIRecord::RK_ObjCInstanceMethod: 469 Kind["identifier"] = AddLangPrefix("method"); 470 Kind["displayName"] = "Instance Method"; 471 break; 472 case APIRecord::RK_ObjCClassMethod: 473 Kind["identifier"] = AddLangPrefix("type.method"); 474 Kind["displayName"] = "Type Method"; 475 break; 476 case APIRecord::RK_ObjCInstanceProperty: 477 Kind["identifier"] = AddLangPrefix("property"); 478 Kind["displayName"] = "Instance Property"; 479 break; 480 case APIRecord::RK_ObjCClassProperty: 481 Kind["identifier"] = AddLangPrefix("type.property"); 482 Kind["displayName"] = "Type Property"; 483 break; 484 case APIRecord::RK_ObjCInterface: 485 Kind["identifier"] = AddLangPrefix("class"); 486 Kind["displayName"] = "Class"; 487 break; 488 case APIRecord::RK_ObjCCategory: 489 Kind["identifier"] = AddLangPrefix("class.extension"); 490 Kind["displayName"] = "Class 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 default: 505 llvm_unreachable("API Record with uninstantiable kind"); 506 } 507 508 return Kind; 509 } 510 511 /// Serialize the symbol kind information. 512 /// 513 /// The Symbol Graph symbol kind property contains a shorthand \c identifier 514 /// which is prefixed by the source language name, useful for tooling to parse 515 /// the kind, and a \c displayName for rendering human-readable names. 516 Object serializeSymbolKind(const APIRecord &Record, Language Lang) { 517 return serializeSymbolKind(Record.getKind(), Lang); 518 } 519 520 /// Serialize the function signature field, as specified by the 521 /// Symbol Graph format. 522 /// 523 /// The Symbol Graph function signature property contains two arrays. 524 /// - The \c returns array is the declaration fragments of the return type; 525 /// - The \c parameters array contains names and declaration fragments of the 526 /// parameters. 527 template <typename RecordTy> 528 void serializeFunctionSignatureMixin(Object &Paren, const RecordTy &Record) { 529 const auto &FS = Record.Signature; 530 if (FS.empty()) 531 return; 532 533 Object Signature; 534 serializeArray(Signature, "returns", 535 serializeDeclarationFragments(FS.getReturnType())); 536 537 Array Parameters; 538 for (const auto &P : FS.getParameters()) { 539 Object Parameter; 540 Parameter["name"] = P.Name; 541 serializeArray(Parameter, "declarationFragments", 542 serializeDeclarationFragments(P.Fragments)); 543 Parameters.emplace_back(std::move(Parameter)); 544 } 545 546 if (!Parameters.empty()) 547 Signature["parameters"] = std::move(Parameters); 548 549 serializeObject(Paren, "functionSignature", std::move(Signature)); 550 } 551 552 template <typename RecordTy> 553 void serializeTemplateMixin(Object &Paren, const RecordTy &Record) { 554 const auto &Template = Record.Templ; 555 if (Template.empty()) 556 return; 557 558 Object Generics; 559 Array GenericParameters; 560 for (const auto &Param : Template.getParameters()) { 561 Object Parameter; 562 Parameter["name"] = Param.Name; 563 Parameter["index"] = Param.Index; 564 Parameter["depth"] = Param.Depth; 565 GenericParameters.emplace_back(std::move(Parameter)); 566 } 567 if (!GenericParameters.empty()) 568 Generics["parameters"] = std::move(GenericParameters); 569 570 Array GenericConstraints; 571 for (const auto &Constr : Template.getConstraints()) { 572 Object Constraint; 573 Constraint["kind"] = Constr.Kind; 574 Constraint["lhs"] = Constr.LHS; 575 Constraint["rhs"] = Constr.RHS; 576 GenericConstraints.emplace_back(std::move(Constraint)); 577 } 578 579 if (!GenericConstraints.empty()) 580 Generics["constraints"] = std::move(GenericConstraints); 581 582 serializeObject(Paren, "swiftGenerics", Generics); 583 } 584 585 Array generateParentContexts(const SmallVectorImpl<SymbolReference> &Parents, 586 Language Lang) { 587 Array ParentContexts; 588 589 for (const auto &Parent : Parents) { 590 Object Elem; 591 Elem["usr"] = Parent.USR; 592 Elem["name"] = Parent.Name; 593 if (Parent.Record) 594 Elem["kind"] = 595 serializeSymbolKind(Parent.Record->getKind(), Lang)["identifier"]; 596 else 597 Elem["kind"] = 598 serializeSymbolKind(APIRecord::RK_Unknown, Lang)["identifier"]; 599 ParentContexts.emplace_back(std::move(Elem)); 600 } 601 602 return ParentContexts; 603 } 604 605 /// Walk the records parent information in reverse to generate a hierarchy 606 /// suitable for serialization. 607 SmallVector<SymbolReference, 8> 608 generateHierarchyFromRecord(const APIRecord *Record) { 609 SmallVector<SymbolReference, 8> ReverseHierarchy; 610 for (const auto *Current = Record; Current != nullptr; 611 Current = Current->Parent.Record) 612 ReverseHierarchy.emplace_back(Current); 613 614 return SmallVector<SymbolReference, 8>( 615 std::make_move_iterator(ReverseHierarchy.rbegin()), 616 std::make_move_iterator(ReverseHierarchy.rend())); 617 } 618 619 SymbolReference getHierarchyReference(const APIRecord *Record, 620 const APISet &API) { 621 // If the parent is a category extended from internal module then we need to 622 // pretend this belongs to the associated interface. 623 if (auto *CategoryRecord = dyn_cast_or_null<ObjCCategoryRecord>(Record)) { 624 return CategoryRecord->Interface; 625 // FIXME: TODO generate path components correctly for categories extending 626 // an external module. 627 } 628 629 return SymbolReference(Record); 630 } 631 632 } // namespace 633 634 Object *ExtendedModule::addSymbol(Object &&Symbol) { 635 Symbols.emplace_back(std::move(Symbol)); 636 return Symbols.back().getAsObject(); 637 } 638 639 void ExtendedModule::addRelationship(Object &&Relationship) { 640 Relationships.emplace_back(std::move(Relationship)); 641 } 642 643 /// Defines the format version emitted by SymbolGraphSerializer. 644 const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3}; 645 646 Object SymbolGraphSerializer::serializeMetadata() const { 647 Object Metadata; 648 serializeObject(Metadata, "formatVersion", 649 serializeSemanticVersion(FormatVersion)); 650 Metadata["generator"] = clang::getClangFullVersion(); 651 return Metadata; 652 } 653 654 Object 655 SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const { 656 Object Module; 657 Module["name"] = ModuleName; 658 serializeObject(Module, "platform", serializePlatform(API.getTarget())); 659 return Module; 660 } 661 662 bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const { 663 if (!Record) 664 return true; 665 666 // Skip unconditionally unavailable symbols 667 if (Record->Availability.isUnconditionallyUnavailable()) 668 return true; 669 670 // Filter out symbols prefixed with an underscored as they are understood to 671 // be symbols clients should not use. 672 if (Record->Name.starts_with("_")) 673 return true; 674 675 // Skip explicitly ignored symbols. 676 if (IgnoresList.shouldIgnore(Record->Name)) 677 return true; 678 679 return false; 680 } 681 682 ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() { 683 if (!ForceEmitToMainModule && ModuleForCurrentSymbol) 684 return *ModuleForCurrentSymbol; 685 686 return MainModule; 687 } 688 689 Array SymbolGraphSerializer::serializePathComponents( 690 const APIRecord *Record) const { 691 return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; })); 692 } 693 694 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 695 switch (Kind) { 696 case RelationshipKind::MemberOf: 697 return "memberOf"; 698 case RelationshipKind::InheritsFrom: 699 return "inheritsFrom"; 700 case RelationshipKind::ConformsTo: 701 return "conformsTo"; 702 case RelationshipKind::ExtensionTo: 703 return "extensionTo"; 704 } 705 llvm_unreachable("Unhandled relationship kind"); 706 } 707 708 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 709 const SymbolReference &Source, 710 const SymbolReference &Target, 711 ExtendedModule &Into) { 712 Object Relationship; 713 SmallString<64> TestRelLabel; 714 if (EmitSymbolLabelsForTesting) { 715 llvm::raw_svector_ostream OS(TestRelLabel); 716 OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ " 717 << Source.USR << " $ "; 718 if (Target.USR.empty()) 719 OS << Target.Name; 720 else 721 OS << Target.USR; 722 Relationship["!testRelLabel"] = TestRelLabel; 723 } 724 Relationship["source"] = Source.USR; 725 Relationship["target"] = Target.USR; 726 Relationship["targetFallback"] = Target.Name; 727 Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind); 728 729 if (ForceEmitToMainModule) 730 MainModule.addRelationship(std::move(Relationship)); 731 else 732 Into.addRelationship(std::move(Relationship)); 733 } 734 735 StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { 736 switch (Kind) { 737 case ConstraintKind::Conformance: 738 return "conformance"; 739 case ConstraintKind::ConditionalConformance: 740 return "conditionalConformance"; 741 } 742 llvm_unreachable("Unhandled constraint kind"); 743 } 744 745 void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) { 746 Object Obj; 747 748 // If we need symbol labels for testing emit the USR as the value and the key 749 // starts with '!'' to ensure it ends up at the top of the object. 750 if (EmitSymbolLabelsForTesting) 751 Obj["!testLabel"] = Record->USR; 752 753 serializeObject(Obj, "identifier", 754 serializeIdentifier(*Record, API.getLanguage())); 755 serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage())); 756 serializeObject(Obj, "names", serializeNames(Record)); 757 serializeObject( 758 Obj, "location", 759 serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true)); 760 serializeArray(Obj, "availability", 761 serializeAvailability(Record->Availability)); 762 serializeObject(Obj, "docComment", serializeDocComment(Record->Comment)); 763 serializeArray(Obj, "declarationFragments", 764 serializeDeclarationFragments(Record->Declaration)); 765 766 Obj["pathComponents"] = serializePathComponents(Record); 767 Obj["accessLevel"] = Record->Access.getAccess(); 768 769 ExtendedModule &Module = getModuleForCurrentSymbol(); 770 // If the hierarchy has at least one parent and child. 771 if (Hierarchy.size() >= 2) 772 serializeRelationship(MemberOf, Hierarchy.back(), 773 Hierarchy[Hierarchy.size() - 2], Module); 774 775 CurrentSymbol = Module.addSymbol(std::move(Obj)); 776 } 777 778 bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) { 779 if (!Record) 780 return true; 781 if (shouldSkip(Record)) 782 return true; 783 Hierarchy.push_back(getHierarchyReference(Record, API)); 784 // Defer traversal mechanics to APISetVisitor base implementation 785 auto RetVal = Base::traverseAPIRecord(Record); 786 Hierarchy.pop_back(); 787 return RetVal; 788 } 789 790 bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) { 791 serializeAPIRecord(Record); 792 return true; 793 } 794 795 bool SymbolGraphSerializer::visitGlobalFunctionRecord( 796 const GlobalFunctionRecord *Record) { 797 if (!CurrentSymbol) 798 return true; 799 800 serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 801 return true; 802 } 803 804 bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) { 805 if (!CurrentSymbol) 806 return true; 807 808 for (const auto &Base : Record->Bases) 809 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base, 810 getModuleForCurrentSymbol()); 811 return true; 812 } 813 814 bool SymbolGraphSerializer::visitClassTemplateRecord( 815 const ClassTemplateRecord *Record) { 816 if (!CurrentSymbol) 817 return true; 818 819 serializeTemplateMixin(*CurrentSymbol, *Record); 820 return true; 821 } 822 823 bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( 824 const ClassTemplatePartialSpecializationRecord *Record) { 825 if (!CurrentSymbol) 826 return true; 827 828 serializeTemplateMixin(*CurrentSymbol, *Record); 829 return true; 830 } 831 832 bool SymbolGraphSerializer::visitCXXMethodRecord( 833 const CXXMethodRecord *Record) { 834 if (!CurrentSymbol) 835 return true; 836 837 serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 838 return true; 839 } 840 841 bool SymbolGraphSerializer::visitCXXMethodTemplateRecord( 842 const CXXMethodTemplateRecord *Record) { 843 if (!CurrentSymbol) 844 return true; 845 846 serializeTemplateMixin(*CurrentSymbol, *Record); 847 return true; 848 } 849 850 bool SymbolGraphSerializer::visitCXXFieldTemplateRecord( 851 const CXXFieldTemplateRecord *Record) { 852 if (!CurrentSymbol) 853 return true; 854 855 serializeTemplateMixin(*CurrentSymbol, *Record); 856 return true; 857 } 858 859 bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) { 860 if (!CurrentSymbol) 861 return true; 862 863 serializeTemplateMixin(*CurrentSymbol, *Record); 864 return true; 865 } 866 867 bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord( 868 const GlobalVariableTemplateRecord *Record) { 869 if (!CurrentSymbol) 870 return true; 871 872 serializeTemplateMixin(*CurrentSymbol, *Record); 873 return true; 874 } 875 876 bool SymbolGraphSerializer:: 877 visitGlobalVariableTemplatePartialSpecializationRecord( 878 const GlobalVariableTemplatePartialSpecializationRecord *Record) { 879 if (!CurrentSymbol) 880 return true; 881 882 serializeTemplateMixin(*CurrentSymbol, *Record); 883 return true; 884 } 885 886 bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( 887 const GlobalFunctionTemplateRecord *Record) { 888 if (!CurrentSymbol) 889 return true; 890 891 serializeTemplateMixin(*CurrentSymbol, *Record); 892 return true; 893 } 894 895 bool SymbolGraphSerializer::visitObjCContainerRecord( 896 const ObjCContainerRecord *Record) { 897 if (!CurrentSymbol) 898 return true; 899 900 for (const auto &Protocol : Record->Protocols) 901 serializeRelationship(ConformsTo, Record, Protocol, 902 getModuleForCurrentSymbol()); 903 904 return true; 905 } 906 907 bool SymbolGraphSerializer::visitObjCInterfaceRecord( 908 const ObjCInterfaceRecord *Record) { 909 if (!CurrentSymbol) 910 return true; 911 912 if (!Record->SuperClass.empty()) 913 serializeRelationship(InheritsFrom, Record, Record->SuperClass, 914 getModuleForCurrentSymbol()); 915 return true; 916 } 917 918 bool SymbolGraphSerializer::traverseObjCCategoryRecord( 919 const ObjCCategoryRecord *Record) { 920 auto *CurrentModule = ModuleForCurrentSymbol; 921 if (Record->isExtendingExternalModule()) 922 ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source]; 923 924 if (!walkUpFromObjCCategoryRecord(Record)) 925 return false; 926 927 bool RetVal = traverseRecordContext(Record); 928 ModuleForCurrentSymbol = CurrentModule; 929 return RetVal; 930 } 931 932 bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord( 933 const ObjCCategoryRecord *Record) { 934 return visitObjCCategoryRecord(Record); 935 } 936 937 bool SymbolGraphSerializer::visitObjCCategoryRecord( 938 const ObjCCategoryRecord *Record) { 939 // If we need to create a record for the category in the future do so here, 940 // otherwise everything is set up to pretend that the category is in fact the 941 // interface it extends. 942 for (const auto &Protocol : Record->Protocols) 943 serializeRelationship(ConformsTo, Record->Interface, Protocol, 944 getModuleForCurrentSymbol()); 945 946 return true; 947 } 948 949 bool SymbolGraphSerializer::visitObjCMethodRecord( 950 const ObjCMethodRecord *Record) { 951 if (!CurrentSymbol) 952 return true; 953 954 serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 955 return true; 956 } 957 958 bool SymbolGraphSerializer::visitObjCInstanceVariableRecord( 959 const ObjCInstanceVariableRecord *Record) { 960 // FIXME: serialize ivar access control here. 961 return true; 962 } 963 964 bool SymbolGraphSerializer::walkUpFromTypedefRecord( 965 const TypedefRecord *Record) { 966 // Short-circuit walking up the class hierarchy and handle creating typedef 967 // symbol objects manually as there are additional symbol dropping rules to 968 // respect. 969 return visitTypedefRecord(Record); 970 } 971 972 bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) { 973 // Typedefs of anonymous types have their entries unified with the underlying 974 // type. 975 bool ShouldDrop = Record->UnderlyingType.Name.empty(); 976 // enums declared with `NS_OPTION` have a named enum and a named typedef, with 977 // the same name 978 ShouldDrop |= (Record->UnderlyingType.Name == Record->Name); 979 if (ShouldDrop) 980 return true; 981 982 // Create the symbol record if the other symbol droppping rules permit it. 983 serializeAPIRecord(Record); 984 if (!CurrentSymbol) 985 return true; 986 987 (*CurrentSymbol)["type"] = Record->UnderlyingType.USR; 988 989 return true; 990 } 991 992 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { 993 switch (Record->getKind()) { 994 // dispatch to the relevant walkUpFromMethod 995 #define CONCRETE_RECORD(CLASS, BASE, KIND) \ 996 case APIRecord::KIND: { \ 997 walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \ 998 break; \ 999 } 1000 #include "clang/ExtractAPI/APIRecords.inc" 1001 // otherwise fallback on the only behavior we can implement safely. 1002 case APIRecord::RK_Unknown: 1003 visitAPIRecord(Record); 1004 break; 1005 default: 1006 llvm_unreachable("API Record with uninstantiable kind"); 1007 } 1008 } 1009 1010 Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName, 1011 ExtendedModule &&EM) { 1012 Object Root; 1013 serializeObject(Root, "metadata", serializeMetadata()); 1014 serializeObject(Root, "module", serializeModuleObject(ModuleName)); 1015 1016 Root["symbols"] = std::move(EM.Symbols); 1017 Root["relationships"] = std::move(EM.Relationships); 1018 1019 return Root; 1020 } 1021 1022 void SymbolGraphSerializer::serializeGraphToStream( 1023 raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName, 1024 ExtendedModule &&EM) { 1025 Object Root = serializeGraph(ModuleName, std::move(EM)); 1026 if (Options.Compact) 1027 OS << formatv("{0}", Value(std::move(Root))) << "\n"; 1028 else 1029 OS << formatv("{0:2}", Value(std::move(Root))) << "\n"; 1030 } 1031 1032 void SymbolGraphSerializer::serializeMainSymbolGraph( 1033 raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, 1034 SymbolGraphSerializerOption Options) { 1035 SymbolGraphSerializer Serializer(API, IgnoresList, 1036 Options.EmitSymbolLabelsForTesting); 1037 Serializer.traverseAPISet(); 1038 Serializer.serializeGraphToStream(OS, Options, API.ProductName, 1039 std::move(Serializer.MainModule)); 1040 // FIXME: TODO handle extended modules here 1041 } 1042 1043 void SymbolGraphSerializer::serializeWithExtensionGraphs( 1044 raw_ostream &MainOutput, const APISet &API, 1045 const APIIgnoresList &IgnoresList, 1046 llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)> 1047 CreateOutputStream, 1048 SymbolGraphSerializerOption Options) { 1049 SymbolGraphSerializer Serializer(API, IgnoresList, 1050 Options.EmitSymbolLabelsForTesting); 1051 Serializer.traverseAPISet(); 1052 1053 Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName, 1054 std::move(Serializer.MainModule)); 1055 1056 for (auto &ExtensionSGF : Serializer.ExtendedModules) { 1057 if (auto ExtensionOS = 1058 CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName)) 1059 Serializer.serializeGraphToStream(*ExtensionOS, Options, 1060 ExtensionSGF.getKey(), 1061 std::move(ExtensionSGF.getValue())); 1062 } 1063 } 1064 1065 std::optional<Object> 1066 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, 1067 const APISet &API) { 1068 APIRecord *Record = API.findRecordForUSR(USR); 1069 if (!Record) 1070 return {}; 1071 1072 Object Root; 1073 APIIgnoresList EmptyIgnores; 1074 SymbolGraphSerializer Serializer(API, EmptyIgnores, 1075 /*EmitSymbolLabelsForTesting*/ false, 1076 /*ForceEmitToMainModule*/ true); 1077 1078 // Set up serializer parent chain 1079 Serializer.Hierarchy = generateHierarchyFromRecord(Record); 1080 1081 Serializer.serializeSingleRecord(Record); 1082 serializeObject(Root, "symbolGraph", 1083 Serializer.serializeGraph(API.ProductName, 1084 std::move(Serializer.MainModule))); 1085 1086 Language Lang = API.getLanguage(); 1087 serializeArray(Root, "parentContexts", 1088 generateParentContexts(Serializer.Hierarchy, Lang)); 1089 1090 Array RelatedSymbols; 1091 1092 for (const auto &Fragment : Record->Declaration.getFragments()) { 1093 // If we don't have a USR there isn't much we can do. 1094 if (Fragment.PreciseIdentifier.empty()) 1095 continue; 1096 1097 APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier); 1098 1099 // If we can't find the record let's skip. 1100 if (!RelatedRecord) 1101 continue; 1102 1103 Object RelatedSymbol; 1104 RelatedSymbol["usr"] = RelatedRecord->USR; 1105 RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); 1106 RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess(); 1107 RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); 1108 RelatedSymbol["moduleName"] = API.ProductName; 1109 RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; 1110 1111 serializeArray(RelatedSymbol, "parentContexts", 1112 generateParentContexts( 1113 generateHierarchyFromRecord(RelatedRecord), Lang)); 1114 1115 RelatedSymbols.push_back(std::move(RelatedSymbol)); 1116 } 1117 1118 serializeArray(Root, "relatedSymbols", RelatedSymbols); 1119 return Root; 1120 } 1121