Move Symbol logic into SymbolGraph

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
This commit is contained in:
Ashley Garland
2020-02-06 15:26:11 -08:00
parent a4ba2cec27
commit be68f864e0
11 changed files with 390 additions and 391 deletions

View File

@@ -10,21 +10,11 @@
//
//===----------------------------------------------------------------------===//
#include "clang/AST/DeclObjC.h"
#include "llvm/ADT/StringSwitch.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/ASTPrinter.h"
#include "swift/AST/Decl.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/Module.h"
#include "swift/AST/ParameterList.h"
#include "swift/AST/ProtocolConformance.h"
#include "swift/AST/USRGeneration.h"
#include "swift/Basic/PrimitiveParsing.h"
#include "swift/Markup/Markup.h"
#include "swift/SymbolGraphGen/SymbolGraphGen.h"
#include "DeclarationFragmentPrinter.h"
#include "SymbolGraphASTWalker.h"
using namespace swift;
@@ -34,7 +24,7 @@ SymbolGraphASTWalker::SymbolGraphASTWalker(ModuleDecl &M,
const SymbolGraphOptions &Options)
: Options(Options),
M(M),
Graph(M, Options.Target) {}
Graph(M, Options.Target, Ctx) {}
/// Returns `true` if the symbol should be included as a node in the graph.
bool SymbolGraphASTWalker::shouldIncludeNode(const Decl *D) const {
@@ -125,223 +115,13 @@ bool SymbolGraphASTWalker::walkToDeclPre(Decl *D, CharSourceRange Range) {
// 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);
Graph.recordMemberRelationship(VD);
Graph.recordConformanceRelationships(VD);
Graph.recordInheritanceRelationships(VD);
Graph.recordDefaultImplementationRelationships(VD);
Graph.recordOverrideRelationship(VD);
Graph.recordRequirementRelationships(VD);
Graph.recordOptionalRequirementRelationships(VD);
return true;
}
StringRef SymbolGraphASTWalker::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
SymbolGraphASTWalker::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 SymbolGraphASTWalker::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;
}
void
SymbolGraphASTWalker::serializeDeclarationFragments(StringRef Key,
const ValueDecl *VD,
llvm::json::OStream &OS) {
DeclarationFragmentPrinter Printer(*this, OS, Key);
VD->print(Printer, getDeclarationFragmentsPrintOptions());
}
void
SymbolGraphASTWalker::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
SymbolGraphASTWalker::serializeDeclarationFragments(StringRef Key, Type T,
llvm::json::OStream &OS) {
DeclarationFragmentPrinter Printer(*this, OS, Key);
T->print(Printer, getDeclarationFragmentsPrintOptions());
}
void SymbolGraphASTWalker::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;
}
Graph.Nodes.insert(Source);
Graph.Nodes.insert(Target);
Graph.Edges.insert({this, Kind, Source, Target});
}
void SymbolGraphASTWalker::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
SymbolGraphASTWalker::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 SymbolGraphASTWalker::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
SymbolGraphASTWalker::recordRequirementRelationships(const ValueDecl *VD) {
if (const auto *Protocol = dyn_cast<ProtocolDecl>(VD->getDeclContext())) {
if (VD->isProtocolRequirement()) {
recordEdge(VD, Protocol, RelationshipKind::RequirementOf());
}
}
}
void SymbolGraphASTWalker::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
SymbolGraphASTWalker::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 SymbolGraphASTWalker::recordOverrideRelationship(const ValueDecl *VD) {
if (const auto *Override = VD->getOverriddenDecl()) {
recordEdge(VD, Override, RelationshipKind::Overrides());
}
}