aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2014-05-04 13:42:45 +0200
committerSamuel Gruetter <samuel.gruetter@epfl.ch>2014-05-20 13:37:35 +0200
commit94ceb9895a539b05fd81c8abe040c276178b5507 (patch)
tree84992aee9920f62e4ffbf62529b32cffd2c3b505
parent1b32071acef5c7c2c08e21ee577c7cc709876ffa (diff)
downloaddotty-94ceb9895a539b05fd81c8abe040c276178b5507.tar.gz
dotty-94ceb9895a539b05fd81c8abe040c276178b5507.tar.bz2
dotty-94ceb9895a539b05fd81c8abe040c276178b5507.zip
Reporter refactoring
Refactored reporters to increase clarity and to pave the way for having Diagnostics subclasses.
-rw-r--r--src/dotty/tools/dotc/reporting/ConsoleReporter.scala15
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala166
-rw-r--r--src/dotty/tools/dotc/reporting/StoreReporter.scala10
-rw-r--r--src/dotty/tools/dotc/reporting/ThrowingReporter.scala6
-rw-r--r--src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala10
-rw-r--r--src/dotty/tools/dotc/typer/ProtoTypes.scala4
-rw-r--r--test/test/CompilerTest.scala2
7 files changed, 100 insertions, 113 deletions
diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
index 1bad29e23..6991cdbb6 100644
--- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
+++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala
@@ -40,11 +40,16 @@ class ConsoleReporter(
}
}
- override def doReport(d: Diagnostic)(implicit ctx: Context): Unit =
- if (d.severity != ERROR || count(d.severity.level) <= ErrorLimit && !d.isSuppressed) {
- printMessageAndPos(label(d.severity) + d.msg, d.pos)
- if (d.severity == ERROR && ctx.settings.prompt.value) displayPrompt()
- }
+ override def doReport(d: Diagnostic)(implicit ctx: Context): Unit = d match {
+ case d: Error =>
+ printMessageAndPos(s"error: ${d.msg}", d.pos)
+ if (ctx.settings.prompt.value) displayPrompt()
+ case d: ConditionalWarning if !d.enablingOption.value =>
+ case d: Warning =>
+ printMessageAndPos(s"warning: ${d.msg}", d.pos)
+ case _ =>
+ printMessageAndPos(d.msg, d.pos)
+ }
def displayPrompt(): Unit = {
writer.print("\na)bort, s)tack, r)esume: ")
diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala
index b0404c6b3..82b0a1158 100644
--- a/src/dotty/tools/dotc/reporting/Reporter.scala
+++ b/src/dotty/tools/dotc/reporting/Reporter.scala
@@ -14,10 +14,17 @@ import typer.ErrorReporting.DiagnosticString
object Reporter {
- class Diagnostic(msgFn: => String, val pos: SourcePosition, val severity: Severity) extends Exception {
+ private val ERROR = 2
+ private val WARNING = 1
+ private val INFO = 0
+
+ class Diagnostic(msgFn: => String, val pos: SourcePosition, val level: Int) extends Exception {
import DiagnosticString._
+
private var myMsg: String = null
private var myIsNonSensical: Boolean = false
+
+ /** The message to report */
def msg: String = {
if (myMsg == null) {
myMsg = msgFn
@@ -29,48 +36,32 @@ object Reporter {
}
myMsg
}
+
+ /** Report in current reporter */
+ def report(implicit ctx: Context) = ctx.reporter.report(this)
+
def isNonSensical = { msg; myIsNonSensical }
def isSuppressed(implicit ctx: Context): Boolean = !ctx.settings.YshowSuppressedErrors.value && isNonSensical
- override def toString = s"$severity at $pos: $msg"
- override def getMessage() = msg
-
- def promotedSeverity(implicit ctx: Context): Severity =
- if (isConditionalWarning(severity) && enablingOption(severity).value) WARNING
- else severity
- }
- def Diagnostic(msgFn: => String, pos: SourcePosition, severity: Severity) =
- new Diagnostic(msgFn, pos, severity)
-
- class Severity(val level: Int) extends AnyVal {
- override def toString = this match {
- case VerboseINFO => "VerboseINFO"
- case INFO => "INFO"
- case DeprecationWARNING => "DeprecationWARNING"
- case UncheckedWARNING => "UncheckedWARNING"
- case FeatureWARNING => "FeatureWARNING"
- case WARNING => "WARNING"
- case ERROR => "ERROR"
- }
+ override def toString = s"$getClass at $pos: $msg"
+ override def getMessage() = msg
}
- final val VerboseINFO = new Severity(0)
- final val INFO = new Severity(1)
- final val DeprecationWARNING = new Severity(2)
- final val UncheckedWARNING = new Severity(3)
- final val FeatureWARNING = new Severity(4)
- final val WARNING = new Severity(5)
- final val ERROR = new Severity(6)
-
- def isConditionalWarning(s: Severity) =
- DeprecationWARNING.level <= s.level && s.level <= FeatureWARNING.level
+ class Error(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, ERROR)
+ class Warning(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, WARNING)
+ class Info(msgFn: => String, pos: SourcePosition) extends Diagnostic(msgFn, pos, INFO)
- val conditionalWarnings = List(DeprecationWARNING, UncheckedWARNING, FeatureWARNING)
-
- private def enablingOption(warning: Severity)(implicit ctx: Context) = warning match {
- case DeprecationWARNING => ctx.settings.deprecation
- case UncheckedWARNING => ctx.settings.unchecked
- case FeatureWARNING => ctx.settings.feature
+ abstract class ConditionalWarning(msgFn: => String, pos: SourcePosition) extends Warning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context): Setting[Boolean]
+ }
+ class FeatureWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context) = ctx.settings.feature
+ }
+ class UncheckedWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context) = ctx.settings.unchecked
+ }
+ class DeprecationWarning(msgFn: => String, pos: SourcePosition) extends ConditionalWarning(msgFn, pos) {
+ def enablingOption(implicit ctx: Context) = ctx.settings.deprecation
}
}
@@ -80,30 +71,30 @@ trait Reporting { this: Context =>
/** For sending messages that are printed only if -verbose is set */
def inform(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, VerboseINFO))
+ if (this.settings.verbose.value) echo(msg, pos)
def echo(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, INFO))
+ reporter.report(new Info(msg, pos))
def deprecationWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, DeprecationWARNING))
+ reporter.report(new DeprecationWarning(msg, pos))
def uncheckedWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, UncheckedWARNING))
+ reporter.report(new UncheckedWarning(msg, pos))
def featureWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, FeatureWARNING))
+ reporter.report(new FeatureWarning(msg, pos))
def warning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit =
- reporter.report(Diagnostic(msg, pos, WARNING))
+ reporter.report(new Warning(msg, pos))
def error(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = {
// println("*** ERROR: " + msg) // !!! DEBUG
- reporter.report(Diagnostic(msg, pos, ERROR))
+ reporter.report(new Error(msg, pos))
}
def incompleteInputError(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit =
- reporter.incomplete(Diagnostic(msg, pos, ERROR))(ctx)
+ reporter.incomplete(new Error(msg, pos))(ctx)
/** Log msg if current phase or its precedessor is mentioned in
* settings.log.
@@ -209,71 +200,54 @@ abstract class Reporter {
finally incompleteHandler = saved
}
- protected def isHidden(d: Diagnostic)(implicit ctx: Context) = d.promotedSeverity match {
- case VerboseINFO => !ctx.settings.verbose.value
- case DeprecationWARNING | UncheckedWARNING | FeatureWARNING => true
- case _ => false
- }
+ var errorCount = 0
+ var warningCount = 0
+ def hasErrors = errorCount > 0
+ def hasWarnings = warningCount > 0
- val count = new Array[Int](ERROR.level + 1)
+ val unreportedWarnings = new mutable.HashMap[String, Int] {
+ override def default(key: String) = 0
+ }
- def report(d: Diagnostic)(implicit ctx: Context): Unit =
- if (!isHidden(d)) {
- doReport(d)
- if (!d.isSuppressed) count(d.promotedSeverity.level) += 1
+ def report(d: Diagnostic)(implicit ctx: Context): Unit = if (!isHidden(d)) {
+ doReport(d)
+ if (!d.isSuppressed) d match {
+ case d: ConditionalWarning if !d.enablingOption.value => unreportedWarnings(d.enablingOption.name) += 1
+ case d: Warning => warningCount += 1
+ case d: Error => errorCount += 1
+ case d: Info => // nothing to do here
+ // match error if d is something else
}
+ }
def incomplete(d: Diagnostic)(implicit ctx: Context): Unit =
incompleteHandler(d)(ctx)
- def hasErrors = count(ERROR.level) > 0
- def hasWarnings = count(WARNING.level) > 0
- def errorCounts: Any = count.clone
-
- def wasSilent[T](counts: Any): Boolean = {
- val prevCount = counts.asInstanceOf[Array[Int]]
- var i = 0
- while (i < count.length) {
- if (prevCount(i) != count(i)) return false
- i += 1
- }
- true
+ /** Print a summary */
+ def printSummary(implicit ctx: Context): Unit = {
+ if (warningCount > 0) ctx.echo(countString(warningCount, "warning") + " found")
+ if (errorCount > 0) ctx.echo(countString(errorCount, "error") + " found")
+ for ((settingName, count) <- unreportedWarnings)
+ ctx.echo(s"there were $count ${settingName.tail} warning(s); re-run with $settingName for details")
}
/** Returns a string meaning "n elements". */
- private def countElementsAsString(n: Int, elements: String): String =
- n match {
- case 0 => "no " + elements + "s"
- case 1 => "one " + elements
- case 2 => "two " + elements + "s"
- case 3 => "three " + elements + "s"
- case 4 => "four " + elements + "s"
- case _ => n + " " + elements + "s"
- }
-
- protected def label(severity: Severity): String = severity match {
- case ERROR => "error: "
- case WARNING => "warning: "
- case _ => ""
+ private def countString(n: Int, elements: String): String = n match {
+ case 0 => "no " + elements + "s"
+ case 1 => "one " + elements
+ case 2 => "two " + elements + "s"
+ case 3 => "three " + elements + "s"
+ case 4 => "four " + elements + "s"
+ case _ => n + " " + elements + "s"
}
- protected def countString(severity: Severity) = {
- assert(severity.level >= WARNING.level)
- countElementsAsString(count(severity.level), label(severity).dropRight(2))
- }
+ /** Should this diagnostic not be reported at all? */
+ def isHidden(d: Diagnostic)(implicit ctx: Context): Boolean = false
- def printSummary(implicit ctx: Context): Unit = {
- if (count(WARNING.level) > 0) ctx.echo(countString(WARNING) + " found")
- if ( count(ERROR.level) > 0) ctx.echo(countString(ERROR ) + " found")
- for (cwarning <- conditionalWarnings) {
- val unreported = count(cwarning.level)
- if (unreported > 0) {
- val what = enablingOption(cwarning).name.tail
- ctx.warning(s"there were $unreported $what warning(s); re-run with -$what for details")
- }
- }
- }
+ /** Does this reporter contain not yet reported errors or warnings? */
+ def hasPending: Boolean = false
+ /** Issue all error messages in this reporter to next outer one, or make sure they are written. */
def flush()(implicit ctx: Context): Unit = {}
}
diff --git a/src/dotty/tools/dotc/reporting/StoreReporter.scala b/src/dotty/tools/dotc/reporting/StoreReporter.scala
index 67b90eec0..ea8199102 100644
--- a/src/dotty/tools/dotc/reporting/StoreReporter.scala
+++ b/src/dotty/tools/dotc/reporting/StoreReporter.scala
@@ -4,7 +4,7 @@ package reporting
import core.Contexts.Context
import collection.mutable
-import Reporter.Diagnostic
+import Reporter.{Diagnostic, Error, Warning}
import config.Printers._
/**
@@ -20,6 +20,14 @@ class StoreReporter extends Reporter {
infos += d
}
+ override def hasPending: Boolean = infos != null && {
+ infos exists {
+ case d: Error => true
+ case d: Warning => true
+ case _ => false
+ }
+ }
+
override def flush()(implicit ctx: Context) =
if (infos != null) infos foreach ctx.reporter.report
}
diff --git a/src/dotty/tools/dotc/reporting/ThrowingReporter.scala b/src/dotty/tools/dotc/reporting/ThrowingReporter.scala
index d44a08fb6..eb854d513 100644
--- a/src/dotty/tools/dotc/reporting/ThrowingReporter.scala
+++ b/src/dotty/tools/dotc/reporting/ThrowingReporter.scala
@@ -10,6 +10,8 @@ import Reporter._
* This class implements a Reporter that stores all messages
*/
class ThrowingReporter(reportInfo: Reporter) extends Reporter {
- protected def doReport(d: Diagnostic)(implicit ctx: Context): Unit =
- if (d.severity == ERROR) throw d else reportInfo.report(d)
+ protected def doReport(d: Diagnostic)(implicit ctx: Context): Unit = d match {
+ case _: Error => throw d
+ case _ => reportInfo.report(d)
+ }
}
diff --git a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
index 93e24b27f..c1f240a23 100644
--- a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
+++ b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala
@@ -4,16 +4,16 @@ package reporting
import scala.collection.mutable
import util.{SourcePosition, SourceFile}
-import Reporter.{Severity, Diagnostic}
+import Reporter.Diagnostic
import core.Contexts.Context
/**
- * This trait implements `isHidden` do that multiple messages per position
+ * This trait implements `isHidden` so that multiple messages per position
* are suppressed, unless they are of increasing severity.
*/
trait UniqueMessagePositions extends Reporter {
- private val positions = new mutable.HashMap[(SourceFile, Int), Severity]
+ private val positions = new mutable.HashMap[(SourceFile, Int), Int]
/** Logs a position and returns true if it was already logged.
* @note Two positions are considered identical for logging if they have the same point.
@@ -22,8 +22,8 @@ trait UniqueMessagePositions extends Reporter {
super.isHidden(d) || {
d.pos.exists && {
positions get (ctx.source, d.pos.point) match {
- case Some(s) if s.level >= d.severity.level => true
- case _ => positions((ctx.source, d.pos.point)) = d.severity; false
+ case Some(level) if level >= d.level => true
+ case _ => positions((ctx.source, d.pos.point)) = d.level; false
}
}
}
diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala
index 4aba4fb59..fab652849 100644
--- a/src/dotty/tools/dotc/typer/ProtoTypes.scala
+++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala
@@ -183,10 +183,8 @@ object ProtoTypes {
def typedArg(arg: untpd.Tree, formal: Type)(implicit ctx: Context): Tree = {
var targ = myTypedArg(arg)
if (targ == null) {
- val counts = ctx.reporter.errorCounts
targ = typer.typedUnadapted(arg, formal)
- if (ctx.reporter.wasSilent(counts))
- myTypedArg = myTypedArg.updated(arg, targ)
+ if (!ctx.reporter.hasPending) myTypedArg = myTypedArg.updated(arg, targ)
}
typer.adapt(targ, formal)
}
diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala
index 1bf138d54..3a24e0421 100644
--- a/test/test/CompilerTest.scala
+++ b/test/test/CompilerTest.scala
@@ -11,7 +11,7 @@ class CompilerTest extends DottyTest {
def compileArgs(args: Array[String], xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = {
val allArgs = args ++ defaultOptions
val processor = if (allArgs.exists(_.startsWith("#"))) Bench else Main
- val nerrors = processor.process(allArgs, ctx).count(Reporter.ERROR.level)
+ val nerrors = processor.process(allArgs, ctx).errorCount
assert(nerrors == xerrors, s"Wrong # of errors. Expected: $xerrors, found: $nerrors")
}