Skip to content

Commit f4df299

Browse files
almazrafiileitch
andauthored
Open class method params (#271)
* Fixed false positive for public protocols with extensions * Renamed fixtures and updated changelog * Fixed false positive for params of foreign protocol in subclass * Removed unused params * Renamed fixtures and updated changelog * Updated changelog * Fixed false positive for open methods parameters * Updated changelog Co-authored-by: Ian Leitch <[email protected]>
1 parent 1f19db3 commit f4df299

File tree

4 files changed

+42
-15
lines changed

4 files changed

+42
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
- In Swift 5.3 and lower, all optional protocol members are now retained in order to workaround a Swift bug. This bug is resolved in Swift 5.4.
1414
- Cases of public enums are now also retained when using `--retain-public`.
15+
- Open method parameters are now also retained when using `--retain-public`.
1516
- Empty public protocols that have an implementation in extensions are no longer identified as redundant.
1617
- Foreign protocol method parameters are no longer identified as unused.
1718

Sources/PeripheryKit/Analyzer/Visitors/UnusedParameterRetainer.swift

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ final class UnusedParameterRetainer: SourceGraphVisitor {
4747
if configuration.retainUnusedProtocolFuncParams {
4848
functionDecl.unusedParameters.forEach { graph.markRetained($0) }
4949
} else {
50-
retain(functionDecl.unusedParameters, usedIn: allFunctionDecls)
50+
retain(params: functionDecl.unusedParameters, usedIn: allFunctionDecls)
5151
}
5252
}
5353
}
@@ -64,12 +64,12 @@ final class UnusedParameterRetainer: SourceGraphVisitor {
6464
+ graph.superclasses(of: classDeclaration)
6565
+ graph.subclasses(of: classDeclaration)
6666

67-
allMethodDeclarations = allClassDeclarations.compactMap { declaration in
67+
allMethodDeclarations = allClassDeclarations.flatMap { declaration in
6868
declaration
6969
.declarations
7070
.lazy
7171
.filter { $0.kind == methodDeclaration.kind }
72-
.first { $0.name == methodDeclaration.name }
72+
.filter { $0.name == methodDeclaration.name }
7373
}
7474

7575
retainIfNeeded(
@@ -110,23 +110,28 @@ final class UnusedParameterRetainer: SourceGraphVisitor {
110110
}
111111

112112
private func retainIfNeeded(params: Set<Declaration>, inOverridenMethods methodDeclarations: [Declaration]) {
113-
let isSuperclassForeign = methodDeclarations.allSatisfy { declaration in
114-
declaration.modifiers.contains("override")
113+
guard let baseDeclaration = methodDeclarations.first(where: { !$0.modifiers.contains("override") }) else {
114+
// Must be overriding a declaration in a foreign class.
115+
return retainAllUnusedParams(inMethods: methodDeclarations)
115116
}
116117

117-
if isSuperclassForeign {
118-
// Must be overriding a declaration in a foreign class.
119-
methodDeclarations
120-
.lazy
121-
.flatMap { $0.unusedParameters }
122-
.forEach { graph.markRetained($0) }
123-
} else {
124-
// Retain all params that are used in any of the functions.
125-
retain(params, usedIn: methodDeclarations)
118+
guard baseDeclaration.accessibility.value != .open || !configuration.retainPublic else {
119+
// Parameters can be used in methods that are overridden from the outside
120+
return retainAllUnusedParams(inMethods: methodDeclarations)
126121
}
122+
123+
// Retain all params that are used in any of the functions.
124+
return retain(params: params, usedIn: methodDeclarations)
125+
}
126+
127+
private func retainAllUnusedParams(inMethods methodDeclarations: [Declaration]) {
128+
methodDeclarations
129+
.lazy
130+
.flatMap { $0.unusedParameters }
131+
.forEach { graph.markRetained($0) }
127132
}
128133

129-
private func retain(_ params: Set<Declaration>, usedIn functionDecls: [Declaration]) {
134+
private func retain(params: Set<Declaration>, usedIn functionDecls: [Declaration]) {
130135
for param in params {
131136
if isParam(param, usedInAnyOf: functionDecls) {
132137
graph.markRetained(param)

Tests/PeripheryTests/RetentionTest.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,6 +1012,14 @@ class RetentionTest: SourceGraphTestCase {
10121012
}
10131013
}
10141014

1015+
func testRetainsOpenClassParameters() {
1016+
analyze(retainPublic: true) {
1017+
XCTAssertReferenced((.varParameter, "value"),
1018+
descendentOf: (.functionMethodInstance, "doSomething(with:)"),
1019+
(.class, "FixtureClass112"))
1020+
}
1021+
}
1022+
10151023
func testIgnoreUnusedParamInUnusedFunction() {
10161024
analyze() {
10171025
XCTAssertNotReferenced((.class, "FixtureClass105"))
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import Foundation
2+
3+
open class FixtureClass112 {
4+
open func doSomething(with value: Int) { }
5+
}
6+
7+
public class FixtureClass112Retainer {
8+
var instance: FixtureClass112?
9+
10+
public func doSomething() {
11+
instance?.doSomething(with: .random(in: 0...10))
12+
}
13+
}

0 commit comments

Comments
 (0)