brintos

brintos / llvm-project-archived public Read only

0
0
Text · 37.6 KiB · d3df9eb Raw
1146 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// 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 29using namespace clang;30using namespace clang::extractapi;31using namespace llvm;32 33namespace {34 35/// Helper function to inject a JSON object \p Obj into another object \p Paren36/// at position \p Key.37void 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 at44/// position \p Key.45void 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 into52/// object \p Paren at position \p Key.53template <typename ContainerTy>54void 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 version59/// format.60///61/// A semantic version object contains three numeric fields, representing the62/// \c major, \c minor, and \c patch parts of the version tuple.63/// For example version tuple 1.0.3 is serialized as:64/// \code65///   {66///     "major" : 1,67///     "minor" : 0,68///     "patch" : 369///   }70/// \endcode71///72/// \returns \c std::nullopt if the version \p V is empty, or an \c Object73/// containing the semantic version representation of \p V.74std::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 an88/// optional \c minimumVersion semantic version field.89Object 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 corresponding100/// three fields: \c architecture, \c vendor, and \c operatingSystem.101Object 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.114Object 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.129Object 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.145Object 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 obsoleted156/// versions of the symbol as semantic versions, if not default.157/// Availability information also contains flags to indicate if the symbol is158/// 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 availability163/// information.164std::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.199StringRef 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 currently211  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 compile218  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 unique231/// references, and the interface language name.232Object 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 by241/// the Symbol Graph format.242///243/// The Symbol Graph \c docComment object contains an array of lines. Each line244/// represents one line of striped documentation comment, with source range245/// information.246/// e.g.247/// \code248///   /// This is a documentation comment249///       ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'  First line.250///   ///     with multiple lines.251///       ^~~~~~~~~~~~~~~~~~~~~~~'         Second line.252/// \endcode253///254/// \returns \c std::nullopt if \p Comment is empty, or an \c Object containing255/// the formatted lines.256std::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 important279/// parts of a symbol's declaration. The fragments sequence can be joined to280/// form spans of declaration text, with attached information useful for281/// purposes like syntax-highlighting etc. For example:282/// \code283///   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/// \endcode307///308/// \returns \c std::nullopt if \p DF is empty, or an \c Array containing the309/// formatted declaration fragments array.310std::optional<Array>311serializeDeclarationFragments(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 Graph329/// format.330///331/// The Symbol Graph names field contains multiple representations of a symbol332/// 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 for336///     Objective-C methods). Can be used as sub-headings for documentation.337Object 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, and345  // should be included in the navigator fragment. The entire subheading is346  // 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 369Object 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 identifier533/// which is prefixed by the source language name, useful for tooling to parse534/// the kind, and a \c displayName for rendering human-readable names.535Object serializeSymbolKind(const APIRecord &Record, Language Lang) {536  return serializeSymbolKind(Record.KindForDisplay, Lang);537}538 539/// Serialize the function signature field, as specified by the540/// 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 the545///     parameters.546template <typename RecordTy>547void 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 571template <typename RecordTy>572void 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 604Array 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    else616      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 hierarchy625/// suitable for serialization.626SmallVector<SymbolReference, 8>627generateHierarchyFromRecord(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 638SymbolReference getHierarchyReference(const APIRecord *Record,639                                      const APISet &API) {640  // If the parent is a category extended from internal module then we need to641  // 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 extending645    // an external module.646  }647 648  return SymbolReference(Record);649}650 651} // namespace652 653Object *ExtendedModule::addSymbol(Object &&Symbol) {654  Symbols.emplace_back(std::move(Symbol));655  return Symbols.back().getAsObject();656}657 658void ExtendedModule::addRelationship(Object &&Relationship) {659  Relationships.emplace_back(std::move(Relationship));660}661 662/// Defines the format version emitted by SymbolGraphSerializer.663const VersionTuple SymbolGraphSerializer::FormatVersion{0, 5, 3};664 665Object SymbolGraphSerializer::serializeMetadata() const {666  Object Metadata;667  serializeObject(Metadata, "formatVersion",668                  serializeSemanticVersion(FormatVersion));669  Metadata["generator"] = clang::getClangFullVersion();670  return Metadata;671}672 673Object674SymbolGraphSerializer::serializeModuleObject(StringRef ModuleName) const {675  Object Module;676  Module["name"] = ModuleName;677  serializeObject(Module, "platform", serializePlatform(API.getTarget()));678  return Module;679}680 681bool SymbolGraphSerializer::shouldSkip(const APIRecord *Record) const {682  if (!Record)683    return true;684 685  // Skip unconditionally unavailable symbols686  if (Record->Availability.isUnconditionallyUnavailable())687    return true;688 689  // Filter out symbols prefixed with an underscored as they are understood to690  // 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 701ExtendedModule &SymbolGraphSerializer::getModuleForCurrentSymbol() {702  if (!ForceEmitToMainModule && ModuleForCurrentSymbol)703    return *ModuleForCurrentSymbol;704 705  return MainModule;706}707 708Array SymbolGraphSerializer::serializePathComponents(709    const APIRecord *Record) const {710  return Array(map_range(Hierarchy, [](auto Elt) { return Elt.Name; }));711}712 713StringRef 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 727void 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    else740      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  else751    Into.addRelationship(std::move(Relationship));752}753 754StringRef 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 764void 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 key768  // 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 797bool 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 implementation804  auto RetVal = Base::traverseAPIRecord(Record);805  Hierarchy.pop_back();806  return RetVal;807}808 809bool SymbolGraphSerializer::visitAPIRecord(const APIRecord *Record) {810  serializeAPIRecord(Record);811  return true;812}813 814bool SymbolGraphSerializer::visitGlobalFunctionRecord(815    const GlobalFunctionRecord *Record) {816  if (!CurrentSymbol)817    return true;818 819  serializeFunctionSignatureMixin(*CurrentSymbol, *Record);820  return true;821}822 823bool 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 833bool SymbolGraphSerializer::visitClassTemplateRecord(834    const ClassTemplateRecord *Record) {835  if (!CurrentSymbol)836    return true;837 838  serializeTemplateMixin(*CurrentSymbol, *Record);839  return true;840}841 842bool SymbolGraphSerializer::visitClassTemplatePartialSpecializationRecord(843    const ClassTemplatePartialSpecializationRecord *Record) {844  if (!CurrentSymbol)845    return true;846 847  serializeTemplateMixin(*CurrentSymbol, *Record);848  return true;849}850 851bool SymbolGraphSerializer::visitCXXMethodRecord(852    const CXXMethodRecord *Record) {853  if (!CurrentSymbol)854    return true;855 856  serializeFunctionSignatureMixin(*CurrentSymbol, *Record);857  return true;858}859 860bool SymbolGraphSerializer::visitCXXMethodTemplateRecord(861    const CXXMethodTemplateRecord *Record) {862  if (!CurrentSymbol)863    return true;864 865  serializeTemplateMixin(*CurrentSymbol, *Record);866  return true;867}868 869bool SymbolGraphSerializer::visitCXXFieldTemplateRecord(870    const CXXFieldTemplateRecord *Record) {871  if (!CurrentSymbol)872    return true;873 874  serializeTemplateMixin(*CurrentSymbol, *Record);875  return true;876}877 878bool SymbolGraphSerializer::visitConceptRecord(const ConceptRecord *Record) {879  if (!CurrentSymbol)880    return true;881 882  serializeTemplateMixin(*CurrentSymbol, *Record);883  return true;884}885 886bool SymbolGraphSerializer::visitGlobalVariableTemplateRecord(887    const GlobalVariableTemplateRecord *Record) {888  if (!CurrentSymbol)889    return true;890 891  serializeTemplateMixin(*CurrentSymbol, *Record);892  return true;893}894 895bool SymbolGraphSerializer::896    visitGlobalVariableTemplatePartialSpecializationRecord(897        const GlobalVariableTemplatePartialSpecializationRecord *Record) {898  if (!CurrentSymbol)899    return true;900 901  serializeTemplateMixin(*CurrentSymbol, *Record);902  return true;903}904 905bool SymbolGraphSerializer::visitGlobalFunctionTemplateRecord(906    const GlobalFunctionTemplateRecord *Record) {907  if (!CurrentSymbol)908    return true;909 910  serializeTemplateMixin(*CurrentSymbol, *Record);911  return true;912}913 914bool 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 926bool 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 937bool 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 955bool SymbolGraphSerializer::walkUpFromObjCCategoryRecord(956    const ObjCCategoryRecord *Record) {957  return visitObjCCategoryRecord(Record);958}959 960bool 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 the964  // interface it extends.965  for (const auto &Protocol : Record->Protocols)966    serializeRelationship(ConformsTo, Record->Interface, Protocol,967                          getModuleForCurrentSymbol());968 969  return true;970}971 972bool SymbolGraphSerializer::visitObjCMethodRecord(973    const ObjCMethodRecord *Record) {974  if (!CurrentSymbol)975    return true;976 977  serializeFunctionSignatureMixin(*CurrentSymbol, *Record);978  return true;979}980 981bool SymbolGraphSerializer::visitObjCInstanceVariableRecord(982    const ObjCInstanceVariableRecord *Record) {983  // FIXME: serialize ivar access control here.984  return true;985}986 987bool SymbolGraphSerializer::walkUpFromTypedefRecord(988    const TypedefRecord *Record) {989  // Short-circuit walking up the class hierarchy and handle creating typedef990  // symbol objects manually as there are additional symbol dropping rules to991  // respect.992  return visitTypedefRecord(Record);993}994 995bool SymbolGraphSerializer::visitTypedefRecord(const TypedefRecord *Record) {996  // Typedefs of anonymous types have their entries unified with the underlying997  // type.998  bool ShouldDrop = Record->UnderlyingType.Name.empty();999  // enums declared with `NS_OPTION` have a named enum and a named typedef, with1000  // the same name1001  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 1015void SymbolGraphSerializer::serializeSingleRecord(const APIRecord *Record) {1016  switch (Record->getKind()) {1017    // dispatch to the relevant walkUpFromMethod1018#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 1033Object 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 1045void 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  else1052    OS << formatv("{0:2}", json::Value(std::move(Root))) << "\n";1053}1054 1055void 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 here1067}1068 1069void 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 1090std::optional<Object>1091SymbolGraphSerializer::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 chain1104  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