mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Up to now, the `SymbolGraphASTWalker` was only concerned with one module. This change prepares for emitting multiple symbol graph files, for each module that the module of interest extended. There is only one walker, so extract the symbol logic into `SymbolGraph`, where it can be reused. rdar://58941718
291 lines
9.3 KiB
C++
291 lines
9.3 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 "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<llvm::VersionTuple> 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<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: - 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<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);
|
|
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());
|
|
}
|