Skip to content

Commit 288dbe3

Browse files
committed
Modify AccessScope to allow checks for package access level
Resolves rdar://103534243
1 parent cfe49a0 commit 288dbe3

File tree

4 files changed

+72
-24
lines changed

4 files changed

+72
-24
lines changed

include/swift/AST/AccessScope.h

Lines changed: 58 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,40 @@
2020

2121
namespace swift {
2222

23+
/// Used to provide the kind of scope limitation in AccessScope::Value
24+
enum class AccessLimitKind : uint8_t { None = 0, Private, Package };
25+
2326
/// The wrapper around the outermost DeclContext from which
2427
/// a particular declaration can be accessed.
2528
class AccessScope {
26-
/// The declaration context (if not public) along with a bit saying
27-
/// whether this scope is private, SPI or not.
28-
/// If the declaration context is set, the bit means that the scope is
29-
/// private or not. If the declaration context is null, the bit means that
30-
/// this scope is SPI or not.
31-
llvm::PointerIntPair<const DeclContext *, 1, bool> Value;
29+
/// The declaration context along with an enum indicating the level of
30+
/// scope limitation.
31+
/// If the declaration context is set, and the limit kind is Private, the
32+
/// access level is considered 'private'. Whether it's 'internal' or
33+
/// 'fileprivate' is determined by what the declaration context casts to. If
34+
/// the declaration context is null, and the limit kind is None, the access
35+
/// level is considered 'public'. If the limit kind is Private, the access
36+
/// level is considered SPI. If it's Package, the access level is considered
37+
/// 'package'. Below is a table showing the combinations.
38+
///
39+
/// AccessLimitKind DC == nullptr DC != nullptr
40+
/// ---------------------------------------------------------------------------
41+
/// None public fileprivate or internal (check DC to tell which)
42+
/// Private `@_spi` public private
43+
/// Package package (unused)
44+
45+
llvm::PointerIntPair<const DeclContext *, 2, AccessLimitKind> Value;
3246

3347
public:
34-
AccessScope(const DeclContext *DC, bool isPrivate = false);
48+
AccessScope(const DeclContext *DC,
49+
AccessLimitKind limitKind = AccessLimitKind::None);
3550

36-
static AccessScope getPublic() { return AccessScope(nullptr, false); }
51+
static AccessScope getPublic() {
52+
return AccessScope(nullptr, AccessLimitKind::None);
53+
}
54+
static AccessScope getPackage() {
55+
return AccessScope(nullptr, AccessLimitKind::Package);
56+
}
3757

3858
/// Check if private access is allowed. This is a lexical scope check in Swift
3959
/// 3 mode. In Swift 4 mode, declarations and extensions of the same type will
@@ -46,25 +66,46 @@ class AccessScope {
4666
bool operator==(AccessScope RHS) const { return Value == RHS.Value; }
4767
bool operator!=(AccessScope RHS) const { return !(*this == RHS); }
4868
bool hasEqualDeclContextWith(AccessScope RHS) const {
69+
if (isPublic())
70+
return RHS.isPublic();
71+
if (isPackage())
72+
return RHS.isPackage();
4973
return getDeclContext() == RHS.getDeclContext();
5074
}
5175

52-
bool isPublic() const { return !Value.getPointer(); }
53-
bool isPrivate() const { return Value.getPointer() && Value.getInt(); }
76+
bool isPublic() const {
77+
return !Value.getPointer() && Value.getInt() == AccessLimitKind::None;
78+
}
79+
bool isPrivate() const {
80+
return Value.getPointer() && Value.getInt() == AccessLimitKind::Private;
81+
}
5482
bool isFileScope() const;
5583
bool isInternal() const;
84+
bool isPackage() const {
85+
return !Value.getPointer() && Value.getInt() == AccessLimitKind::Package;
86+
}
5687

57-
/// Returns true if this is a child scope of the specified other access scope.
58-
///
88+
/// Returns true if this scope is more restrictive than the argument scope.
89+
/// It's often used to compute the min access scope. The order of restrictiveness
90+
/// is: private (most restrictive), fileprivate, internal, package, public (least restrictive).
5991
/// \see DeclContext::isChildContextOf
6092
bool isChildOf(AccessScope AS) const {
61-
if (!isPublic() && !AS.isPublic())
62-
return allowsPrivateAccess(getDeclContext(), AS.getDeclContext());
63-
if (isPublic() && AS.isPublic())
64-
return false;
65-
return AS.isPublic();
93+
if (isInternalOrLess()) {
94+
if (AS.isInternalOrLess())
95+
return allowsPrivateAccess(getDeclContext(), AS.getDeclContext());
96+
else
97+
return AS.isPackage() || AS.isPublic();
98+
}
99+
if (isPackage())
100+
return AS.isPublic();
101+
102+
// If this is public, it can't be less than access level of AS
103+
// so return false
104+
return false;
66105
}
67106

107+
bool isInternalOrLess() const { return getDeclContext() != nullptr; }
108+
68109
/// Returns the associated access level for diagnostic purposes.
69110
AccessLevel accessLevelForDiagnostics() const;
70111

lib/AST/Decl.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3678,11 +3678,13 @@ getAccessScopeForFormalAccess(const ValueDecl *VD,
36783678
while (!resultDC->isModuleScopeContext()) {
36793679
if (isa<TopLevelCodeDecl>(resultDC)) {
36803680
return AccessScope(resultDC->getModuleScopeContext(),
3681-
access == AccessLevel::Private);
3681+
access == AccessLevel::Private
3682+
? AccessLimitKind::Private
3683+
: AccessLimitKind::None);
36823684
}
36833685

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

36873689
if (auto enclosingNominal = dyn_cast<GenericTypeDecl>(resultDC)) {
36883690
auto enclosingAccess =
@@ -3713,7 +3715,9 @@ getAccessScopeForFormalAccess(const ValueDecl *VD,
37133715
case AccessLevel::Private:
37143716
case AccessLevel::FilePrivate:
37153717
assert(resultDC->isModuleScopeContext());
3716-
return AccessScope(resultDC, access == AccessLevel::Private);
3718+
return AccessScope(resultDC, access == AccessLevel::Private
3719+
? AccessLimitKind::Private
3720+
: AccessLimitKind::None);
37173721
case AccessLevel::Internal:
37183722
return AccessScope(resultDC->getParentModule());
37193723
case AccessLevel::Public:

lib/AST/DeclContext.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,11 +1136,13 @@ getPrivateDeclContext(const DeclContext *DC, const SourceFile *useSF) {
11361136
return lastExtension ? lastExtension : DC;
11371137
}
11381138

1139-
AccessScope::AccessScope(const DeclContext *DC, bool isPrivate)
1140-
: Value(DC, isPrivate) {
1141-
if (isPrivate) {
1139+
AccessScope::AccessScope(const DeclContext *DC, AccessLimitKind limitKind)
1140+
: Value(DC, limitKind) {
1141+
auto isPrivate = false;
1142+
if (limitKind == AccessLimitKind::Private) {
11421143
DC = getPrivateDeclContext(DC, DC->getParentSourceFile());
11431144
Value.setPointer(DC);
1145+
isPrivate = true;
11441146
}
11451147
if (!DC || isa<ModuleDecl>(DC))
11461148
assert(!isPrivate && "public or internal scope can't be private");

lib/Sema/TypeCheckAccess.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2095,7 +2095,8 @@ static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) {
20952095
case AccessLevel::FilePrivate: {
20962096
const DeclContext *DC = ED->getModuleScopeContext();
20972097
bool isPrivate = (userSpecifiedAccess == AccessLevel::Private);
2098-
desiredAccessScope = AccessScope(DC, isPrivate);
2098+
desiredAccessScope = AccessScope(DC, isPrivate ? AccessLimitKind::Private
2099+
: AccessLimitKind::None);
20992100
break;
21002101
}
21012102
case AccessLevel::Internal:

0 commit comments

Comments
 (0)