Skip to content

Add suppression if nowarn differs #23652

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 25 additions & 13 deletions compiler/src/dotty/tools/dotc/Run.scala
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,21 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
mySuspendedMessages.getOrElseUpdate(warning.pos.source, mutable.LinkedHashSet.empty) += warning

def nowarnAction(dia: Diagnostic): Action.Warning.type | Action.Verbose.type | Action.Silent.type =
mySuppressions.getOrElse(dia.pos.source, Nil).find(_.matches(dia)) match {
case Some(s) =>
mySuppressions.get(dia.pos.source) match
case Some(suppressions) =>
val matching = suppressions.iterator.filter(_.matches(dia))
if matching.hasNext then
val s = matching.next()
for other <- matching do
if !other.used then
other.markSuperseded() // superseded unless marked used later
s.markUsed()
if (s.verbose) Action.Verbose
if s.verbose then Action.Verbose
else Action.Silent
case _ =>
else
Action.Warning
}
case none =>
Action.Warning

def registerNowarn(annotPos: SourcePosition, range: Span)(conf: String, pos: SrcPos)(using Context): Unit =
var verbose = false
Expand All @@ -118,12 +125,10 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
.merge
addSuppression:
Suppression(annotPos, filters, range.start, range.end, verbose)
.tap: sup =>
if filters == List(MessageFilter.None) then sup.markUsed() // invalid suppressions, don't report as unused

def addSuppression(sup: Suppression): Unit =
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
if sup.start != sup.end then
suppressions += sup

def reportSuspendedMessages(source: SourceFile)(using Context): Unit = {
Expand All @@ -134,18 +139,25 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
mySuspendedMessages.remove(source).foreach(_.foreach(ctx.reporter.issueIfNotSuppressed))
}

def runFinished(hasErrors: Boolean): Unit =
def runFinished()(using Context): Unit =
val hasErrors = ctx.reporter.hasErrors
// report suspended messages (in case the run finished before typer)
mySuspendedMessages.keysIterator.toList.foreach(reportSuspendedMessages)
// report unused nowarns only if all all phases are done
if !hasErrors && ctx.settings.WunusedHas.nowarn then
for
source <- mySuppressions.keysIterator.toList
sups <- mySuppressions.remove(source)
sup <- sups.reverse
if !sup.used
do
report.warning("@nowarn annotation does not suppress any warnings", sup.annotPos)
val suppressions = sups.reverse.toList
for sup <- suppressions do
if !sup.used
&& !suppressions.exists(s => s.ne(sup) && s.used && s.annotPos == sup.annotPos) // duplicate
&& sup.filters != List(MessageFilter.None) // invalid suppression, don't report as unused
then
val more = if sup.superseded then " but matches a diagnostic" else ""
report.warning("@nowarn annotation does not suppress any warnings"+more, sup.annotPos)
end suppressions

/** The compilation units currently being compiled, this may return different
* results over time.
Expand Down Expand Up @@ -411,7 +423,7 @@ extends ImplicitRunInfo, ConstraintRunInfo, cc.CaptureRunInfo {
ctx.reporter.finalizeReporting()
if (!ctx.reporter.hasErrors)
Rewrites.writeBack()
suppressions.runFinished(hasErrors = ctx.reporter.hasErrors)
suppressions.runFinished()
while (finalizeActions.nonEmpty && canProgress()) {
val action = finalizeActions.remove(0)
action()
Expand Down
16 changes: 12 additions & 4 deletions compiler/src/dotty/tools/dotc/reporting/WConf.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import dotty.tools.dotc.interfaces.SourceFile
import dotty.tools.dotc.reporting.MessageFilter.SourcePattern

import java.util.regex.PatternSyntaxException
import scala.PartialFunction.cond
import scala.annotation.internal.sharable
import scala.util.matching.Regex

Expand Down Expand Up @@ -136,13 +137,20 @@ object WConf:
if (parseErrorss.nonEmpty) Left(parseErrorss.flatten)
else Right(WConf(configs))

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
class Suppression(val annotPos: SourcePosition, val filters: List[MessageFilter], val start: Int, val end: Int, val verbose: Boolean):
inline def unusedState = 0
inline def usedState = 1
inline def supersededState = 2
private var _used = unusedState
def used: Boolean = _used == usedState
def superseded: Boolean = _used == supersededState
def markUsed(): Unit =
_used = true
_used = usedState
def markSuperseded(): Unit =
_used = supersededState
def matches(dia: Diagnostic): Boolean =
val pos = dia.pos
pos.exists && start <= pos.start && pos.end <= end && filters.forall(_.matches(dia))

override def toString = s"Suppress in ${annotPos.source} $start..$end [${filters.mkString(", ")}]"
end Suppression
110 changes: 0 additions & 110 deletions tests/neg/nowarn.check

This file was deleted.

89 changes: 0 additions & 89 deletions tests/neg/nowarn.scala

This file was deleted.

27 changes: 27 additions & 0 deletions tests/warn/i23651.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//> using options -deprecation -Wunused:nowarn

import scala.annotation.nowarn

@deprecated
class A

@deprecated
class B

@nowarn("msg=trait C is deprecated") // warn
// @nowarn annotation does not suppress any warnings
@nowarn("msg=class A is deprecated")
@nowarn("cat=deprecation&msg=class A is deprecated") // warn
// @nowarn annotation does not suppress any warnings but matches a diagnostic
@nowarn("cat=deprecation&msg=class B is deprecated")
trait C1:
def a: A
def b: B

@nowarn("cat=deprecation&msg=class B is deprecated")
@nowarn("cat=deprecation&msg=class B is deprecated") // warn
// @nowarn annotation does not suppress any warnings but matches a diagnostic
@nowarn("cat=deprecation&msg=class A is deprecated")
trait C2:
def a: A
def b: B
Loading
Loading