Skip to content

Commit

Permalink
-Wconf compiler flag for configuring compiler warnings
Browse files Browse the repository at this point in the history
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.

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.

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`.

Message filtering is performed in `global.currentRun.reporting`, not
in the `Global.reporter`. The reasons are:
  - Separation of concerns: `Reporter`s worry about how to do reporting,
    removing duplicate messages.
  - Custom `Reporter`s 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 all OK not to
categorize / allow filtering. E.g., when running Scaladoc

```
reporter.warning(null, "Plugins are not available when using Scaladoc")
```
  • Loading branch information
lrytz committed Mar 5, 2020
1 parent 2cf8e5c commit 39d3b3a
Show file tree
Hide file tree
Showing 103 changed files with 1,532 additions and 382 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ val mimaFilterSettings = Seq {
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.VirtualFile.unsafeToByteArray"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.ZipArchive#Entry.unsafeToByteArray"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.io.NoAbstractFile.unsafeToByteArray"),
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.reflect.runtime.JavaUniverse#PerRunReporting.deprecationWarning"),
),
}

Expand Down
4 changes: 3 additions & 1 deletion src/compiler/scala/reflect/macros/contexts/FrontEnds.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ package scala.reflect.macros
package contexts

import scala.reflect.macros.runtime.AbortMacroException
import scala.tools.nsc.Reporting.WarningCategory

trait FrontEnds {
self: Context =>
Expand All @@ -27,7 +28,8 @@ trait FrontEnds {

def hasErrors: Boolean = universe.reporter.hasErrors

def warning(pos: Position, msg: String): Unit = callsiteTyper.context.warning(pos, msg)
// TODO: add WarningCategory parameter in 2.14 (not binary compatible)
def warning(pos: Position, msg: String): Unit = callsiteTyper.context.warning(pos, msg, WarningCategory.Other)

def error(pos: Position, msg: String): Unit = callsiteTyper.context.error(pos, msg)

Expand Down
24 changes: 13 additions & 11 deletions src/compiler/scala/tools/nsc/Global.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import scala.reflect.ClassTag
import scala.reflect.internal.pickling.PickleBuffer
import scala.reflect.internal.util.{BatchSourceFile, FreshNameCreator, NoSourceFile, ScriptSourceFile, SourceFile}
import scala.reflect.internal.{Reporter => InternalReporter}
import scala.tools.nsc.Reporting.WarningCategory
import scala.tools.nsc.ast.parser._
import scala.tools.nsc.ast.{TreeGen => AstTreeGen, _}
import scala.tools.nsc.backend.jvm.{BackendStats, GenBCode}
Expand Down Expand Up @@ -294,7 +295,7 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
@inline final def devWarning(pos: Position, msg: => String): Unit = {
def pos_s = if (pos eq NoPosition) "" else s" [@ $pos]"
if (isDeveloper)
warning(pos, "!!! " + msg)
runReporting.warning(pos, "!!! " + msg, WarningCategory.OtherDebug, site = "")
else
log(s"!!!$pos_s $msg") // such warnings always at least logged
}
Expand Down Expand Up @@ -992,10 +993,11 @@ class Global(var currentSettings: Settings, reporter0: Reporter)

/** The currently active run
*/
def currentRun: Run = curRun
def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit
def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile
def currentFreshNameCreator = if (curFreshNameCreator == null) currentUnit.fresh else curFreshNameCreator
def currentRun: Run = curRun
def currentUnit: CompilationUnit = if (currentRun eq null) NoCompilationUnit else currentRun.currentUnit
def currentSource: SourceFile = if (currentUnit.exists) currentUnit.source else lastSeenSourceFile
def runReporting: PerRunReporting = currentRun.reporting
def currentFreshNameCreator = if (curFreshNameCreator == null) currentUnit.fresh else curFreshNameCreator
private[this] var curFreshNameCreator: FreshNameCreator = null
private[scala] def currentFreshNameCreator_=(fresh: FreshNameCreator): Unit = curFreshNameCreator = fresh

Expand Down Expand Up @@ -1139,9 +1141,9 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
val isScala300: Boolean = settings.isScala300

// used in sbt
def uncheckedWarnings: List[(Position, String)] = reporting.uncheckedWarnings.map{case (pos, (msg, since)) => (pos, msg)}
def uncheckedWarnings: List[(Position, String)] = reporting.uncheckedWarnings
// used in sbt
def deprecationWarnings: List[(Position, String)] = reporting.deprecationWarnings.map{case (pos, (msg, since)) => (pos, msg)}
def deprecationWarnings: List[(Position, String)] = reporting.deprecationWarnings

private class SyncedCompilationBuffer { self =>
private val underlying = new mutable.ArrayBuffer[CompilationUnit]
Expand Down Expand Up @@ -1249,8 +1251,8 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
val count =
if (including) first.iterator.count(tester.containsPhase(_))
else phaseDescriptors.count(pd => tester.contains(pd.phaseName))
if (count == 0) warning(s"'$p' specifies no phase")
if (count > 1 && !isSpecial(p)) warning(s"'$p' selects $count phases")
if (count == 0) runReporting.warning(NoPosition, s"'$p' specifies no phase", WarningCategory.Other, site = "")
if (count > 1 && !isSpecial(p)) runReporting.warning(NoPosition, s"'$p' selects $count phases", WarningCategory.Other, site = "")
if (!including && isSpecial(p)) globalError(s"-Yskip and -Ystop values must name phases: '$p'")
tester.clear()
}
Expand Down Expand Up @@ -1360,9 +1362,9 @@ class Global(var currentSettings: Settings, reporter0: Reporter)
private def warnDeprecatedAndConflictingSettings(): Unit = {
// issue warnings for any usage of deprecated settings
settings.userSetSettings filter (_.isDeprecated) foreach { s =>
currentRun.reporting.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get, "")
runReporting.deprecationWarning(NoPosition, s.name + " is deprecated: " + s.deprecationMessage.get, "", "", "")
}
settings.conflictWarning.foreach(reporter.warning(NoPosition, _))
settings.conflictWarning.foreach(runReporting.warning(NoPosition, _, WarningCategory.Other, site = ""))
}

/* An iterator returning all the units being compiled in this run */
Expand Down
5 changes: 5 additions & 0 deletions src/compiler/scala/tools/nsc/GlobalSymbolLoaders.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ package scala
package tools
package nsc

import scala.tools.nsc.Reporting.WarningCategory

/**
* Symbol loaders implementation that wires dependencies using Global.
*/
Expand All @@ -34,4 +36,7 @@ abstract class GlobalSymbolLoaders extends symtab.SymbolLoaders {

protected def compileLate(srcfile: io.AbstractFile): Unit =
currentRun.compileLate(srcfile)

def warning(pos: Position, msg: String, category: WarningCategory, site: String): Unit =
runReporting.warning(pos, msg, category, site)
}
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/PhaseAssembly.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package scala.tools.nsc

import scala.collection.mutable
import scala.tools.nsc.Reporting.WarningCategory

/** Converts an unordered morass of components into an order that
* satisfies their mutual constraints.
Expand Down Expand Up @@ -202,7 +203,7 @@ trait PhaseAssembly {
edges -= edge
edge.frm.after -= edge
if (edge.frm.phaseobj exists (lsc => !lsc.head.internal))
warning(msg)
runReporting.warning(NoPosition, msg, WarningCategory.Other, site = "")
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/scala/tools/nsc/PipelineMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import scala.math.Ordering.Double.TotalOrdering
import scala.reflect.internal.util.{BatchSourceFile, FakePos, NoPosition, Position}
import scala.reflect.io.PlainNioFile
import scala.tools.nsc.PipelineMain.{OutlineTypePipeline, Pipeline, Traditional}
import scala.tools.nsc.Reporting.WarningCategory
import scala.tools.nsc.io.AbstractFile
import scala.tools.nsc.reporters.{ConsoleReporter, Reporter}
import scala.tools.nsc.util.ClassPath
Expand Down Expand Up @@ -564,7 +565,7 @@ class PipelineMainClass(argFiles: Seq[Path], pipelineSettings: PipelineMain.Pipe
}
diagnostic.getKind match {
case Kind.ERROR => reporter.error(position, msg)
case Kind.WARNING | Kind.MANDATORY_WARNING => reporter.warning(position, msg)
case Kind.WARNING | Kind.MANDATORY_WARNING => Task.this.compiler.runReporting.warning(position, msg, WarningCategory.JavaSource, site = "")
case Kind.NOTE | Kind.OTHER => reporter.echo(position, msg)
}
}
Expand Down
Loading

0 comments on commit 39d3b3a

Please sign in to comment.