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