Skip to content

Commit e6a12af

Browse files
authored
Merge pull request #546 from scala/backport-lts-3.3-23652
Backport "Add suppression if nowarn differs" to 3.3 LTS
2 parents d248ce3 + 4059d1c commit e6a12af

File tree

7 files changed

+257
-216
lines changed

7 files changed

+257
-216
lines changed

compiler/src/dotty/tools/dotc/Run.scala

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,21 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
9090
mySuspendedMessages.getOrElseUpdate(warning.pos.source, mutable.LinkedHashSet.empty) += warning
9191

9292
def nowarnAction(dia: Diagnostic): Action.Warning.type | Action.Verbose.type | Action.Silent.type =
93-
mySuppressions.getOrElse(dia.pos.source, Nil).find(_.matches(dia)) match {
94-
case Some(s) =>
93+
mySuppressions.get(dia.pos.source) match
94+
case Some(suppressions) =>
95+
val matching = suppressions.iterator.filter(_.matches(dia))
96+
if matching.hasNext then
97+
val s = matching.next()
98+
for other <- matching do
99+
if !other.used then
100+
other.markSuperseded() // superseded unless marked used later
95101
s.markUsed()
96-
if (s.verbose) Action.Verbose
102+
if s.verbose then Action.Verbose
97103
else Action.Silent
98-
case _ =>
104+
else
99105
Action.Warning
100-
}
106+
case none =>
107+
Action.Warning
101108

102109
def registerNowarn(annotPos: SourcePosition, range: Span)(conf: String, pos: SrcPos)(using Context): Unit =
103110
var verbose = false
@@ -116,12 +123,10 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
116123
.merge
117124
addSuppression:
118125
Suppression(annotPos, filters, range.start, range.end, verbose)
119-
.tap: sup =>
120-
if filters == List(MessageFilter.None) then sup.markUsed() // invalid suppressions, don't report as unused
121126

122127
def addSuppression(sup: Suppression): Unit =
123128
val suppressions = mySuppressions.getOrElseUpdate(sup.annotPos.source, ListBuffer.empty)
124-
if sup.start != sup.end && suppressions.forall(x => x.start != sup.start || x.end != sup.end) then
129+
if sup.start != sup.end then
125130
suppressions += sup
126131

127132
def reportSuspendedMessages(source: SourceFile)(using Context): Unit = {
@@ -132,18 +137,25 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
132137
mySuspendedMessages.remove(source).foreach(_.foreach(ctx.reporter.issueIfNotSuppressed))
133138
}
134139

135-
def runFinished(hasErrors: Boolean): Unit =
140+
def runFinished()(using Context): Unit =
141+
val hasErrors = ctx.reporter.hasErrors
136142
// report suspended messages (in case the run finished before typer)
137143
mySuspendedMessages.keysIterator.toList.foreach(reportSuspendedMessages)
138144
// report unused nowarns only if all all phases are done
139145
if !hasErrors && ctx.settings.WunusedHas.nowarn then
140146
for
141147
source <- mySuppressions.keysIterator.toList
142148
sups <- mySuppressions.remove(source)
143-
sup <- sups.reverse
144-
if !sup.used
145149
do
146-
report.warning("@nowarn annotation does not suppress any warnings", sup.annotPos)
150+
val suppressions = sups.reverse.toList
151+
for sup <- suppressions do
152+
if !sup.used
153+
&& !suppressions.exists(s => s.ne(sup) && s.used && s.annotPos == sup.annotPos) // duplicate
154+
&& sup.filters != List(MessageFilter.None) // invalid suppression, don't report as unused
155+
then
156+
val more = if sup.superseded then " but matches a diagnostic" else ""
157+
report.warning("@nowarn annotation does not suppress any warnings"+more, sup.annotPos)
158+
end suppressions
147159

148160
/** The compilation units currently being compiled, this may return different
149161
* results over time.
@@ -372,7 +384,7 @@ class Run(comp: Compiler, ictx: Context) extends ImplicitRunInfo with Constraint
372384
runPhases(allPhases = fusedPhases)(using runCtx)
373385
if (!ctx.reporter.hasErrors)
374386
Rewrites.writeBack()
375-
suppressions.runFinished(hasErrors = ctx.reporter.hasErrors)
387+
suppressions.runFinished()
376388
while (finalizeActions.nonEmpty && canProgress()) {
377389
val action = finalizeActions.remove(0)
378390
action()

compiler/src/dotty/tools/dotc/reporting/WConf.scala

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import dotty.tools.dotc.interfaces.SourceFile
1010
import dotty.tools.dotc.reporting.MessageFilter.SourcePattern
1111

1212
import java.util.regex.PatternSyntaxException
13+
import scala.PartialFunction.cond
1314
import scala.annotation.internal.sharable
1415
import scala.util.matching.Regex
1516

@@ -136,13 +137,20 @@ object WConf:
136137
if (parseErrorss.nonEmpty) Left(parseErrorss.flatten)
137138
else Right(WConf(configs))
138139

139-
class Suppression(val annotPos: SourcePosition, filters: List[MessageFilter], val start: Int, val end: Int, val verbose: Boolean):
140-
private[this] var _used = false
141-
def used: Boolean = _used
140+
class Suppression(val annotPos: SourcePosition, val filters: List[MessageFilter], val start: Int, val end: Int, val verbose: Boolean):
141+
inline def unusedState = 0
142+
inline def usedState = 1
143+
inline def supersededState = 2
144+
private var _used = unusedState
145+
def used: Boolean = _used == usedState
146+
def superseded: Boolean = _used == supersededState
142147
def markUsed(): Unit =
143-
_used = true
148+
_used = usedState
149+
def markSuperseded(): Unit =
150+
_used = supersededState
144151
def matches(dia: Diagnostic): Boolean =
145152
val pos = dia.pos
146153
pos.exists && start <= pos.start && pos.end <= end && filters.forall(_.matches(dia))
147154

148155
override def toString = s"Suppress in ${annotPos.source} $start..$end [${filters.mkString(", ")}]"
156+
end Suppression

tests/neg/nowarn.check

Lines changed: 0 additions & 110 deletions
This file was deleted.

tests/neg/nowarn.scala

Lines changed: 0 additions & 89 deletions
This file was deleted.

tests/warn/i23651.scala

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//> using options -deprecation -Wunused:nowarn
2+
3+
import scala.annotation.nowarn
4+
5+
@deprecated
6+
class A
7+
8+
@deprecated
9+
class B
10+
11+
@nowarn("msg=trait C is deprecated") // warn
12+
// @nowarn annotation does not suppress any warnings
13+
@nowarn("msg=class A is deprecated")
14+
@nowarn("cat=deprecation&msg=class A is deprecated") // warn
15+
// @nowarn annotation does not suppress any warnings but matches a diagnostic
16+
@nowarn("cat=deprecation&msg=class B is deprecated")
17+
trait C1:
18+
def a: A
19+
def b: B
20+
21+
@nowarn("cat=deprecation&msg=class B is deprecated")
22+
@nowarn("cat=deprecation&msg=class B is deprecated") // warn
23+
// @nowarn annotation does not suppress any warnings but matches a diagnostic
24+
@nowarn("cat=deprecation&msg=class A is deprecated")
25+
trait C2:
26+
def a: A
27+
def b: B

0 commit comments

Comments
 (0)