@@ -5,9 +5,9 @@ import dotty.tools.dotc.ast.tpd.TreeTraverser
5
5
import dotty .tools .dotc .ast .untpd
6
6
import dotty .tools .dotc .ast .untpd .ImportSelector
7
7
import dotty .tools .dotc .config .ScalaSettings
8
- import dotty .tools .dotc .core .Contexts ._
9
- import dotty .tools .dotc .core .Decorators .{i , em }
10
- import dotty .tools .dotc .core .Flags .{Private , Given }
8
+ import dotty .tools .dotc .core .Contexts .*
9
+ import dotty .tools .dotc .core .Decorators .{em , i }
10
+ import dotty .tools .dotc .core .Flags .{Given , GivenVal , Param , Private }
11
11
import dotty .tools .dotc .core .Phases .Phase
12
12
import dotty .tools .dotc .core .StdNames
13
13
import dotty .tools .dotc .report
@@ -17,6 +17,8 @@ import dotty.tools.dotc.util.Property
17
17
import dotty .tools .dotc .transform .CheckUnused .UnusedData .UnusedResult
18
18
import dotty .tools .dotc .core .Mode
19
19
20
+ import scala .collection .mutable
21
+
20
22
21
23
/**
22
24
* A compiler phase that checks for unused imports or definitions
@@ -36,11 +38,14 @@ class CheckUnused extends Phase:
36
38
override def isRunnable (using Context ): Boolean =
37
39
ctx.settings.WunusedHas .imports ||
38
40
ctx.settings.WunusedHas .locals ||
39
- ctx.settings.WunusedHas .privates
41
+ ctx.settings.WunusedHas .explicits ||
42
+ ctx.settings.WunusedHas .implicits ||
43
+ ctx.settings.WunusedHas .privates ||
44
+ ctx.settings.WunusedHas .patvars
40
45
41
46
override def run (using Context ): Unit =
42
47
val tree = ctx.compilationUnit.tpdTree
43
- val data = UnusedData (ctx )
48
+ val data = UnusedData ()
44
49
val fresh = ctx.fresh.setProperty(_key, data)
45
50
traverser.traverse(tree)(using fresh)
46
51
reportUnused(data.getUnused)
@@ -56,7 +61,7 @@ class CheckUnused extends Phase:
56
61
import UnusedData .ScopeType
57
62
58
63
override def traverse (tree : tpd.Tree )(using Context ): Unit = tree match
59
- case imp@ Import (_, sels) => sels.foreach { s =>
64
+ case imp@ Import (_, sels) => sels.foreach { _ =>
60
65
ctx.property(_key).foreach(_.registerImport(imp))
61
66
}
62
67
case ident : Ident =>
@@ -97,20 +102,29 @@ class CheckUnused extends Phase:
97
102
case t: tpd.DefDef =>
98
103
ctx.property(_key).foreach(_.registerDef(t))
99
104
traverseChildren(tree)
105
+ case t : tpd.Bind =>
106
+ ctx.property(_key).foreach(_.registerPatVar(t))
107
+ traverseChildren(tree)
100
108
case _ => traverseChildren(tree)
101
109
102
110
}
103
111
104
- private def reportUnused (res : UnusedData .UnusedResult )(using Context ) =
112
+ private def reportUnused (res : UnusedData .UnusedResult )(using Context ): Unit =
105
113
import CheckUnused .WarnTypes
106
114
res.foreach { s =>
107
115
s match
108
116
case (t, WarnTypes .Imports ) =>
109
117
report.warning(s " unused import " , t)
110
118
case (t, WarnTypes .LocalDefs ) =>
111
119
report.warning(s " unused local definition " , t)
120
+ case (t, WarnTypes .ExplicitParams ) =>
121
+ report.warning(s " unused explicit parameter " , t)
122
+ case (t, WarnTypes .ImplicitParams ) =>
123
+ report.warning(s " unused implicit parameter " , t)
112
124
case (t, WarnTypes .PrivateMembers ) =>
113
125
report.warning(s " unused private member " , t)
126
+ case (t, WarnTypes .PatVars ) =>
127
+ report.warning(s " unused pattern variable " , t)
114
128
}
115
129
116
130
end CheckUnused
@@ -122,34 +136,45 @@ object CheckUnused:
122
136
enum WarnTypes :
123
137
case Imports
124
138
case LocalDefs
139
+ case ExplicitParams
140
+ case ImplicitParams
125
141
case PrivateMembers
142
+ case PatVars
126
143
127
144
/**
128
145
* A stateful class gathering the infos on :
129
146
* - imports
130
147
* - definitions
131
148
* - usage
132
149
*/
133
- private class UnusedData ( initctx : Context ) :
134
- import collection .mutable .{Set => MutSet , Map => MutMap , Stack , ListBuffer }
150
+ private class UnusedData :
151
+ import collection .mutable .{Set => MutSet , Map => MutMap , Stack => MutStack , ListBuffer }
135
152
import UnusedData .ScopeType
136
153
137
154
var currScope : ScopeType = ScopeType .Other
138
155
139
156
/* IMPORTS */
140
- private val impInScope = Stack (MutMap [Int , ListBuffer [ImportSelector ]]())
157
+ private val impInScope = MutStack (MutMap [Int , ListBuffer [ImportSelector ]]())
141
158
private val unusedImport = MutSet [ImportSelector ]()
142
- private val usedImports = Stack (MutSet [Int ]())
159
+ private val usedImports = MutStack (MutSet [Int ]())
160
+
161
+ /* LOCAL DEF OR VAL / Private Def or Val / Pattern variables */
162
+ private val localDefInScope = MutStack (MutSet [tpd.ValOrDefDef ]())
163
+ private val privateDefInScope = MutStack (MutSet [tpd.ValOrDefDef ]())
164
+ private val explicitParamInScope = MutStack (MutSet [tpd.ValOrDefDef ]())
165
+ private val implicitParamInScope = MutStack (MutSet [tpd.ValOrDefDef ]())
166
+ private val patVarsInScope = MutStack (MutSet [tpd.Bind ]())
143
167
144
- /* LOCAL DEF OR VAL / Private Def or Val*/
145
- private val localDefInScope = Stack (MutSet [tpd.ValOrDefDef ]())
146
- private val privateDefInScope = Stack (MutSet [tpd.ValOrDefDef ]())
147
168
private val unusedLocalDef = ListBuffer [tpd.ValOrDefDef ]()
148
169
private val unusedPrivateDef = ListBuffer [tpd.ValOrDefDef ]()
170
+ private val unusedExplicitParams = ListBuffer [tpd.ValOrDefDef ]()
171
+ private val unusedImplicitParams = ListBuffer [tpd.ValOrDefDef ]()
172
+ private val unusedPatVars = ListBuffer [tpd.Bind ]()
173
+
149
174
private val usedDef = MutSet [Int ]()
150
175
151
176
private def isImportExclusion (sel : ImportSelector ): Boolean = sel.renamed match
152
- case ident @ untpd.Ident (name) => name == StdNames .nme.WILDCARD
177
+ case untpd.Ident (name) => name == StdNames .nme.WILDCARD
153
178
case _ => false
154
179
155
180
/** Register the id of a found (used) symbol */
@@ -181,25 +206,39 @@ object CheckUnused:
181
206
}
182
207
183
208
def registerDef (valOrDef : tpd.ValOrDefDef )(using Context ): Unit =
184
- if currScope == ScopeType .Local then
209
+ if valOrDef.symbol.is(Param ) then
210
+ if valOrDef.symbol.is(Given ) then
211
+ implicitParamInScope.top += valOrDef
212
+ else
213
+ explicitParamInScope.top += valOrDef
214
+ else if currScope == ScopeType .Local then
185
215
localDefInScope.top += valOrDef
186
216
else if currScope == ScopeType .Template && valOrDef.symbol.is(Private ) then
187
217
privateDefInScope.top += valOrDef
188
218
219
+ def registerPatVar (patvar : tpd.Bind )(using Context ): Unit =
220
+ patVarsInScope.top += patvar
221
+
189
222
/** enter a new scope */
190
223
def pushScope (): Unit =
191
224
// unused imports :
192
225
usedImports.push(MutSet ())
193
226
impInScope.push(MutMap ())
194
227
// local and private defs :
195
228
localDefInScope.push(MutSet ())
229
+ explicitParamInScope.push(MutSet ())
230
+ implicitParamInScope.push(MutSet ())
196
231
privateDefInScope.push(MutSet ())
232
+ patVarsInScope.push(MutSet ())
197
233
198
234
/** leave the current scope */
199
235
def popScope ()(using Context ): Unit =
200
236
popScopeImport()
201
237
popScopeLocalDef()
238
+ popScopeExplicitParam()
239
+ popScopeImplicitParam()
202
240
popScopePrivateDef()
241
+ popScopePatVars()
203
242
204
243
def popScopeImport (): Unit =
205
244
val usedImp = MutSet [ImportSelector ]()
@@ -211,7 +250,7 @@ object CheckUnused:
211
250
usedImp.addAll(value)
212
251
false
213
252
}
214
- if usedImports.size > 0 then
253
+ if usedImports.nonEmpty then
215
254
usedImports.top.addAll(notDefined)
216
255
217
256
poppedImp.values.flatten.foreach{ sel =>
@@ -225,12 +264,22 @@ object CheckUnused:
225
264
val unused = localDefInScope.pop().filterInPlace(d => ! usedDef(d.symbol.id))
226
265
unusedLocalDef ++= unused
227
266
267
+ def popScopeExplicitParam ()(using Context ): Unit =
268
+ val unused = explicitParamInScope.pop().filterInPlace(d => ! usedDef(d.symbol.id))
269
+ unusedExplicitParams ++= unused
270
+
271
+ def popScopeImplicitParam ()(using Context ): Unit =
272
+ val unused = implicitParamInScope.pop().filterInPlace(d => ! usedDef(d.symbol.id))
273
+ unusedImplicitParams ++= unused
274
+
228
275
def popScopePrivateDef ()(using Context ): Unit =
229
- val unused = privateDefInScope.pop().filterInPlace{d =>
230
- ! usedDef(d.symbol.id)
231
- }
276
+ val unused = privateDefInScope.pop().filterInPlace(d => ! usedDef(d.symbol.id))
232
277
unusedPrivateDef ++= unused
233
278
279
+ def popScopePatVars ()(using Context ): Unit =
280
+ val unused = patVarsInScope.pop().filterInPlace(d => ! usedDef(d.symbol.id))
281
+ unusedPatVars ++= unused
282
+
234
283
/**
235
284
* Leave the scope and return a `List` of unused `ImportSelector`s
236
285
*
@@ -245,15 +294,30 @@ object CheckUnused:
245
294
Nil
246
295
val sortedLocalDefs =
247
296
if ctx.settings.WunusedHas .locals then
248
- unusedLocalDef.map(d => d.withSpan(d.span.withEnd(d.tpt.startPos.start)) -> WarnTypes .LocalDefs ).toList
297
+ unusedLocalDef.map(d => d.namePos -> WarnTypes .LocalDefs ).toList
298
+ else
299
+ Nil
300
+ val sortedExplicitParams =
301
+ if ctx.settings.WunusedHas .explicits then
302
+ unusedExplicitParams.map(d => d.namePos -> WarnTypes .ExplicitParams ).toList
303
+ else
304
+ Nil
305
+ val sortedImplicitParams =
306
+ if ctx.settings.WunusedHas .implicits then
307
+ unusedImplicitParams.map(d => d.namePos -> WarnTypes .ImplicitParams ).toList
249
308
else
250
309
Nil
251
310
val sortedPrivateDefs =
252
311
if ctx.settings.WunusedHas .privates then
253
- unusedPrivateDef.map(d => d.withSpan(d.span.withEnd(d.tpt.startPos.start)) -> WarnTypes .PrivateMembers ).toList
312
+ unusedPrivateDef.map(d => d.namePos -> WarnTypes .PrivateMembers ).toList
313
+ else
314
+ Nil
315
+ val sortedPatVars =
316
+ if ctx.settings.WunusedHas .patvars then
317
+ unusedPatVars.map(d => d.namePos -> WarnTypes .PatVars ).toList
254
318
else
255
319
Nil
256
- List (sortedImp, sortedLocalDefs, sortedPrivateDefs).flatten.sortBy { s =>
320
+ List (sortedImp, sortedLocalDefs, sortedExplicitParams, sortedImplicitParams, sortedPrivateDefs, sortedPatVars ).flatten.sortBy { s =>
257
321
val pos = s._1.sourcePos
258
322
(pos.line, pos.column)
259
323
}
@@ -264,6 +328,7 @@ object CheckUnused:
264
328
enum ScopeType :
265
329
case Local
266
330
case Template
331
+ case Param
267
332
case Other
268
333
269
334
type UnusedResult = List [(dotty.tools.dotc.util.SrcPos , WarnTypes )]
0 commit comments