mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
When a module extends a type from another module, serialize those symbols into separated files dedicated to those extended modules. This makes it easier to ingest and categorize those symbols under the extended module if desired. rdar://58941718
344 lines
11 KiB
C++
344 lines
11 KiB
C++
//===--- 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 "swift/ClangImporter/ClangModule.h"
|
|
#include "swift/Serialization/SerializedModuleLoader.h"
|
|
|
|
#include "DeclarationFragmentPrinter.h"
|
|
#include "FormatVersion.h"
|
|
#include "Symbol.h"
|
|
#include "SymbolGraph.h"
|
|
|
|
using namespace swift;
|
|
using namespace symbolgraphgen;
|
|
|
|
SymbolGraph::SymbolGraph(ModuleDecl &M,
|
|
Optional<ModuleDecl *> ExtendedModule,
|
|
llvm::Triple Target,
|
|
markup::MarkupContext &Ctx,
|
|
Optional<llvm::VersionTuple> ModuleVersion)
|
|
: M(M),
|
|
ExtendedModule(ExtendedModule),
|
|
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<SmallString<32>> &Components) {
|
|
// Collect the spellings of the fully qualified identifier components.
|
|
auto Decl = VD;
|
|
while (Decl && !isa<ModuleDecl>(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<ExtensionDecl>(DC->getAsDecl())) {
|
|
Decl = Ext->getExtendedNominal();
|
|
} else {
|
|
Decl = dyn_cast_or_null<ValueDecl>(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: - Symbols (Nodes)
|
|
|
|
void SymbolGraph::recordNode(const ValueDecl *VD) {
|
|
Nodes.insert(VD);
|
|
|
|
// Record all of the possible relationships (edges) originating
|
|
// with this declaration.
|
|
recordMemberRelationship(VD);
|
|
recordConformanceRelationships(VD);
|
|
recordInheritanceRelationships(VD);
|
|
recordDefaultImplementationRelationships(VD);
|
|
recordOverrideRelationship(VD);
|
|
recordRequirementRelationships(VD);
|
|
recordOptionalRequirementRelationships(VD);
|
|
}
|
|
|
|
// MARK: - Relationships (Edges)
|
|
|
|
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<NominalTypeDecl>(VD)) {
|
|
for (const auto &InheritanceLoc : NTD->getInherited()) {
|
|
auto Ty = InheritanceLoc.getType();
|
|
if (!Ty) {
|
|
continue;
|
|
}
|
|
auto *InheritedTypeDecl =
|
|
dyn_cast_or_null<ClassDecl>(Ty->getAnyNominal());
|
|
if (!InheritedTypeDecl) {
|
|
continue;
|
|
}
|
|
|
|
recordEdge(VD, InheritedTypeDecl, RelationshipKind::InheritsFrom());
|
|
}
|
|
}
|
|
}
|
|
|
|
void SymbolGraph::recordDefaultImplementationRelationships(
|
|
const ValueDecl *VD) {
|
|
if (const auto *Extension = dyn_cast<ExtensionDecl>(VD->getDeclContext())) {
|
|
if (const auto *Protocol = Extension->getExtendedProtocolDecl()) {
|
|
for (const auto *Member : Protocol->getMembers()) {
|
|
if (const auto *MemberVD = dyn_cast<ValueDecl>(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<ProtocolDecl>(VD->getDeclContext())) {
|
|
if (VD->isProtocolRequirement()) {
|
|
recordEdge(VD, Protocol, RelationshipKind::RequirementOf());
|
|
}
|
|
}
|
|
}
|
|
|
|
void SymbolGraph::recordOptionalRequirementRelationships(
|
|
const ValueDecl *VD) {
|
|
if (const auto *Protocol = dyn_cast<ProtocolDecl>(VD->getDeclContext())) {
|
|
if (VD->isProtocolRequirement()) {
|
|
if (const auto *ClangDecl = VD->getClangDecl()) {
|
|
if (const auto *Method = dyn_cast<clang::ObjCMethodDecl>(ClangDecl)) {
|
|
if (Method->isOptional()) {
|
|
recordEdge(VD, Protocol,
|
|
RelationshipKind::OptionalRequirementOf());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
SymbolGraph::recordConformanceRelationships(const ValueDecl *VD) {
|
|
if (const auto *NTD = dyn_cast<NominalTypeDecl>(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);
|
|
|
|
auto *MainFile = M.getFiles().front();
|
|
switch (MainFile->getKind()) {
|
|
case FileUnitKind::Builtin:
|
|
llvm_unreachable("Unexpected module kind: Builtin");
|
|
case FileUnitKind::DWARFModule:
|
|
llvm_unreachable("Unexpected module kind: DWARFModule");
|
|
case FileUnitKind::Source:
|
|
llvm_unreachable("Unexpected module kind: Source");
|
|
break;
|
|
case FileUnitKind::SerializedAST: {
|
|
auto SerializedAST = cast<SerializedASTFile>(MainFile);
|
|
auto Target = llvm::Triple(SerializedAST->getTargetTriple());
|
|
symbolgraphgen::serialize(Target, OS);
|
|
break;
|
|
}
|
|
case FileUnitKind::ClangModule: {
|
|
auto ClangModule = cast<ClangModuleUnit>(MainFile);
|
|
if (const auto *Overlay = ClangModule->getOverlayModule()) {
|
|
auto &OverlayMainFile =
|
|
Overlay->getMainFile(FileUnitKind::SerializedAST);
|
|
auto SerializedAST = cast<SerializedASTFile>(OverlayMainFile);
|
|
auto Target = llvm::Triple(SerializedAST.getTargetTriple());
|
|
symbolgraphgen::serialize(Target, OS);
|
|
} else {
|
|
symbolgraphgen::serialize(Target, OS);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
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());
|
|
}
|