From ad9fd2a8980d992a957f2d5c33b95d7cdf504607 Mon Sep 17 00:00:00 2001 From: "Chris (Krzysztof) Pado" Date: Sat, 28 Oct 2023 14:25:54 -0700 Subject: [PATCH] Support src filter in -WConf (Closes #18782) --- .../tools/dotc/config/ScalaSettings.scala | 4 ++ .../dotty/tools/dotc/reporting/WConf.scala | 25 +++++++-- .../dotc/config/ScalaSettingsTests.scala | 52 +++++++++++++++++++ 3 files changed, 78 insertions(+), 3 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala index b10c9859e4d0..95f71ecfc143 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala @@ -247,6 +247,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`). @@ -266,6 +269,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/.* | |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 5303ccd7f219..07ff7e6da273 100644 --- a/compiler/src/dotty/tools/dotc/reporting/WConf.scala +++ b/compiler/src/dotty/tools/dotc/reporting/WConf.scala @@ -3,15 +3,21 @@ package dotc package reporting import scala.language.unsafeNulls - -import dotty.tools.dotc.core.Contexts._ -import dotty.tools.dotc.util.SourcePosition +import dotty.tools.dotc.core.Contexts.* +import dotty.tools.dotc.interfaces.SourceFile +import dotty.tools.dotc.reporting.MessageFilter.SourcePattern +import dotty.tools.dotc.util.{NoSourcePosition, SourcePosition} import java.util.regex.PatternSyntaxException import scala.annotation.internal.sharable import scala.util.matching.Regex +import scala.jdk.OptionConverters.* +import scala.collection.mutable enum MessageFilter: + + private val sourcePatternCache = mutable.Map.empty[SourceFile, Boolean] + def matches(message: Diagnostic): Boolean = this match case Any => true case Deprecated => message.isInstanceOf[Diagnostic.DeprecationWarning] @@ -21,11 +27,21 @@ 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() + sourcePatternCache.getOrElseUpdate(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 +100,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..e6b123cf1be1 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,52 @@ class ScalaSettingsTests: assertEquals(Action.Silent, sut.action(depr)) + private def wconfSrcFilterTest(argsStr: String, source: util.SourceFile, expectedAction: reporting.Action): 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 warning = new Diagnostic.Warning( + "A warning".toMessage, + util.SourcePosition( + source = source, + span = util.Spans.Span(1L) + ) + ) + val wconf = reporting.WConf.fromSettings(wconfStr) + assertEquals(Right(expectedAction), 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", + source = util.SourceFile.virtual(new URI("file:///some/path/file.scala"), ""), + expectedAction = reporting.Action.Silent + ) + + @Test def `WConf src filter doesn't silence warnings from a non-matching path`: Unit = + wconfSrcFilterTest( + argsStr = "-Wconf:src=another/.*:s", + source = util.SourceFile.virtual(new URI("file:///some/path/file.scala"), ""), + expectedAction = 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", + source = util.SourceFile(new PlainFile(Path(file)), "UTF-8"), + expectedAction = 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", + source = util.SourceFile(new PlainFile(Path(file)), "UTF-8"), + expectedAction = reporting.Action.Warning + ) + }(Files.deleteIfExists(_)) + end ScalaSettingsTests