//===--- SymbolGraph.cpp - Symbol Graph Data Structure -------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #include "clang/AST/DeclObjC.h" #include "swift/AST/Decl.h" #include "swift/AST/Module.h" #include "swift/AST/ProtocolConformance.h" #include "swift/AST/USRGeneration.h" #include "swift/Basic/Version.h" #include "DeclarationFragmentPrinter.h" #include "FormatVersion.h" #include "Symbol.h" #include "SymbolGraph.h" using namespace swift; using namespace symbolgraphgen; SymbolGraph::SymbolGraph(ModuleDecl &M, llvm::Triple Target, markup::MarkupContext &Ctx, Optional ModuleVersion) : M(M), Target(Target), Ctx(Ctx), ModuleVersion(ModuleVersion) {} // MARK: - Utilities StringRef SymbolGraph::getUSR(const ValueDecl *VD) { auto Found = USRCache.find(VD); if (Found != USRCache.end()) { return Found->second; } llvm::SmallString<32> Scratch; llvm::raw_svector_ostream OS(Scratch); ide::printDeclUSR(VD, OS); auto USR = Ctx.allocateCopy(Scratch.str()); USRCache.insert({VD, USR}); return USR; } void SymbolGraph::getPathComponents(const ValueDecl *VD, SmallVectorImpl> &Components) { // Collect the spellings of the fully qualified identifier components. auto Decl = VD; while (Decl && !isa(Decl)) { SmallString<32> Scratch; Decl->getFullName().getString(Scratch); Components.push_back(Scratch); if (const auto *DC = Decl->getDeclContext()) { if (const auto *Proto = DC->getExtendedProtocolDecl()) { Decl = Proto; } else if (const auto *Ext = dyn_cast_or_null(DC->getAsDecl())) { Decl = Ext->getExtendedNominal(); } else { Decl = dyn_cast_or_null(DC->getAsDecl()); } } else { Decl = nullptr; } } // The list is leaf-to-root, but our list is root-to-leaf, so reverse it. std::reverse(Components.begin(), Components.end()); } PrintOptions SymbolGraph::getDeclarationFragmentsPrintOptions() const { PrintOptions Opts; Opts.FunctionDefinitions = false; Opts.ArgAndParamPrinting = PrintOptions::ArgAndParamPrintingMode::ArgumentOnly; Opts.PrintGetSetOnRWProperties = false; Opts.PrintPropertyAccessors = false; Opts.PrintSubscriptAccessors = false; Opts.SkipUnderscoredKeywords = true; Opts.SkipAttributes = true; Opts.PrintOverrideKeyword = true; Opts.PrintImplicitAttrs = false; Opts.PrintFunctionRepresentationAttrs = PrintOptions::FunctionRepresentationMode::None; Opts.PrintUserInaccessibleAttrs = false; Opts.SkipPrivateStdlibDecls = true; Opts.SkipUnderscoredStdlibProtocols = true; Opts.ExclusiveAttrList.clear(); #define DECL_ATTR(SPELLING, CLASS, OPTIONS, CODE) Opts.ExcludeAttrList.push_back(DAK_##CLASS); #define TYPE_ATTR(X) Opts.ExcludeAttrList.push_back(TAK_##X); #include "swift/AST/Attr.def" return Opts; } // MARK: - Relationships void SymbolGraph::recordEdge(const ValueDecl *Source, const ValueDecl *Target, RelationshipKind Kind) { if (Target->isPrivateStdlibDecl( /*treatNonBuiltinProtocolsAsPublic = */false)) { return; } // There might be relationships on implicit declarations, // such as overriding implicit @objc init(). if (Target->isImplicit()) { return; } Nodes.insert(Source); Nodes.insert(Target); Edges.insert({this, Kind, Source, Target}); } void SymbolGraph::recordMemberRelationship(const ValueDecl *VD) { auto *DC = VD->getDeclContext(); switch (DC->getContextKind()) { case DeclContextKind::GenericTypeDecl: case DeclContextKind::ExtensionDecl: case swift::DeclContextKind::EnumElementDecl: return recordEdge(VD, VD->getDeclContext()->getSelfNominalTypeDecl(), RelationshipKind::MemberOf()); case swift::DeclContextKind::AbstractClosureExpr: case swift::DeclContextKind::Initializer: case swift::DeclContextKind::TopLevelCodeDecl: case swift::DeclContextKind::SubscriptDecl: case swift::DeclContextKind::AbstractFunctionDecl: case swift::DeclContextKind::SerializedLocal: case swift::DeclContextKind::Module: case swift::DeclContextKind::FileUnit: break; } } void SymbolGraph::recordInheritanceRelationships(const ValueDecl *VD) { if (const auto *NTD = dyn_cast(VD)) { for (const auto &InheritanceLoc : NTD->getInherited()) { auto Ty = InheritanceLoc.getType(); if (!Ty) { continue; } auto *InheritedTypeDecl = dyn_cast_or_null(Ty->getAnyNominal()); if (!InheritedTypeDecl) { continue; } recordEdge(VD, InheritedTypeDecl, RelationshipKind::InheritsFrom()); } } } void SymbolGraph::recordDefaultImplementationRelationships( const ValueDecl *VD) { if (const auto *Extension = dyn_cast(VD->getDeclContext())) { if (const auto *Protocol = Extension->getExtendedProtocolDecl()) { for (const auto *Member : Protocol->getMembers()) { if (const auto *MemberVD = dyn_cast(Member)) { if (MemberVD->getFullName().compare(VD->getFullName()) == 0) { recordEdge(VD, MemberVD, RelationshipKind::DefaultImplementationOf()); } } } } } } void SymbolGraph::recordRequirementRelationships(const ValueDecl *VD) { if (const auto *Protocol = dyn_cast(VD->getDeclContext())) { if (VD->isProtocolRequirement()) { recordEdge(VD, Protocol, RelationshipKind::RequirementOf()); } } } void SymbolGraph::recordOptionalRequirementRelationships( const ValueDecl *VD) { if (const auto *Protocol = dyn_cast(VD->getDeclContext())) { if (VD->isProtocolRequirement()) { if (const auto *ClangDecl = VD->getClangDecl()) { if (const auto *Method = dyn_cast(ClangDecl)) { if (Method->isOptional()) { recordEdge(VD, Protocol, RelationshipKind::OptionalRequirementOf()); } } } } } } void SymbolGraph::recordConformanceRelationships(const ValueDecl *VD) { if (const auto *NTD = dyn_cast(VD)) { for (const auto *Conformance : NTD->getAllConformances()) { recordEdge(VD, Conformance->getProtocol(), RelationshipKind::ConformsTo()); } } } void SymbolGraph::recordOverrideRelationship(const ValueDecl *VD) { if (const auto *Override = VD->getOverriddenDecl()) { recordEdge(VD, Override, RelationshipKind::Overrides()); } } // MARK: - Serialization void SymbolGraph::serialize(llvm::json::OStream &OS) { OS.object([&](){ OS.attributeObject("metadata", [&](){ { AttributeRAII FV("formatVersion", OS); llvm::VersionTuple FormatVersion(SWIFT_SYMBOLGRAPH_FORMAT_MAJOR, SWIFT_SYMBOLGRAPH_FORMAT_MINOR, SWIFT_SYMBOLGRAPH_FORMAT_PATCH); symbolgraphgen::serialize(FormatVersion, OS); } // end formatVersion: auto VersionString = version::getSwiftFullVersion(); StringRef VersionStringRef(VersionString.c_str(), VersionString.size()); OS.attribute("generator", VersionStringRef); }); // end metadata: OS.attributeObject("module", [&](){ OS.attribute("name", M.getNameStr()); AttributeRAII Platform("platform", OS); symbolgraphgen::serialize(Target, OS); }); if (ModuleVersion) { AttributeRAII MV("moduleVersion", OS); symbolgraphgen::serialize(*ModuleVersion, OS); } OS.attributeArray("symbols", [&](){ for (const auto *VD: Nodes) { Symbol S { *this, VD }; S.serialize(OS); } }); OS.attributeArray("relationships", [&](){ for (const auto Relationship : Edges) { Relationship.serialize(OS); } }); }); } void SymbolGraph::serializeDeclarationFragments(StringRef Key, const ValueDecl *VD, llvm::json::OStream &OS) { DeclarationFragmentPrinter Printer(*this, OS, Key); VD->print(Printer, getDeclarationFragmentsPrintOptions()); } void SymbolGraph::serializeSubheadingDeclarationFragments(StringRef Key, const ValueDecl *VD, llvm::json::OStream &OS) { DeclarationFragmentPrinter Printer(*this, OS, Key); auto Options = getDeclarationFragmentsPrintOptions(); Options.VarInitializers = false; Options.PrintDefaultArgumentValue = false; Options.PrintEmptyArgumentNames = false; Options.PrintOverrideKeyword = false; VD->print(Printer, Options); } void SymbolGraph::serializeDeclarationFragments(StringRef Key, Type T, llvm::json::OStream &OS) { DeclarationFragmentPrinter Printer(*this, OS, Key); T->print(Printer, getDeclarationFragmentsPrintOptions()); }