Skip to content

Commit

Permalink
Modify AccessScope to allow checks for package access level
Browse files Browse the repository at this point in the history
Resolves rdar://103534243
  • Loading branch information
elsh committed Jan 13, 2023
1 parent cfe49a0 commit 6f796fb
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 23 deletions.
65 changes: 49 additions & 16 deletions include/swift/AST/AccessScope.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,33 @@

namespace swift {

/// Used to provide the kind of scope limitation in AccessScope::Value
enum class AccessLimitKind : uint8_t { None = 0, Private, Package };

/// The wrapper around the outermost DeclContext from which
/// a particular declaration can be accessed.
class AccessScope {
/// The declaration context (if not public) along with a bit saying
/// whether this scope is private, SPI or not.
/// If the declaration context is set, the bit means that the scope is
/// private or not. If the declaration context is null, the bit means that
/// this scope is SPI or not.
llvm::PointerIntPair<const DeclContext *, 1, bool> Value;
/// The declaration context along with an enum indicating the level of
/// scope limitation.
/// If the declaration context is set, and the limit kind is Private, the
/// access level is considered 'private'. Whether it's 'internal' or
/// 'fileprivate' is determined by what the declaration context casts to. If
/// the declaration context is null, and the limit kind is None, the access
/// level is considered 'public'. If the limit kind is Private, the access
/// level is considered SPI. If it's Package, the access level is considered
/// 'package'.
llvm::PointerIntPair<const DeclContext *, 2, AccessLimitKind> Value;

public:
AccessScope(const DeclContext *DC, bool isPrivate = false);
AccessScope(const DeclContext *DC,
AccessLimitKind limitKind = AccessLimitKind::None);

static AccessScope getPublic() { return AccessScope(nullptr, false); }
static AccessScope getPublic() {
return AccessScope(nullptr, AccessLimitKind::None);
}
static AccessScope getPackage() {
return AccessScope(nullptr, AccessLimitKind::Package);
}

/// Check if private access is allowed. This is a lexical scope check in Swift
/// 3 mode. In Swift 4 mode, declarations and extensions of the same type will
Expand All @@ -46,25 +59,45 @@ class AccessScope {
bool operator==(AccessScope RHS) const { return Value == RHS.Value; }
bool operator!=(AccessScope RHS) const { return !(*this == RHS); }
bool hasEqualDeclContextWith(AccessScope RHS) const {
if (isPublic())
return RHS.isPublic();
if (isPackage())
return RHS.isPackage();
return getDeclContext() == RHS.getDeclContext();
}

bool isPublic() const { return !Value.getPointer(); }
bool isPrivate() const { return Value.getPointer() && Value.getInt(); }
bool isPublic() const {
return !Value.getPointer() && Value.getInt() == AccessLimitKind::None;
}
bool isPrivate() const {
return Value.getPointer() && Value.getInt() == AccessLimitKind::Private;
}
bool isFileScope() const;
bool isInternal() const;
bool isPackage() const {
return !Value.getPointer() && Value.getInt() == AccessLimitKind::Package;
}

/// Returns true if this is a child scope of the specified other access scope.
///
/// The 'package' scope is between internal and public.
/// \see DeclContext::isChildContextOf
bool isChildOf(AccessScope AS) const {
if (!isPublic() && !AS.isPublic())
return allowsPrivateAccess(getDeclContext(), AS.getDeclContext());
if (isPublic() && AS.isPublic())
return false;
return AS.isPublic();
if (isInternalOrLess()) {
if (AS.isInternalOrLess())
return allowsPrivateAccess(getDeclContext(), AS.getDeclContext());
else
return AS.isPackage() || AS.isPublic();
}
if (isPackage())
return AS.isPublic();

// If this is public, it can't be less than access level of AS, so return
// false
return false;
}

bool isInternalOrLess() const { return getDeclContext() != nullptr; }

/// Returns the associated access level for diagnostic purposes.
AccessLevel accessLevelForDiagnostics() const;

Expand Down
10 changes: 7 additions & 3 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3678,11 +3678,13 @@ getAccessScopeForFormalAccess(const ValueDecl *VD,
while (!resultDC->isModuleScopeContext()) {
if (isa<TopLevelCodeDecl>(resultDC)) {
return AccessScope(resultDC->getModuleScopeContext(),
access == AccessLevel::Private);
access == AccessLevel::Private
? AccessLimitKind::Private
: AccessLimitKind::None);
}

if (resultDC->isLocalContext() || access == AccessLevel::Private)
return AccessScope(resultDC, /*private*/true);
return AccessScope(resultDC, AccessLimitKind::Private);

if (auto enclosingNominal = dyn_cast<GenericTypeDecl>(resultDC)) {
auto enclosingAccess =
Expand Down Expand Up @@ -3713,7 +3715,9 @@ getAccessScopeForFormalAccess(const ValueDecl *VD,
case AccessLevel::Private:
case AccessLevel::FilePrivate:
assert(resultDC->isModuleScopeContext());
return AccessScope(resultDC, access == AccessLevel::Private);
return AccessScope(resultDC, access == AccessLevel::Private
? AccessLimitKind::Private
: AccessLimitKind::None);
case AccessLevel::Internal:
return AccessScope(resultDC->getParentModule());
case AccessLevel::Public:
Expand Down
8 changes: 5 additions & 3 deletions lib/AST/DeclContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1136,11 +1136,13 @@ getPrivateDeclContext(const DeclContext *DC, const SourceFile *useSF) {
return lastExtension ? lastExtension : DC;
}

AccessScope::AccessScope(const DeclContext *DC, bool isPrivate)
: Value(DC, isPrivate) {
if (isPrivate) {
AccessScope::AccessScope(const DeclContext *DC, AccessLimitKind limitKind)
: Value(DC, limitKind) {
auto isPrivate = false;
if (limitKind == AccessLimitKind::Private) {
DC = getPrivateDeclContext(DC, DC->getParentSourceFile());
Value.setPointer(DC);
isPrivate = true;
}
if (!DC || isa<ModuleDecl>(DC))
assert(!isPrivate && "public or internal scope can't be private");
Expand Down
3 changes: 2 additions & 1 deletion lib/Sema/TypeCheckAccess.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2095,7 +2095,8 @@ static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) {
case AccessLevel::FilePrivate: {
const DeclContext *DC = ED->getModuleScopeContext();
bool isPrivate = (userSpecifiedAccess == AccessLevel::Private);
desiredAccessScope = AccessScope(DC, isPrivate);
desiredAccessScope = AccessScope(DC, isPrivate ? AccessLimitKind::Private
: AccessLimitKind::None);
break;
}
case AccessLevel::Internal:
Expand Down

0 comments on commit 6f796fb

Please sign in to comment.