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 without a name as we can generate correct symbol graphs 671 // for them. In practice these are anonymous record types that aren't attached 672 // to a declaration. 673 if (auto *Tag = dyn_cast<TagRecord>(Record)) { 674 if (Tag->IsEmbeddedInVarDeclarator) 675 return true; 676 } 677 678 // Filter out symbols prefixed with an underscored as they are understood to 679 // be symbols clients should not use. 680 if (Record->Name.starts_with("_")) 681 return true; 682 683 // Skip explicitly ignored symbols. 684 if (IgnoresList.shouldIgnore(Record->Name)) 685 return true; 686 687 return false; 688 } 689 690 ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() { 691 if (!ForceEmitToMainModule && ModuleForCurrentSymbol) 692 return *ModuleForCurrentSymbol; 693 694 return MainModule; 695 } 696 697 Array SymbolGraphSerializer::serializePathComponents( 698 const APIRecord *Record) const { 699 return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; })); 700 } 701 702 StringRef SymbolGraphSerializer::getRelationshipString(RelationshipKind Kind) { 703 switch (Kind) { 704 case RelationshipKind::MemberOf: 705 return "memberOf"; 706 case RelationshipKind::InheritsFrom: 707 return "inheritsFrom"; 708 case RelationshipKind::ConformsTo: 709 return "conformsTo"; 710 case RelationshipKind::ExtensionTo: 711 return "extensionTo"; 712 } 713 llvm_unreachable("Unhandled relationship kind"); 714 } 715 716 void SymbolGraphSerializer::serializeRelationship(RelationshipKind Kind, 717 const SymbolReference &Source, 718 const SymbolReference &Target, 719 ExtendedModule &Into) { 720 Object Relationship; 721 SmallString<64> TestRelLabel; 722 if (EmitSymbolLabelsForTesting) { 723 llvm::raw_svector_ostream OS(TestRelLabel); 724 OS << SymbolGraphSerializer::getRelationshipString(Kind) << " $ " 725 << Source.USR << " $ "; 726 if (Target.USR.empty()) 727 OS << Target.Name; 728 else 729 OS << Target.USR; 730 Relationship["!testRelLabel"] = TestRelLabel; 731 } 732 Relationship["source"] = Source.USR; 733 Relationship["target"] = Target.USR; 734 Relationship["targetFallback"] = Target.Name; 735 Relationship["kind"] = SymbolGraphSerializer::getRelationshipString(Kind); 736 737 if (ForceEmitToMainModule) 738 MainModule.addRelationship(std::move(Relationship)); 739 else 740 Into.addRelationship(std::move(Relationship)); 741 } 742 743 StringRef SymbolGraphSerializer::getConstraintString(ConstraintKind Kind) { 744 switch (Kind) { 745 case ConstraintKind::Conformance: 746 return "conformance"; 747 case ConstraintKind::ConditionalConformance: 748 return "conditionalConformance"; 749 } 750 llvm_unreachable("Unhandled constraint kind"); 751 } 752 753 void SymbolGraphSerializer::serializeAPIRecord(const APIRecord *Record) { 754 Object Obj; 755 756 // If we need symbol labels for testing emit the USR as the value and the key 757 // starts with '!'' to ensure it ends up at the top of the object. 758 if (EmitSymbolLabelsForTesting) 759 Obj["!testLabel"] = Record->USR; 760 761 serializeObject(Obj, "identifier", 762 serializeIdentifier(*Record, API.getLanguage())); 763 serializeObject(Obj, "kind", serializeSymbolKind(*Record, API.getLanguage())); 764 serializeObject(Obj, "names", serializeNames(Record)); 765 serializeObject( 766 Obj, "location", 767 serializeSourceLocation(Record->Location, /*IncludeFileURI=*/true)); 768 serializeArray(Obj, "availability", 769 serializeAvailability(Record->Availability)); 770 serializeObject(Obj, "docComment", serializeDocComment(Record->Comment)); 771 serializeArray(Obj, "declarationFragments", 772 serializeDeclarationFragments(Record->Declaration)); 773 774 Obj["pathComponents"] = serializePathComponents(Record); 775 Obj["accessLevel"] = Record->Access.getAccess(); 776 777 ExtendedModule &Module = getModuleForCurrentSymbol(); 778 // If the hierarchy has at least one parent and child. 779 if (Hierarchy.size() >= 2) 780 serializeRelationship(MemberOf, Hierarchy.back(), 781 Hierarchy[Hierarchy.size() - 2], Module); 782 783 CurrentSymbol = Module.addSymbol(std::move(Obj)); 784 } 785 786 bool SymbolGraphSerializer::traverseAPIRecord(const APIRecord *Record) { 787 if (!Record) 788 return true; 789 if (shouldSkip(Record)) 790 return true; 791 Hierarchy.push_back(getHierarchyReference(Record, API)); 792 // Defer traversal mechanics to APISetVisitor base implementation 793 auto RetVal = Base::traverseAPIRecord(Record); 794 Hierarchy.pop_back(); 795 return RetVal; 796 } 797 798 bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) { 799 serializeAPIRecord(Record); 800 return true; 801 } 802 803 bool SymbolGraphSerializer::visitGlobalFunctionRecord( 804 const GlobalFunctionRecord *Record) { 805 if (!CurrentSymbol) 806 return true; 807 808 serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 809 return true; 810 } 811 812 bool SymbolGraphSerializer::visitCXXClassRecord(const CXXClassRecord *Record) { 813 if (!CurrentSymbol) 814 return true; 815 816 for (const auto &Base : Record->Bases) 817 serializeRelationship(RelationshipKind::InheritsFrom, Record, Base, 818 getModuleForCurrentSymbol()); 819 return true; 820 } 821 822 bool SymbolGraphSerializer::visitClassTemplateRecord( 823 const ClassTemplateRecord *Record) { 824 if (!CurrentSymbol) 825 return true; 826 827 serializeTemplateMixin(*CurrentSymbol, *Record); 828 return true; 829 } 830 831 bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord( 832 const ClassTemplatePartialSpecializationRecord *Record) { 833 if (!CurrentSymbol) 834 return true; 835 836 serializeTemplateMixin(*CurrentSymbol, *Record); 837 return true; 838 } 839 840 bool SymbolGraphSerializer::visitCXXMethodRecord( 841 const CXXMethodRecord *Record) { 842 if (!CurrentSymbol) 843 return true; 844 845 serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 846 return true; 847 } 848 849 bool SymbolGraphSerializer::visitCXXMethodTemplateRecord( 850 const CXXMethodTemplateRecord *Record) { 851 if (!CurrentSymbol) 852 return true; 853 854 serializeTemplateMixin(*CurrentSymbol, *Record); 855 return true; 856 } 857 858 bool SymbolGraphSerializer::visitCXXFieldTemplateRecord( 859 const CXXFieldTemplateRecord *Record) { 860 if (!CurrentSymbol) 861 return true; 862 863 serializeTemplateMixin(*CurrentSymbol, *Record); 864 return true; 865 } 866 867 bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) { 868 if (!CurrentSymbol) 869 return true; 870 871 serializeTemplateMixin(*CurrentSymbol, *Record); 872 return true; 873 } 874 875 bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord( 876 const GlobalVariableTemplateRecord *Record) { 877 if (!CurrentSymbol) 878 return true; 879 880 serializeTemplateMixin(*CurrentSymbol, *Record); 881 return true; 882 } 883 884 bool SymbolGraphSerializer:: 885 visitGlobalVariableTemplatePartialSpecializationRecord( 886 const GlobalVariableTemplatePartialSpecializationRecord *Record) { 887 if (!CurrentSymbol) 888 return true; 889 890 serializeTemplateMixin(*CurrentSymbol, *Record); 891 return true; 892 } 893 894 bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord( 895 const GlobalFunctionTemplateRecord *Record) { 896 if (!CurrentSymbol) 897 return true; 898 899 serializeTemplateMixin(*CurrentSymbol, *Record); 900 return true; 901 } 902 903 bool SymbolGraphSerializer::visitObjCContainerRecord( 904 const ObjCContainerRecord *Record) { 905 if (!CurrentSymbol) 906 return true; 907 908 for (const auto &Protocol : Record->Protocols) 909 serializeRelationship(ConformsTo, Record, Protocol, 910 getModuleForCurrentSymbol()); 911 912 return true; 913 } 914 915 bool SymbolGraphSerializer::visitObjCInterfaceRecord( 916 const ObjCInterfaceRecord *Record) { 917 if (!CurrentSymbol) 918 return true; 919 920 if (!Record->SuperClass.empty()) 921 serializeRelationship(InheritsFrom, Record, Record->SuperClass, 922 getModuleForCurrentSymbol()); 923 return true; 924 } 925 926 bool SymbolGraphSerializer::traverseObjCCategoryRecord( 927 const ObjCCategoryRecord *Record) { 928 auto *CurrentModule = ModuleForCurrentSymbol; 929 if (Record->isExtendingExternalModule()) 930 ModuleForCurrentSymbol = &ExtendedModules[Record->Interface.Source]; 931 932 if (!walkUpFromObjCCategoryRecord(Record)) 933 return false; 934 935 bool RetVal = traverseRecordContext(Record); 936 ModuleForCurrentSymbol = CurrentModule; 937 return RetVal; 938 } 939 940 bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord( 941 const ObjCCategoryRecord *Record) { 942 return visitObjCCategoryRecord(Record); 943 } 944 945 bool SymbolGraphSerializer::visitObjCCategoryRecord( 946 const ObjCCategoryRecord *Record) { 947 // If we need to create a record for the category in the future do so here, 948 // otherwise everything is set up to pretend that the category is in fact the 949 // interface it extends. 950 for (const auto &Protocol : Record->Protocols) 951 serializeRelationship(ConformsTo, Record->Interface, Protocol, 952 getModuleForCurrentSymbol()); 953 954 return true; 955 } 956 957 bool SymbolGraphSerializer::visitObjCMethodRecord( 958 const ObjCMethodRecord *Record) { 959 if (!CurrentSymbol) 960 return true; 961 962 serializeFunctionSignatureMixin(*CurrentSymbol, *Record); 963 return true; 964 } 965 966 bool SymbolGraphSerializer::visitObjCInstanceVariableRecord( 967 const ObjCInstanceVariableRecord *Record) { 968 // FIXME: serialize ivar access control here. 969 return true; 970 } 971 972 bool SymbolGraphSerializer::walkUpFromTypedefRecord( 973 const TypedefRecord *Record) { 974 // Short-circuit walking up the class hierarchy and handle creating typedef 975 // symbol objects manually as there are additional symbol dropping rules to 976 // respect. 977 return visitTypedefRecord(Record); 978 } 979 980 bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) { 981 // Typedefs of anonymous types have their entries unified with the underlying 982 // type. 983 bool ShouldDrop = Record->UnderlyingType.Name.empty(); 984 // enums declared with `NS_OPTION` have a named enum and a named typedef, with 985 // the same name 986 ShouldDrop |= (Record->UnderlyingType.Name == Record->Name); 987 if (ShouldDrop) 988 return true; 989 990 // Create the symbol record if the other symbol droppping rules permit it. 991 serializeAPIRecord(Record); 992 if (!CurrentSymbol) 993 return true; 994 995 (*CurrentSymbol)["type"] = Record->UnderlyingType.USR; 996 997 return true; 998 } 999 1000 void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) { 1001 switch (Record->getKind()) { 1002 // dispatch to the relevant walkUpFromMethod 1003 #define CONCRETE_RECORD(CLASS, BASE, KIND) \ 1004 case APIRecord::KIND: { \ 1005 walkUpFrom##CLASS(static_cast<const CLASS *>(Record)); \ 1006 break; \ 1007 } 1008 #include "clang/ExtractAPI/APIRecords.inc" 1009 // otherwise fallback on the only behavior we can implement safely. 1010 case APIRecord::RK_Unknown: 1011 visitAPIRecord(Record); 1012 break; 1013 default: 1014 llvm_unreachable("API Record with uninstantiable kind"); 1015 } 1016 } 1017 1018 Object SymbolGraphSerializer::serializeGraph(StringRef ModuleName, 1019 ExtendedModule &&EM) { 1020 Object Root; 1021 serializeObject(Root, "metadata", serializeMetadata()); 1022 serializeObject(Root, "module", serializeModuleObject(ModuleName)); 1023 1024 Root["symbols"] = std::move(EM.Symbols); 1025 Root["relationships"] = std::move(EM.Relationships); 1026 1027 return Root; 1028 } 1029 1030 void SymbolGraphSerializer::serializeGraphToStream( 1031 raw_ostream &OS, SymbolGraphSerializerOption Options, StringRef ModuleName, 1032 ExtendedModule &&EM) { 1033 Object Root = serializeGraph(ModuleName, std::move(EM)); 1034 if (Options.Compact) 1035 OS << formatv("{0}", Value(std::move(Root))) << "\n"; 1036 else 1037 OS << formatv("{0:2}", Value(std::move(Root))) << "\n"; 1038 } 1039 1040 void SymbolGraphSerializer::serializeMainSymbolGraph( 1041 raw_ostream &OS, const APISet &API, const APIIgnoresList &IgnoresList, 1042 SymbolGraphSerializerOption Options) { 1043 SymbolGraphSerializer Serializer(API, IgnoresList, 1044 Options.EmitSymbolLabelsForTesting); 1045 Serializer.traverseAPISet(); 1046 Serializer.serializeGraphToStream(OS, Options, API.ProductName, 1047 std::move(Serializer.MainModule)); 1048 // FIXME: TODO handle extended modules here 1049 } 1050 1051 void SymbolGraphSerializer::serializeWithExtensionGraphs( 1052 raw_ostream &MainOutput, const APISet &API, 1053 const APIIgnoresList &IgnoresList, 1054 llvm::function_ref<std::unique_ptr<llvm::raw_pwrite_stream>(Twine BaseName)> 1055 CreateOutputStream, 1056 SymbolGraphSerializerOption Options) { 1057 SymbolGraphSerializer Serializer(API, IgnoresList, 1058 Options.EmitSymbolLabelsForTesting); 1059 Serializer.traverseAPISet(); 1060 1061 Serializer.serializeGraphToStream(MainOutput, Options, API.ProductName, 1062 std::move(Serializer.MainModule)); 1063 1064 for (auto &ExtensionSGF : Serializer.ExtendedModules) { 1065 if (auto ExtensionOS = 1066 CreateOutputStream(ExtensionSGF.getKey() + "@" + API.ProductName)) 1067 Serializer.serializeGraphToStream(*ExtensionOS, Options, 1068 ExtensionSGF.getKey(), 1069 std::move(ExtensionSGF.getValue())); 1070 } 1071 } 1072 1073 std::optional<Object> 1074 SymbolGraphSerializer::serializeSingleSymbolSGF(StringRef USR, 1075 const APISet &API) { 1076 APIRecord *Record = API.findRecordForUSR(USR); 1077 if (!Record) 1078 return {}; 1079 1080 Object Root; 1081 APIIgnoresList EmptyIgnores; 1082 SymbolGraphSerializer Serializer(API, EmptyIgnores, 1083 /*EmitSymbolLabelsForTesting*/ false, 1084 /*ForceEmitToMainModule*/ true); 1085 1086 // Set up serializer parent chain 1087 Serializer.Hierarchy = generateHierarchyFromRecord(Record); 1088 1089 Serializer.serializeSingleRecord(Record); 1090 serializeObject(Root, "symbolGraph", 1091 Serializer.serializeGraph(API.ProductName, 1092 std::move(Serializer.MainModule))); 1093 1094 Language Lang = API.getLanguage(); 1095 serializeArray(Root, "parentContexts", 1096 generateParentContexts(Serializer.Hierarchy, Lang)); 1097 1098 Array RelatedSymbols; 1099 1100 for (const auto &Fragment : Record->Declaration.getFragments()) { 1101 // If we don't have a USR there isn't much we can do. 1102 if (Fragment.PreciseIdentifier.empty()) 1103 continue; 1104 1105 APIRecord *RelatedRecord = API.findRecordForUSR(Fragment.PreciseIdentifier); 1106 1107 // If we can't find the record let's skip. 1108 if (!RelatedRecord) 1109 continue; 1110 1111 Object RelatedSymbol; 1112 RelatedSymbol["usr"] = RelatedRecord->USR; 1113 RelatedSymbol["declarationLanguage"] = getLanguageName(Lang); 1114 RelatedSymbol["accessLevel"] = RelatedRecord->Access.getAccess(); 1115 RelatedSymbol["filePath"] = RelatedRecord->Location.getFilename(); 1116 RelatedSymbol["moduleName"] = API.ProductName; 1117 RelatedSymbol["isSystem"] = RelatedRecord->IsFromSystemHeader; 1118 1119 serializeArray(RelatedSymbol, "parentContexts", 1120 generateParentContexts( 1121 generateHierarchyFromRecord(RelatedRecord), Lang)); 1122 1123 RelatedSymbols.push_back(std::move(RelatedSymbol)); 1124 } 1125 1126 serializeArray(Root, "relatedSymbols", RelatedSymbols); 1127 return Root; 1128 } 1129