diff --git a/compiler/src/dotty/tools/dotc/report.scala b/compiler/src/dotty/tools/dotc/report.scala index c77d4eb2fc7e..e24e6be38b2b 100644 --- a/compiler/src/dotty/tools/dotc/report.scala +++ b/compiler/src/dotty/tools/dotc/report.scala @@ -23,8 +23,8 @@ object report: private def issueWarning(warning: Warning)(using Context): Unit = ctx.reporter.report(warning) - def deprecationWarning(msg: Message, pos: SrcPos)(using Context): Unit = - issueWarning(new DeprecationWarning(msg, pos.sourcePos)) + def deprecationWarning(msg: Message, pos: SrcPos, origin: String = "")(using Context): Unit = + issueWarning(new DeprecationWarning(msg, pos.sourcePos, origin)) def migrationWarning(msg: Message, pos: SrcPos)(using Context): Unit = issueWarning(new MigrationWarning(msg, pos.sourcePos)) diff --git a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala index 7a8edb233aee..6a2d88f4e82f 100644 --- a/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala +++ b/compiler/src/dotty/tools/dotc/reporting/Diagnostic.scala @@ -75,7 +75,8 @@ object Diagnostic: class DeprecationWarning( msg: Message, - pos: SourcePosition + pos: SourcePosition, + val origin: String ) extends ConditionalWarning(msg, pos) { def enablingOption(using Context): Setting[Boolean] = ctx.settings.deprecation } diff --git a/compiler/src/dotty/tools/dotc/reporting/WConf.scala b/compiler/src/dotty/tools/dotc/reporting/WConf.scala index 54a6fc14e054..1896e5269d6c 100644 --- a/compiler/src/dotty/tools/dotc/reporting/WConf.scala +++ b/compiler/src/dotty/tools/dotc/reporting/WConf.scala @@ -19,23 +19,27 @@ enum MessageFilter: case Deprecated => message.isInstanceOf[Diagnostic.DeprecationWarning] case Feature => message.isInstanceOf[Diagnostic.FeatureWarning] case Unchecked => message.isInstanceOf[Diagnostic.UncheckedWarning] + case MessageID(errorId) => message.msg.errorId == errorId case MessagePattern(pattern) => val noHighlight = message.msg.message.replaceAll("\\e\\[[\\d;]*[^\\d;]","") pattern.findFirstIn(noHighlight).nonEmpty - case MessageID(errorId) => message.msg.errorId == errorId case SourcePattern(pattern) => val source = message.position.orElse(NoSourcePosition).source() val path = source.jfile() .map(_.toPath.toAbsolutePath.toUri.normalize().getRawPath) .orElse(source.path()) pattern.findFirstIn(path).nonEmpty - + case Origin(pattern) => + message match + case message: Diagnostic.DeprecationWarning => pattern.findFirstIn(message.origin).nonEmpty + case _ => false case None => false case Any, Deprecated, Feature, Unchecked, None case MessagePattern(pattern: Regex) case MessageID(errorId: ErrorMessageID) case SourcePattern(pattern: Regex) + case Origin(pattern: Regex) enum Action: case Error, Warning, Verbose, Info, Silent @@ -96,6 +100,7 @@ object WConf: case _ => Left(s"unknown category: $conf") case "src" => regex(conf).map(SourcePattern.apply) + case "origin" => regex(conf).map(Origin.apply) case _ => Left(s"unknown filter: $filter") case _ => Left(s"unknown filter: $s") diff --git a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala index 5ce1b02733d0..6020431672b9 100644 --- a/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/CrossVersionChecks.scala @@ -78,7 +78,7 @@ class CrossVersionChecks extends MiniPhase: do val msg = annot.argumentConstantString(0).map(msg => s": $msg").getOrElse("") val since = annot.argumentConstantString(1).map(version => s" (since: $version)").getOrElse("") - report.deprecationWarning(em"inheritance from $psym is deprecated$since$msg", parent.srcPos) + report.deprecationWarning(em"inheritance from $psym is deprecated$since$msg", parent.srcPos, origin=psym.showFullName) } override def transformValDef(tree: ValDef)(using Context): ValDef = @@ -171,7 +171,7 @@ object CrossVersionChecks: def maybeWarn(annotee: Symbol, annot: Annotation) = if !skipWarning(sym) then val message = annot.argumentConstantString(0).filter(!_.isEmpty).map(": " + _).getOrElse("") val since = annot.argumentConstantString(1).filter(!_.isEmpty).map(" since " + _).getOrElse("") - report.deprecationWarning(em"${annotee.showLocated} is deprecated${since}${message}", pos) + report.deprecationWarning(em"${annotee.showLocated} is deprecated${since}${message}", pos, origin=annotee.showFullName) sym.getAnnotation(defn.DeprecatedAnnot) match case Some(annot) => maybeWarn(sym, annot) case _ => diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 5f7504fa072f..0a0356707048 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -484,7 +484,9 @@ object RefChecks { def overrideDeprecation(what: String, member: Symbol, other: Symbol, fix: String): Unit = report.deprecationWarning( em"overriding $what${infoStringWithLocation(other)} is deprecated;\n ${infoString(member)} should be $fix.", - if member.owner == clazz then member.srcPos else clazz.srcPos) + if member.owner == clazz then member.srcPos else clazz.srcPos, + origin = other.showFullName + ) def autoOverride(sym: Symbol) = sym.is(Synthetic) && ( diff --git a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala index 3dc4f4e4ec5e..a412848eaa98 100644 --- a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala +++ b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala @@ -81,7 +81,7 @@ class ScalaSettingsTests: val conf = sets.Wconf.valueIn(proc.sstate) val sut = reporting.WConf.fromSettings(conf).getOrElse(???) val msg = "There was a problem!".toMessage - val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition) + val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition, origin="") assertEquals(Action.Silent, sut.action(depr)) val feat = new Diagnostic.FeatureWarning(msg, util.NoSourcePosition) assertEquals(Action.Error, sut.action(feat)) @@ -197,7 +197,7 @@ class ScalaSettingsTests: val proc = sets.processArguments(sumy, processAll = true, skipped = Nil) val conf = sets.Wconf.valueIn(proc.sstate) val msg = "Don't use that!".toMessage - val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition) + val depr = new Diagnostic.DeprecationWarning(msg, util.NoSourcePosition, origin="") val sut = reporting.WConf.fromSettings(conf).getOrElse(???) assertEquals(Action.Silent, sut.action(depr)) @@ -293,7 +293,8 @@ class ScalaSettingsTests: util.SourcePosition( source = util.SourceFile.virtual(new URI("file:///some/path/file.scala"), ""), span = util.Spans.Span(1L) - ) + ), + origin="", ) ) assertEquals(result, Right(reporting.Action.Error)) diff --git a/tests/warn/deprecated-origin.scala b/tests/warn/deprecated-origin.scala new file mode 100644 index 000000000000..e028515d795c --- /dev/null +++ b/tests/warn/deprecated-origin.scala @@ -0,0 +1,15 @@ +//> using options -deprecation -Wconf:origin=p\.C$:s + +package p: + @deprecated("Old style", since="1.0") + class C + @deprecated("Bad style", since="1.0") + class Crude + +package q: + import annotation.* + import p.* + class D extends C // nowarn - C$ pattern avoids matching Crude + class Oil extends Crude // warn + @nowarn("""origin=p\.Crude""") + class Language extends Crude // nowarn obvs