Skip to content

Commit 8ac97b3

Browse files
committed
Fix requested changes, add new tests
- Fix minor changes - Add more tests - -Wunused:nowarn does not run the CheckUnused phase fix nowarn clean useless val
1 parent e69c4a3 commit 8ac97b3

File tree

4 files changed

+111
-62
lines changed

4 files changed

+111
-62
lines changed

compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,21 +163,28 @@ private sealed trait WarningSettings:
163163
name = "-Wunused",
164164
helpArg = "warning",
165165
descr = "Enable or disable specific `unused` warnings",
166-
choices = List("nowarn", "all", "imports", "locals", "privates", "patvars", "explicits", "implicits", "params"),
166+
choices = List("nowarn", "all", "imports", "locals", "privates", "patvars", "explicits", "implicits", "params", "linted"),
167167
default = Nil
168168
)
169169
object WunusedHas:
170170
def allOr(s: String)(using Context) = Wunused.value.pipe(us => us.contains("all") || us.contains(s))
171171
def nowarn(using Context) = allOr("nowarn")
172-
def imports(using Context) = allOr("imports")
173-
def locals(using Context) = allOr("locals")
172+
173+
def imports(using Context) =
174+
allOr("imports") || allOr("linted")
175+
def locals(using Context) =
176+
allOr("locals") || allOr("linted")
174177
/** -Wunused:explicits OR -Wunused:params */
175-
def explicits(using Context) = allOr("explicits") || allOr("params")
178+
def explicits(using Context) =
179+
allOr("explicits") || allOr("params")
176180
/** -Wunused:implicits OR -Wunused:params */
177-
def implicits(using Context) = allOr("implicits") || allOr("params")
181+
def implicits(using Context) =
182+
allOr("implicits") || allOr("params") || allOr("linted")
178183
def params(using Context) = allOr("params")
179-
def privates(using Context) = allOr("privates")
184+
def privates(using Context) =
185+
allOr("privates") || allOr("linted")
180186
def patvars(using Context) = allOr("patvars")
187+
def linted(using Context) = allOr("linted")
181188

182189
val Wconf: Setting[List[String]] = MultiStringSetting(
183190
"-Wconf",

compiler/src/dotty/tools/dotc/transform/CheckUnused.scala

Lines changed: 46 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,7 @@ class CheckUnused extends Phase:
3636
override def description: String = CheckUnused.description
3737

3838
override def isRunnable(using Context): Boolean =
39-
ctx.settings.WunusedHas.imports ||
40-
ctx.settings.WunusedHas.locals ||
41-
ctx.settings.WunusedHas.explicits ||
42-
ctx.settings.WunusedHas.implicits ||
43-
ctx.settings.WunusedHas.privates ||
44-
ctx.settings.WunusedHas.patvars
39+
ctx.settings.Wunused.value.nonEmpty
4540

4641
override def run(using Context): Unit =
4742
val tree = ctx.compilationUnit.tpdTree
@@ -61,40 +56,17 @@ class CheckUnused extends Phase:
6156
import UnusedData.ScopeType
6257

6358
override def traverse(tree: tpd.Tree)(using Context): Unit = tree match
64-
case imp@Import(_, sels) => sels.foreach { _ =>
65-
ctx.property(_key).foreach(_.registerImport(imp))
66-
}
59+
case imp:tpd.Import =>
60+
ctx.property(_key).foreach(_.registerImport(imp))
6761
case ident: Ident =>
68-
val id = ident.symbol.id
69-
ctx.property(_key).foreach(_.registerUsed(id))
62+
ctx.property(_key).foreach(_.registerUsed(ident.symbol))
7063
traverseChildren(tree)
7164
case sel: Select =>
72-
val id = sel.symbol.id
73-
ctx.property(_key).foreach(_.registerUsed(id))
74-
traverseChildren(tree)
75-
case tpd.Block(_,_) =>
76-
var prev: ScopeType = ScopeType.Other
77-
ctx.property(_key).foreach { ud =>
78-
ud.pushScope()
79-
prev = ud.currScope
80-
ud.currScope = ScopeType.Local
81-
}
65+
ctx.property(_key).foreach(_.registerUsed(sel.symbol))
8266
traverseChildren(tree)
67+
case _: (tpd.Block | tpd.Template) =>
8368
ctx.property(_key).foreach { ud =>
84-
ud.popScope()
85-
ud.currScope = prev
86-
}
87-
case tpd.Template(_,_,_,_) =>
88-
var prev: ScopeType = ScopeType.Other
89-
ctx.property(_key).foreach { ud =>
90-
ud.pushScope()
91-
prev = ud.currScope
92-
ud.currScope = ScopeType.Template
93-
}
94-
traverseChildren(tree)
95-
ctx.property(_key).foreach { ud =>
96-
ud.popScope()
97-
ud.currScope = prev
69+
ud.inNewScope(ScopeType.fromTree(tree))(traverseChildren(tree))
9870
}
9971
case t:tpd.ValDef =>
10072
ctx.property(_key).foreach(_.registerDef(t))
@@ -111,7 +83,7 @@ class CheckUnused extends Phase:
11183

11284
private def reportUnused(res: UnusedData.UnusedResult)(using Context): Unit =
11385
import CheckUnused.WarnTypes
114-
res.foreach { s =>
86+
res.warnings.foreach { s =>
11587
s match
11688
case (t, WarnTypes.Imports) =>
11789
report.warning(s"unused import", t)
@@ -149,14 +121,15 @@ object CheckUnused:
149121
*/
150122
private class UnusedData:
151123
import collection.mutable.{Set => MutSet, Map => MutMap, Stack => MutStack, ListBuffer}
124+
import dotty.tools.dotc.core.Symbols.Symbol
152125
import UnusedData.ScopeType
153126

154-
var currScope: ScopeType = ScopeType.Other
127+
var currScopeType: ScopeType = ScopeType.Other
155128

156129
/* IMPORTS */
157-
private val impInScope = MutStack(MutMap[Int, ListBuffer[ImportSelector]]())
130+
private val impInScope = MutStack(MutMap[Symbol, ListBuffer[ImportSelector]]())
158131
private val unusedImport = MutSet[ImportSelector]()
159-
private val usedImports = MutStack(MutSet[Int]())
132+
private val usedImports = MutStack(MutSet[Symbol]())
160133

161134
/* LOCAL DEF OR VAL / Private Def or Val / Pattern variables */
162135
private val localDefInScope = MutStack(MutSet[tpd.ValOrDefDef]())
@@ -171,14 +144,26 @@ object CheckUnused:
171144
private val unusedImplicitParams = ListBuffer[tpd.ValOrDefDef]()
172145
private val unusedPatVars = ListBuffer[tpd.Bind]()
173146

174-
private val usedDef = MutSet[Int]()
147+
private val usedDef = MutSet[Symbol]()
148+
149+
/**
150+
* Push a new Scope of the given type, executes the given Unit and
151+
* pop it back to the original type.
152+
*/
153+
def inNewScope(newScope: ScopeType)(execInNewScope: => Unit)(using Context): Unit =
154+
val prev = currScopeType
155+
currScopeType = newScope
156+
pushScope()
157+
execInNewScope
158+
popScope()
159+
currScopeType = prev
175160

176161
private def isImportExclusion(sel: ImportSelector): Boolean = sel.renamed match
177162
case untpd.Ident(name) => name == StdNames.nme.WILDCARD
178163
case _ => false
179164

180165
/** Register the id of a found (used) symbol */
181-
def registerUsed(id: Int): Unit =
166+
def registerUsed(id: Symbol): Unit =
182167
usedImports.top += id
183168
usedDef += id
184169

@@ -192,12 +177,11 @@ object CheckUnused:
192177
else if s.isWildcard then
193178
tree.tpe.allMembers
194179
.filter(m => m.symbol.is(Given) == s.isGiven) // given imports
195-
.map(_.symbol.id -> s)
196-
180+
.map(_.symbol -> s)
197181
else
198-
val id = tree.tpe.member(s.name.toTermName).symbol.id
199-
val typeId = tree.tpe.member(s.name.toTypeName).symbol.id
200-
List(id -> s, typeId -> s)
182+
val termSymbol = tree.tpe.member(s.name.toTermName).symbol
183+
val typeSymbol = tree.tpe.member(s.name.toTypeName).symbol
184+
List(termSymbol -> s, typeSymbol -> s)
201185
}
202186
entries.foreach{(id, sel) =>
203187
map.get(id) match
@@ -211,9 +195,9 @@ object CheckUnused:
211195
implicitParamInScope.top += valOrDef
212196
else
213197
explicitParamInScope.top += valOrDef
214-
else if currScope == ScopeType.Local then
198+
else if currScopeType == ScopeType.Local then
215199
localDefInScope.top += valOrDef
216-
else if currScope == ScopeType.Template && valOrDef.symbol.is(Private) then
200+
else if currScopeType == ScopeType.Template && valOrDef.symbol.is(Private) then
217201
privateDefInScope.top += valOrDef
218202

219203
def registerPatVar(patvar: tpd.Bind)(using Context): Unit =
@@ -261,23 +245,23 @@ object CheckUnused:
261245
}
262246

263247
def popScopeLocalDef()(using Context): Unit =
264-
val unused = localDefInScope.pop().filterInPlace(d => !usedDef(d.symbol.id))
248+
val unused = localDefInScope.pop().filterInPlace(d => !usedDef(d.symbol))
265249
unusedLocalDef ++= unused
266250

267251
def popScopeExplicitParam()(using Context): Unit =
268-
val unused = explicitParamInScope.pop().filterInPlace(d => !usedDef(d.symbol.id))
252+
val unused = explicitParamInScope.pop().filterInPlace(d => !usedDef(d.symbol))
269253
unusedExplicitParams ++= unused
270254

271255
def popScopeImplicitParam()(using Context): Unit =
272-
val unused = implicitParamInScope.pop().filterInPlace(d => !usedDef(d.symbol.id))
256+
val unused = implicitParamInScope.pop().filterInPlace(d => !usedDef(d.symbol))
273257
unusedImplicitParams ++= unused
274258

275259
def popScopePrivateDef()(using Context): Unit =
276-
val unused = privateDefInScope.pop().filterInPlace(d => !usedDef(d.symbol.id))
260+
val unused = privateDefInScope.pop().filterInPlace(d => !usedDef(d.symbol))
277261
unusedPrivateDef ++= unused
278262

279263
def popScopePatVars()(using Context): Unit =
280-
val unused = patVarsInScope.pop().filterInPlace(d => !usedDef(d.symbol.id))
264+
val unused = patVarsInScope.pop().filterInPlace(d => !usedDef(d.symbol))
281265
unusedPatVars ++= unused
282266

283267
/**
@@ -317,20 +301,26 @@ object CheckUnused:
317301
unusedPatVars.map(d => d.namePos -> WarnTypes.PatVars).toList
318302
else
319303
Nil
320-
List(sortedImp, sortedLocalDefs, sortedExplicitParams, sortedImplicitParams, sortedPrivateDefs, sortedPatVars).flatten.sortBy { s =>
304+
val warnings = List(sortedImp, sortedLocalDefs, sortedExplicitParams, sortedImplicitParams, sortedPrivateDefs, sortedPatVars).flatten.sortBy { s =>
321305
val pos = s._1.sourcePos
322306
(pos.line, pos.column)
323307
}
308+
UnusedResult(warnings, Nil)
324309

325310
end UnusedData
326311

327312
object UnusedData:
328313
enum ScopeType:
329314
case Local
330315
case Template
331-
case Param
332316
case Other
333317

334-
type UnusedResult = List[(dotty.tools.dotc.util.SrcPos, WarnTypes)]
318+
object ScopeType:
319+
def fromTree(tree: tpd.Tree): ScopeType = tree match
320+
case _:tpd.Template => Template
321+
case _:tpd.Block => Local
322+
case _ => Other
323+
324+
case class UnusedResult(warnings: List[(dotty.tools.dotc.util.SrcPos, WarnTypes)], usedImports: List[(tpd.Import, untpd.ImportSelector)])
335325
end CheckUnused
336326

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// scalac: -Wunused:linted
2+
3+
import collection.mutable.Set // error
4+
5+
class A {
6+
private val a = 1 // error
7+
val b = 2 // OK
8+
9+
private def c = 2 // error
10+
def d(using x:Int): Int = 1 // error
11+
def e(x: Int) = 1 // OK
12+
def f =
13+
val x = 1 // error
14+
def f = 2 // error
15+
3
16+
17+
def g(x: Int): Int = x match
18+
case x:1 => 0 // OK
19+
case _ => 1
20+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// scalac: -Wunused:all
2+
3+
import collection.mutable.{Map => MutMap} // error
4+
import collection.mutable.Set // error
5+
6+
class A {
7+
import collection.mutable.{Map => MutMap} // OK
8+
private val a = 1 // error
9+
val b = 2 // OK
10+
val someMap = MutMap()
11+
12+
private def c1 = 2 // error
13+
private def c2 = 2 // OK
14+
def c3 = c2
15+
16+
def d1(using x:Int): Int = 1 // error
17+
def d2(using x:Int): Int = x // OK
18+
19+
def e1(x: Int) = 1 // error
20+
def e2(x: Int) = x // OK
21+
def f =
22+
val x = 1 // error
23+
def f = 2 // error
24+
val y = 3 // OK
25+
def g = 4 // OK
26+
y + g
27+
28+
def g(x: Int): Int = x match
29+
case x:1 => 0 // error
30+
case x:2 => x // OK
31+
case _ => 1 // OK
32+
}

0 commit comments

Comments
 (0)