Skip to content

Commit 1604e77

Browse files
authored
Add origin filter to WConf, DeprecationWarning (#21404)
The `origin` parameter to `deprecationWarning` is optional; the parameter to `DeprecationWarning` is not. The `origin` of a deprecation is simply the deprecated symbol. The full name is matched by the regex specified by `-Wconf`. The other important use case is the `origin` of an unused element, in particular, the selector which causes an "unused import" warning. That use case will be supported in a follow-up PR, and should work as in Scala 2. Fixes #17538
2 parents 5101daf + 929e7eb commit 1604e77

12 files changed

+93
-30
lines changed

Diff for: compiler/src/dotty/tools/dotc/config/CompilerCommand.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ abstract class CompilerCommand extends CliCommand:
99

1010
final def helpMsg(using settings: ConcreteSettings)(using SettingsState, Context): String =
1111
settings.allSettings.find(isHelping) match
12-
case Some(s) => availableOptionsMsg(_ == s, showArgFileMsg = false)
12+
case Some(s @ settings.language) => availableOptionsMsg(_ == s, showArgFileMsg = false)
13+
case Some(s) => s.description
1314
case _ =>
1415
if (settings.help.value) usageMessage
1516
else if (settings.Vhelp.value) vusageMessage

Diff for: compiler/src/dotty/tools/dotc/config/ScalaSettings.scala

+5-1
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ private sealed trait WarningSettings:
233233
"patterns",
234234
default = List(),
235235
descr =
236-
s"""Configure compiler warnings.
236+
raw"""Configure compiler warnings.
237237
|Syntax: -Wconf:<filters>:<action>,<filters>:<action>,...
238238
|multiple <filters> are combined with &, i.e., <filter>&...&<filter>
239239
|
@@ -254,6 +254,9 @@ private sealed trait WarningSettings:
254254
| - Source location: src=regex
255255
| The regex is evaluated against the full source path.
256256
|
257+
| - Origin of warning: origin=regex
258+
| The regex must match the full name (`package.Class.method`) of the deprecated entity.
259+
|
257260
|In verbose warning mode the compiler prints matching filters for warnings.
258261
|Verbose mode can be enabled globally using `-Wconf:any:verbose`, or locally
259262
|using the @nowarn annotation (example: `@nowarn("v") def test = try 1`).
@@ -273,6 +276,7 @@ private sealed trait WarningSettings:
273276
|Examples:
274277
| - change every warning into an error: -Wconf:any:error
275278
| - silence deprecations: -Wconf:cat=deprecation:s
279+
| - silence a deprecation: -Wconf:origin=java\.lang\.Thread\.getId:s
276280
| - silence warnings in src_managed directory: -Wconf:src=src_managed/.*:s
277281
|
278282
|Note: on the command-line you might need to quote configurations containing `*` or `&`

Diff for: compiler/src/dotty/tools/dotc/report.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ object report:
2323
private def issueWarning(warning: Warning)(using Context): Unit =
2424
ctx.reporter.report(warning)
2525

26-
def deprecationWarning(msg: Message, pos: SrcPos)(using Context): Unit =
27-
issueWarning(new DeprecationWarning(msg, pos.sourcePos))
26+
def deprecationWarning(msg: Message, pos: SrcPos, origin: String = "")(using Context): Unit =
27+
issueWarning(new DeprecationWarning(msg, pos.sourcePos, origin))
2828

2929
def migrationWarning(msg: Message, pos: SrcPos)(using Context): Unit =
3030
issueWarning(new MigrationWarning(msg, pos.sourcePos))

Diff for: compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala

+2-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ object Diagnostic:
7575

7676
class DeprecationWarning(
7777
msg: Message,
78-
pos: SourcePosition
78+
pos: SourcePosition,
79+
val origin: String
7980
) extends ConditionalWarning(msg, pos) {
8081
def enablingOption(using Context): Setting[Boolean] = ctx.settings.deprecation
8182
}

Diff for: compiler/src/dotty/tools/dotc/reporting/MessageRendering.scala

+22-17
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import util.{ SourcePosition, NoSourcePosition }
1515
import util.Chars.{ LF, CR, FF, SU }
1616
import scala.annotation.switch
1717

18-
import scala.collection.mutable
18+
import scala.collection.mutable.StringBuilder
1919

2020
trait MessageRendering {
2121
import Highlight.*
@@ -209,22 +209,27 @@ trait MessageRendering {
209209
sb.toString
210210
}
211211

212-
private def appendFilterHelp(dia: Diagnostic, sb: mutable.StringBuilder): Unit =
213-
import dia.*
212+
private def appendFilterHelp(dia: Diagnostic, sb: StringBuilder): Unit =
213+
import dia.msg
214214
val hasId = msg.errorId.errorNumber >= 0
215-
val category = dia match {
216-
case _: UncheckedWarning => "unchecked"
217-
case _: DeprecationWarning => "deprecation"
218-
case _: FeatureWarning => "feature"
219-
case _ => ""
220-
}
221-
if (hasId || category.nonEmpty)
222-
sb.append(EOL).append("Matching filters for @nowarn or -Wconf:")
223-
if (hasId)
224-
sb.append(EOL).append(" - id=E").append(msg.errorId.errorNumber)
225-
sb.append(EOL).append(" - name=").append(msg.errorId.productPrefix.stripSuffix("ID"))
226-
if (category.nonEmpty)
227-
sb.append(EOL).append(" - cat=").append(category)
215+
val (category, origin) = dia match
216+
case _: UncheckedWarning => ("unchecked", "")
217+
case w: DeprecationWarning => ("deprecation", w.origin)
218+
case _: FeatureWarning => ("feature", "")
219+
case _ => ("", "")
220+
var entitled = false
221+
def addHelp(what: String)(value: String): Unit =
222+
if !entitled then
223+
sb.append(EOL).append("Matching filters for @nowarn or -Wconf:")
224+
entitled = true
225+
sb.append(EOL).append(" - ").append(what).append(value)
226+
if hasId then
227+
addHelp("id=E")(msg.errorId.errorNumber.toString)
228+
addHelp("name=")(msg.errorId.productPrefix.stripSuffix("ID"))
229+
if category.nonEmpty then
230+
addHelp("cat=")(category)
231+
if origin.nonEmpty then
232+
addHelp("origin=")(origin)
228233

229234
/** The whole message rendered from `msg` */
230235
def messageAndPos(dia: Diagnostic)(using Context): String = {
@@ -236,7 +241,7 @@ trait MessageRendering {
236241
else 0
237242
given Level = Level(level)
238243
given Offset = Offset(maxLineNumber.toString.length + 2)
239-
val sb = mutable.StringBuilder()
244+
val sb = StringBuilder()
240245
val posString = posStr(pos, msg, diagnosticLevel(dia))
241246
if (posString.nonEmpty) sb.append(posString).append(EOL)
242247
if (pos.exists) {

Diff for: compiler/src/dotty/tools/dotc/reporting/WConf.scala

+7-2
Original file line numberDiff line numberDiff line change
@@ -19,23 +19,27 @@ enum MessageFilter:
1919
case Deprecated => message.isInstanceOf[Diagnostic.DeprecationWarning]
2020
case Feature => message.isInstanceOf[Diagnostic.FeatureWarning]
2121
case Unchecked => message.isInstanceOf[Diagnostic.UncheckedWarning]
22+
case MessageID(errorId) => message.msg.errorId == errorId
2223
case MessagePattern(pattern) =>
2324
val noHighlight = message.msg.message.replaceAll("\\e\\[[\\d;]*[^\\d;]","")
2425
pattern.findFirstIn(noHighlight).nonEmpty
25-
case MessageID(errorId) => message.msg.errorId == errorId
2626
case SourcePattern(pattern) =>
2727
val source = message.position.orElse(NoSourcePosition).source()
2828
val path = source.jfile()
2929
.map(_.toPath.toAbsolutePath.toUri.normalize().getRawPath)
3030
.orElse(source.path())
3131
pattern.findFirstIn(path).nonEmpty
32-
32+
case Origin(pattern) =>
33+
message match
34+
case message: Diagnostic.DeprecationWarning => pattern.findFirstIn(message.origin).nonEmpty
35+
case _ => false
3336
case None => false
3437

3538
case Any, Deprecated, Feature, Unchecked, None
3639
case MessagePattern(pattern: Regex)
3740
case MessageID(errorId: ErrorMessageID)
3841
case SourcePattern(pattern: Regex)
42+
case Origin(pattern: Regex)
3943

4044
enum Action:
4145
case Error, Warning, Verbose, Info, Silent
@@ -96,6 +100,7 @@ object WConf:
96100
case _ => Left(s"unknown category: $conf")
97101

98102
case "src" => regex(conf).map(SourcePattern.apply)
103+
case "origin" => regex(conf).map(Origin.apply)
99104

100105
case _ => Left(s"unknown filter: $filter")
101106
case _ => Left(s"unknown filter: $s")

Diff for: compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ class CrossVersionChecks extends MiniPhase:
7878
do
7979
val msg = annot.argumentConstantString(0).map(msg => s": $msg").getOrElse("")
8080
val since = annot.argumentConstantString(1).map(version => s" (since: $version)").getOrElse("")
81-
report.deprecationWarning(em"inheritance from $psym is deprecated$since$msg", parent.srcPos)
81+
report.deprecationWarning(em"inheritance from $psym is deprecated$since$msg", parent.srcPos, origin=psym.showFullName)
8282
}
8383

8484
override def transformValDef(tree: ValDef)(using Context): ValDef =
@@ -171,7 +171,7 @@ object CrossVersionChecks:
171171
def maybeWarn(annotee: Symbol, annot: Annotation) = if !skipWarning(sym) then
172172
val message = annot.argumentConstantString(0).filter(!_.isEmpty).map(": " + _).getOrElse("")
173173
val since = annot.argumentConstantString(1).filter(!_.isEmpty).map(" since " + _).getOrElse("")
174-
report.deprecationWarning(em"${annotee.showLocated} is deprecated${since}${message}", pos)
174+
report.deprecationWarning(em"${annotee.showLocated} is deprecated${since}${message}", pos, origin=annotee.showFullName)
175175
sym.getAnnotation(defn.DeprecatedAnnot) match
176176
case Some(annot) => maybeWarn(sym, annot)
177177
case _ =>

Diff for: compiler/src/dotty/tools/dotc/typer/RefChecks.scala

+3-1
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,9 @@ object RefChecks {
484484
def overrideDeprecation(what: String, member: Symbol, other: Symbol, fix: String): Unit =
485485
report.deprecationWarning(
486486
em"overriding $what${infoStringWithLocation(other)} is deprecated;\n ${infoString(member)} should be $fix.",
487-
if member.owner == clazz then member.srcPos else clazz.srcPos)
487+
if member.owner == clazz then member.srcPos else clazz.srcPos,
488+
origin = other.showFullName
489+
)
488490

489491
def autoOverride(sym: Symbol) =
490492
sym.is(Synthetic) && (

Diff for: compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala

+4-3
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ class ScalaSettingsTests:
8181
val conf = sets.Wconf.valueIn(proc.sstate)
8282
val sut = reporting.WConf.fromSettings(conf).getOrElse(???)
8383
val msg = "There was a problem!".toMessage
84-
val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition)
84+
val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition, origin="")
8585
assertEquals(Action.Silent, sut.action(depr))
8686
val feat = new Diagnostic.FeatureWarning(msg, util.NoSourcePosition)
8787
assertEquals(Action.Error, sut.action(feat))
@@ -197,7 +197,7 @@ class ScalaSettingsTests:
197197
val proc = sets.processArguments(sumy, processAll = true, skipped = Nil)
198198
val conf = sets.Wconf.valueIn(proc.sstate)
199199
val msg = "Don't use that!".toMessage
200-
val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition)
200+
val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition, origin="")
201201
val sut = reporting.WConf.fromSettings(conf).getOrElse(???)
202202
assertEquals(Action.Silent, sut.action(depr))
203203

@@ -293,7 +293,8 @@ class ScalaSettingsTests:
293293
util.SourcePosition(
294294
source = util.SourceFile.virtual(new URI("file:///some/path/file.scala"), ""),
295295
span = util.Spans.Span(1L)
296-
)
296+
),
297+
origin="",
297298
)
298299
)
299300
assertEquals(result, Right(reporting.Action.Error))

Diff for: tests/warn/deprecated-origin-verbose.check

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
-- Deprecation Warning: tests/warn/deprecated-origin-verbose.scala:12:18 -----------------------------------------------
2+
12 | class D extends C // warn
3+
| ^
4+
| class C in package p is deprecated since 1.0: Old style
5+
Matching filters for @nowarn or -Wconf:
6+
- cat=deprecation
7+
- origin=p.C
8+
-- Deprecation Warning: tests/warn/deprecated-origin-verbose.scala:13:20 -----------------------------------------------
9+
13 | class Oil extends Crude // warn
10+
| ^^^^^
11+
| class Crude in package p is deprecated since 1.0: Bad style
12+
Matching filters for @nowarn or -Wconf:
13+
- cat=deprecation
14+
- origin=p.Crude

Diff for: tests/warn/deprecated-origin-verbose.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//> using options -deprecation -Wconf:any:verbose
2+
3+
package p:
4+
@deprecated("Old style", since="1.0")
5+
class C
6+
@deprecated("Bad style", since="1.0")
7+
class Crude
8+
9+
package q:
10+
import annotation.*
11+
import p.*
12+
class D extends C // warn
13+
class Oil extends Crude // warn
14+
@nowarn("""origin=p\.Crude""")
15+
class Language extends Crude // nowarn obvs

Diff for: tests/warn/deprecated-origin.scala

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//> using options -deprecation -Wconf:origin=p\.C$:s
2+
3+
package p:
4+
@deprecated("Old style", since="1.0")
5+
class C
6+
@deprecated("Bad style", since="1.0")
7+
class Crude
8+
9+
package q:
10+
import annotation.*
11+
import p.*
12+
class D extends C // nowarn - C$ pattern avoids matching Crude
13+
class Oil extends Crude // warn
14+
@nowarn("""origin=p\.Crude""")
15+
class Language extends Crude // nowarn obvs

0 commit comments

Comments
 (0)