diff options
author | Martin Odersky <odersky@gmail.com> | 2013-07-19 19:08:42 +0200 |
---|---|---|
committer | Martin Odersky <odersky@gmail.com> | 2013-07-19 19:08:42 +0200 |
commit | 919310a29daebabe3335d428f5f5e52ed6295cbd (patch) | |
tree | 8f8e898afb10b3735cd1aa6101f19b19fbf18682 /src/dotty/tools | |
parent | 702c4fc89f3ff2abbc7457fd72ab19b5bbdbb782 (diff) | |
download | dotty-919310a29daebabe3335d428f5f5e52ed6295cbd.tar.gz dotty-919310a29daebabe3335d428f5f5e52ed6295cbd.tar.bz2 dotty-919310a29daebabe3335d428f5f5e52ed6295cbd.zip |
Made reporting framework more lightweight and uniform in preparation of future integration of reporters in typerstate.
Diffstat (limited to 'src/dotty/tools')
-rw-r--r-- | src/dotty/tools/dotc/core/Diagnostic.scala | 10 | ||||
-rw-r--r-- | src/dotty/tools/dotc/core/TyperState.scala | 1 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Parsers.scala | 4 | ||||
-rw-r--r-- | src/dotty/tools/dotc/parsing/Scanners.scala | 2 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/ConsoleReporter.scala | 22 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/Reporter.scala | 190 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/StoreReporter.scala | 22 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala | 20 |
8 files changed, 132 insertions, 139 deletions
diff --git a/src/dotty/tools/dotc/core/Diagnostic.scala b/src/dotty/tools/dotc/core/Diagnostic.scala deleted file mode 100644 index e1b7ee848..000000000 --- a/src/dotty/tools/dotc/core/Diagnostic.scala +++ /dev/null @@ -1,10 +0,0 @@ -package dotty.tools -package dotc -package core - -import util.SourcePosition -import reporting.Reporter - -class Diagnostic(msgFn: => String, val pos: SourcePosition, severity: Reporter.Severity.Value) { - lazy val msg: String = msgFn -} diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala index 76787e070..89589c164 100644 --- a/src/dotty/tools/dotc/core/TyperState.scala +++ b/src/dotty/tools/dotc/core/TyperState.scala @@ -6,6 +6,7 @@ import Types._ import Flags._ import Contexts._ import util.SimpleMap +import reporting.Reporter.Diagnostic class TyperState extends DotClass { diff --git a/src/dotty/tools/dotc/parsing/Parsers.scala b/src/dotty/tools/dotc/parsing/Parsers.scala index 85d134653..04932c7f0 100644 --- a/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/src/dotty/tools/dotc/parsing/Parsers.scala @@ -176,7 +176,7 @@ object Parsers { ctx.warning(msg, source atPos Position(offset)) def deprecationWarning(msg: String, offset: Int = in.offset) = - ctx.deprecation.warning(msg, source atPos Position(offset)) + ctx.deprecationWarning(msg, source atPos Position(offset)) /** The offset where the last syntax error was reported, or if a skip to a * safepoint occurred afterwards, the offset of the safe point. @@ -200,7 +200,7 @@ object Parsers { /** Issue an error at current offset taht input is incomplete */ def incompleteInputError(msg: String) = - ctx.reporter.incompleteInputError(msg, source atPos Position(in.offset)) + ctx.incompleteInputError(msg, source atPos Position(in.offset)) /** If at end of file, issue an incompleteInputError. * Otherwise issue a syntax error and skip to next safe point. diff --git a/src/dotty/tools/dotc/parsing/Scanners.scala b/src/dotty/tools/dotc/parsing/Scanners.scala index c923b7c6c..f254cab17 100644 --- a/src/dotty/tools/dotc/parsing/Scanners.scala +++ b/src/dotty/tools/dotc/parsing/Scanners.scala @@ -940,7 +940,7 @@ object Scanners { /** signal an error where the input ended in the middle of a token */ def incompleteInputError(msg: String) { - ctx.reporter.incompleteInputError(msg, source atPos Position(offset)) + ctx.incompleteInputError(msg, source atPos Position(offset)) token = EOF errOffset = offset } diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index 9b72c4f5c..461697bfc 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -5,7 +5,7 @@ package reporting import scala.collection.mutable import util.SourcePosition import core.Contexts._ -import Reporter.Severity.{Value => Severity, _} +import Reporter._ import java.io.{ BufferedReader, IOException, PrintWriter } import scala.reflect.internal.util._ @@ -18,9 +18,6 @@ class ConsoleReporter( writer: PrintWriter = new PrintWriter(Console.err, true))(ctx: Context) extends Reporter(ctx) with UniqueMessagePositions { - /** Whether a short file name should be displayed before errors */ - protected def shortName: Boolean = false - /** maximal number of error messages to be printed */ protected def ErrorLimit = 100 @@ -34,22 +31,19 @@ class ConsoleReporter( def printMessage(msg: String) { writer.print(msg + "\n"); writer.flush() } /** Prints the message with the given position indication. */ - def printMessage(msg: String, pos: SourcePosition)(implicit ctx: Context) { - printMessage(s"${if (pos.exists) s"$pos: " else ""}$msg") + def printMessageAndPos(msg: String, pos: SourcePosition)(implicit ctx: Context) { + val posStr = if (pos.exists) s"$pos: " else "" + printMessage(posStr + msg) if (pos.exists) { printSourceLine(pos) printColumnMarker(pos) } } - def printMessage(msg: String, severity: Severity, pos: SourcePosition)(implicit ctx: Context) { - printMessage(label(severity) + msg, pos) - } - - override def report(msg: String, severity: Severity, pos: SourcePosition)(implicit ctx: Context) { - if (severity != ERROR || count(severity) <= ErrorLimit) - printMessage(msg, severity, pos) - if (severity != INFO && ctx.settings.prompt.value) displayPrompt() + override def doReport(d: Diagnostic)(implicit ctx: Context) { + if (d.severity != ERROR || count(d.severity.level) <= ErrorLimit) + printMessageAndPos(label(d.severity) + d.msg, d.pos) + if (d.severity.level > INFO.level && ctx.settings.prompt.value) displayPrompt() } def displayPrompt(): Unit = { diff --git a/src/dotty/tools/dotc/reporting/Reporter.scala b/src/dotty/tools/dotc/reporting/Reporter.scala index 851aa084d..2f580c2f9 100644 --- a/src/dotty/tools/dotc/reporting/Reporter.scala +++ b/src/dotty/tools/dotc/reporting/Reporter.scala @@ -10,37 +10,88 @@ import collection.mutable import config.Settings.Setting import java.lang.System.currentTimeMillis +object Reporter { + class Diagnostic(msgFn: => String, val pos: SourcePosition, val severity: Severity) { + lazy val msg: String = msgFn + override def toString = s"$severity at $pos: $msg" + } + + 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" + } + } + + 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 + + val conditionalWarnings = List(DeprecationWARNING, UncheckedWARNING, FeatureWARNING) +} + +import Reporter._ + trait Reporting { this: Context => - def error(msg: String, pos: SourcePosition = NoSourcePosition): Unit = reporter.error(msg, pos) - def warning(msg: String, pos: SourcePosition = NoSourcePosition): Unit = reporter.warning(msg, pos) - def inform(msg: String, pos: SourcePosition = NoSourcePosition): Unit = reporter.info(msg, pos) + + /** For sending messages that are printed only if -verbose is set */ + def inform(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + reporter.report(new Diagnostic(msg, pos, VerboseINFO)) + + def echo(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + reporter.report(new Diagnostic(msg, pos, INFO)) + + def deprecationWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + reporter.report(new Diagnostic(msg, pos, DeprecationWARNING)) + + def uncheckedWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + reporter.report(new Diagnostic(msg, pos, UncheckedWARNING)) + + def featureWarning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + reporter.report(new Diagnostic(msg, pos, FeatureWARNING)) + + def warning(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + reporter.report(new Diagnostic(msg, pos, WARNING)) + + def error(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = + reporter.report(new Diagnostic(msg, pos, ERROR)) + + def incompleteInputError(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = + reporter.incomplete(new Diagnostic(msg, pos, ERROR))(ctx) def log(msg: => String): Unit = if (this.settings.log.value.containsPhase(phase)) - inform(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg") + echo(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg") def debuglog(msg: => String): Unit = if (ctx.debug) log(msg) - def informTime(msg: => String, start: Long): Unit = - informProgress(msg + elapsed(start)) - - def deprecation = reporter.deprecation - def unchecked = reporter.unchecked - def feature = reporter.feature - - private def elapsed(start: Long) = - " in " + (currentTimeMillis - start) + "ms" + def informTime(msg: => String, start: Long): Unit = { + def elapsed = s" in ${currentTimeMillis - start}ms" + informProgress(msg + elapsed) + } def informProgress(msg: => String) = - if (this.settings.verbose.value) inform("[" + msg + "]") + inform("[" + msg + "]") def trace[T](msg: => String)(value: T) = { log(msg + " " + value) value } - def debugwarn(msg: String, pos: SourcePosition = NoSourcePosition): Unit = + def debugwarn(msg: => String, pos: SourcePosition = NoSourcePosition): Unit = if (this.settings.debug.value) warning(msg, pos) def debugTraceIndented[T](question: => String)(op: => T): T = @@ -72,27 +123,14 @@ trait Reporting { this: Context => } } -object Reporter { - object Severity extends Enumeration { - val INFO, WARNING, ERROR = Value - } -} - /** * This interface provides methods to issue information, warning and * error messages. */ abstract class Reporter(ctx: Context) { - import Reporter.Severity.{Value => Severity, _} - - protected def report(msg: String, severity: Severity, pos: SourcePosition)(implicit ctx: Context): Unit - - protected def isHidden(severity: Severity, pos: SourcePosition)(implicit ctx: Context) = false - - val count = new mutable.HashMap[Severity, Int]() { - override def default(key: Severity) = 0 - } + /** Report a diagnostic */ + protected def doReport(d: Diagnostic)(implicit ctx: Context): Unit /** Whether very long lines can be truncated. This exists so important * debugging information (like printing the classpath) is not rendered @@ -107,8 +145,8 @@ abstract class Reporter(ctx: Context) { finally _truncationOK = saved } - type ErrorHandler = (String, SourcePosition, Context) => Unit - private var incompleteHandler: ErrorHandler = error(_, _)(_) + type ErrorHandler = Diagnostic => Context => Unit + private var incompleteHandler: ErrorHandler = d => c => report(d)(c) def withIncompleteHandler[T](handler: ErrorHandler)(op: => T): T = { val saved = incompleteHandler incompleteHandler = handler @@ -116,35 +154,34 @@ abstract class Reporter(ctx: Context) { finally incompleteHandler = saved } - def hasErrors = count(ERROR) > 0 - def hasWarnings = count(WARNING) > 0 + protected def isHidden(s: Severity, pos: SourcePosition)(implicit ctx: Context) = s match { + case VerboseINFO => !ctx.settings.verbose.value + case DeprecationWARNING | UncheckedWARNING | FeatureWARNING => true + case _ => false + } - /** For sending messages that are printed only if -verbose is set */ - def info(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = - if (ctx.settings.verbose.value) info0(msg, INFO, pos) + 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 + } - /** 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, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = - info0(msg, INFO, pos) + private def promoteSeverity(s: Severity)(implicit ctx: Context): Severity = + if (isConditionalWarning(s) && enablingOption(s).value) WARNING else s - def warning(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = - if (!ctx.settings.nowarn.value) - withoutTruncating(info0(msg, WARNING, pos)) + val count = new Array[Int](ERROR.level + 1) - def error(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = - withoutTruncating(info0(msg, ERROR, pos)) + def report(d: Diagnostic)(implicit ctx: Context): Unit = { + val severity = promoteSeverity(d.severity) + if (!isHidden(severity, d.pos)) doReport(d) + count(severity.level) += 1 + } - def incompleteInputError(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context): Unit = - incompleteHandler(msg, pos, ctx) + def incomplete(d: Diagnostic)(implicit ctx: Context): Unit = + incompleteHandler(d)(ctx) - private def info0(msg: String, severity: Severity, pos: SourcePosition)(implicit ctx: Context): Unit = { - if (!isHidden(severity, pos)) { - count(severity) += 1 - report(msg, severity, pos) - } - } + def hasErrors = count(ERROR.level) > 0 + def hasWarnings = count(WARNING.level) > 0 /** Returns a string meaning "n elements". */ private def countElementsAsString(n: Int, elements: String): String = @@ -158,46 +195,27 @@ abstract class Reporter(ctx: Context) { } protected def label(severity: Severity): String = severity match { - case INFO => "" case ERROR => "error: " case WARNING => "warning: " + case _ => "" } protected def countString(severity: Severity) = { - assert(severity != INFO) - countElementsAsString(count(severity), label(severity).dropRight(2)) + assert(severity.level >= WARNING.level) + countElementsAsString(count(severity.level), label(severity).dropRight(2)) } def printSummary(implicit ctx: Context) { - if (count(WARNING) > 0) info(countString(WARNING) + " found") - if ( count(ERROR) > 0) info(countString(ERROR ) + " found") - allConditionalWarnings foreach (_.summarize) + 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") + } + } } def flush(): Unit = {} - - def reset(): Unit = { - count.clear() - allConditionalWarnings foreach (_.clear()) - } - - protected val allConditionalWarnings = new mutable.ListBuffer[ConditionalWarning] - - val deprecation = new ConditionalWarning("deprecation", ctx.settings.deprecation) - val unchecked = new ConditionalWarning("unchecked", ctx.settings.unchecked) - val feature = new ConditionalWarning("feature", ctx.settings.feature) - - /** Collects for certain classes of warnings during this run. */ - class ConditionalWarning(what: String, option: Setting[Boolean]) { - private var unreported: Int = 0 - def clear() = - unreported = 0 - def warning(msg: String, pos: SourcePosition = NoSourcePosition)(implicit ctx: Context) = - if (option.value) Reporter.this.warning(msg, pos) - else unreported += 1 - def summarize(implicit ctx: Context) = - if (unreported > 0) - Reporter.this.warning(s"there were $unreported $what warning(s); re-run with ${option.name} for details") - allConditionalWarnings += this - } } diff --git a/src/dotty/tools/dotc/reporting/StoreReporter.scala b/src/dotty/tools/dotc/reporting/StoreReporter.scala index 6818825f7..54daf2b6b 100644 --- a/src/dotty/tools/dotc/reporting/StoreReporter.scala +++ b/src/dotty/tools/dotc/reporting/StoreReporter.scala @@ -3,26 +3,20 @@ package dotc package reporting import core.Contexts.Context -import scala.collection.mutable -import util.SourcePosition -import Reporter.Severity.{Value => Severity} +import collection.mutable +import Reporter.Diagnostic /** * This class implements a Reporter that stores all messages */ class StoreReporter(ctx: Context) extends Reporter(ctx) { - class Info(val msg: String, val severity: Severity, val pos: SourcePosition) { - override def toString() = "pos: " + pos + " " + msg + " " + severity - } - val infos = new mutable.LinkedHashSet[Info] + val infos = new mutable.ListBuffer[Diagnostic] - protected def report(msg: String, severity: Severity, pos: SourcePosition)(implicit ctx: Context): Unit = { - infos += new Info(msg, severity, pos) - } + protected def doReport(d: Diagnostic)(implicit ctx: Context): Unit = + infos += d + + def replay(implicit ctx: Context) = + infos foreach ctx.reporter.report - override def reset() { - super.reset() - infos.clear() - } } diff --git a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala index 78c39ac7c..b14b842d0 100644 --- a/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala +++ b/src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala @@ -4,7 +4,7 @@ package reporting import scala.collection.mutable import util.{SourcePosition, SourceFile} -import Reporter.Severity.{Value => Severity} +import Reporter.Severity import core.Contexts.Context /** @@ -13,22 +13,18 @@ import core.Contexts.Context */ trait UniqueMessagePositions extends Reporter { - private val positions = - new mutable.HashMap[(SourceFile, Int), Severity] + private val positions = new mutable.HashMap[(SourceFile, Int), Severity] /** 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. */ override def isHidden(severity: Severity, pos: SourcePosition)(implicit ctx: Context): Boolean = - pos.exists && { - positions get (ctx.source, pos.point) match { - case Some(level) if level >= severity => true - case _ => positions((ctx.source, pos.point)) = severity; false + super.isHidden(severity, pos) || { + pos.exists && { + positions get (ctx.source, pos.point) match { + case Some(s) if s.level >= severity.level => true + case _ => positions((ctx.source, pos.point)) = severity; false + } } } - - override def reset(): Unit = { - super.reset() - positions.clear() - } } |