From 1bf2dfab6bd14d429ea788633d6409df7f229d59 Mon Sep 17 00:00:00 2001 From: Som Snytt Date: Wed, 15 Jan 2025 14:31:52 -0800 Subject: [PATCH] Add Suppression only once for (start, end), ignore if start==end --- compiler/src/dotty/tools/dotc/Run.scala | 18 +++++++++------- .../dotty/tools/dotc/reporting/WConf.scala | 2 +- tests/warn/i18341.scala | 21 +++++++++++++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 tests/warn/i18341.scala diff --git a/compiler/src/dotty/tools/dotc/Run.scala b/compiler/src/dotty/tools/dotc/Run.scala index 50fd668c7696..e505ace061a4 100644 --- a/compiler/src/dotty/tools/dotc/Run.scala +++ b/compiler/src/dotty/tools/dotc/Run.scala @@ -30,7 +30,7 @@ import StdNames.nme import java.io.{BufferedWriter, OutputStreamWriter} import java.nio.charset.StandardCharsets -import scala.collection.mutable +import scala.collection.mutable, mutable.ListBuffer import scala.util.control.NonFatal import scala.io.Codec @@ -69,7 +69,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint private var myFiles: Set[AbstractFile] = uninitialized // `@nowarn` annotations by source file, populated during typer - private val mySuppressions: mutable.LinkedHashMap[SourceFile, mutable.ListBuffer[Suppression]] = mutable.LinkedHashMap.empty + private val mySuppressions: mutable.LinkedHashMap[SourceFile, ListBuffer[Suppression]] = mutable.LinkedHashMap.empty // source files whose `@nowarn` annotations are processed private val mySuppressionsComplete: mutable.Set[SourceFile] = mutable.Set.empty // warnings issued before a source file's `@nowarn` annotations are processed, suspended so that `@nowarn` can filter them @@ -99,8 +99,9 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint } def addSuppression(sup: Suppression): Unit = - val source = sup.annotPos.source - mySuppressions.getOrElseUpdate(source, mutable.ListBuffer.empty) += sup + val suppressions = mySuppressions.getOrElseUpdate(sup.annotPos.source, ListBuffer.empty) + if sup.start != sup.end && suppressions.forall(x => x.start != sup.start || x.end != sup.end) then + suppressions += sup def reportSuspendedMessages(source: SourceFile)(using Context): Unit = { // sort suppressions. they are not added in any particular order because of lazy type completion @@ -115,11 +116,12 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint mySuspendedMessages.keysIterator.toList.foreach(reportSuspendedMessages) // report unused nowarns only if all all phases are done if !hasErrors && ctx.settings.WunusedHas.nowarn then - for { + for source <- mySuppressions.keysIterator.toList sups <- mySuppressions.remove(source) sup <- sups.reverse - } if (!sup.used) + if !sup.used + do report.warning("@nowarn annotation does not suppress any warnings", sup.annotPos) /** The compilation units currently being compiled, this may return different @@ -130,7 +132,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint private def units_=(us: List[CompilationUnit]): Unit = myUnits = us - var suspendedUnits: mutable.ListBuffer[CompilationUnit] = mutable.ListBuffer() + var suspendedUnits: ListBuffer[CompilationUnit] = ListBuffer.empty var suspendedHints: mutable.Map[CompilationUnit, (String, Boolean)] = mutable.HashMap() /** Were any units suspended in the typer phase? if so then pipeline tasty can not complete. */ @@ -172,7 +174,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint val staticRefs = util.EqHashMap[Name, Denotation](initialCapacity = 1024) /** Actions that need to be performed at the end of the current compilation run */ - private var finalizeActions = mutable.ListBuffer[() => Unit]() + private var finalizeActions = ListBuffer.empty[() => Unit] private var _progress: Progress | Null = null // Set if progress reporting is enabled diff --git a/compiler/src/dotty/tools/dotc/reporting/WConf.scala b/compiler/src/dotty/tools/dotc/reporting/WConf.scala index 1896e5269d6c..4ca62a8ebe3d 100644 --- a/compiler/src/dotty/tools/dotc/reporting/WConf.scala +++ b/compiler/src/dotty/tools/dotc/reporting/WConf.scala @@ -134,7 +134,7 @@ object WConf: if (parseErrorss.nonEmpty) Left(parseErrorss.flatten) else Right(WConf(configs)) -class Suppression(val annotPos: SourcePosition, filters: List[MessageFilter], val start: Int, end: Int, val verbose: Boolean): +class Suppression(val annotPos: SourcePosition, filters: List[MessageFilter], val start: Int, val end: Int, val verbose: Boolean): private var _used = false def used: Boolean = _used def markUsed(): Unit = { _used = true } diff --git a/tests/warn/i18341.scala b/tests/warn/i18341.scala new file mode 100644 index 000000000000..63b725df000f --- /dev/null +++ b/tests/warn/i18341.scala @@ -0,0 +1,21 @@ + +//> using options -Wunused:params,nowarn + +import annotation.* + +class B(@nowarn useless: Int) + +class C(@nowarn("msg=unused") useless: Int) + +class D(useless: Int) // warn + +class E(@nowarn useful: Int): // warn + def e = useful * 10 // 10x useful + +class X: + def extensionInCompanion: String = ??? +@nowarn // extensionInCompanion +object X: + implicit def companionConversion(x: X): B = ??? + + extension (x: X) def extensionInCompanion: String = ???