@@ -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
274285end CheckUnused
275286
276287object 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+
708738end CheckUnused
709739
0 commit comments