Description
Periphery 3.7.2 incorrectly reports redundant public accessibility on a property that implements a public protocol requirement defined in another module. The property is used — via the protocol extension in the defining module — but Periphery does not track cross-module protocol witness usage.
Issue
When a public protocol in module A requires a property (static var bundle: Bundle), and module A also provides a protocol extension that uses that property, a conforming type in module B gets flagged for "redundant public accessibility" on the property — even though removing public would be a compile error (protocol requirement from a public protocol must be at least as accessible).
Example
Repository: https://github.com/AllDmeat/PeripheryIssueSample
Commit hash: e04b7a5
Protocol in SampleDS module: Storyboardable.swift
import UIKit
@MainActor
public protocol Storyboardable {
static var bundle: Bundle { get }
}
extension Storyboardable where Self: UIViewController {
public static func instantiateInitialFromStoryboard() -> Self {
let name = String(describing: self)
let storyboard = UIStoryboard(name: name, bundle: bundle) // ← bundle is used here
return storyboard.instantiateInitialViewController() as! Self
}
}
Conforming type in MyProject target: RedundantPublicExample.swift
import UIKit
import SampleDS
final class SampleViewController: UIViewController, Storyboardable {
// ⚠️ Periphery reports: "Redundant public accessibility"
// But removing `public` is a compile error — protocol is public.
public static var bundle: Bundle { Bundle(for: SampleViewController.self) }
}
Usage in ViewController.swift
func showSample() {
let vc = SampleViewController.instantiateInitialFromStoryboard()
present(vc, animated: true)
}
The call chain: showSample() → instantiateInitialFromStoryboard() (protocol extension in SampleDS) → reads bundle property. So bundle is used at runtime.
Periphery Output
RedundantPublicExample.swift:30:23: warning: Redundant public accessibility for property 'bundle' (not used outside of MyProject)
Expected Behavior
bundle should not be flagged as having redundant public accessibility, since:
- It implements a requirement of a
public protocol from another module
- Removing
public is a compile error
- The property is actively used via the protocol extension in
SampleDS
Real-World Impact
In our iOS project (~50 modules), this pattern produces 13 identical false positives for Storyboardable.bundle and similar cross-module protocol conformances. These cannot be suppressed with // periphery:ignore without triggering "superfluous ignore comment" warnings in a second scan configuration.
Environment
- Periphery version: 3.7.2
- Xcode version: 26.3 (Build version 17C529)
- Swift version: 6.2.4
Description
Periphery 3.7.2 incorrectly reports
redundant public accessibilityon a property that implements apublicprotocol requirement defined in another module. The property is used — via the protocol extension in the defining module — but Periphery does not track cross-module protocol witness usage.Issue
When a public protocol in module A requires a property (
static var bundle: Bundle), and module A also provides a protocol extension that uses that property, a conforming type in module B gets flagged for "redundant public accessibility" on the property — even though removingpublicwould be a compile error (protocol requirement from a public protocol must be at least as accessible).Example
Repository: https://github.com/AllDmeat/PeripheryIssueSample
Commit hash:
e04b7a5Protocol in
SampleDSmodule:Storyboardable.swiftConforming type in
MyProjecttarget:RedundantPublicExample.swiftUsage in
ViewController.swiftThe call chain:
showSample()→instantiateInitialFromStoryboard()(protocol extension in SampleDS) → readsbundleproperty. Sobundleis used at runtime.Periphery Output
Expected Behavior
bundleshould not be flagged as having redundant public accessibility, since:publicprotocol from another modulepublicis a compile errorSampleDSReal-World Impact
In our iOS project (~50 modules), this pattern produces 13 identical false positives for
Storyboardable.bundleand similar cross-module protocol conformances. These cannot be suppressed with// periphery:ignorewithout triggering "superfluous ignore comment" warnings in a second scan configuration.Environment