aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Odersky <odersky@gmail.com>2013-07-19 19:08:42 +0200
committerMartin Odersky <odersky@gmail.com>2013-07-19 19:08:42 +0200
commit919310a29daebabe3335d428f5f5e52ed6295cbd (patch)
tree8f8e898afb10b3735cd1aa6101f19b19fbf18682
parent702c4fc89f3ff2abbc7457fd72ab19b5bbdbb782 (diff)
downloaddotty-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.
-rw-r--r--src/dotty/tools/dotc/core/Diagnostic.scala10
-rw-r--r--src/dotty/tools/dotc/core/TyperState.scala1
-rw-r--r--src/dotty/tools/dotc/parsing/Parsers.scala4
-rw-r--r--src/dotty/tools/dotc/parsing/Scanners.scala2
-rw-r--r--src/dotty/tools/dotc/reporting/ConsoleReporter.scala22
-rw-r--r--src/dotty/tools/dotc/reporting/Reporter.scala190
-rw-r--r--src/dotty/tools/dotc/reporting/StoreReporter.scala22
-rw-r--r--src/dotty/tools/dotc/reporting/UniqueMessagePositions.scala20
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()
- }
}