Skip to content

Commit 258b13b

Browse files
authored
Merge pull request swiftlang#63355 from apple/es-export-pr
Add access level and scope checks to package types
2 parents 75dfb56 + ea10ed0 commit 258b13b

File tree

9 files changed

+916
-40
lines changed

9 files changed

+916
-40
lines changed

include/swift/AST/AccessScope.h

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,13 @@ class AccessScope {
8585
return !Value.getPointer() && Value.getInt() == AccessLimitKind::Package;
8686
}
8787

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).
91-
/// \see DeclContext::isChildContextOf
88+
/// Returns true if the context of this (use site) is more restrictive than
89+
/// the argument context (decl site). This function does _not_ check the
90+
/// restrictiveness of the access level between this and the argument. \see
91+
/// AccessScope::isInContext
9292
bool isChildOf(AccessScope AS) const {
93-
if (isInternalOrLess()) {
94-
if (AS.isInternalOrLess())
93+
if (isInContext()) {
94+
if (AS.isInContext())
9595
return allowsPrivateAccess(getDeclContext(), AS.getDeclContext());
9696
else
9797
return AS.isPackage() || AS.isPublic();
@@ -103,7 +103,27 @@ class AccessScope {
103103
return false;
104104
}
105105

106-
bool isInternalOrLess() const { return getDeclContext() != nullptr; }
106+
/// Result depends on whether it's called at a use site or a decl site:
107+
///
108+
/// For example,
109+
///
110+
/// ```
111+
/// public func foo(_ arg: bar) {} // `bar` is a `package` decl in another
112+
/// module
113+
/// ```
114+
///
115+
/// The meaning of \c isInContext changes whether it's at the use site or the
116+
/// decl site.
117+
///
118+
/// The use site of \c bar, i.e. \c foo, is "in context" (decl context is
119+
/// non-null), regardless of the access level of \c foo (\c public in this
120+
/// case).
121+
///
122+
/// The decl site of \c bar is only "in context" if the access level of the
123+
/// decl is \c internal or more restrictive. The context at the decl site is\c
124+
/// FileUnit if the decl is \c fileprivate or \c private; \c ModuleDecl if \c
125+
/// internal, and null if \c package or \c public.
126+
bool isInContext() const { return getDeclContext() != nullptr; }
107127

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

lib/AST/ASTVerifier.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -944,12 +944,19 @@ class Verifier : public ASTWalker {
944944

945945
if (D->hasAccess()) {
946946
PrettyStackTraceDecl debugStack("verifying access", D);
947-
if (!D->getASTContext().isAccessControlDisabled() &&
948-
D->getFormalAccessScope().isPublic() &&
949-
D->getFormalAccess() <= AccessLevel::Package) {
950-
Out << "non-public decl has no formal access scope\n";
951-
D->dump(Out);
952-
abort();
947+
if (!D->getASTContext().isAccessControlDisabled()) {
948+
if (D->getFormalAccessScope().isPackage() &&
949+
D->getFormalAccess() < AccessLevel::Package) {
950+
Out << "non-package decl has no formal access scope\n";
951+
D->dump(Out);
952+
abort();
953+
}
954+
if (D->getFormalAccessScope().isPublic() &&
955+
D->getFormalAccess() < AccessLevel::Public) {
956+
Out << "non-public decl has no formal access scope\n";
957+
D->dump(Out);
958+
abort();
959+
}
953960
}
954961
if (D->getEffectiveAccess() == AccessLevel::Private) {
955962
Out << "effective access should use 'fileprivate' for 'private'\n";

lib/AST/Decl.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3793,6 +3793,7 @@ getAccessScopeForFormalAccess(const ValueDecl *VD,
37933793
case AccessLevel::Internal:
37943794
return AccessScope(resultDC->getParentModule());
37953795
case AccessLevel::Package:
3796+
return AccessScope::getPackage();
37963797
case AccessLevel::Public:
37973798
case AccessLevel::Open:
37983799
return AccessScope::getPublic();
@@ -3828,8 +3829,15 @@ static bool checkAccessUsingAccessScopes(const DeclContext *useDC,
38283829
if (accessScope.getDeclContext() == useDC) return true;
38293830
if (!AccessScope(useDC).isChildOf(accessScope)) return false;
38303831

3832+
// useDC is null only when caller wants to skip non-public type checks.
3833+
if (!useDC) return true;
3834+
3835+
// Check package access; accessing package decl should not be allowed if package names are different
3836+
if (accessScope.isPackage())
3837+
return VD->getDeclContext()->getParentModule()->getPackageName() == useDC->getParentModule()->getPackageName();
3838+
38313839
// Check SPI access
3832-
if (!useDC || !VD->isSPI()) return true;
3840+
if (!VD->isSPI()) return true;
38333841
auto useSF = dyn_cast<SourceFile>(useDC->getModuleScopeContext());
38343842
return !useSF || useSF->isImportedAsSPI(VD) ||
38353843
VD->getDeclContext()->getParentModule() == useDC->getParentModule();

lib/AST/DeclContext.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ void DeclContext::dumpContext() const {
583583
void AccessScope::dump() const {
584584
llvm::errs() << getAccessLevelSpelling(accessLevelForDiagnostics()) << ": ";
585585

586-
if (isPublic()) {
586+
if (isPublic() || isPackage()) {
587587
llvm::errs() << "(null)\n";
588588
return;
589589
}
@@ -1194,7 +1194,7 @@ AccessScope::AccessScope(const DeclContext *DC, AccessLimitKind limitKind)
11941194
isPrivate = true;
11951195
}
11961196
if (!DC || isa<ModuleDecl>(DC))
1197-
assert(!isPrivate && "public or internal scope can't be private");
1197+
assert(!isPrivate && "public, package, or internal scope can't be private");
11981198
}
11991199

12001200
bool AccessScope::isFileScope() const {
@@ -1210,6 +1210,8 @@ bool AccessScope::isInternal() const {
12101210
AccessLevel AccessScope::accessLevelForDiagnostics() const {
12111211
if (isPublic())
12121212
return AccessLevel::Public;
1213+
if (isPackage())
1214+
return AccessLevel::Package;
12131215
if (isa<ModuleDecl>(getDeclContext()))
12141216
return AccessLevel::Internal;
12151217
if (getDeclContext()->isModuleScopeContext()) {

lib/DriverTool/swift_symbolgraph_extract_main.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ int swift_symbolgraph_extract_main(ArrayRef<const char *> Args,
181181
llvm::StringSwitch<AccessLevel>(A->getValue())
182182
.Case("open", AccessLevel::Open)
183183
.Case("public", AccessLevel::Public)
184+
.Case("package", AccessLevel::Package)
184185
.Case("internal", AccessLevel::Internal)
185186
.Case("fileprivate", AccessLevel::FilePrivate)
186187
.Case("private", AccessLevel::Private)

lib/Frontend/CompilerInvocation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1347,6 +1347,7 @@ static void ParseSymbolGraphArgs(symbolgraphgen::SymbolGraphOptions &Opts,
13471347
llvm::StringSwitch<AccessLevel>(A->getValue())
13481348
.Case("open", AccessLevel::Open)
13491349
.Case("public", AccessLevel::Public)
1350+
.Case("package", AccessLevel::Package)
13501351
.Case("internal", AccessLevel::Internal)
13511352
.Case("fileprivate", AccessLevel::FilePrivate)
13521353
.Case("private", AccessLevel::Private)

lib/Parse/ParseDecl.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2067,6 +2067,7 @@ bool Parser::parseDocumentationAttributeArgument(Optional<StringRef> &Metadata,
20672067
llvm::StringSwitch<Optional<AccessLevel>>(ArgumentValue)
20682068
.Case("open", AccessLevel::Open)
20692069
.Case("public", AccessLevel::Public)
2070+
.Case("package", AccessLevel::Package)
20702071
.Case("internal", AccessLevel::Internal)
20712072
.Case("private", AccessLevel::Private)
20722073
.Case("fileprivate", AccessLevel::FilePrivate)
@@ -2728,6 +2729,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
27282729
.Case("private", AccessLevel::Private)
27292730
.Case("fileprivate", AccessLevel::FilePrivate)
27302731
.Case("internal", AccessLevel::Internal)
2732+
.Case("package", AccessLevel::Package)
27312733
.Case("public", AccessLevel::Public)
27322734
.Case("open", AccessLevel::Open);
27332735

lib/Sema/TypeCheckAccess.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ void AccessControlCheckerBase::checkTypeAccessImpl(
182182
return;
183183
// Don't spend time checking local declarations; this is always valid by the
184184
// time we get to this point.
185-
if (!contextAccessScope.isPublic() &&
185+
if (contextAccessScope.isInContext() &&
186186
contextAccessScope.getDeclContext()->isLocalContext())
187187
return;
188188

@@ -2106,6 +2106,8 @@ static void checkExtensionGenericParamAccess(const ExtensionDecl *ED) {
21062106
desiredAccessScope = AccessScope(ED->getModuleContext());
21072107
break;
21082108
case AccessLevel::Package:
2109+
desiredAccessScope = AccessScope::getPackage();
2110+
break;
21092111
case AccessLevel::Public:
21102112
case AccessLevel::Open:
21112113
break;

0 commit comments

Comments
 (0)