@@ -16,7 +16,7 @@ import dotty.tools.dotc.core.Types.{AnnotatedType, ClassInfo, ConstantType, Name
1616import dotty .tools .dotc .core .Flags
1717import dotty .tools .dotc .core .Names .{Name , TermName , termName }
1818import dotty .tools .dotc .core .NameOps .isReplWrapperName
19- import dotty .tools .dotc .core .NameKinds .WildcardParamName
19+ import dotty .tools .dotc .core .NameKinds .{ ContextFunctionParamName , WildcardParamName }
2020import dotty .tools .dotc .core .Symbols .{NoSymbol , Symbol , defn , isDeprecated }
2121import dotty .tools .dotc .report
2222import dotty .tools .dotc .reporting .{Message , UnusedSymbol as UnusedSymbolMessage }
@@ -517,13 +517,25 @@ object CheckUnused:
517517 warnings.addOne(UnusedSymbol (d.namePos, d.name, WarnTypes .LocalDefs ))
518518
519519 if ctx.settings.WunusedHas .explicits then
520+ def forgiven (sym : Symbol ) =
521+ containsSyntheticSuffix(sym)
522+ || sym.owner.hasAnnotation(defn.UnusedAnnot )
523+ || sym.info.isSingleton
520524 for d <- explicitParamInScope do
521- if ! d.symbol.usedDefContains && ! isUsedInPosition(d.symbol.name, d.span) && ! containsSyntheticSuffix (d.symbol) then
525+ if ! d.symbol.usedDefContains && ! isUsedInPosition(d.symbol.name, d.span) && ! forgiven (d.symbol) then
522526 warnings.addOne(UnusedSymbol (d.namePos, d.name, WarnTypes .ExplicitParams ))
523527
524528 if ctx.settings.WunusedHas .implicits then
529+ def forgiven (sym : Symbol ) =
530+ val dd = defn
531+ sym.name.is(ContextFunctionParamName )
532+ || sym.owner.hasAnnotation(defn.UnusedAnnot )
533+ || sym.info.typeSymbol.match
534+ case dd.DummyImplicitClass | dd.SubTypeClass | dd.SameTypeClass => true
535+ case _ => false
536+ || sym.info.isSingleton
525537 for d <- implicitParamInScope do
526- if ! d.symbol.usedDefContains && ! containsSyntheticSuffix (d.symbol) then
538+ if ! d.symbol.usedDefContains && ! forgiven (d.symbol) then
527539 warnings.addOne(UnusedSymbol (d.namePos, d.name, WarnTypes .ImplicitParams ))
528540
529541 // Partition to extract unset private variables from usedPrivates
@@ -556,7 +568,9 @@ object CheckUnused:
556568 /** Heuristic to detect synthetic suffixes in names of symbols.
557569 */
558570 private def containsSyntheticSuffix (symbol : Symbol )(using Context ): Boolean =
559- symbol.name.mangledString.contains(" $" )
571+ val mangled = symbol.name.mangledString
572+ val index = mangled.indexOf('$' )
573+ index >= 0 && ! (index == mangled.length - 1 && symbol.is(Module ))
560574
561575 /**
562576 * Is the constructor of synthetic package object
@@ -659,8 +673,7 @@ object CheckUnused:
659673 owner.isPrimaryConstructor ||
660674 owner.isDeprecated ||
661675 owner.isAllOf(Synthetic | PrivateLocal ) ||
662- owner.is(Accessor ) ||
663- owner.isOverridden
676+ owner.is(Accessor )
664677 }
665678
666679 private def usedDefContains (using Context ): Boolean =
@@ -669,9 +682,10 @@ object CheckUnused:
669682 private def everySymbol (using Context ): List [Symbol ] =
670683 List (sym, sym.companionClass, sym.companionModule, sym.moduleClass).filter(_.exists)
671684
672- /** A function is overridden. Either has `override flags` or parent has a matching member (type and name) */
685+ /** A function is overridden. Either has `override flags` or parent has a matching member (type and name)
673686 private def isOverridden(using Context): Boolean =
674687 sym.is(Flags.Override) || (sym.exists && sym.owner.thisType.parents.exists(p => sym.matchingMember(p).exists))
688+ */
675689
676690 end extension
677691
@@ -688,7 +702,7 @@ object CheckUnused:
688702 case ConstantType (_) => true
689703 case tp : TermRef =>
690704 // Detect Scala 2 SingleType
691- tp.underlying.classSymbol.is(Flags . Module )
705+ tp.underlying.classSymbol.is(Module )
692706 case _ =>
693707 false
694708 def registerTrivial (using Context ): Unit =
0 commit comments