Skip to content

Commit 07662fc

Browse files
committed
[Sema] Don't report public imports of submodules as being unused in API
An import of a submodule implies an import of its top module, and referenced decl will be associated with the top module. Make sure we don't warn on public imports of a submodule being unused in API and only report if the top module is unused.
1 parent 503c326 commit 07662fc

File tree

3 files changed

+86
-19
lines changed

3 files changed

+86
-19
lines changed

lib/Sema/TypeCheckAccess.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,24 +2440,30 @@ void swift::diagnoseUnnecessaryPublicImports(SourceFile &SF) {
24402440
import.accessLevel <= AccessLevel::Internal)
24412441
continue;
24422442

2443-
AccessLevel levelUsed = SF.getMaxAccessLevelUsingImport(import.module.importedModule);
2444-
if (import.accessLevel > levelUsed) {
2445-
auto diagId = import.accessLevel == AccessLevel::Public ?
2446-
diag::remove_public_import :
2447-
diag::remove_package_import;
2448-
2449-
auto inFlight = ctx.Diags.diagnose(import.importLoc,
2450-
diagId,
2451-
import.module.importedModule);
2452-
2453-
if (levelUsed == AccessLevel::Package) {
2454-
inFlight.fixItReplace(import.accessLevelRange, "package");
2455-
} else if (ctx.LangOpts.hasFeature(Feature::InternalImportsByDefault)) {
2456-
// Let it default to internal.
2457-
inFlight.fixItRemove(import.accessLevelRange);
2458-
} else {
2459-
inFlight.fixItReplace(import.accessLevelRange, "internal");
2460-
}
2443+
// Ignore submodules as we associate decls with the top module.
2444+
// The top module will be reported if it's not used.
2445+
auto importedModule = import.module.importedModule;
2446+
if (importedModule->getTopLevelModule() != importedModule)
2447+
continue;
2448+
2449+
AccessLevel levelUsed = SF.getMaxAccessLevelUsingImport(importedModule);
2450+
if (import.accessLevel <= levelUsed)
2451+
continue;
2452+
2453+
auto diagId = import.accessLevel == AccessLevel::Public ?
2454+
diag::remove_public_import :
2455+
diag::remove_package_import;
2456+
auto inFlight = ctx.Diags.diagnose(import.importLoc,
2457+
diagId,
2458+
importedModule);
2459+
2460+
if (levelUsed == AccessLevel::Package) {
2461+
inFlight.fixItReplace(import.accessLevelRange, "package");
2462+
} else if (ctx.LangOpts.hasFeature(Feature::InternalImportsByDefault)) {
2463+
// Let it default to internal.
2464+
inFlight.fixItRemove(import.accessLevelRange);
2465+
} else {
2466+
inFlight.fixItReplace(import.accessLevelRange, "internal");
24612467
}
24622468
}
24632469
}

test/Sema/access-level-import-inconsistent-same-file.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ public func dummyAPI(t: Lib1.Type1) {}
9191
//--- Client_Clang.swift
9292

9393
public import ClangLib.Sub1 // expected-note {{imported 'public' here}}
94-
// expected-warning @-1 {{public import of 'Sub1' was not used in public declarations or inlinable code}}
9594
private import ClangLib.Sub1 // expected-warning {{module 'Sub1' is imported as 'public' from the same file; this 'private' access level will be ignored}}
9695
internal import ClangLib.Sub2
9796

test/Sema/superfluously-public-imports.swift

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
/// Check diagnostics.
2525
// RUN: %target-swift-frontend -typecheck %t/Client.swift -I %t \
2626
// RUN: -package-name pkg -Rmodule-api-import -swift-version 6 -verify
27+
// RUN: %target-swift-frontend -typecheck %t/ClientOfClangModules.swift -I %t \
28+
// RUN: -package-name pkg -Rmodule-api-import -swift-version 6 -verify
2729
// RUN: %target-swift-frontend -typecheck %t/Client_Swift5.swift -I %t \
2830
// RUN: -swift-version 5 -verify
2931

@@ -211,3 +213,63 @@ func implicitlyInternalFunc(a: NotAnAPIType = notAnAPIFunc()) {}
211213

212214
// For package decls we only remark on types used in signatures, not for inlinable code.
213215
package func packageFunc(a: PackageType = packageFunc()) {} // expected-remark {{struct 'PackageType' is imported via 'ImportUsedInPackage'}}
216+
217+
/// Tests for imports of clang modules.
218+
//--- module.modulemap
219+
module ClangSimpleUnused {
220+
header "ClangSimpleUnused.h"
221+
}
222+
module ClangSimple {
223+
header "ClangSimple.h"
224+
}
225+
226+
module ClangSubmodule {
227+
header "ClangSubmodule.h"
228+
229+
module ClangSubmoduleSubmodule {
230+
header "ClangSubmoduleSubmodule.h"
231+
}
232+
}
233+
234+
module ClangSubmoduleUnused {
235+
header "ClangSubmoduleUnused.h"
236+
237+
module ClangSubmoduleUnsuedSubmodule {
238+
header "ClangSubmoduleUnusedSubmodule.h"
239+
}
240+
}
241+
242+
module ClangTopModule {
243+
header "ClangTopModule.h"
244+
module ClangTopModuleSubmodule {
245+
header "ClangTopModuleSubmodule.h"
246+
}
247+
}
248+
249+
//--- ClangSimpleUnused.h
250+
//--- ClangSimple.h
251+
struct ClangSimpleType {};
252+
253+
//--- ClangSubmodule.h
254+
//--- ClangSubmoduleSubmodule.h
255+
struct ClangSubmoduleSubmoduleType {};
256+
257+
//--- ClangSubmoduleUnused.h
258+
//--- ClangSubmoduleUnusedSubmodule.h
259+
260+
//--- ClangTopModule.h
261+
struct ClangTopModuleType {};
262+
//--- ClangTopModuleSubmodule.h
263+
264+
//--- ClientOfClangModules.swift
265+
public import ClangSimple
266+
public import ClangSimpleUnused // expected-warning {{public import of 'ClangSimpleUnused' was not used in public declarations or inlinable code}}
267+
public import ClangSubmodule.ClangSubmoduleSubmodule
268+
public import ClangSubmoduleUnused.ClangSubmoduleUnsuedSubmodule // expected-warning {{public import of 'ClangSubmoduleUnused' was not used in public declarations or inlinable code}}
269+
270+
// Only the top-level module is used, but we can't detect whether the submodule was used or not.
271+
public import ClangTopModule.ClangTopModuleSubmodule
272+
273+
public func clangUser(a: ClangSimpleType) {} // expected-remark {{struct 'ClangSimpleType' is imported via 'ClangSimple'}}
274+
public func clangUser(a: ClangSubmoduleSubmoduleType) {} // expected-remark {{struct 'ClangSubmoduleSubmoduleType' is imported via 'ClangSubmodule'}}
275+
public func clangUser(a: ClangTopModuleType) {} // expected-remark {{struct 'ClangTopModuleType' is imported via 'ClangTopModule'}}

0 commit comments

Comments
 (0)