@@ -2,8 +2,105 @@ import SwiftSyntax
2
2
3
3
final class Rewriter : SyntaxRewriter {
4
4
override func visit( _ node: SwitchCaseSyntax ) -> SwitchCaseSyntax {
5
- let newNode = self . removeUnusedLet ( node)
6
- return newNode
5
+ self . removeUnusedLet (
6
+ self . removeUnusedArguments (
7
+ node
8
+ )
9
+ )
10
+ }
11
+
12
+ /// Rewrites and removed unused arguments in switch cases.
13
+ /// For example, it rewrites:
14
+ /// ```swift
15
+ /// switch self {
16
+ /// case let .testCase(x, y):
17
+ /// return x
18
+ /// ```
19
+ /// to:
20
+ /// ```swift
21
+ /// switch self {
22
+ /// case .testCase(x):
23
+ /// ```
24
+ /// because `b` is unused.
25
+ private func removeUnusedArguments( _ node: SwitchCaseSyntax ) -> SwitchCaseSyntax {
26
+ guard let label = node. label. as ( SwitchCaseLabelSyntax . self) else {
27
+ return node
28
+ }
29
+ var items = label. caseItems
30
+
31
+ for (idx, item) in items. enumerated ( ) {
32
+ guard let pattern = item. pattern. as ( ValueBindingPatternSyntax . self) ,
33
+ let expr = pattern. pattern. as ( ExpressionPatternSyntax . self) ,
34
+ let functionCallSyntax = expr. expression. as ( FunctionCallExprSyntax . self) else {
35
+ continue
36
+ }
37
+
38
+ var missingPresenceIndices : [ Int ] = [ ]
39
+ for (idx, argument) in functionCallSyntax. arguments. enumerated ( ) {
40
+ guard let patternExpr = argument. expression. as ( PatternExprSyntax . self) ,
41
+ let identifier = patternExpr. pattern. as ( IdentifierPatternSyntax . self) else {
42
+ continue
43
+ }
44
+ let presenceDetector = PresenceDetector ( toDetect: identifier. identifier. tokenKind)
45
+ presenceDetector. walk ( node)
46
+ if presenceDetector. detectCount < 2 {
47
+ missingPresenceIndices. append ( idx)
48
+ }
49
+ }
50
+
51
+ var arguments = functionCallSyntax. arguments
52
+
53
+ for (index, idxInArguments) in missingPresenceIndices. enumerated ( ) {
54
+ let idx = arguments. index ( at: idxInArguments - index)
55
+ arguments. remove ( at: idx)
56
+ }
57
+
58
+ if !missingPresenceIndices. isEmpty {
59
+ let innerExpression : ExprSyntax = if arguments. isEmpty {
60
+ functionCallSyntax. calledExpression
61
+ } else {
62
+ ExprSyntax (
63
+ functionCallSyntax. with (
64
+ \. arguments,
65
+ arguments. with (
66
+ /// Remove the trailing comma from the last arg, if it's there.
67
+ \. [ arguments. lastIndex ( where: { _ in true } ) !] ,
68
+ arguments. last!. with (
69
+ \. trailingComma,
70
+ nil
71
+ )
72
+ )
73
+ )
74
+ )
75
+ }
76
+ items = items. with (
77
+ \. [ items. index ( at: idx) ] . pattern,
78
+ PatternSyntax (
79
+ pattern. with (
80
+ \. pattern,
81
+ PatternSyntax (
82
+ expr. with (
83
+ \. expression,
84
+ innerExpression
85
+ )
86
+ )
87
+ )
88
+ )
89
+ )
90
+ }
91
+ }
92
+
93
+ let node = node. with (
94
+ \. label,
95
+ SwitchCaseSyntax . Label (
96
+ label. with (
97
+ \. caseItems,
98
+ items
99
+ )
100
+ )
101
+ )
102
+
103
+ return node
7
104
}
8
105
9
106
/// Rewrites and removed unused `let`s in switch cases.
@@ -18,7 +115,7 @@ final class Rewriter: SyntaxRewriter {
18
115
/// case .testCase:
19
116
/// ```
20
117
private func removeUnusedLet( _ node: SwitchCaseSyntax ) -> SwitchCaseSyntax {
21
- guard var label = node. label. as ( SwitchCaseLabelSyntax . self) else {
118
+ guard let label = node. label. as ( SwitchCaseLabelSyntax . self) else {
22
119
return node
23
120
}
24
121
var items = label. caseItems
@@ -30,15 +127,43 @@ final class Rewriter: SyntaxRewriter {
30
127
expr. expression. is ( MemberAccessExprSyntax . self) else {
31
128
continue
32
129
}
33
- let idx = items. index ( at: idx)
34
- let newPattern = expr
35
- items [ idx] . pattern = PatternSyntax ( newPattern)
130
+
131
+ items = items. with (
132
+ \. [ items. index ( at: idx) ] . pattern,
133
+ PatternSyntax ( expr)
134
+ )
36
135
}
37
136
38
- label. caseItems = items
39
- var node = node
40
- node. label = SwitchCaseSyntax . Label ( label)
137
+ let node = node. with (
138
+ \. label,
139
+ SwitchCaseSyntax . Label (
140
+ label. with (
141
+ \. caseItems,
142
+ items
143
+ )
144
+ )
145
+ )
41
146
42
147
return node
43
148
}
44
149
}
150
+
151
+ private final class PresenceDetector : SyntaxVisitor {
152
+ var detectCount = 0
153
+ var toDetect : TokenKind
154
+
155
+ init (
156
+ viewMode: SyntaxTreeViewMode = . sourceAccurate,
157
+ toDetect: TokenKind
158
+ ) {
159
+ self . toDetect = toDetect
160
+ super. init ( viewMode: viewMode)
161
+ }
162
+
163
+ override func visit( _ node: TokenSyntax ) -> SyntaxVisitorContinueKind {
164
+ if node. tokenKind == self . toDetect {
165
+ self . detectCount += 1
166
+ }
167
+ return . visitChildren
168
+ }
169
+ }
0 commit comments