Skip to content

Commit f6040ad

Browse files
committed
Make CheckUnused run both after Typer and Inlining
1 parent d577300 commit f6040ad

File tree

2 files changed

+63
-32
lines changed

2 files changed

+63
-32
lines changed

compiler/src/dotty/tools/dotc/Compiler.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class Compiler {
3535
protected def frontendPhases: List[List[Phase]] =
3636
List(new Parser) :: // Compiler frontend: scanner, parser
3737
List(new TyperPhase) :: // Compiler frontend: namer, typer
38-
List(new CheckUnused) :: // Check for unused elements
38+
List(CheckUnused.PostTyper) :: // Check for unused elements
3939
List(new YCheckPositions) :: // YCheck positions
4040
List(new sbt.ExtractDependencies) :: // Sends information on classes' dependencies to sbt via callbacks
4141
List(new semanticdb.ExtractSemanticDB) :: // Extract info into .semanticdb files
@@ -50,6 +50,7 @@ class Compiler {
5050
List(new Pickler) :: // Generate TASTY info
5151
List(new Inlining) :: // Inline and execute macros
5252
List(new PostInlining) :: // Add mirror support for inlined code
53+
List(CheckUnused.PostInlining) :: // Check for unused elements
5354
List(new Staging) :: // Check staging levels and heal staged types
5455
List(new Splicing) :: // Replace level 1 splices with holes
5556
List(new PickleQuotes) :: // Turn quoted trees into explicit run-time data structures

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

Lines changed: 61 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,15 @@ import dotty.tools.dotc.core.StdNames.nme
3333
* Basically, it gathers definition/imports and their usage. If a
3434
* definition/imports does not have any usage, then it is reported.
3535
*/
36-
class CheckUnused extends MiniPhase:
37-
import CheckUnused.UnusedData
38-
39-
/**
40-
* The key used to retrieve the "unused entity" analysis metadata,
41-
* from the compilation `Context`
42-
*/
43-
private val _key = Property.Key[UnusedData]
36+
class CheckUnused private (phaseMode: CheckUnused.PhaseMode, suffix: String, _key: Property.Key[CheckUnused.UnusedData]) extends MiniPhase:
37+
import CheckUnused.*
38+
import UnusedData.*
4439

4540
private def unusedDataApply[U](f: UnusedData => U)(using Context): Context =
4641
ctx.property(_key).foreach(f)
4742
ctx
48-
private def getUnusedData(using Context): Option[UnusedData] =
49-
ctx.property(_key)
5043

51-
override def phaseName: String = CheckUnused.phaseName
44+
override def phaseName: String = CheckUnused.phaseNamePrefix + suffix
5245

5346
override def description: String = CheckUnused.description
5447

@@ -60,13 +53,21 @@ class CheckUnused extends MiniPhase:
6053

6154
override def prepareForUnit(tree: tpd.Tree)(using Context): Context =
6255
val data = UnusedData()
56+
tree.getAttachment(_key).foreach(oldData =>
57+
data.unusedAggregate = oldData.unusedAggregate
58+
)
6359
val fresh = ctx.fresh.setProperty(_key, data)
60+
tree.putAttachment(_key, data)
6461
fresh
6562

6663
// ========== END + REPORTING ==========
6764

6865
override def transformUnit(tree: tpd.Tree)(using Context): tpd.Tree =
69-
unusedDataApply(ud => reportUnused(ud.getUnused))
66+
unusedDataApply { ud =>
67+
aggregateUnused(ud, ud.getUnused)
68+
if(phaseMode == PhaseMode.Report) then
69+
ud.unusedAggregate.foreach(reportUnused)
70+
}
7071
tree
7172

7273
// ========== MiniPhase Prepare ==========
@@ -252,31 +253,45 @@ class CheckUnused extends MiniPhase:
252253
private def traverseAnnotations(sym: Symbol)(using Context): Unit =
253254
sym.denot.annotations.foreach(annot => traverser.traverse(annot.tree))
254255

256+
private def aggregateUnused(data: UnusedData, res: UnusedData.UnusedResult)(using Context): Unit =
257+
data.unusedAggregate match {
258+
case None =>
259+
data.unusedAggregate = Some(res)
260+
case Some(prevUnused) =>
261+
val intersection = res.warnings.filter(sym => prevUnused.warnings.contains(sym))
262+
data.unusedAggregate = Some(UnusedResult(intersection))
263+
}
264+
265+
266+
255267
/** Do the actual reporting given the result of the anaylsis */
256268
private def reportUnused(res: UnusedData.UnusedResult)(using Context): Unit =
257-
import CheckUnused.WarnTypes
258269
res.warnings.foreach { s =>
259270
s match
260-
case (t, WarnTypes.Imports) =>
271+
case UnusedSymbol(t, _, WarnTypes.Imports) =>
261272
report.warning(s"unused import", t)
262-
case (t, WarnTypes.LocalDefs) =>
273+
case UnusedSymbol(t, _, WarnTypes.LocalDefs) =>
263274
report.warning(s"unused local definition", t)
264-
case (t, WarnTypes.ExplicitParams) =>
275+
case UnusedSymbol(t, _, WarnTypes.ExplicitParams) =>
265276
report.warning(s"unused explicit parameter", t)
266-
case (t, WarnTypes.ImplicitParams) =>
277+
case UnusedSymbol(t, _, WarnTypes.ImplicitParams) =>
267278
report.warning(s"unused implicit parameter", t)
268-
case (t, WarnTypes.PrivateMembers) =>
279+
case UnusedSymbol(t, _, WarnTypes.PrivateMembers) =>
269280
report.warning(s"unused private member", t)
270-
case (t, WarnTypes.PatVars) =>
281+
case UnusedSymbol(t, _, WarnTypes.PatVars) =>
271282
report.warning(s"unused pattern variable", t)
272283
}
273284

274285
end CheckUnused
275286

276287
object CheckUnused:
277-
val phaseName: String = "checkUnused"
288+
val phaseNamePrefix: String = "checkUnused"
278289
val description: String = "check for unused elements"
279290

291+
enum PhaseMode:
292+
case Aggregate
293+
case Report
294+
280295
private enum WarnTypes:
281296
case Imports
282297
case LocalDefs
@@ -285,20 +300,30 @@ object CheckUnused:
285300
case PrivateMembers
286301
case PatVars
287302

303+
/**
304+
* The key used to retrieve the "unused entity" analysis metadata,
305+
* from the compilation `Context`
306+
*/
307+
private val _key = Property.StickyKey[UnusedData]
308+
309+
val PostTyper = new CheckUnused(PhaseMode.Aggregate, "PostTyper", _key)
310+
val PostInlining = new CheckUnused(PhaseMode.Report, "PostInlining", _key)
311+
288312
/**
289313
* A stateful class gathering the infos on :
290314
* - imports
291315
* - definitions
292316
* - usage
293317
*/
294318
private class UnusedData:
295-
import dotty.tools.dotc.transform.CheckUnused.UnusedData.UnusedResult
296319
import collection.mutable.{Set => MutSet, Map => MutMap, Stack => MutStack}
297-
import UnusedData.ScopeType
320+
import UnusedData.*
298321

299322
/** The current scope during the tree traversal */
300323
var currScopeType: MutStack[ScopeType] = MutStack(ScopeType.Other)
301324

325+
var unusedAggregate: Option[UnusedResult] = None
326+
302327
/* IMPORTS */
303328
private val impInScope = MutStack(MutSet[tpd.Import]())
304329
/**
@@ -452,12 +477,13 @@ object CheckUnused:
452477
*
453478
* The given `List` is sorted by line and then column of the position
454479
*/
480+
455481
def getUnused(using Context): UnusedResult =
456482
popScope()
457483

458484
val sortedImp =
459485
if ctx.settings.WunusedHas.imports || ctx.settings.WunusedHas.strictNoImplicitWarn then
460-
unusedImport.map(d => d.srcPos -> WarnTypes.Imports).toList
486+
unusedImport.map(d => UnusedSymbol(d.srcPos, d.name, WarnTypes.Imports)).toList
461487
else
462488
Nil
463489
val sortedLocalDefs =
@@ -466,31 +492,31 @@ object CheckUnused:
466492
.filterNot(d => d.symbol.usedDefContains)
467493
.filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name})
468494
.filterNot(d => containsSyntheticSuffix(d.symbol))
469-
.map(d => d.namePos -> WarnTypes.LocalDefs).toList
495+
.map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.LocalDefs)).toList
470496
else
471497
Nil
472498
val sortedExplicitParams =
473499
if ctx.settings.WunusedHas.explicits then
474500
explicitParamInScope
475501
.filterNot(d => d.symbol.usedDefContains)
476502
.filterNot(d => containsSyntheticSuffix(d.symbol))
477-
.map(d => d.namePos -> WarnTypes.ExplicitParams).toList
503+
.map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.ExplicitParams)).toList
478504
else
479505
Nil
480506
val sortedImplicitParams =
481507
if ctx.settings.WunusedHas.implicits then
482508
implicitParamInScope
483509
.filterNot(d => d.symbol.usedDefContains)
484510
.filterNot(d => containsSyntheticSuffix(d.symbol))
485-
.map(d => d.namePos -> WarnTypes.ImplicitParams).toList
511+
.map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.ImplicitParams)).toList
486512
else
487513
Nil
488514
val sortedPrivateDefs =
489515
if ctx.settings.WunusedHas.privates then
490516
privateDefInScope
491517
.filterNot(d => d.symbol.usedDefContains)
492518
.filterNot(d => containsSyntheticSuffix(d.symbol))
493-
.map(d => d.namePos -> WarnTypes.PrivateMembers).toList
519+
.map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.PrivateMembers)).toList
494520
else
495521
Nil
496522
val sortedPatVars =
@@ -499,14 +525,14 @@ object CheckUnused:
499525
.filterNot(d => d.symbol.usedDefContains)
500526
.filterNot(d => containsSyntheticSuffix(d.symbol))
501527
.filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name})
502-
.map(d => d.namePos -> WarnTypes.PatVars).toList
528+
.map(d => UnusedSymbol(d.namePos, d.name, WarnTypes.PatVars)).toList
503529
else
504530
Nil
505531
val warnings = List(sortedImp, sortedLocalDefs, sortedExplicitParams, sortedImplicitParams, sortedPrivateDefs, sortedPatVars).flatten.sortBy { s =>
506-
val pos = s._1.sourcePos
532+
val pos = s.pos.sourcePos
507533
(pos.line, pos.column)
508534
}
509-
UnusedResult(warnings, Nil)
535+
UnusedResult(warnings)
510536
end getUnused
511537
//============================ HELPERS ====================================
512538

@@ -703,7 +729,11 @@ object CheckUnused:
703729
case _:tpd.Block => Local
704730
case _ => Other
705731

732+
case class UnusedSymbol(pos: SrcPos, name: Name, warnType: WarnTypes)
706733
/** A container for the results of the used elements analysis */
707-
case class UnusedResult(warnings: List[(dotty.tools.dotc.util.SrcPos, WarnTypes)], usedImports: List[(tpd.Import, untpd.ImportSelector)])
734+
case class UnusedResult(warnings: List[UnusedSymbol])
735+
object UnusedResult:
736+
val Empty = UnusedResult(Nil)
737+
708738
end CheckUnused
709739

0 commit comments

Comments
 (0)