Skip to content

Commit ae24d64

Browse files
committed
Improve -Wunused:locals
1 parent d37d99e commit ae24d64

File tree

2 files changed

+101
-22
lines changed

2 files changed

+101
-22
lines changed

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

Lines changed: 61 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ class CheckUnused extends MiniPhase:
6161
// ========== SETUP ============
6262

6363
override def prepareForUnit(tree: tpd.Tree)(using Context): Context =
64-
val tree = ctx.compilationUnit.tpdTree
6564
val data = UnusedData()
6665
val fresh = ctx.fresh.setProperty(_key, data)
6766
fresh
@@ -94,7 +93,11 @@ class CheckUnused extends MiniPhase:
9493
pushInBlockTemplatePackageDef(tree)
9594

9695
override def prepareForValDef(tree: tpd.ValDef)(using Context): Context =
97-
_key.unusedDataApply(_.registerDef(tree))
96+
_key.unusedDataApply{ud =>
97+
ud.registerDef(tree)
98+
if tree.symbol.is(Flags.Module) then
99+
ud.addIgnoredUsage(tree.symbol)
100+
}
98101

99102
override def prepareForDefDef(tree: tpd.DefDef)(using Context): Context =
100103
_key.unusedDataApply{ ud =>
@@ -103,6 +106,12 @@ class CheckUnused extends MiniPhase:
103106
ud.registerDef(tree)
104107
}
105108

109+
override def prepareForTypeDef(tree: tpd.TypeDef)(using Context): Context =
110+
_key.unusedDataApply{ ud =>
111+
ud.registerDef(tree)
112+
ud.addIgnoredUsage(tree.symbol)
113+
}
114+
106115
override def prepareForBind(tree: tpd.Bind)(using Context): Context =
107116
_key.unusedDataApply(_.registerPatVar(tree))
108117

@@ -112,6 +121,11 @@ class CheckUnused extends MiniPhase:
112121

113122
// ========== MiniPhase Transform ==========
114123

124+
override def transformValDef(tree: tpd.ValDef)(using Context): tpd.Tree =
125+
if tree.symbol.is(Flags.Module) then
126+
_key.unusedDataApply(_.removeIgnoredUsage(tree.symbol))
127+
tree
128+
115129
override def transformBlock(tree: tpd.Block)(using Context): tpd.Tree =
116130
popOutBlockTemplatePackageDef()
117131
tree
@@ -124,6 +138,10 @@ class CheckUnused extends MiniPhase:
124138
popOutBlockTemplatePackageDef()
125139
tree
126140

141+
override def transformTypeDef(tree: tpd.TypeDef)(using Context): tpd.Tree =
142+
_key.unusedDataApply(_.removeIgnoredUsage(tree.symbol))
143+
tree
144+
127145
// ---------- MiniPhase HELPERS -----------
128146

129147
private def pushInBlockTemplatePackageDef(tree: tpd.Block | tpd.Template | tpd.PackageDef)(using Context): Context =
@@ -175,6 +193,9 @@ class CheckUnused extends MiniPhase:
175193
case t:tpd.DefDef =>
176194
prepareForDefDef(t)
177195
traverseChildren(tree)(using newCtx)
196+
case t:tpd.TypeDef =>
197+
prepareForTypeDef(t)
198+
traverseChildren(tree)(using newCtx)
178199
case t: tpd.Bind =>
179200
prepareForBind(t)
180201
traverseChildren(tree)(using newCtx)
@@ -255,21 +276,23 @@ object CheckUnused:
255276
private val unusedImport = MutSet[ImportSelector]()
256277

257278
/* LOCAL DEF OR VAL / Private Def or Val / Pattern variables */
258-
private val localDefInScope = MutSet[tpd.ValOrDefDef]()
259-
private val privateDefInScope = MutSet[tpd.ValOrDefDef]()
260-
private val explicitParamInScope = MutSet[tpd.ValOrDefDef]()
261-
private val implicitParamInScope = MutSet[tpd.ValOrDefDef]()
279+
private val localDefInScope = MutSet[tpd.MemberDef]()
280+
private val privateDefInScope = MutSet[tpd.MemberDef]()
281+
private val explicitParamInScope = MutSet[tpd.MemberDef]()
282+
private val implicitParamInScope = MutSet[tpd.MemberDef]()
262283
private val patVarsInScope = MutSet[tpd.Bind]()
263284

264285
/* Unused collection collected at the end */
265-
private val unusedLocalDef = MutSet[tpd.ValOrDefDef]()
266-
private val unusedPrivateDef = MutSet[tpd.ValOrDefDef]()
267-
private val unusedExplicitParams = MutSet[tpd.ValOrDefDef]()
268-
private val unusedImplicitParams = MutSet[tpd.ValOrDefDef]()
286+
private val unusedLocalDef = MutSet[tpd.MemberDef]()
287+
private val unusedPrivateDef = MutSet[tpd.MemberDef]()
288+
private val unusedExplicitParams = MutSet[tpd.MemberDef]()
289+
private val unusedImplicitParams = MutSet[tpd.MemberDef]()
269290
private val unusedPatVars = MutSet[tpd.Bind]()
270291

271292
/** All used symbols */
272293
private val usedDef = MutSet[Symbol]()
294+
/** Do not register as used */
295+
private val doNotRegister = MutSet[Symbol]()
273296

274297
/** Trivial definitions, avoid registering params */
275298
private val trivialDefs = MutSet[Symbol]()
@@ -296,14 +319,30 @@ object CheckUnused:
296319
* as the same element can be imported with different renaming
297320
*/
298321
def registerUsed(sym: Symbol, name: Option[Name])(using Context): Unit =
299-
if !isConstructorOfSynth(sym) then
322+
if !isConstructorOfSynth(sym) && !doNotRegister(sym) then
300323
usedInScope.top += ((sym, sym.isAccessibleAsIdent, name))
301324
if sym.isConstructor && sym.exists then
302325
registerUsed(sym.owner, None) // constructor are "implicitly" imported with the class
303326

304327
/** Register a list of found (used) symbols */
305328
def registerUsed(syms: Seq[Symbol])(using Context): Unit =
306-
usedInScope.top ++= syms.filterNot(isConstructorOfSynth).map(s => (s, s.isAccessibleAsIdent, None))
329+
usedInScope.top ++=
330+
syms
331+
.filterNot(s => isConstructorOfSynth(s) || doNotRegister(s))
332+
.map(s => (s, s.isAccessibleAsIdent, None))
333+
334+
/** Register a symbol that should be ignored */
335+
def addIgnoredUsage(sym: Symbol)(using Context): Unit =
336+
doNotRegister += sym
337+
if sym.is(Flags.Module) then
338+
doNotRegister += sym.moduleClass
339+
340+
/** Remove a symbol that shouldn't be ignored anymore */
341+
def removeIgnoredUsage(sym: Symbol)(using Context): Unit =
342+
doNotRegister -= sym
343+
if sym.is(Flags.Module) then
344+
doNotRegister -= sym.moduleClass
345+
307346

308347
/** Register an import */
309348
def registerImport(imp: tpd.Import)(using Context): Unit =
@@ -314,19 +353,19 @@ object CheckUnused:
314353
}
315354

316355
/** Register (or not) some `val` or `def` according to the context, scope and flags */
317-
def registerDef(valOrDef: tpd.ValOrDefDef)(using Context): Unit =
356+
def registerDef(memDef: tpd.MemberDef)(using Context): Unit =
318357
// register the annotations for usage
319-
registerUsedAnnotation(valOrDef.symbol)
320-
if !valOrDef.symbol.isUnusedAnnot then
321-
if valOrDef.symbol.is(Param) && !isSyntheticMainParam(valOrDef.symbol) && !valOrDef.symbol.ownerIsTrivial then
322-
if valOrDef.symbol.isOneOf(GivenOrImplicit) then
323-
implicitParamInScope += valOrDef
358+
registerUsedAnnotation(memDef.symbol)
359+
if !memDef.symbol.isUnusedAnnot then
360+
if memDef.symbol.is(Param) && !isSyntheticMainParam(memDef.symbol) && !memDef.symbol.ownerIsTrivial then
361+
if memDef.symbol.isOneOf(GivenOrImplicit) then
362+
implicitParamInScope += memDef
324363
else
325-
explicitParamInScope += valOrDef
364+
explicitParamInScope += memDef
326365
else if currScopeType.top == ScopeType.Local then
327-
localDefInScope += valOrDef
328-
else if currScopeType.top == ScopeType.Template && valOrDef.symbol.is(Private, butNot = SelfName) then
329-
privateDefInScope += valOrDef
366+
localDefInScope += memDef
367+
else if currScopeType.top == ScopeType.Template && memDef.symbol.is(Private, butNot = SelfName) then
368+
privateDefInScope += memDef
330369

331370
/** Register pattern variable */
332371
def registerPatVar(patvar: tpd.Bind)(using Context): Unit =

tests/neg-custom-args/fatal-warnings/i15503b.scala

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,43 @@ class Foo {
4747
def f2 = f1 // OK
4848
f2
4949
}
50+
51+
// ---- SCALA 2 tests ----
52+
53+
package foo.scala2.tests:
54+
class Outer {
55+
class Inner
56+
}
57+
58+
trait Locals {
59+
def f0 = {
60+
var x = 1 // error
61+
var y = 2 // OK
62+
y = 3
63+
y + y
64+
}
65+
def f1 = {
66+
val a = new Outer // OK
67+
val b = new Outer // error
68+
new a.Inner
69+
}
70+
def f2 = {
71+
var x = 100
72+
x
73+
}
74+
}
75+
76+
object Types {
77+
def l1() = {
78+
object HiObject { def f = this } // error
79+
class Hi { // error
80+
def f1: Hi = new Hi
81+
def f2(x: Hi) = x
82+
}
83+
class DingDongDoobie // error
84+
class Bippy // OK
85+
type Something = Bippy // OK
86+
type OtherThing = String // error
87+
(new Bippy): Something
88+
}
89+
}

0 commit comments

Comments
 (0)