diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index 3dafedd8e2e0..77c4eb332aca 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -252,6 +252,9 @@ private sealed trait WarningSettings: | - Message name: name=PureExpressionInStatementPosition | The message name is printed with the warning in verbose warning mode. | + | - Source location: src=regex + | The regex is evaluated against the full source path. + | |In verbose warning mode the compiler prints matching filters for warnings. |Verbose mode can be enabled globally using `-Wconf:any:verbose`, or locally |using the @nowarn annotation (example: `@nowarn("v") def test = try 1`). @@ -271,6 +274,7 @@ private sealed trait WarningSettings: |Examples: | - change every warning into an error: -Wconf:any:error | - silence deprecations: -Wconf:cat=deprecation:s + | - silence warnings in src_managed directory: -Wconf:src=src_managed/.*:s | |Note: on the command-line you might need to quote configurations containing `*` or `&` |to prevent the shell from expanding patterns.""".stripMargin, diff --git a/compiler/src/dotty/tools/dotc/reporting/WConf.scala b/compiler/src/dotty/tools/dotc/reporting/WConf.scala index cc0a63cb1532..54a6fc14e054 100644 --- a/compiler/src/dotty/tools/dotc/reporting/WConf.scala +++ b/compiler/src/dotty/tools/dotc/reporting/WConf.scala @@ -5,7 +5,9 @@ package reporting import scala.language.unsafeNulls import dotty.tools.dotc.core.Contexts.* -import dotty.tools.dotc.util.SourcePosition +import dotty.tools.dotc.util.{NoSourcePosition, SourcePosition} +import dotty.tools.dotc.interfaces.SourceFile +import dotty.tools.dotc.reporting.MessageFilter.SourcePattern import java.util.regex.PatternSyntaxException import scala.annotation.internal.sharable @@ -21,11 +23,19 @@ enum MessageFilter: 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 None => false case Any, Deprecated, Feature, Unchecked, None case MessagePattern(pattern: Regex) case MessageID(errorId: ErrorMessageID) + case SourcePattern(pattern: Regex) enum Action: case Error, Warning, Verbose, Info, Silent @@ -84,6 +94,9 @@ object WConf: case "feature" => Right(Feature) case "unchecked" => Right(Unchecked) case _ => Left(s"unknown category: $conf") + + case "src" => regex(conf).map(SourcePattern.apply) + case _ => Left(s"unknown filter: $filter") case _ => Left(s"unknown filter: $s") diff --git a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala index a1014043724e..71bbf055cde2 100644 --- a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala +++ b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala @@ -7,6 +7,11 @@ import Settings._ import org.junit.Test import org.junit.Assert._ import core.Decorators.toMessage +import dotty.tools.io.{Path, PlainFile} + +import java.net.URI +import java.nio.file.Files +import scala.util.Using class ScalaSettingsTests: @@ -96,5 +101,97 @@ class ScalaSettingsTests: assertEquals(Action.Silent, sut.action(depr)) + private def wconfSrcFilterTest(argsStr: String, + expectedOutcome: Either[List[String], reporting.Action], + warning: reporting.Diagnostic.Warning): Unit = + import reporting.Diagnostic + val settings = new ScalaSettings + val args = ArgsSummary(settings.defaultState, List(argsStr), errors = Nil, warnings = Nil) + val proc = settings.processArguments(args, processAll = true, skipped = Nil) + val wconfStr = settings.Wconf.valueIn(proc.sstate) + val wconf = reporting.WConf.fromSettings(wconfStr) + assertEquals(expectedOutcome, wconf.map(_.action(warning))) + + @Test def `WConf src filter silences warnings from a matching path for virtual file`: Unit = + wconfSrcFilterTest( + argsStr = "-Wconf:src=path/.*:s", + warning = reporting.Diagnostic.Warning( + "A warning".toMessage, + util.SourcePosition( + source = util.SourceFile.virtual(new URI("file:///some/path/file.scala"), ""), + span = util.Spans.Span(1L) + ) + ), + expectedOutcome = Right(reporting.Action.Silent) + ) + + @Test def `WConf src filter doesn't silence warnings from a non-matching path`: Unit = + wconfSrcFilterTest( + argsStr = "-Wconf:src=another/.*:s", + warning = reporting.Diagnostic.Warning( + "A warning".toMessage, + util.SourcePosition( + source = util.SourceFile.virtual(new URI("file:///some/path/file.scala"), ""), + span = util.Spans.Span(1L) + ) + ), + expectedOutcome = Right(reporting.Action.Warning) + ) + + @Test def `WConf src filter silences warnings from a matching path for real file`: Unit = + Using.resource(Files.createTempFile("myfile", ".scala").nn) { file => + wconfSrcFilterTest( + argsStr = "-Wconf:src=myfile.*?\\.scala:s", + warning = reporting.Diagnostic.Warning( + "A warning".toMessage, + util.SourcePosition( + source = util.SourceFile(new PlainFile(Path(file)), "UTF-8"), + span = util.Spans.Span(1L) + ) + ), + expectedOutcome = Right(reporting.Action.Silent) + ) + }(Files.deleteIfExists(_)) + + @Test def `WConf src filter doesn't silence warnings from a non-matching path for real file`: Unit = + Using.resource(Files.createTempFile("myfile", ".scala").nn) { file => + wconfSrcFilterTest( + argsStr = "-Wconf:src=another.*?\\.scala:s", + warning = reporting.Diagnostic.Warning( + "A warning".toMessage, + util.SourcePosition( + source = util.SourceFile(new PlainFile(Path(file)), "UTF-8"), + span = util.Spans.Span(1L) + ) + ), + expectedOutcome = Right(reporting.Action.Warning) + ) + }(Files.deleteIfExists(_)) + + @Test def `WConf src filter reports an error on an invalid regex`: Unit = + wconfSrcFilterTest( + argsStr = """-Wconf:src=\:s""", + warning = reporting.Diagnostic.Warning( + "A warning".toMessage, + util.SourcePosition( + source = util.SourceFile.virtual(new URI("file:///some/path/file.scala"), ""), + span = util.Spans.Span(1L) + ) + ), + expectedOutcome = Left(List("invalid pattern `\\`: Unescaped trailing backslash near index 1\n\\")) + ) + + @Test def `WConf src filter can be mixed with other filters with rightmost taking precedence`: Unit = + wconfSrcFilterTest( + argsStr = "-Wconf:src=.*:s,cat=deprecation:e", + warning = reporting.Diagnostic.DeprecationWarning( + "A warning".toMessage, + util.SourcePosition( + source = util.SourceFile.virtual(new URI("file:///some/path/file.scala"), ""), + span = util.Spans.Span(1L) + ) + ), + expectedOutcome = Right(reporting.Action.Error), + ) end ScalaSettingsTests