Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support src filter in -WConf (Closes #17635) #18783

Merged
merged 1 commit into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions compiler/src/dotty/tools/dotc/config/ScalaSettings.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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`).
Expand All @@ -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,
Expand Down
15 changes: 14 additions & 1 deletion compiler/src/dotty/tools/dotc/reporting/WConf.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Old code had a cache, shouldn't that be provided too?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cache added


enum Action:
case Error, Warning, Verbose, Info, Silent
Expand Down Expand Up @@ -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")

Expand Down
100 changes: 100 additions & 0 deletions compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down Expand Up @@ -96,5 +101,100 @@ class ScalaSettingsTests:
assertEquals(Action.Silent, sut.action(depr))


private def wconfSrcFilterTest(argsStr: String,
warning: reporting.Diagnostic.Warning): Either[List[String], reporting.Action] =
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)
wconf.map(_.action(warning))

@Test def `WConf src filter silences warnings from a matching path for virtual file`: Unit =
val result = 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)
)
)
)
assertEquals(result, Right(reporting.Action.Silent))

@Test def `WConf src filter doesn't silence warnings from a non-matching path`: Unit =
val result = 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)
)
)
)
assertEquals(result, Right(reporting.Action.Warning))

@Test def `WConf src filter silences warnings from a matching path for real file`: Unit =
val result = 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)
)
)
)
}(Files.deleteIfExists(_))
assertEquals(result, Right(reporting.Action.Silent))

@Test def `WConf src filter doesn't silence warnings from a non-matching path for real file`: Unit =
val result = 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)
)
)
)
}(Files.deleteIfExists(_))
assertEquals(result, Right(reporting.Action.Warning))

@Test def `WConf src filter reports an error on an invalid regex`: Unit =
val result = 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)
)
),
)
assertTrue(
result.left.exists(errors =>
errors.sizeIs == 1 && errors.headOption.exists(_.startsWith("invalid pattern"))
)
)

@Test def `WConf src filter can be mixed with other filters with rightmost taking precedence`: Unit =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, in Scala 2 the leftmost takes precedence. Also -Wconf:help (on Scala 3) says otherwise.

https://github.com/lampepfl/dotty/blob/a095115b43398feeac3ee4329edb87f87da00012/compiler/src/dotty/tools/dotc/config/ScalaSettings.scala#L268-L269

So this is a bug that should be fixed. I think a separate PR is better, so I filed #19885.

val result = 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)
)
)
)
assertEquals(result, Right(reporting.Action.Error))

end ScalaSettingsTests
Loading