[AST] Intro request to list declared and inherited SPI groups

This commit is contained in:
Alexis Laferrière
2020-02-20 12:50:18 -08:00
parent b8a87f651e
commit fd4feacb0d
5 changed files with 80 additions and 10 deletions

View File

@@ -54,3 +54,4 @@ SWIFT_TYPEID_NAMED(TypeAliasDecl *, TypeAliasDecl)
SWIFT_TYPEID_NAMED(ValueDecl *, ValueDecl) SWIFT_TYPEID_NAMED(ValueDecl *, ValueDecl)
SWIFT_TYPEID_NAMED(VarDecl *, VarDecl) SWIFT_TYPEID_NAMED(VarDecl *, VarDecl)
SWIFT_TYPEID(FingerprintAndMembers) SWIFT_TYPEID(FingerprintAndMembers)
SWIFT_TYPEID(Identifier)

View File

@@ -62,6 +62,7 @@ struct TypeWitnessAndDecl;
enum class AncestryFlags : uint8_t; enum class AncestryFlags : uint8_t;
enum class ImplicitMemberAction : uint8_t; enum class ImplicitMemberAction : uint8_t;
struct FingerprintAndMembers; struct FingerprintAndMembers;
class Identifier;
// Define the AST type zone (zone 1) // Define the AST type zone (zone 1)
#define SWIFT_TYPEID_ZONE AST #define SWIFT_TYPEID_ZONE AST

View File

@@ -2025,6 +2025,26 @@ public:
} }
}; };
/// List SPI group ids declared on a decl.
class SPIGroupsRequest :
public SimpleRequest<SPIGroupsRequest,
llvm::ArrayRef<Identifier>(const Decl *),
CacheKind::Cached> {
public:
using SimpleRequest::SimpleRequest;
private:
friend SimpleRequest;
// Evaluation.
llvm::Expected<llvm::ArrayRef<Identifier>>
evaluate(Evaluator &evaluator, const Decl *decl) const;
public:
bool isCached() const { return true; }
};
/// Type-checks a `@differentiable` attribute and returns the resolved parameter /// Type-checks a `@differentiable` attribute and returns the resolved parameter
/// indices on success. On failure, emits diagnostics and returns `nullptr`. /// indices on success. On failure, emits diagnostics and returns `nullptr`.
/// ///

View File

@@ -105,6 +105,9 @@ SWIFT_REQUEST(TypeChecker, IsDynamicRequest, bool(ValueDecl *),
SeparatelyCached, NoLocationInfo) SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached, SWIFT_REQUEST(TypeChecker, IsFinalRequest, bool(ValueDecl *), SeparatelyCached,
NoLocationInfo) NoLocationInfo)
SWIFT_REQUEST(TypeChecker, SPIGroupsRequest,
llvm::ArrayRef<Identifier>(Decl *),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsGetterMutatingRequest, bool(AbstractStorageDecl *), SWIFT_REQUEST(TypeChecker, IsGetterMutatingRequest, bool(AbstractStorageDecl *),
SeparatelyCached, NoLocationInfo) SeparatelyCached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, IsImplicitlyUnwrappedOptionalRequest, SWIFT_REQUEST(TypeChecker, IsImplicitlyUnwrappedOptionalRequest,

View File

@@ -1820,22 +1820,67 @@ void SourceFile::lookupImportedSPIGroups(const ModuleDecl *importedModule,
} }
bool SourceFile::isImportedAsSPI(const ValueDecl *targetDecl) const { bool SourceFile::isImportedAsSPI(const ValueDecl *targetDecl) const {
if (!targetDecl->getAttrs().hasAttribute<SPIAccessControlAttr>())
return false;
auto targetModule = targetDecl->getModuleContext(); auto targetModule = targetDecl->getModuleContext();
SmallVector<Identifier, 4> importedSpis; SmallVector<Identifier, 4> importedSPIGroups;
lookupImportedSPIGroups(targetModule, importedSpis); lookupImportedSPIGroups(targetModule, importedSPIGroups);
if (importedSPIGroups.empty()) return false;
for (auto attr : targetDecl->getAttrs().getAttributes<SPIAccessControlAttr>()) auto declSPIGroups = evaluateOrDefault(
for (auto declSPI : attr->getSPIGroups()) targetDecl->getASTContext().evaluator,
for (auto importedSPI : importedSpis) SPIGroupsRequest{ targetDecl },
if (importedSPI == declSPI) ArrayRef<Identifier>());
return true;
// Note: If we reach a point where there are many SPI imports or SPI groups
// on decls we could optimize this further by using a set.
for (auto importedSPI : importedSPIGroups)
for (auto declSPI : declSPIGroups)
if (importedSPI == declSPI)
return true;
return false; return false;
} }
llvm::Expected<llvm::ArrayRef<Identifier>>
SPIGroupsRequest::evaluate(Evaluator &evaluator, const Decl *decl) const {
// Applies only to public ValueDecls and ExtensionDecls.
if (auto vd = dyn_cast<ValueDecl>(decl)) {
if (vd->getFormalAccess() < AccessLevel::Public)
return ArrayRef<Identifier>();
} else if (!isa<ExtensionDecl>(decl))
return ArrayRef<Identifier>();
// First, look for local attributes.
llvm::SetVector<Identifier> spiGroups;
for (auto attr : decl->getAttrs().getAttributes<SPIAccessControlAttr>())
for (auto spi : attr->getSPIGroups())
spiGroups.insert(spi);
auto &ctx = decl->getASTContext();
if (spiGroups.empty()) {
// Then in the extended nominal type.
if (auto extension = dyn_cast<ExtensionDecl>(decl)) {
auto extended = extension->getExtendedNominal();
auto extSPIs = evaluateOrDefault(ctx.evaluator,
SPIGroupsRequest{ extended },
ArrayRef<Identifier>());
if (!extSPIs.empty()) return extSPIs;
}
// And finally in the parent context.
auto parent = decl->getDeclContext();
if (auto parentD = parent->getAsDecl()) {
if (!isa<ModuleDecl>(parentD)) {
return evaluateOrDefault(ctx.evaluator,
SPIGroupsRequest{ parentD },
ArrayRef<Identifier>());
}
}
}
return ctx.AllocateCopy(spiGroups.getArrayRef());
}
bool SourceFile::shouldCrossImport() const { bool SourceFile::shouldCrossImport() const {
return Kind != SourceFileKind::SIL && Kind != SourceFileKind::Interface && return Kind != SourceFileKind::SIL && Kind != SourceFileKind::Interface &&
getASTContext().LangOpts.EnableCrossImportOverlays; getASTContext().LangOpts.EnableCrossImportOverlays;