Skip to content

[SymbolGraph][CursorInfo] Add option to SourceKit's CursorInfo request to include the SymbolGraph JSON #34934

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions include/swift/SymbolGraphGen/SymbolGraphGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,26 @@
#define SWIFT_SYMBOLGRAPHGEN_SYMBOLGRAPHGEN_H

#include "swift/AST/Module.h"
#include "swift/AST/Type.h"
#include "SymbolGraphOptions.h"

namespace swift {
class ValueDecl;

namespace symbolgraphgen {

/// Emit a Symbol Graph JSON file for a module.
int emitSymbolGraphForModule(ModuleDecl *M, const SymbolGraphOptions &Options);

/// Print a Symbol Graph containing a single node for the given decl.
///
/// \returns \c EXIT_SUCCESS if the kind of the provided node is supported and
/// its Symbo lGraph was printed, or \c EXIT_FAILURE otherwise.
int printSymbolGraphForDecl(const ValueDecl *D, Type BaseTy,
bool InSynthesizedExtensions,
const SymbolGraphOptions &Options,
llvm::raw_ostream &OS);

} // end namespace symbolgraphgen
} // end namespace swift

Expand Down
8 changes: 7 additions & 1 deletion lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -750,8 +750,14 @@ class PrintAST : public ASTVisitor<PrintAST> {
else if (auto *ED = dyn_cast<ExtensionDecl>(Current))
subMap = CurrentType->getContextSubstitutionMap(M, ED);
else {
Decl *subTarget = Current;
if (isa<ParamDecl>(Current)) {
auto *DC = Current->getDeclContext();
if (auto *FD = dyn_cast<AbstractFunctionDecl>(DC))
subTarget = FD;
}
subMap = CurrentType->getMemberSubstitutionMap(
M, cast<ValueDecl>(Current));
M, cast<ValueDecl>(subTarget));
}

T = T.subst(subMap, SubstFlags::DesugarMemberTypes);
Expand Down
8 changes: 5 additions & 3 deletions lib/SymbolGraphGen/DeclarationFragmentPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,11 @@ void DeclarationFragmentPrinter::printTypeRef(Type T, const TypeDecl *RefTo,
USR.clear();

auto ShouldLink = Name.str() != "Self";
if (const auto *TD = T->getAnyNominal()) {
if (SG->isImplicitlyPrivate(TD)) {
ShouldLink = false;
if (T) {
if (const auto *TD = T->getAnyNominal()) {
if (SG->isImplicitlyPrivate(TD)) {
ShouldLink = false;
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/SymbolGraphGen/Edge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ void Edge::serialize(llvm::json::OStream &OS) const {
ConformanceExtension->getGenericRequirements(),
ConformanceExtension->getExtendedNominal()
->getDeclContext()->getSelfNominalTypeDecl(),
FilteredRequirements);
FilteredRequirements);
if (!FilteredRequirements.empty()) {
OS.attributeArray("swiftConstraints", [&](){
for (const auto &Req :
Expand Down
92 changes: 89 additions & 3 deletions lib/SymbolGraphGen/JSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
//===----------------------------------------------------------------------===//

#include "swift/AST/Decl.h"
#include "swift/AST/GenericParamList.h"
#include "swift/AST/Module.h"
#include "swift/AST/Type.h"
#include "JSON.h"

void swift::symbolgraphgen::serialize(const llvm::VersionTuple &VT,
Expand Down Expand Up @@ -115,10 +117,75 @@ void swift::symbolgraphgen::serialize(const swift::GenericTypeParamType *Param,
});
}

void
swift::symbolgraphgen::filterGenericParams(
TypeArrayView<GenericTypeParamType> GenericParams,
SmallVectorImpl<const GenericTypeParamType*> &FilteredParams,
SubstitutionMap SubMap) {

for (auto Param : GenericParams) {
if (const auto *GPD = Param->getDecl()) {

// Ignore the implicit Self param
if (GPD->isImplicit()) {
if (!isa<ExtensionDecl>(GPD->getDeclContext()))
continue;

// Extension decls (and their children) refer to implicit copies of the
// explicit params of the nominal they extend. Don't filter those out.
auto *ED = cast<ExtensionDecl>(GPD->getDeclContext());
if (auto *NTD = ED->getExtendedNominal()) {
if (auto *GPL = NTD->getGenericParams()) {
auto ImplicitAndSameName = [&](GenericTypeParamDecl *NominalGPD) {
return NominalGPD->isImplicit() &&
GPD->getName() == NominalGPD->getName();
};
if (llvm::any_of(GPL->getParams(), ImplicitAndSameName))
continue;
}
}
}

// Ignore parameters that have been substituted.
if (!SubMap.empty()) {
Type SubTy = Type(Param).subst(SubMap);
if (!SubTy->hasError() && SubTy.getPointer() != Param) {
if (!SubTy->is<ArchetypeType>()) {
continue;
}
auto AT = SubTy->castTo<ArchetypeType>();
if (!AT->getInterfaceType()->isEqual(Param)) {
continue;
}
}
}

FilteredParams.push_back(Param);
}
}
}

static bool containsParams(swift::Type Ty, llvm::ArrayRef<const swift::GenericTypeParamType*> Others) {
return Ty.findIf([&](swift::Type T) -> bool {
if (auto AT = T->getAs<swift::ArchetypeType>()) {
T = AT->getInterfaceType();
}

for (auto *Param: Others) {
if (T->isEqual(const_cast<swift::GenericTypeParamType*>(Param)))
return true;
}
return false;
});
}

void swift::symbolgraphgen::filterGenericRequirements(
ArrayRef<Requirement> Requirements,
const NominalTypeDecl *Self,
SmallVectorImpl<Requirement> &FilteredRequirements) {
SmallVectorImpl<Requirement> &FilteredRequirements,
SubstitutionMap SubMap,
ArrayRef<const GenericTypeParamType *> FilteredParams) {

for (const auto &Req : Requirements) {
if (Req.getKind() == RequirementKind::Layout) {
continue;
Expand All @@ -130,10 +197,29 @@ void swift::symbolgraphgen::filterGenericRequirements(
if (Req.getSecondType()->getAnyNominal() == Self) {
continue;
}
FilteredRequirements.push_back(Req);

// Ignore requirements that don't involve the filtered set of generic
// parameters after substitution.
if (!SubMap.empty()) {
Type SubFirst = Req.getFirstType().subst(SubMap);
if (SubFirst->hasError())
SubFirst = Req.getFirstType();
Type SubSecond = Req.getSecondType().subst(SubMap);
if (SubSecond->hasError())
SubSecond = Req.getSecondType();

if (!containsParams(SubFirst, FilteredParams) &&
!containsParams(SubSecond, FilteredParams))
continue;

// Use the same requirement kind with the substituted types.
FilteredRequirements.emplace_back(Req.getKind(), SubFirst, SubSecond);
} else {
// Use the original requirement.
FilteredRequirements.push_back(Req);
}
}
}

void
swift::symbolgraphgen::filterGenericRequirements(const ExtensionDecl *Extension,
SmallVectorImpl<Requirement> &FilteredRequirements) {
Expand Down
17 changes: 11 additions & 6 deletions lib/SymbolGraphGen/JSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "llvm/Support/JSON.h"
#include "llvm/Support/VersionTuple.h"
#include "swift/AST/GenericSignature.h"
#include "swift/AST/SubstitutionMap.h"
#include "swift/AST/Type.h"

namespace swift {
Expand All @@ -41,16 +42,20 @@ void serialize(const llvm::VersionTuple &VT, llvm::json::OStream &OS);
void serialize(const llvm::Triple &T, llvm::json::OStream &OS);
void serialize(const ExtensionDecl *Extension, llvm::json::OStream &OS);
void serialize(const Requirement &Req, llvm::json::OStream &OS);
void serialize(const swift::GenericTypeParamType *Param,
llvm::json::OStream &OS);
void serialize(const swift::GenericTypeParamType *Param, llvm::json::OStream &OS);

void filterGenericParams(
TypeArrayView<GenericTypeParamType> GenericParams,
SmallVectorImpl<const GenericTypeParamType*> &FilteredParams,
SubstitutionMap SubMap = {});

/// Filter generic requirements on an extension that aren't relevant
/// for documentation.
void
filterGenericRequirements(ArrayRef<Requirement> Requirements,
const NominalTypeDecl *Self,
SmallVectorImpl<Requirement> &FilteredRequirements);
void filterGenericRequirements(
ArrayRef<Requirement> Requirements, const NominalTypeDecl *Self,
SmallVectorImpl<Requirement> &FilteredRequirements,
SubstitutionMap SubMap = {},
ArrayRef<const GenericTypeParamType *> FilteredParams = {});

/// Filter generic requirements on an extension that aren't relevant
/// for documentation.
Expand Down
86 changes: 71 additions & 15 deletions lib/SymbolGraphGen/Symbol.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,15 @@ using namespace swift;
using namespace symbolgraphgen;

Symbol::Symbol(SymbolGraph *Graph, const ValueDecl *VD,
const NominalTypeDecl *SynthesizedBaseTypeDecl)
const NominalTypeDecl *SynthesizedBaseTypeDecl,
Type BaseType)
: Graph(Graph),
VD(VD),
SynthesizedBaseTypeDecl(SynthesizedBaseTypeDecl) {}
BaseType(BaseType),
SynthesizedBaseTypeDecl(SynthesizedBaseTypeDecl) {
if (!BaseType && SynthesizedBaseTypeDecl)
BaseType = SynthesizedBaseTypeDecl->getDeclaredInterfaceType();
}

void Symbol::serializeKind(StringRef Identifier, StringRef DisplayName,
llvm::json::OStream &OS) const {
Expand All @@ -40,6 +45,9 @@ void Symbol::serializeKind(StringRef Identifier, StringRef DisplayName,
}

void Symbol::serializeKind(llvm::json::OStream &OS) const {
// supportsKind and serializeKind must agree.
assert(Symbol::supportsKind(VD->getKind()) && "unsupported decl kind");

AttributeRAII A("kind", OS);
switch (VD->getKind()) {
case swift::DeclKind::Class:
Expand Down Expand Up @@ -244,7 +252,8 @@ void Symbol::serializeFunctionSignature(llvm::json::OStream &OS) const {
}
Graph->serializeDeclarationFragments("declarationFragments",
Symbol(Graph, Param,
nullptr), OS);
getSynthesizedBaseTypeDecl(),
getBaseType()), OS);
}); // end parameter object
}
}); // end parameters:
Expand All @@ -253,35 +262,62 @@ void Symbol::serializeFunctionSignature(llvm::json::OStream &OS) const {

// Returns
if (const auto ReturnType = FD->getResultInterfaceType()) {
Graph->serializeDeclarationFragments("returns", ReturnType, OS);
Graph->serializeDeclarationFragments("returns", ReturnType, BaseType,
OS);
}
});
}
}

static SubstitutionMap getSubMapForDecl(const ValueDecl *D, Type BaseType) {
if (!BaseType || BaseType->isExistentialType())
return {};

// Map from the base type into the this declaration's innermost type context,
// or if we're dealing with an extention rather than a member, into its
// extended nominal (the extension's own requirements shouldn't be considered
// in the substitution).
swift::DeclContext *DC;
if (isa<swift::ExtensionDecl>(D))
DC = cast<swift::ExtensionDecl>(D)->getExtendedNominal();
else
DC = D->getInnermostDeclContext()->getInnermostTypeContext();

swift::ModuleDecl *M = DC->getParentModule();
if (isa<swift::NominalTypeDecl>(D) || isa<swift::ExtensionDecl>(D)) {
return BaseType->getContextSubstitutionMap(M, DC);
}

const swift::ValueDecl *SubTarget = D;
if (isa<swift::ParamDecl>(D)) {
auto *DC = D->getDeclContext();
if (auto *FD = dyn_cast<swift::AbstractFunctionDecl>(DC))
SubTarget = FD;
}
return BaseType->getMemberSubstitutionMap(M, SubTarget);
}

void Symbol::serializeSwiftGenericMixin(llvm::json::OStream &OS) const {

SubstitutionMap SubMap;
if (BaseType)
SubMap = getSubMapForDecl(VD, BaseType);

if (const auto *GC = VD->getAsGenericContext()) {
if (const auto Generics = GC->getGenericSignature()) {

SmallVector<const GenericTypeParamType *, 4> FilteredParams;
SmallVector<Requirement, 4> FilteredRequirements;
for (const auto Param : Generics->getGenericParams()) {
if (const auto *D = Param->getDecl()) {
if (D->isImplicit()) {
continue;
}
FilteredParams.push_back(Param);
}
}
filterGenericParams(Generics->getGenericParams(), FilteredParams,
SubMap);

const auto *Self = dyn_cast<NominalTypeDecl>(VD);
if (!Self) {
Self = VD->getDeclContext()->getSelfNominalTypeDecl();
}

filterGenericRequirements(Generics->getRequirements(),
Self,
FilteredRequirements);
filterGenericRequirements(Generics->getRequirements(), Self,
FilteredRequirements, SubMap, FilteredParams);

if (FilteredParams.empty() && FilteredRequirements.empty()) {
return;
Expand Down Expand Up @@ -503,3 +539,23 @@ void Symbol::getUSR(SmallVectorImpl<char> &USR) const {
ide::printDeclUSR(SynthesizedBaseTypeDecl, OS);
}
}

bool Symbol::supportsKind(DeclKind Kind) {
switch (Kind) {
case DeclKind::Class: LLVM_FALLTHROUGH;
case DeclKind::Struct: LLVM_FALLTHROUGH;
case DeclKind::Enum: LLVM_FALLTHROUGH;
case DeclKind::EnumElement: LLVM_FALLTHROUGH;
case DeclKind::Protocol: LLVM_FALLTHROUGH;
case DeclKind::Constructor: LLVM_FALLTHROUGH;
case DeclKind::Destructor: LLVM_FALLTHROUGH;
case DeclKind::Func: LLVM_FALLTHROUGH;
case DeclKind::Var: LLVM_FALLTHROUGH;
case DeclKind::Subscript: LLVM_FALLTHROUGH;
case DeclKind::TypeAlias: LLVM_FALLTHROUGH;
case DeclKind::AssociatedType:
return true;
default:
return false;
}
}
Loading