@@ -29,6 +29,7 @@ import dotty.tools.dotc.core.Definitions
29
29
import dotty .tools .dotc .core .NameKinds .WildcardParamName
30
30
import dotty .tools .dotc .core .Symbols .Symbol
31
31
import dotty .tools .dotc .core .StdNames .nme
32
+ import dotty .tools .dotc .util .Spans .Span
32
33
import scala .math .Ordering
33
34
34
35
@@ -365,16 +366,16 @@ object CheckUnused:
365
366
* See the `isAccessibleAsIdent` extension method below in the file
366
367
*/
367
368
private val usedInScope = MutStack (MutSet [(Symbol ,Boolean , Option [Name ], Boolean )]())
368
- private val usedInPosition = MutSet [( SrcPos , Name )]()
369
+ private val usedInPosition = MutMap .empty[ Name , MutSet [ Symbol ]]
369
370
/* unused import collected during traversal */
370
- private val unusedImport = MutSet [ImportSelector ]()
371
+ private val unusedImport = new java.util. IdentityHashMap [ImportSelector , Unit ]
371
372
372
373
/* LOCAL DEF OR VAL / Private Def or Val / Pattern variables */
373
- private val localDefInScope = MutSet [tpd.MemberDef ]()
374
- private val privateDefInScope = MutSet [tpd.MemberDef ]()
375
- private val explicitParamInScope = MutSet [tpd.MemberDef ]()
376
- private val implicitParamInScope = MutSet [tpd.MemberDef ]()
377
- private val patVarsInScope = MutSet [tpd.Bind ]()
374
+ private val localDefInScope = MutList .empty [tpd.MemberDef ]
375
+ private val privateDefInScope = MutList .empty [tpd.MemberDef ]
376
+ private val explicitParamInScope = MutList .empty [tpd.MemberDef ]
377
+ private val implicitParamInScope = MutList .empty [tpd.MemberDef ]
378
+ private val patVarsInScope = MutList .empty [tpd.Bind ]
378
379
379
380
/** All variables sets*/
380
381
private val setVars = MutSet [Symbol ]()
@@ -416,7 +417,8 @@ object CheckUnused:
416
417
usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name, isDerived))
417
418
usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name, isDerived))
418
419
if sym.sourcePos.exists then
419
- name.map(n => usedInPosition += ((sym.sourcePos, n)))
420
+ for n <- name do
421
+ usedInPosition.getOrElseUpdate(n, MutSet .empty) += sym
420
422
421
423
/** Register a symbol that should be ignored */
422
424
def addIgnoredUsage (sym : Symbol )(using Context ): Unit =
@@ -434,9 +436,9 @@ object CheckUnused:
434
436
if ! tpd.languageImport(imp.expr).nonEmpty && ! imp.isGeneratedByEnum && ! isTransparentAndInline(imp) then
435
437
impInScope.top += imp
436
438
if currScopeType.top != ScopeType .ReplWrapper then // #18383 Do not report top-level import's in the repl as unused
437
- unusedImport ++= imp.selectors.filter { s =>
438
- ! shouldSelectorBeReported(imp, s) && ! isImportExclusion(s) && ! isImportIgnored(imp, s)
439
- }
439
+ for s <- imp.selectors do
440
+ if ! shouldSelectorBeReported(imp, s) && ! isImportExclusion(s) && ! isImportIgnored(imp, s) then
441
+ unusedImport.put(s, ())
440
442
end registerImport
441
443
442
444
/** Register (or not) some `val` or `def` according to the context, scope and flags */
@@ -491,11 +493,11 @@ object CheckUnused:
491
493
// We keep wildcard symbol for the end as they have the least precedence
492
494
false
493
495
case Some (sel) =>
494
- unusedImport -= sel
496
+ unusedImport.remove( sel)
495
497
true
496
498
}
497
499
if ! matchedExplicitImport && selWildCard.isDefined then
498
- unusedImport -= selWildCard.get
500
+ unusedImport.remove( selWildCard.get)
499
501
true // a matching import exists so the symbol won't be kept for outer scope
500
502
else
501
503
matchedExplicitImport
@@ -520,56 +522,64 @@ object CheckUnused:
520
522
521
523
def getUnused (using Context ): UnusedResult =
522
524
popScope()
525
+
526
+ def isUsedInPosition (name : Name , span : Span ): Boolean =
527
+ usedInPosition.get(name) match
528
+ case Some (syms) => syms.exists(sym => span.contains(sym.span))
529
+ case None => false
530
+
523
531
val sortedImp =
524
532
if ctx.settings.WunusedHas .imports || ctx.settings.WunusedHas .strictNoImplicitWarn then
525
- unusedImport.map(d => UnusedSymbol (d.srcPos, d.name, WarnTypes .Imports )).toList
533
+ import scala .jdk .CollectionConverters .*
534
+ unusedImport.keySet().nn.iterator().nn.asScala
535
+ .map(d => UnusedSymbol (d.srcPos, d.name, WarnTypes .Imports )).toList
526
536
else
527
537
Nil
528
538
// Partition to extract unset local variables from usedLocalDefs
529
539
val (usedLocalDefs, unusedLocalDefs) =
530
540
if ctx.settings.WunusedHas .locals then
531
- localDefInScope.partition(d => d.symbol.usedDefContains)
541
+ localDefInScope.toList. partition(d => d.symbol.usedDefContains)
532
542
else
533
543
(Nil , Nil )
534
544
val sortedLocalDefs =
535
545
unusedLocalDefs
536
- .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name} )
546
+ .filterNot(d => isUsedInPosition(d.symbol. name, d.span) )
537
547
.filterNot(d => containsSyntheticSuffix(d.symbol))
538
- .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .LocalDefs )).toList
548
+ .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .LocalDefs ))
539
549
val unsetLocalDefs = usedLocalDefs.filter(isUnsetVarDef).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .UnsetLocals )).toList
540
550
541
551
val sortedExplicitParams =
542
552
if ctx.settings.WunusedHas .explicits then
543
- explicitParamInScope
553
+ explicitParamInScope.toList
544
554
.filterNot(d => d.symbol.usedDefContains)
545
- .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name} )
555
+ .filterNot(d => isUsedInPosition(d.symbol. name, d.span) )
546
556
.filterNot(d => containsSyntheticSuffix(d.symbol))
547
- .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .ExplicitParams )).toList
557
+ .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .ExplicitParams ))
548
558
else
549
559
Nil
550
560
val sortedImplicitParams =
551
561
if ctx.settings.WunusedHas .implicits then
552
- implicitParamInScope
562
+ implicitParamInScope.toList
553
563
.filterNot(d => d.symbol.usedDefContains)
554
564
.filterNot(d => containsSyntheticSuffix(d.symbol))
555
- .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .ImplicitParams )).toList
565
+ .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .ImplicitParams ))
556
566
else
557
567
Nil
558
568
// Partition to extract unset private variables from usedPrivates
559
569
val (usedPrivates, unusedPrivates) =
560
570
if ctx.settings.WunusedHas .privates then
561
- privateDefInScope.partition(d => d.symbol.usedDefContains)
571
+ privateDefInScope.toList. partition(d => d.symbol.usedDefContains)
562
572
else
563
573
(Nil , Nil )
564
- val sortedPrivateDefs = unusedPrivates.filterNot(d => containsSyntheticSuffix(d.symbol)).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .PrivateMembers )).toList
565
- val unsetPrivateDefs = usedPrivates.filter(isUnsetVarDef).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .UnsetPrivates )).toList
574
+ val sortedPrivateDefs = unusedPrivates.filterNot(d => containsSyntheticSuffix(d.symbol)).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .PrivateMembers ))
575
+ val unsetPrivateDefs = usedPrivates.filter(isUnsetVarDef).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .UnsetPrivates ))
566
576
val sortedPatVars =
567
577
if ctx.settings.WunusedHas .patvars then
568
- patVarsInScope
578
+ patVarsInScope.toList
569
579
.filterNot(d => d.symbol.usedDefContains)
570
580
.filterNot(d => containsSyntheticSuffix(d.symbol))
571
- .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name} )
572
- .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .PatVars )).toList
581
+ .filterNot(d => isUsedInPosition(d.symbol. name, d.span) )
582
+ .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .PatVars ))
573
583
else
574
584
Nil
575
585
val warnings =
0 commit comments