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

add -Wconf flag for configurable warnings, @nowarn annotation for local suppression #8373

Merged
merged 9 commits into from Mar 9, 2020

Conversation

lrytz
Copy link
Member

@lrytz lrytz commented Aug 26, 2019

This PR adds a -Wconf compiler flag that allows filtering and configuring compiler warnings (silence them, or turn them into errors).

It also integrates the fantastic silencer compiler plugin by @ghik into the compiler, which allows suppressing warnings locally using the @nowarn annotation.

Configurable Warnings

Warnings are assigned a category.

Warnings can be filtered by category, by message regex, by site where they are issued, and by source path. Deprecations can additionally be filtered by origin (deprecated definition) and since version.

Filtered warnings can be reported as error, warning, info, summary (like deprecations) or silent.

Local Suppression

The @nowarn annotation suppresses warnings within the scope covered by the annotation.

  • @nowarn def foo = ..., @nowarn class C { ... }: suppress warnings in a definition
  • expression: @nowarn: suppress warnings in a specific expression

The annotation can be configured to filter selected warnings, for example @nowarn("cat=deprecation") only suppresses deprecation warnings. The filter configuration syntax is the same as in -Wconf.

Help Text

$> scalac -Wconf:help
Configure compiler warnings.
Syntax: -Wconf:<filters>:<action>,<filters>:<action>,...
multiple <filters> are combined with &, i.e., <filter>&...&<filter>

Note: Run with `-Wconf:any:warning-verbose` to print warnings with their category, site,
and (for deprecations) origin and since-version.

<filter>
  - Any message: any

  - Message categories: cat=deprecation, cat=lint, cat=lint-infer-any
    The full list of warning categories is shown at the end of this help text.

  - Message content: msg=regex
    The regex need only match some part of the message, not all of it.

  - Site where the warning is triggered: site=my\.package\..*
    The regex must match the full name (`package.Class.method`) of the warning position.

  - Source file name: src=src_managed/.*
    If `-rootdir` is specified, the regex must match the canonical path relative to the
    root directory. Otherwise, the regex must match the canonical path relative to any
    path segment (`b/.*Test.scala` matches `/a/b/XTest.scala` but not `/ab/Test.scala`).
    Use unix-style paths, separated by `/`.

  - Origin of deprecation: origin=external\.package\..*
    The regex must match the full name (`package.Class.method`) of the deprecated entity.

  - Since of deprecation: since<1.24
    Valid operators: <, =, >, valid versions: N, N.M, N.M.P. Compares against the first
    version of the form N, N.M or N.M.P found in the `since` parameter of the deprecation,
    for example `1.2.3` in `@deprecated("", "some lib 1.2.3-foo")`.

<action>
  - error / e
  - warning / w
  - warning-summary / ws (summary with the number of warnings, like for deprecations)
  - warning-verbose / wv (show warning category and site)
  - info / i             (infos are not counted as warnings and don't affect `-Werror`)
  - info-summary / is
  - info-verbose / iv
  - silent / s

The default configuration is:
  -Wconf:cat=deprecation:ws,cat=feature:ws,cat=optimizer:ws

User-defined configurations are added to the left. The leftmost rule matching
a warning message defines the action.

Examples:
  - change every warning into an error: -Wconf:any:error
  - silence certain deprecations: -Wconf:origin=some\.lib\..*&since>2.2:s

Full list of message categories:
 - deprecation
 - feature, feature-dynamics, feature-existentials, feature-higher-kinds, feature-implicit-conversions, feature-macros, feature-postfix-ops, feature-reflective-calls
 - java-source
 - lint, lint-adapted-args, lint-byname-implicit, lint-constant, lint-delayedinit-select, lint-deprecation, lint-doc-detached, lint-eta-sam, lint-eta-zero, lint-implicit-not-found, lint-inaccessible, lint-infer-any, lint-missing-interpolator, lint-nonlocal-return, lint-nullary-override, lint-nullary-unit, lint-option-implicit, lint-package-object-classes, lint-poly-implicit-overload, lint-private-shadow, lint-recurse-with-default, lint-serial, lint-stars-align, lint-type-parameter-shadow, lint-unit-specialization
 - optimizer
 - other, other-debug, other-match-analysis, other-migration, other-pure-statement, other-shadowing
 - scaladoc
 - unchecked
 - unused, unused-imports, unused-locals, unused-nowarn, unused-params, unused-pat-vars, unused-privates
 - w-flag, w-flag-dead-code, w-flag-extra-implicit, w-flag-numeric-widen, w-flag-self-implicit, w-flag-value-discard

To suppress warnings locally, use the `scala.annotation.nowarn` annotation.

Note: on the command-line you might need to quote configurations containing `*` or `&`
to prevent the shell from expanding patterns.

Significant changes

  • What's described above in the PR description
  • MiMa exception for addition of scala.annotation.nowarn
  • Adds a -rootdir compiler flag. It is used to relativize file paths when using source filters (-Wconf:src=some/source/File.scala:s), there might be other uses for it in the future.
  • Compiler API changes
    • warning methods in currentRun.reporting and context reporter take new Category parameter. The global.reporter is unchanged, warnings reported through it are not filtered by Wconf.
    • Removed a few deprecated methods (compilationUnit.error/warning)
  • Reporting warnings is now delayed until after typer, because the typer collects @nowarn annotations.
  • If we stop before typer (e.g., because there are errors in the parser), all warnings are shown, even if they are enclosed in @nowarn
  • If a phase before typer has both errors and warnings, all errors are printed before the warnings.
  • Unchecked warnings are now all shown by default (they were summarized like deprecations before)
  • The -deprecation, -feature and -unchecked settings are no longer directly used in the compiler, they are shortcuts for specific Wconf configurations. the compiler only looks at -Wconf.

@scala-jenkins scala-jenkins added this to the 2.13.2 milestone Aug 26, 2019
@lrytz lrytz added the WIP label Aug 26, 2019
@lrytz
Copy link
Member Author

lrytz commented Aug 26, 2019

Message filtering is performed in global.currentRun.reporting, not in the Global.reporter.

The reasons are:

  • Separation of concerns: Reporters worry about how to do reporting, removing duplicate messages.
  • Custom Reporters are used by sbt, silencer, REPL, etc. It's too hard to do the necessary changes to the Reporter interface.
  • The Wconf setting could change between compiler runs. currentRun.reporting respects those changes.

So all warnings in the compiler should go through global.runReporting (which is the same as global.currentRun.reporting). This method takes four parameters: pos, msg, category (new), site (new). The site is usually context.owner (in the frontend) or currentOwner (in transformations).

Context has a warn method with 3 parameters (pos, msg, category) and inserts the owner as site, so this is used in the frontend (context reporters are also used to support silent mode / trying twice).

The global.warning method is deprecated and no longer used.

There are a few calls to Reporter.warning left in the codebase where no runReporting is reachable, I think they are aoll OK not to categorize / allow filtering. E.g., when running Scaladoc

    else if (docSettings.showPlugins.value)
      reporter.warning(null, "Plugins are not available when using Scaladoc")

@lrytz
Copy link
Member Author

lrytz commented Sep 5, 2019

Added support for local warning suppression using @silent. I borrowed heavily from silencer, in design, implementation and tests; cc @ghik, a huge THANK YOU for your work!

@ijuma
Copy link
Contributor

ijuma commented Sep 5, 2019

This will be immensely useful. Thanks for working on this!

@lrytz lrytz force-pushed the confwarn branch 4 times, most recently from 7729d15 to 9c37e5e Compare September 9, 2019 12:25
@lrytz lrytz changed the title Wconf flag for configurable warnings [ci: last-only] Wconf flag for configurable warnings, @silent for local suppression [ci: last-only] Sep 9, 2019
@lrytz lrytz removed the WIP label Sep 9, 2019
@lrytz
Copy link
Member Author

lrytz commented Sep 9, 2019

Removed the WIP flag and update the PR description, this is ready to be reviewed!

@lrytz lrytz force-pushed the confwarn branch 3 times, most recently from 174a43e to 8aa1750 Compare September 23, 2019 12:10
@lrytz
Copy link
Member Author

lrytz commented Sep 23, 2019

@SethTisue would you be interested to review this, at least on a high level? I updated the PR description, and also included a section on significant changes.

eed3si9n added a commit to eed3si9n/scala that referenced this pull request Mar 26, 2020
This implements `apiStatus ` annotation as a generic form of `deprecated` annotation. `apiStatus` takes `category` and `defaultAction` parameters, corresponding to configurable warning's category and action.

One of the usage is to trigger compiler error from the library when a method is invoked to display migration message. Another usage would be to denote bincompat status of the API as warning.

This is a resend of scala#7790 based on the configurable warnings.
Ref scala#8373 / https://twitter.com/not_xuwei_k/status/1240354073297268737
eed3si9n added a commit to eed3si9n/scala that referenced this pull request Mar 29, 2020
This implements `apiStatus` annotation as a generic form of `deprecated` annotation. While deprecated is only able to discourage someone from using the some API, `apiStatus` can be more nuanced about the state (for instance Category.ApiMayChange), and choose the default compile-time actions (Action.Error, Action.Warning, etc). In other words, this gives library authors the lever to trigger compilation warning or
compilation errors!

One of the usage is to trigger compiler error from the library when a method is invoked to display migration message. Another usage would be to denote bincompat status of the API as warning.

This is a resend of scala#7790 based on the configurable warnings.
Ref scala#8373 / https://twitter.com/not_xuwei_k/status/1240354073297268737
@ijuma
Copy link
Contributor

ijuma commented Apr 1, 2020

I tested this feature in Apache Kafka and I have a branch with 0 warnings and -Xfatal-warnings enabled. This is awesome. :) Two observations:

  1. It would be really useful for the nowarn annotation to be added to Scala 2.12 even if it doesn't do anything. Kafka, like most projects, supports Scala 2.12 and Scala 2.13. I am fine with compiling with Scala 2.13 by default and having -Xfatal-warnings enabled for that version only, but I can't easily use the annotation if it's not present at all in Scala 2.12.

  2. I was unable to get the site filter to work via a compilation argument. I had to fallback to the source filter instead, which is less precise. This could be user error, but I noticed that the tests seemingly only cover the default package:

check(infos(code, "site=A.f:i"), Nil)
check(infos(code, "site=A.invokeDeprecated:i"), List(l5a, l5b))

I will try this on a minimized test case and report an issue (hopefully soon), but I wanted to give a heads up since 2.13.2 has not been released yet.

@lrytz
Copy link
Member Author

lrytz commented Apr 2, 2020

nowarn annotation to be added to Scala 2.12

That's certainly an option. Alternatively, adding it to https://github.com/scala/scala-collection-compat would be lower overhead - would it be an option to add this dependency?

For the site filter, it seems to work for me; is it maybe that the leftmost matching rule defines the action?

$> cat Test.scala
package a.pu
class K {
  def f = 1  2
  @annotation.nowarn("site=a.pu.K.g")
  def g = 1  2
}
$>

$> scv 2.13.2-bin-cd56924 -Wconf:cat=deprecation:wv Test.scala
Test.scala:4: warning: [deprecation @ a.pu.K.f | origin=scala.Predef.ArrowAssoc. | version=2.13.0] method  in class ArrowAssoc is deprecated (since 2.13.0): Use `->` instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.
  def f = 1  2
            ^
1 warning
$>

$> scv 2.13.2-bin-cd56924 -Wconf:site=a.pu.K.f:s,cat=deprecation:wv Test.scala
$>

$> scv 2.13.2-bin-cd56924 -Wconf:cat=deprecation:wv,site=a.pu.K.f:s Test.scala
Test.scala:4: warning: [deprecation @ a.pu.K.f | origin=scala.Predef.ArrowAssoc. | version=2.13.0] method  in class ArrowAssoc is deprecated (since 2.13.0): Use `->` instead. If you still wish to display it as one character, consider using a font with programming ligatures such as Fira Code.
  def f = 1  2
            ^
1 warning
$>

@ijuma
Copy link
Contributor

ijuma commented Apr 2, 2020

@lrytz Thanks for the quick response.

scala-collection-compat would be perfect, we already use it for other reasons.

I got site to work with the help from your example. I got confused because the help text in the PR description shows a \ before the .:

image

@lrytz
Copy link
Member Author

lrytz commented Apr 2, 2020

OK, I see how the \ can be annoying to get right... The thing is, the pattern is a java regex, so if you write site=my.pack.*, it matches myApack.

The following command line worked as expected for me:

scv 2.13.2-bin-cd56924 '-Wconf:site=a\.pu\.K\.f:s,cat=deprecation:wv' Test.scala

@ijuma
Copy link
Contributor

ijuma commented Apr 2, 2020

@lrytz I investigated more and I found the issue. I got a bit unlucky and the first warning I tried to suppress didn't seem to have the @ location captured correctly:

"Error:(109, 68) [unused-params @ ] parameter value nn in method body is never used
def body[T <: AbstractRequest](implicit classTag: ClassTag[T], nn: NotNothing[T]): T = {"

In the Kafka codebase, we had one other example like the above (similar pattern), but all other ones worked fine. The usage of wv from your example helped track this down.

@lrytz
Copy link
Member Author

lrytz commented Apr 2, 2020

I'll take a look if I can reproduce and fix that.

For @nowarn, I submitted scala/scala-collection-compat#312

@lrytz
Copy link
Member Author

lrytz commented Apr 3, 2020

(moved my comment to scala/scala-collection-compat#312 (comment) where I intended to post it)

@lrytz
Copy link
Member Author

lrytz commented Apr 3, 2020

@ijuma #8852 fixes the warning site for unused warnings.

@ijuma
Copy link
Contributor

ijuma commented Apr 3, 2020

Thanks!

@charpov
Copy link

charpov commented Sep 28, 2020

comparing a fresh object using `eq` will always yield false is being suppressed by @nowarn("cat=other") but not by any of the other- subcategories I have tried. Is there one that is missing from the documentation?

@som-snytt
Copy link
Contributor

som-snytt commented Sep 29, 2020

@charpov https://github.com/scala/scala/blob/v2.13.3/src/compiler/scala/tools/nsc/typechecker/RefChecks.scala#L1046 just says other. (Probably I'd ask on gitter instead of the old PR.) (or the forum. It might be a useful topic to consider what cats are useful.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
release-notes worth highlighting in next release notes
Projects
None yet