From 62c8f90f3105b8f19a9f29f104ff232438372c73 Mon Sep 17 00:00:00 2001 From: Adriaan Moors Date: Sat, 14 Jun 2014 00:38:30 +0200 Subject: Uniformly route reporting through reporter. Sharpen interfaces, reduce footprint of Reporting trait. Ideally, all reporting should indirect through reporter, and the `Reporting` trait itself should be restricted to a single method that retrieves the current `reporter`. Pull up some more reporting to reflect.internal. Would like to do more, but need to move partest to the reflect.internal interface first. (Its `errorCount` relies on `ERROR.count` in `tools.nsc.Reporter`.) --- src/compiler/scala/tools/nsc/Reporting.scala | 12 ++-- .../tools/nsc/reporters/AbstractReporter.scala | 11 ++-- .../scala/tools/nsc/reporters/Reporter.scala | 69 +++++++++------------- src/reflect/scala/reflect/internal/Reporting.scala | 65 ++++++++++++++++++-- .../scala/reflect/runtime/JavaUniverse.scala | 10 +++- 5 files changed, 110 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/compiler/scala/tools/nsc/Reporting.scala b/src/compiler/scala/tools/nsc/Reporting.scala index 614eb4f212..a8fd3bec76 100644 --- a/src/compiler/scala/tools/nsc/Reporting.scala +++ b/src/compiler/scala/tools/nsc/Reporting.scala @@ -10,9 +10,15 @@ package nsc import reporters.{ Reporter, ConsoleReporter } import scala.collection.{ mutable, immutable } +/** Provides delegates to the reporter doing the actual work. + * PerRunReporting implements per-Run stateful info tracking and reporting + * + * TODO: make reporting configurable + */ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions with CompilationUnits with scala.reflect.api.Symbols => def settings: Settings - def reporter: Reporter + + // == currentRun.reporting def currentReporting: PerRunReporting def supplementTyperState(errorMessage: String): String @@ -21,10 +27,6 @@ trait Reporting extends scala.reflect.internal.Reporting { self: ast.Positions w // nearly every trait really must go. For now using globalError. def error(msg: String) = globalError(msg) - override def inform(pos: Position, msg: String) = reporter.echo(pos, msg) - override def warning(pos: Position, msg: String) = reporter.warning(pos, msg) - override def globalError(pos: Position, msg: String) = reporter.error(pos, msg) - override def deprecationWarning(pos: Position, msg: String) = currentReporting.deprecationWarning(pos, msg) override def supplementErrorMessage(errorMessage: String) = currentReporting.supplementErrorMessage(errorMessage) diff --git a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala index 16d432438a..6c592ead0d 100644 --- a/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/AbstractReporter.scala @@ -62,12 +62,13 @@ abstract class AbstractReporter extends Reporter { */ private def testAndLog(pos: Position, severity: Severity, msg: String): Boolean = pos != null && pos.isDefined && { - val fpos = pos.focus + val fpos = pos.focus val suppress = positions(fpos) match { - case ERROR => true // already error at position - case highest if highest > severity => true // already message higher than present severity - case `severity` => messages(fpos) contains msg // already issued this exact message - case _ => false // good to go + case ERROR => true // already error at position + case highest + if highest.id > severity.id => true // already message higher than present severity + case `severity` => messages(fpos) contains msg // already issued this exact message + case _ => false // good to go } suppress || { diff --git a/src/compiler/scala/tools/nsc/reporters/Reporter.scala b/src/compiler/scala/tools/nsc/reporters/Reporter.scala index b617e7b530..5b576a547d 100644 --- a/src/compiler/scala/tools/nsc/reporters/Reporter.scala +++ b/src/compiler/scala/tools/nsc/reporters/Reporter.scala @@ -10,59 +10,48 @@ import scala.reflect.internal.util._ /** Report information, warnings and errors. * - * This describes the stable interface for issuing information, warnings and errors. + * This describes the internal interface for issuing information, warnings and errors. * The only abstract method in this class must be info0. + * + * TODO: Move external clients (sbt/ide/partest) to reflect.internal.Reporter + * This interface should be considered private to the compiler. */ -abstract class Reporter { - protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit - +abstract class Reporter extends scala.reflect.internal.Reporter { /** Informational messages. If `!force`, they may be suppressed. */ final def info(pos: Position, msg: String, force: Boolean): Unit = info0(pos, msg, INFO, force) /** For sending a message which should not be labeled as a warning/error, * but also shouldn't require -verbose to be visible. */ - def echo(msg: String): Unit = info(NoPosition, msg, force = true) - def echo(pos: Position, msg: String): Unit = info(pos, msg, force = true) - - /** Warnings and errors. */ - def warning(pos: Position, msg: String): Unit = info0(pos, msg, WARNING, force = false) - def error(pos: Position, msg: String): Unit = info0(pos, msg, ERROR, force = false) - - def flush(): Unit = { } + def echo(msg: String): Unit = info(NoPosition, msg, force = true) - // overridden by sbt, IDE - def reset(): Unit = { - INFO.count = 0 - WARNING.count = 0 - ERROR.count = 0 - cancelled = false - } - - object severity extends Enumeration - class Severity(val id: Int) extends severity.Value { - var count: Int = 0 - } - val INFO = new Severity(0) { - override def toString: String = "INFO" - } - val WARNING = new Severity(1) { - override def toString: String = "WARNING" - } - val ERROR = new Severity(2) { - override def toString: String = "ERROR" - } + // overridden by sbt, IDE -- should not be in the reporting interface + // (IDE receives comments from ScaladocAnalyzer using this hook method) + // TODO: IDE should override a hook method in the parser instead + def comment(pos: Position, msg: String): Unit = {} // used by sbt (via unit.cancel) to cancel a compile (see hasErrors) + // TODO: figure out how sbt uses this, come up with a separate interface for controlling the build var cancelled: Boolean = false - // overridden by sbt - def hasErrors: Boolean = ERROR.count > 0 || cancelled + override def hasErrors: Boolean = super.hasErrors || cancelled - // overridden by sbt - def hasWarnings: Boolean = WARNING.count > 0 + override def reset(): Unit = { + super.reset() + cancelled = false + } - // overridden by sbt, IDE -- should move out of this interface - // it's unrelated to reporting (IDE receives comments from ScaladocAnalyzer) - def comment(pos: Position, msg: String): Unit = {} + // the below is copy/pasted from ReporterImpl for now + // partest expects this inner class + // TODO: rework partest to use the scala.reflect.internal interface, + // remove duplication here, and consolidate reflect.internal.{ReporterImpl & ReporterImpl} + class Severity(val id: Int)(name: String) { var count: Int = 0 ; override def toString = name} + object INFO extends Severity(0)("INFO") + object WARNING extends Severity(1)("WARNING") + // reason for copy/paste: this is used by partest (must be a val, not an object) + // TODO: use count(ERROR) in scala.tools.partest.nest.DirectCompiler#errorCount, rather than ERROR.count + lazy val ERROR = new Severity(2)("ERROR") + + def count(severity: Severity): Int = severity.count + def resetCount(severity: Severity): Unit = severity.count = 0 } diff --git a/src/reflect/scala/reflect/internal/Reporting.scala b/src/reflect/scala/reflect/internal/Reporting.scala index e88e765750..baeed1357d 100644 --- a/src/reflect/scala/reflect/internal/Reporting.scala +++ b/src/reflect/scala/reflect/internal/Reporting.scala @@ -7,11 +7,20 @@ package scala package reflect package internal +/** Provides delegates to the reporter doing the actual work. + * All forwarding methods should be marked final, + * but some subclasses out of our reach stil override them. + */ trait Reporting { self : Positions => + def reporter: Reporter + + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") def inform(msg: String): Unit = inform(NoPosition, msg) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") def warning(msg: String): Unit = warning(NoPosition, msg) // globalError(msg: String) used to abort -- not sure that was a good idea, so I made it more regular // (couldn't find any uses that relied on old behavior) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") def globalError(msg: String): Unit = globalError(NoPosition, msg) def abort(msg: String): Nothing = { @@ -21,12 +30,60 @@ trait Reporting { self : Positions => throw new FatalError(augmented) } - def inform(pos: Position, msg: String) = Console.out.println(msg) - def warning(pos: Position, msg: String) = Console.err.println(msg) - def globalError(pos: Position, msg: String) = Console.err.println(msg) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") + def inform(pos: Position, msg: String) = reporter.echo(pos, msg) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") + def warning(pos: Position, msg: String) = reporter.warning(pos, msg) + @deprecatedOverriding("This forwards to the corresponding method in reporter -- override reporter instead", "2.11.2") + def globalError(pos: Position, msg: String) = reporter.error(pos, msg) def deprecationWarning(pos: Position, msg: String): Unit = warning(msg) /** Overridden when we know more about what was happening during a failure. */ def supplementErrorMessage(msg: String): String = msg -} \ No newline at end of file +} + +import util.Position + +/** Report information, warnings and errors. + * + * This describes the (future) external interface for issuing information, warnings and errors. + * Currently, scala.tools.nsc.Reporter is used by sbt/ide/partest. + */ +abstract class Reporter { + protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit + + def echo(pos: Position, msg: String): Unit = info0(pos, msg, INFO, force = true) + def warning(pos: Position, msg: String): Unit = info0(pos, msg, WARNING, force = false) + def error(pos: Position, msg: String): Unit = info0(pos, msg, ERROR, force = false) + + type Severity + val INFO: Severity + val WARNING: Severity + val ERROR: Severity + + def count(severity: Severity): Int + def resetCount(severity: Severity): Unit + + def hasErrors: Boolean = count(ERROR) > 0 + def hasWarnings: Boolean = count(WARNING) > 0 + + def reset(): Unit = { + resetCount(INFO) + resetCount(WARNING) + resetCount(ERROR) + } + + def flush(): Unit = { } +} + +// TODO: move into superclass once partest cuts tie on Severity +abstract class ReporterImpl extends Reporter { + class Severity(val id: Int)(name: String) { var count: Int = 0 ; override def toString = name} + object INFO extends Severity(0)("INFO") + object WARNING extends Severity(1)("WARNING") + object ERROR extends Severity(2)("ERROR") + + def count(severity: Severity): Int = severity.count + def resetCount(severity: Severity): Unit = severity.count = 0 +} diff --git a/src/reflect/scala/reflect/runtime/JavaUniverse.scala b/src/reflect/scala/reflect/runtime/JavaUniverse.scala index b5446694ed..d846ef2cdd 100644 --- a/src/reflect/scala/reflect/runtime/JavaUniverse.scala +++ b/src/reflect/scala/reflect/runtime/JavaUniverse.scala @@ -14,15 +14,19 @@ import scala.reflect.api.{TreeCreator, TypeCreator, Universe} * @contentDiagram hideNodes "*Api" "*Extractor" */ class JavaUniverse extends InternalSymbolTable with JavaUniverseForce with ReflectSetup with RuntimeSymbolTable { self => - - override def inform(msg: String): Unit = log(msg) def picklerPhase = SomePhase def erasurePhase = SomePhase lazy val settings = new Settings - private val isLogging = sys.props contains "scala.debug.reflect" + private val isLogging = sys.props contains "scala.debug.reflect" def log(msg: => AnyRef): Unit = if (isLogging) Console.err.println("[reflect] " + msg) + // TODO: why put output under isLogging? Calls to inform are already conditional on debug/verbose/... + import scala.reflect.internal.{Reporter, ReporterImpl} + override def reporter: Reporter = new ReporterImpl { + protected def info0(pos: Position, msg: String, severity: Severity, force: Boolean): Unit = log(msg) + } + type TreeCopier = InternalTreeCopierOps implicit val TreeCopierTag: ClassTag[TreeCopier] = ClassTag[TreeCopier](classOf[TreeCopier]) def newStrictTreeCopier: TreeCopier = new StrictTreeCopier -- cgit v1.2.3