mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
ABI-only declarations now inherit access control modifiers like `public` or `private(set)`, as well as `@usableFromInline` and `@_spi`, from their API counterpart. This means these attributes and modifiers don’t need to be specified in an `@abi` attribute. Very few tests because we aren’t yet enforcing the absence of these attributes.
386 lines
14 KiB
C++
386 lines
14 KiB
C++
//===--- AccessRequests.cpp - AccessLevel and AccessScope Requests --------===//
|
|
//
|
|
// 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 "swift/Subsystems.h"
|
|
#include "swift/AST/AccessRequests.h"
|
|
#include "swift/AST/ASTContext.h"
|
|
#include "swift/AST/Decl.h"
|
|
#include "swift/AST/DiagnosticsCommon.h"
|
|
#include "swift/AST/Module.h"
|
|
#include "swift/AST/NameLookupRequests.h"
|
|
#include "swift/AST/SourceFile.h"
|
|
#include "swift/AST/Types.h"
|
|
#include "swift/Basic/Assertions.h"
|
|
|
|
#include "llvm/ADT/bit.h"
|
|
|
|
#include <limits>
|
|
|
|
using namespace swift;
|
|
|
|
namespace swift {
|
|
// Implement the access-control type zone.
|
|
#define SWIFT_TYPEID_ZONE AccessControl
|
|
#define SWIFT_TYPEID_HEADER "swift/AST/AccessTypeIDZone.def"
|
|
#include "swift/Basic/ImplementTypeIDZone.h"
|
|
#undef SWIFT_TYPEID_ZONE
|
|
#undef SWIFT_TYPEID_HEADER
|
|
}
|
|
|
|
//----------------------------------------------------------------------------//
|
|
// AccessLevel computation
|
|
//----------------------------------------------------------------------------//
|
|
AccessLevel
|
|
AccessLevelRequest::evaluate(Evaluator &evaluator, ValueDecl *D) const {
|
|
assert(!D->hasAccess());
|
|
|
|
// ABI decls share the access level of their API decl.
|
|
auto abiRole = ABIRoleInfo(D);
|
|
if (!abiRole.providesAPI() && abiRole.getCounterpart())
|
|
return abiRole.getCounterpart()->getFormalAccess();
|
|
|
|
// Check if the decl has an explicit access control attribute.
|
|
if (auto *AA = D->getAttrs().getAttribute<AccessControlAttr>())
|
|
return AA->getAccess();
|
|
|
|
// Special case for accessors, which inherit the access of their storage.
|
|
// decl. A setter attribute can also override this.
|
|
if (auto accessor = dyn_cast<AccessorDecl>(D)) {
|
|
AbstractStorageDecl *storage = accessor->getStorage();
|
|
switch (accessor->getAccessorKind()) {
|
|
case AccessorKind::Get:
|
|
case AccessorKind::DistributedGet:
|
|
case AccessorKind::Address:
|
|
case AccessorKind::Read:
|
|
case AccessorKind::Read2:
|
|
return storage->getFormalAccess();
|
|
case AccessorKind::Set:
|
|
case AccessorKind::MutableAddress:
|
|
case AccessorKind::Modify:
|
|
case AccessorKind::Modify2:
|
|
return storage->getSetterFormalAccess();
|
|
case AccessorKind::WillSet:
|
|
case AccessorKind::DidSet:
|
|
// These are only needed to synthesize the setter.
|
|
return AccessLevel::Private;
|
|
case AccessorKind::Init:
|
|
// These are only called from within the same module.
|
|
return AccessLevel::Internal;
|
|
}
|
|
}
|
|
|
|
// Special case for opaque type decls, which inherit the access of their
|
|
// naming decls.
|
|
if (auto *opaqueType = dyn_cast<OpaqueTypeDecl>(D)) {
|
|
if (auto *namingDecl = opaqueType->getNamingDecl())
|
|
return namingDecl->getFormalAccess();
|
|
}
|
|
|
|
DeclContext *DC = D->getDeclContext();
|
|
|
|
// Special case for generic parameters; we just give them a dummy
|
|
// access level.
|
|
if (isa<GenericTypeParamDecl>(D)) {
|
|
return AccessLevel::Internal;
|
|
}
|
|
|
|
// Special case for associated types: inherit access from protocol.
|
|
if (auto assocType = dyn_cast<AssociatedTypeDecl>(D)) {
|
|
auto prot = assocType->getProtocol();
|
|
return std::max(prot->getFormalAccess(), AccessLevel::Internal);
|
|
}
|
|
|
|
// Special case for dtors and enum elements: inherit from container
|
|
if (D->getKind() == DeclKind::Destructor ||
|
|
D->getKind() == DeclKind::EnumElement) {
|
|
if (D->hasInterfaceType() && D->isInvalid()) {
|
|
return AccessLevel::Private;
|
|
} else {
|
|
auto container = dyn_cast<NominalTypeDecl>(DC);
|
|
if (D->getKind() == DeclKind::Destructor && !container) {
|
|
// A destructor in an extension means @_objcImplementation. An
|
|
// @_objcImplementation class's deinit is only called by the ObjC thunk,
|
|
// if at all, so it is nonpublic.
|
|
return AccessLevel::Internal;
|
|
}
|
|
|
|
return std::max(container->getFormalAccess(), AccessLevel::Internal);
|
|
}
|
|
}
|
|
|
|
switch (DC->getContextKind()) {
|
|
case DeclContextKind::TopLevelCodeDecl:
|
|
case DeclContextKind::SerializedTopLevelCodeDecl:
|
|
// Variables declared in a top-level 'guard' statement can be accessed in
|
|
// later top-level code.
|
|
return AccessLevel::FilePrivate;
|
|
case DeclContextKind::AbstractClosureExpr:
|
|
case DeclContextKind::SerializedAbstractClosure:
|
|
if (isa<ParamDecl>(D)) {
|
|
// Closure parameters may need to be accessible to the enclosing
|
|
// context, for single-expression closures.
|
|
return AccessLevel::FilePrivate;
|
|
} else {
|
|
return AccessLevel::Private;
|
|
}
|
|
case DeclContextKind::Initializer:
|
|
case DeclContextKind::AbstractFunctionDecl:
|
|
case DeclContextKind::SubscriptDecl:
|
|
case DeclContextKind::EnumElementDecl:
|
|
return AccessLevel::Private;
|
|
case DeclContextKind::Package:
|
|
return AccessLevel::Package;
|
|
case DeclContextKind::Module:
|
|
case DeclContextKind::FileUnit:
|
|
return AccessLevel::Internal;
|
|
case DeclContextKind::GenericTypeDecl: {
|
|
auto generic = cast<GenericTypeDecl>(DC);
|
|
AccessLevel access = AccessLevel::Internal;
|
|
if (isa<ProtocolDecl>(generic))
|
|
access = std::max(AccessLevel::FilePrivate, generic->getFormalAccess());
|
|
return access;
|
|
}
|
|
case DeclContextKind::ExtensionDecl:
|
|
return cast<ExtensionDecl>(DC)->getDefaultAccessLevel();
|
|
case DeclContextKind::MacroDecl:
|
|
// There are no declarations inside a macro.
|
|
return AccessLevel::Private;
|
|
}
|
|
llvm_unreachable("unhandled kind");
|
|
}
|
|
|
|
std::optional<AccessLevel> AccessLevelRequest::getCachedResult() const {
|
|
auto valueDecl = std::get<0>(getStorage());
|
|
if (valueDecl->hasAccess())
|
|
return valueDecl->TypeAndAccess.getInt().getValue();
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
void AccessLevelRequest::cacheResult(AccessLevel value) const {
|
|
auto valueDecl = std::get<0>(getStorage());
|
|
valueDecl->setAccess(value);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------//
|
|
// SetterAccessLevel computation
|
|
//----------------------------------------------------------------------------//
|
|
//
|
|
// An AbstractStorageDecl has both its own formal access and also a special
|
|
// "setter" formal access like "private(set)" that might override (and lower)
|
|
// the normal one, when evaluating the accessibility of mutating accessors.
|
|
//
|
|
// As this value can be computed, stored, synthesized and set independently from
|
|
// the cycle of computation associated with formal accesses, we give it its own
|
|
// request.
|
|
|
|
// In a .swiftinterface file, a stored property with an explicit @_hasStorage
|
|
// attribute but no setter is assumed to have originally been a private(set).
|
|
static bool isStoredWithPrivateSetter(VarDecl *VD) {
|
|
auto *HSA = VD->getAttrs().getAttribute<HasStorageAttr>();
|
|
if (!HSA || HSA->isImplicit())
|
|
return false;
|
|
|
|
auto *DC = VD->getDeclContext();
|
|
auto *SF = DC->getParentSourceFile();
|
|
if (!SF || SF->Kind != SourceFileKind::Interface)
|
|
return false;
|
|
|
|
if (VD->isLet() ||
|
|
VD->getParsedAccessor(AccessorKind::Set))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
AccessLevel
|
|
SetterAccessLevelRequest::evaluate(Evaluator &evaluator,
|
|
AbstractStorageDecl *ASD) const {
|
|
assert(!ASD->Accessors.getInt().hasValue());
|
|
|
|
// ABI decls share the access level of their API decl.
|
|
auto abiRole = ABIRoleInfo(ASD);
|
|
if (!abiRole.providesAPI() && abiRole.getCounterpart())
|
|
return abiRole.getCounterpart()->getSetterFormalAccess();
|
|
|
|
if (auto *SAA = ASD->getAttrs().getAttribute<SetterAccessAttr>())
|
|
return SAA->getAccess();
|
|
|
|
if (auto *VD = dyn_cast<VarDecl>(ASD))
|
|
if (isStoredWithPrivateSetter(VD))
|
|
return AccessLevel::Private;
|
|
|
|
return ASD->getFormalAccess();
|
|
}
|
|
|
|
std::optional<AccessLevel> SetterAccessLevelRequest::getCachedResult() const {
|
|
auto abstractStorageDecl = std::get<0>(getStorage());
|
|
if (abstractStorageDecl->Accessors.getInt().hasValue())
|
|
return abstractStorageDecl->Accessors.getInt().getValue();
|
|
|
|
return std::nullopt;
|
|
}
|
|
|
|
void SetterAccessLevelRequest::cacheResult(AccessLevel value) const {
|
|
auto abstractStorageDecl = std::get<0>(getStorage());
|
|
// NB: don't call setSetterAccess here because it drives values through to the
|
|
// associated accessors' formalAccess, which we might also be in the middle of
|
|
// doing a request for. Reserve setSetterAccess for deserialization &
|
|
// clangImporter use.
|
|
assert(!abstractStorageDecl->Accessors.getInt().hasValue());
|
|
abstractStorageDecl->Accessors.setInt(value);
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------//
|
|
// DefaultAccessLevel computation
|
|
//----------------------------------------------------------------------------//
|
|
|
|
std::pair<AccessLevel, AccessLevel>
|
|
DefaultAndMaxAccessLevelRequest::evaluate(Evaluator &evaluator,
|
|
ExtensionDecl *ED) const {
|
|
auto &Ctx = ED->getASTContext();
|
|
assert(!ED->hasDefaultAccessLevel());
|
|
|
|
AccessLevel maxAccess = AccessLevel::Public;
|
|
|
|
if (ED->getGenericParams()) {
|
|
// Only check the trailing 'where' requirements. Other requirements come
|
|
// from the extended type and have already been checked.
|
|
DirectlyReferencedTypeDecls typeDecls =
|
|
evaluateOrDefault(Ctx.evaluator, TypeDeclsFromWhereClauseRequest{ED}, {});
|
|
|
|
std::optional<AccessScope> maxScope = AccessScope::getPublic();
|
|
|
|
// Try to scope the extension's access to the least public type mentioned
|
|
// in its where clause.
|
|
for (auto *typeDecl : typeDecls.first) {
|
|
if (isa<TypeAliasDecl>(typeDecl) || isa<NominalTypeDecl>(typeDecl)) {
|
|
auto scope = typeDecl->getFormalAccessScope(ED->getDeclContext());
|
|
maxScope = maxScope->intersectWith(scope);
|
|
}
|
|
}
|
|
|
|
// Now include the scope of the extended nominal type.
|
|
if (NominalTypeDecl *nominal = ED->getExtendedNominal()) {
|
|
auto scope = nominal->getFormalAccessScope(ED->getDeclContext());
|
|
maxScope = maxScope->intersectWith(scope);
|
|
}
|
|
|
|
if (!maxScope.has_value()) {
|
|
// This is an error case and will be diagnosed elsewhere.
|
|
maxAccess = AccessLevel::Public;
|
|
} else if (maxScope->isPublic()) {
|
|
maxAccess = AccessLevel::Public;
|
|
} else if (maxScope->isPackage()) {
|
|
maxAccess = AccessLevel::Package;
|
|
} else if (isa<ModuleDecl>(maxScope->getDeclContext())) {
|
|
maxAccess = AccessLevel::Internal;
|
|
} else {
|
|
// Because extensions are always at top-level, they should never
|
|
// reference declarations not at the top level. (And any such references
|
|
// should be diagnosed elsewhere.) This code should not crash if that
|
|
// occurs, though.
|
|
maxAccess = AccessLevel::FilePrivate;
|
|
}
|
|
}
|
|
|
|
AccessLevel defaultAccess;
|
|
if (auto *AA = ED->getAttrs().getAttribute<AccessControlAttr>())
|
|
defaultAccess = std::max(AA->getAccess(), AccessLevel::FilePrivate);
|
|
else
|
|
defaultAccess = AccessLevel::Internal;
|
|
|
|
// Don't set the max or default access level to 'open'. This should
|
|
// be diagnosed as invalid anyway.
|
|
defaultAccess = std::min(defaultAccess, AccessLevel::Public);
|
|
maxAccess = std::min(maxAccess, AccessLevel::Public);
|
|
|
|
// Normally putting a public member in an internal extension is harmless,
|
|
// because that member can never be used elsewhere. But if some of the types
|
|
// in the signature are public, it could actually end up getting picked in
|
|
// overload resolution. Therefore, we only enforce the maximum access if the
|
|
// extension has a 'where' clause.
|
|
if (ED->getTrailingWhereClause())
|
|
defaultAccess = std::min(defaultAccess, maxAccess);
|
|
else
|
|
maxAccess = AccessLevel::Public;
|
|
|
|
return std::make_pair(defaultAccess, maxAccess);
|
|
}
|
|
|
|
// Default and Max access levels are stored combined as a 3-bit bitset. The Bits
|
|
// are numbered using the 3 middle values of the AccessLevel enumeration, and
|
|
// the combined value is just the bitwise-OR of the bits for Default and Max.
|
|
//
|
|
// For example, if Max=Internal and Default=FilePrivate, we will see:
|
|
//
|
|
// 0 1 1
|
|
// | | |
|
|
// | | [FilePrivate]
|
|
// | |
|
|
// | [Internal]
|
|
// |
|
|
// [Public]
|
|
//
|
|
// This is unambiguous to decode because of the following facts:
|
|
//
|
|
// - At least one of the bits is set (all-zero means "not yet set").
|
|
// - At most two of the bits are set.
|
|
// - Max >= Default by definition.
|
|
//
|
|
// So we decode Max as the last (high) bit that is set, and Default as the first
|
|
// (low). And add one to each, to map them back into AccessLevels.
|
|
|
|
std::optional<std::pair<AccessLevel, AccessLevel>>
|
|
DefaultAndMaxAccessLevelRequest::getCachedResult() const {
|
|
auto extensionDecl = std::get<0>(getStorage());
|
|
if (extensionDecl->hasDefaultAccessLevel()) {
|
|
uint8_t Bits = extensionDecl->getDefaultAndMaxAccessLevelBits();
|
|
assert(Bits != 0x7 && "more than two bits set for Default and Max");
|
|
|
|
uint8_t lastSet = Bits == 0 ? std::numeric_limits<uint8_t>::max()
|
|
: (llvm::countl_zero(Bits) ^
|
|
(std::numeric_limits<uint8_t>::digits - 1));
|
|
uint8_t firstSet = Bits == 0 ? std::numeric_limits<uint8_t>::max()
|
|
: llvm::countr_zero(Bits);
|
|
AccessLevel Max = static_cast<AccessLevel>(lastSet + 1);
|
|
AccessLevel Default = static_cast<AccessLevel>(firstSet + 1);
|
|
|
|
assert(Max >= Default);
|
|
return std::make_pair(Default, Max);
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
void
|
|
DefaultAndMaxAccessLevelRequest::cacheResult(
|
|
std::pair<AccessLevel, AccessLevel> value) const {
|
|
auto extensionDecl = std::get<0>(getStorage());
|
|
extensionDecl->setDefaultAndMaxAccessLevelBits(value.first, value.second);
|
|
assert(getCachedResult().value().first == value.first);
|
|
assert(getCachedResult().value().second == value.second);
|
|
}
|
|
|
|
// Define request evaluation functions for each of the access requests.
|
|
static AbstractRequestFunction *accessRequestFunctions[] = {
|
|
#define SWIFT_REQUEST(Zone, Name, Sig, Caching, LocOptions) \
|
|
reinterpret_cast<AbstractRequestFunction *>(&Name::evaluateRequest),
|
|
#include "swift/AST/AccessTypeIDZone.def"
|
|
#undef SWIFT_REQUEST
|
|
};
|
|
|
|
void swift::registerAccessRequestFunctions(Evaluator &evaluator) {
|
|
evaluator.registerRequestFunctions(Zone::AccessControl,
|
|
accessRequestFunctions);
|
|
}
|