@@ -29,6 +29,7 @@ import dotty.tools.dotc.core.Definitions
2929import dotty .tools .dotc .core .NameKinds .WildcardParamName
3030import dotty .tools .dotc .core .Symbols .Symbol
3131import dotty .tools .dotc .core .StdNames .nme
32+ import dotty .tools .dotc .util .Spans .Span
3233import scala .math .Ordering
3334
3435
@@ -362,16 +363,16 @@ object CheckUnused:
362363 * See the `isAccessibleAsIdent` extension method below in the file
363364 */
364365 private val usedInScope = MutStack (MutSet [(Symbol ,Boolean , Option [Name ], Boolean )]())
365- private val usedInPosition = MutSet [( SrcPos , Name )]()
366+ private val usedInPosition = MutMap .empty[ Name , MutSet [ Symbol ]]
366367 /* unused import collected during traversal */
367- private val unusedImport = MutSet [ImportSelector ]()
368+ private val unusedImport = new java.util. IdentityHashMap [ImportSelector , Unit ]
368369
369370 /* LOCAL DEF OR VAL / Private Def or Val / Pattern variables */
370- private val localDefInScope = MutSet [tpd.MemberDef ]()
371- private val privateDefInScope = MutSet [tpd.MemberDef ]()
372- private val explicitParamInScope = MutSet [tpd.MemberDef ]()
373- private val implicitParamInScope = MutSet [tpd.MemberDef ]()
374- private val patVarsInScope = MutSet [tpd.Bind ]()
371+ private val localDefInScope = MutList .empty [tpd.MemberDef ]
372+ private val privateDefInScope = MutList .empty [tpd.MemberDef ]
373+ private val explicitParamInScope = MutList .empty [tpd.MemberDef ]
374+ private val implicitParamInScope = MutList .empty [tpd.MemberDef ]
375+ private val patVarsInScope = MutList .empty [tpd.Bind ]
375376
376377 /** All variables sets*/
377378 private val setVars = MutSet [Symbol ]()
@@ -413,7 +414,8 @@ object CheckUnused:
413414 usedInScope.top += ((sym.companionModule, sym.isAccessibleAsIdent, name, isDerived))
414415 usedInScope.top += ((sym.companionClass, sym.isAccessibleAsIdent, name, isDerived))
415416 if sym.sourcePos.exists then
416- name.map(n => usedInPosition += ((sym.sourcePos, n)))
417+ for n <- name do
418+ usedInPosition.getOrElseUpdate(n, MutSet .empty) += sym
417419
418420 /** Register a symbol that should be ignored */
419421 def addIgnoredUsage (sym : Symbol )(using Context ): Unit =
@@ -431,9 +433,9 @@ object CheckUnused:
431433 if ! tpd.languageImport(imp.expr).nonEmpty && ! imp.isGeneratedByEnum && ! isTransparentAndInline(imp) then
432434 impInScope.top += imp
433435 if currScopeType.top != ScopeType .ReplWrapper then // #18383 Do not report top-level import's in the repl as unused
434- unusedImport ++= imp.selectors.filter { s =>
435- ! shouldSelectorBeReported(imp, s) && ! isImportExclusion(s) && ! isImportIgnored(imp, s)
436- }
436+ for s <- imp.selectors do
437+ if ! shouldSelectorBeReported(imp, s) && ! isImportExclusion(s) && ! isImportIgnored(imp, s) then
438+ unusedImport.put(s, ())
437439 end registerImport
438440
439441 /** Register (or not) some `val` or `def` according to the context, scope and flags */
@@ -488,11 +490,11 @@ object CheckUnused:
488490 // We keep wildcard symbol for the end as they have the least precedence
489491 false
490492 case Some (sel) =>
491- unusedImport -= sel
493+ unusedImport.remove( sel)
492494 true
493495 }
494496 if ! matchedExplicitImport && selWildCard.isDefined then
495- unusedImport -= selWildCard.get
497+ unusedImport.remove( selWildCard.get)
496498 true // a matching import exists so the symbol won't be kept for outer scope
497499 else
498500 matchedExplicitImport
@@ -517,56 +519,64 @@ object CheckUnused:
517519
518520 def getUnused (using Context ): UnusedResult =
519521 popScope()
522+
523+ def isUsedInPosition (name : Name , span : Span ): Boolean =
524+ usedInPosition.get(name) match
525+ case Some (syms) => syms.exists(sym => span.contains(sym.span))
526+ case None => false
527+
520528 val sortedImp =
521529 if ctx.settings.WunusedHas .imports || ctx.settings.WunusedHas .strictNoImplicitWarn then
522- unusedImport.map(d => UnusedSymbol (d.srcPos, d.name, WarnTypes .Imports )).toList
530+ import scala .jdk .CollectionConverters .*
531+ unusedImport.keySet().nn.iterator().nn.asScala
532+ .map(d => UnusedSymbol (d.srcPos, d.name, WarnTypes .Imports )).toList
523533 else
524534 Nil
525535 // Partition to extract unset local variables from usedLocalDefs
526536 val (usedLocalDefs, unusedLocalDefs) =
527537 if ctx.settings.WunusedHas .locals then
528- localDefInScope.partition(d => d.symbol.usedDefContains)
538+ localDefInScope.toList. partition(d => d.symbol.usedDefContains)
529539 else
530540 (Nil , Nil )
531541 val sortedLocalDefs =
532542 unusedLocalDefs
533- .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name} )
543+ .filterNot(d => isUsedInPosition(d.symbol. name, d.span) )
534544 .filterNot(d => containsSyntheticSuffix(d.symbol))
535- .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .LocalDefs )).toList
545+ .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .LocalDefs ))
536546 val unsetLocalDefs = usedLocalDefs.filter(isUnsetVarDef).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .UnsetLocals )).toList
537547
538548 val sortedExplicitParams =
539549 if ctx.settings.WunusedHas .explicits then
540- explicitParamInScope
550+ explicitParamInScope.toList
541551 .filterNot(d => d.symbol.usedDefContains)
542- .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name} )
552+ .filterNot(d => isUsedInPosition(d.symbol. name, d.span) )
543553 .filterNot(d => containsSyntheticSuffix(d.symbol))
544- .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .ExplicitParams )).toList
554+ .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .ExplicitParams ))
545555 else
546556 Nil
547557 val sortedImplicitParams =
548558 if ctx.settings.WunusedHas .implicits then
549- implicitParamInScope
559+ implicitParamInScope.toList
550560 .filterNot(d => d.symbol.usedDefContains)
551561 .filterNot(d => containsSyntheticSuffix(d.symbol))
552- .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .ImplicitParams )).toList
562+ .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .ImplicitParams ))
553563 else
554564 Nil
555565 // Partition to extract unset private variables from usedPrivates
556566 val (usedPrivates, unusedPrivates) =
557567 if ctx.settings.WunusedHas .privates then
558- privateDefInScope.partition(d => d.symbol.usedDefContains)
568+ privateDefInScope.toList. partition(d => d.symbol.usedDefContains)
559569 else
560570 (Nil , Nil )
561- val sortedPrivateDefs = unusedPrivates.filterNot(d => containsSyntheticSuffix(d.symbol)).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .PrivateMembers )).toList
562- val unsetPrivateDefs = usedPrivates.filter(isUnsetVarDef).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .UnsetPrivates )).toList
571+ val sortedPrivateDefs = unusedPrivates.filterNot(d => containsSyntheticSuffix(d.symbol)).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .PrivateMembers ))
572+ val unsetPrivateDefs = usedPrivates.filter(isUnsetVarDef).map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .UnsetPrivates ))
563573 val sortedPatVars =
564574 if ctx.settings.WunusedHas .patvars then
565- patVarsInScope
575+ patVarsInScope.toList
566576 .filterNot(d => d.symbol.usedDefContains)
567577 .filterNot(d => containsSyntheticSuffix(d.symbol))
568- .filterNot(d => usedInPosition.exists { case (pos, name) => d.span.contains(pos.span) && name == d.symbol.name} )
569- .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .PatVars )).toList
578+ .filterNot(d => isUsedInPosition(d.symbol. name, d.span) )
579+ .map(d => UnusedSymbol (d.namePos, d.name, WarnTypes .PatVars ))
570580 else
571581 Nil
572582 val warnings =
0 commit comments