Skip to content

Commit e696b5f

Browse files
committed
Sema: track use of public imports by more extensions
Consider extensions to imported types as users of a public import. This silences false reports of unused public imports in the case of an empty extension satisfying generic requirements via retroactive conformances. It also silences real reports of superfluously public imports used in internal extension, but this isn't very harmful at this time. We should revisit this later and tighten the check, we should refactor the logic use to determine what makes an extension public. rdar://120391841
1 parent 422e4cd commit e696b5f

File tree

2 files changed

+40
-0
lines changed

2 files changed

+40
-0
lines changed

lib/Sema/TypeCheckAccess.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2360,6 +2360,32 @@ class DeclAvailabilityChecker : public DeclVisitor<DeclAvailabilityChecker> {
23602360
Where = wasWhere.withExported(hasExportedMembers ||
23612361
!ED->getInherited().empty());
23622362
checkConstrainedExtensionRequirements(ED, hasExportedMembers);
2363+
2364+
if (!hasExportedMembers &&
2365+
!ED->getInherited().empty()) {
2366+
// If we haven't already visited the extended nominal visit it here.
2367+
// This logic is too wide but prevents false reports of an unused public
2368+
// import. We should instead check for public generic requirements
2369+
// similarly to ShouldPrintForModuleInterface::shouldPrint.
2370+
auto DC = Where.getDeclContext();
2371+
ImportAccessLevel import = extendedType->getImportAccessFrom(DC);
2372+
if (import.has_value()) {
2373+
auto SF = DC->getParentSourceFile();
2374+
if (SF)
2375+
SF->registerAccessLevelUsingImport(import.value(),
2376+
AccessLevel::Public);
2377+
2378+
auto &ctx = DC->getASTContext();
2379+
if (ctx.LangOpts.EnableModuleApiImportRemarks) {
2380+
ModuleDecl *importedVia = import->module.importedModule,
2381+
*sourceModule = ED->getModuleContext();
2382+
ED->diagnose(diag::module_api_import,
2383+
ED, importedVia, sourceModule,
2384+
importedVia == sourceModule,
2385+
/*isImplicit*/false);
2386+
}
2387+
}
2388+
}
23632389
}
23642390

23652391
void checkPrecedenceGroup(const PrecedenceGroupDecl *PGD,

test/Sema/superfluously-public-imports.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
// RUN: %target-swift-frontend -emit-module %t/ImportUsedInPackage.swift -o %t -I %t
2323
// RUN: %target-swift-frontend -emit-module %t/ExportedUnused.swift -o %t -I %t
2424
// RUN: %target-swift-frontend -emit-module %t/SPIOnlyUsedInSPI.swift -o %t -I %t
25+
// RUN: %target-swift-frontend -emit-module %t/RetroactiveConformance.swift -o %t -I %t
2526

2627
/// Check diagnostics.
2728
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t \
@@ -110,6 +111,11 @@ public func packageFunc() -> PackageType { return PackageType() }
110111
//--- SPIOnlyUsedInSPI.swift
111112
public struct ToUseFromSPI {}
112113

114+
//--- RetroactiveConformance.swift
115+
public struct Extended {
116+
public var count: Int { 42 }
117+
}
118+
113119
//--- Client_Swift5.swift
114120
/// No diagnostics should be raised on the implicit access level.
115121
import UnusedImport // expected-error {{ambiguous implicit access level for import of 'UnusedImport'; it is imported as 'public' elsewhere}}
@@ -143,6 +149,7 @@ public import ImportUsedInPackage // expected-warning {{public import of 'Import
143149

144150
@_exported public import ExportedUnused
145151
@_spiOnly public import SPIOnlyUsedInSPI
152+
public import RetroactiveConformance
146153

147154
public func useInSignature(_ a: TypeUsedInSignature) {} // expected-remark {{struct 'TypeUsedInSignature' is imported via 'DepUsedInSignature'}}
148155
public func exportedTypeUseInSignature(_ a: ExportedType) {} // expected-remark {{struct 'ExportedType' is imported via 'Exporter', which reexports definition from 'Exportee'}}
@@ -228,6 +235,13 @@ package func packageFunc(a: PackageType = packageFunc()) {} // expected-remark {
228235
@_spi(X)
229236
public func spiFunc(a: ToUseFromSPI) {} // expected-remark {{struct 'ToUseFromSPI' is imported via 'SPIOnlyUsedInSPI'}}
230237

238+
public protocol Countable {
239+
var count: Int { get } // expected-remark {{struct 'Int' is imported via 'Swift'}}
240+
}
241+
242+
extension Extended: Countable { // expected-remark {{struct 'Extended' is imported via 'RetroactiveConformance'}}
243+
}
244+
231245
/// Tests for imports of clang modules.
232246
//--- module.modulemap
233247
module ClangSimpleUnused {

0 commit comments

Comments
 (0)