Skip to content

Commit 58c386c

Browse files
committed
Sema: Register the extended type of a package-level extension
The warnings on superfluously public/package imports has a hole where it could report a package import as not being used by package decls even if it provides a type extended by a package extension. This is caused by the exportability checker not being enabled for package decls, thus not triggering the usual logic registering this reference. Address this issue by adding a check specifically for package extensions. We can remove this check once we have exportability checking for package decls. rdar://126712864
1 parent 092d01c commit 58c386c

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

lib/Sema/TypeCheckAccess.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2538,6 +2538,49 @@ void swift::diagnoseUnnecessaryPublicImports(SourceFile &SF) {
25382538
}
25392539
}
25402540

2541+
/// Register the type extended by \p ED as being used in a package decl if
2542+
/// any member is a package decl. This patches a hole in the warnings on
2543+
/// superfluously public imports which usually relies on exportability checking
2544+
/// that is not currently executed for package decls.
2545+
void registerPackageAccessForPackageExtendedType(ExtensionDecl *ED) {
2546+
auto extendedType = ED->getExtendedNominal();
2547+
if (!extendedType)
2548+
return;
2549+
2550+
bool hasPackageMembers = llvm::any_of(ED->getMembers(),
2551+
[](const Decl *member) -> bool {
2552+
auto *VD = dyn_cast<ValueDecl>(member);
2553+
if (!VD)
2554+
return false;
2555+
2556+
AccessScope accessScope =
2557+
VD->getFormalAccessScope(nullptr,
2558+
/*treatUsableFromInlineAsPublic*/true);
2559+
return accessScope.isPackage();
2560+
});
2561+
if (!hasPackageMembers)
2562+
return;
2563+
2564+
DeclContext *DC = ED->getDeclContext();
2565+
ImportAccessLevel import = extendedType->getImportAccessFrom(DC);
2566+
if (import.has_value()) {
2567+
auto SF = DC->getParentSourceFile();
2568+
if (SF)
2569+
SF->registerAccessLevelUsingImport(import.value(),
2570+
AccessLevel::Package);
2571+
2572+
auto &ctx = DC->getASTContext();
2573+
if (ctx.LangOpts.EnableModuleApiImportRemarks) {
2574+
ModuleDecl *importedVia = import->module.importedModule,
2575+
*sourceModule = ED->getModuleContext();
2576+
ED->diagnose(diag::module_api_import,
2577+
ED, importedVia, sourceModule,
2578+
importedVia == sourceModule,
2579+
/*isImplicit*/false);
2580+
}
2581+
}
2582+
}
2583+
25412584
void swift::checkAccessControl(Decl *D) {
25422585
if (isa<ValueDecl>(D) || isa<PatternBindingDecl>(D)) {
25432586
bool allowInlineable =
@@ -2546,6 +2589,7 @@ void swift::checkAccessControl(Decl *D) {
25462589
UsableFromInlineChecker().visit(D);
25472590
} else if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
25482591
checkExtensionGenericParamAccess(ED);
2592+
registerPackageAccessForPackageExtendedType(ED);
25492593
}
25502594

25512595
if (isa<AccessorDecl>(D))

test/Sema/superfluously-public-imports.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
// RUN: %target-swift-frontend -emit-module %t/ExtendedDefinitionNonPublic.swift -o %t -I %t
1818
// RUN: %target-swift-frontend -emit-module %t/UnusedImport.swift -o %t -I %t
1919
// RUN: %target-swift-frontend -emit-module %t/UnusedPackageImport.swift -o %t -I %t
20+
// RUN: %target-swift-frontend -emit-module %t/ExtendedPackageTypeImport.swift -o %t -I %t
2021
// RUN: %target-swift-frontend -emit-module %t/ImportNotUseFromAPI.swift -o %t -I %t
2122
// RUN: %target-swift-frontend -emit-module %t/ImportUsedInPackage.swift -o %t -I %t
2223
// RUN: %target-swift-frontend -emit-module %t/ExportedUnused.swift -o %t -I %t
@@ -98,6 +99,9 @@ public struct NonPublicExtendedType {}
9899
//--- UnusedImport.swift
99100

100101
//--- UnusedPackageImport.swift
102+
//--- ExtendedPackageTypeImport.swift
103+
104+
public struct ExtendedPackageType {}
101105

102106
//--- ImportNotUseFromAPI.swift
103107
public struct NotAnAPIType {}
@@ -145,6 +149,7 @@ package import UnusedImport // expected-warning {{package import of 'UnusedImpor
145149
// expected-warning @-1 {{module 'UnusedImport' is imported as 'public' from the same file; this 'package' access level will be ignored}}
146150

147151
package import UnusedPackageImport // expected-warning {{package import of 'UnusedPackageImport' was not used in package declarations}} {{1-9=}}
152+
package import ExtendedPackageTypeImport
148153
public import ImportNotUseFromAPI // expected-warning {{public import of 'ImportNotUseFromAPI' was not used in public declarations or inlinable code}} {{1-8=}}
149154
public import ImportUsedInPackage // expected-warning {{public import of 'ImportUsedInPackage' was not used in public declarations or inlinable code}} {{1-7=package}}
150155

@@ -243,6 +248,10 @@ public protocol Countable {
243248
extension Extended: Countable { // expected-remark {{struct 'Extended' is imported via 'RetroactiveConformance'}}
244249
}
245250

251+
extension ExtendedPackageType { // expected-remark {{struct 'ExtendedPackageType' is imported via 'ExtendedPackageTypeImport'}}
252+
package func useExtendedPackageType() { }
253+
}
254+
246255
/// Tests for imports of clang modules.
247256
//--- module.modulemap
248257
module ClangSimpleUnused {

0 commit comments

Comments
 (0)