diff options
author | Felix Mulder <felix.mulder@gmail.com> | 2016-11-04 10:28:18 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-11-04 10:28:18 +0100 |
commit | 26e98d35c35f251c0f3ab785b7fbc19f5869da8d (patch) | |
tree | 3c7a0df13067af54e74134f894b16da0c987ccbc | |
parent | 0665c4f5accae915afd8abc57ed19f6d57e2cc08 (diff) | |
parent | e5aade87a9d7fb6c0319920c81ef3ee9f146bba1 (diff) | |
download | dotty-26e98d35c35f251c0f3ab785b7fbc19f5869da8d.tar.gz dotty-26e98d35c35f251c0f3ab785b7fbc19f5869da8d.tar.bz2 dotty-26e98d35c35f251c0f3ab785b7fbc19f5869da8d.zip |
Merge pull request #1646 from slothspot/1579
Fix #1579: Adapt the sbt bridge for the new error message
-rw-r--r-- | bridge/src/main/scala/xsbt/DelegatingReporter.scala | 44 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/ConsoleReporter.scala | 108 | ||||
-rw-r--r-- | src/dotty/tools/dotc/reporting/MessageRendering.scala | 111 |
3 files changed, 136 insertions, 127 deletions
diff --git a/bridge/src/main/scala/xsbt/DelegatingReporter.scala b/bridge/src/main/scala/xsbt/DelegatingReporter.scala index 446ef287e..770d6b2c7 100644 --- a/bridge/src/main/scala/xsbt/DelegatingReporter.scala +++ b/bridge/src/main/scala/xsbt/DelegatingReporter.scala @@ -9,12 +9,13 @@ import reporting._ import reporting.diagnostic.MessageContainer import reporting.diagnostic.messages import core.Contexts._ - import xsbti.{Maybe, Position} final class DelegatingReporter(delegate: xsbti.Reporter) extends Reporter with UniqueMessagePositions - with HideNonSensicalMessages { + with HideNonSensicalMessages + with MessageRendering { + import MessageContainer._ override def printSummary(implicit ctx: Context): Unit = delegate.printSummary() @@ -25,36 +26,23 @@ final class DelegatingReporter(delegate: xsbti.Reporter) extends Reporter case _: messages.Warning => xsbti.Severity.Warn case _ => xsbti.Severity.Info } - val pos = - if (cont.pos.exists) Some(cont.pos) - else None - - val file = - if (cont.pos.source.file.exists) Option(cont.pos.source.file.file) - else None - - val offset0 = pos.map(_.point) val position = new Position { - def line: Maybe[Integer] = maybe(pos.map(_.line)) - def lineContent: String = pos.map(_.lineContent).getOrElse("") - def offset: Maybe[Integer] = maybeInt(offset0) - def pointer: Maybe[Integer] = offset - def pointerSpace: Maybe[String] = maybe(offset0.map(" " * _)) - def sourceFile: Maybe[java.io.File] = maybe(file) - def sourcePath: Maybe[String] = maybe(file.map(_.getPath)) + def line: Maybe[Integer] = Maybe.nothing() + def lineContent: String = "" + def offset: Maybe[Integer] = Maybe.nothing() + def pointer: Maybe[Integer] = Maybe.nothing() + def pointerSpace: Maybe[String] = Maybe.nothing() + def sourceFile: Maybe[java.io.File] = Maybe.nothing() + def sourcePath: Maybe[String] = Maybe.nothing() } - delegate.log(position, cont.message, severity) - } + val sb = new StringBuilder() + sb.append(messageAndPos(cont.contained, cont.pos, diagnosticLevel(cont))) + if (ctx.shouldExplain(cont) && cont.contained.explanation.nonEmpty) { + sb.append(explanation(cont.contained)) + } - private[this] def maybe[T](opt: Option[T]): Maybe[T] = opt match { - case None => Maybe.nothing[T] - case Some(s) => Maybe.just[T](s) - } - import java.lang.{ Integer => I } - private[this] def maybeInt(opt: Option[Int]): Maybe[I] = opt match { - case None => Maybe.nothing[I] - case Some(s) => Maybe.just[I](s) + delegate.log(position, sb.toString(), severity) } } diff --git a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala index da3df6984..99a80982f 100644 --- a/src/dotty/tools/dotc/reporting/ConsoleReporter.scala +++ b/src/dotty/tools/dotc/reporting/ConsoleReporter.scala @@ -2,15 +2,10 @@ package dotty.tools package dotc package reporting -import scala.collection.mutable import util.SourcePosition -import core.Contexts._, core.Decorators._ -import Reporter._ -import java.io.{ BufferedReader, IOException, PrintWriter } -import scala.reflect.internal.util._ -import printing.SyntaxHighlighting._ -import printing.Highlighting._ -import diagnostic.{ Message, MessageContainer, NoExplanation } +import core.Contexts._ +import java.io.{ BufferedReader, PrintWriter } +import diagnostic.{ Message, MessageContainer } import diagnostic.messages._ /** @@ -19,7 +14,7 @@ import diagnostic.messages._ class ConsoleReporter( reader: BufferedReader = Console.in, writer: PrintWriter = new PrintWriter(Console.err, true) -) extends Reporter with UniqueMessagePositions with HideNonSensicalMessages { +) extends Reporter with UniqueMessagePositions with HideNonSensicalMessages with MessageRendering { import MessageContainer._ @@ -29,111 +24,26 @@ class ConsoleReporter( /** Prints the message. */ def printMessage(msg: String): Unit = { writer.print(msg + "\n"); writer.flush() } - def stripColor(str: String): String = - str.replaceAll("\u001B\\[[;\\d]*m", "") - - def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = { - var maxLen = Int.MinValue - def render(xs: List[Int]) = - xs.map(pos.source.offsetToLine(_)) - .map { lineNbr => - val prefix = s"${lineNbr + 1} |" - maxLen = math.max(maxLen, prefix.length) - (prefix, pos.lineContent(lineNbr).stripLineEnd) - } - .map { case (prefix, line) => - val lnum = Red(" " * math.max(0, maxLen - prefix.length) + prefix) - hl"$lnum$line" - } - - val (before, after) = pos.beforeAndAfterPoint - (render(before), render(after), maxLen) - } - - def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context) = { - val prefix = " " * (offset - 1) - val whitespace = " " * pos.startColumn - val carets = Red { - if (pos.startLine == pos.endLine) - "^" * math.max(1, pos.endColumn - pos.startColumn) - else "^" - } - - s"$prefix|$whitespace${carets.show}" - } - - def errorMsg(pos: SourcePosition, msg: String, offset: Int)(implicit ctx: Context) = { - val leastWhitespace = msg.lines.foldLeft(Int.MaxValue) { (minPad, line) => - val lineLength = stripColor(line).length - val padding = - math.min(math.max(0, ctx.settings.pageWidth.value - offset - lineLength), offset + pos.startColumn) - - if (padding < minPad) padding - else minPad - } - - msg.lines - .map { line => " " * (offset - 1) + "|" + (" " * (leastWhitespace - offset)) + line } - .mkString(sys.props("line.separator")) - } - - def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(implicit ctx: Context) = - if (pos.exists) Blue({ - val file = pos.source.file.toString - val errId = - if (message.errorId != NoExplanation.ID) - s"[E${"0" * (3 - message.errorId.toString.length) + message.errorId}] " - else "" - val kind = - if (message.kind == "") diagnosticLevel - else s"${message.kind} $diagnosticLevel" - val prefix = s"-- ${errId}${kind}: $file " - - prefix + - ("-" * math.max(ctx.settings.pageWidth.value - stripColor(prefix).length, 0)) - }).show else "" - /** Prints the message with the given position indication. */ def printMessageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): Boolean = { - printMessage(posStr(pos, diagnosticLevel, msg)) - if (pos.exists) { - val (srcBefore, srcAfter, offset) = sourceLines(pos) - val marker = columnMarker(pos, offset) - val err = errorMsg(pos, msg.msg, offset) - - printMessage((srcBefore ::: marker :: err :: srcAfter).mkString("\n")) - } else printMessage(msg.msg) + printMessage(messageAndPos(msg, pos, diagnosticLevel)) true } def printExplanation(m: Message)(implicit ctx: Context): Unit = { - printMessage(hl"""| - |${Blue("Explanation")} - |${Blue("===========")}""".stripMargin) - printMessage(m.explanation) - if (m.explanation.lastOption != Some('\n')) printMessage("") + printMessage(explanation(m)) } override def doReport(m: MessageContainer)(implicit ctx: Context): Unit = { val didPrint = m match { case m: Error => - val didPrint = printMessageAndPos(m.contained, m.pos, "Error") + val didPrint = printMessageAndPos(m.contained, m.pos, diagnosticLevel(m)) if (ctx.settings.prompt.value) displayPrompt() didPrint case m: ConditionalWarning if !m.enablingOption.value => false - case m: FeatureWarning => - printMessageAndPos(m.contained, m.pos, "Feature Warning") - case m: DeprecationWarning => - printMessageAndPos(m.contained, m.pos, "Deprecation Warning") - case m: UncheckedWarning => - printMessageAndPos(m.contained, m.pos, "Unchecked Warning") - case m: MigrationWarning => - printMessageAndPos(m.contained, m.pos, "Migration Warning") - case m: Warning => - printMessageAndPos(m.contained, m.pos, "Warning") - case m: Info => - printMessageAndPos(m.contained, m.pos, "Info") + case m => + printMessageAndPos(m.contained, m.pos, diagnosticLevel(m)) } if (didPrint && ctx.shouldExplain(m)) diff --git a/src/dotty/tools/dotc/reporting/MessageRendering.scala b/src/dotty/tools/dotc/reporting/MessageRendering.scala new file mode 100644 index 000000000..6d9e45a6e --- /dev/null +++ b/src/dotty/tools/dotc/reporting/MessageRendering.scala @@ -0,0 +1,111 @@ +package dotty.tools +package dotc +package reporting + +import core.Contexts.Context +import core.Decorators._ +import printing.Highlighting.{Blue, Red} +import diagnostic.{Message, MessageContainer, NoExplanation} +import diagnostic.messages._ +import util.SourcePosition + +import scala.collection.mutable + +trait MessageRendering { + def stripColor(str: String): String = + str.replaceAll("\u001B\\[[;\\d]*m", "") + + def sourceLines(pos: SourcePosition)(implicit ctx: Context): (List[String], List[String], Int) = { + var maxLen = Int.MinValue + def render(xs: List[Int]) = + xs.map(pos.source.offsetToLine(_)) + .map { lineNbr => + val prefix = s"${lineNbr + 1} |" + maxLen = math.max(maxLen, prefix.length) + (prefix, pos.lineContent(lineNbr).stripLineEnd) + } + .map { case (prefix, line) => + val lnum = Red(" " * math.max(0, maxLen - prefix.length) + prefix) + hl"$lnum$line" + } + + val (before, after) = pos.beforeAndAfterPoint + (render(before), render(after), maxLen) + } + + def columnMarker(pos: SourcePosition, offset: Int)(implicit ctx: Context): String = { + val prefix = " " * (offset - 1) + val whitespace = " " * pos.startColumn + val carets = Red { + if (pos.startLine == pos.endLine) + "^" * math.max(1, pos.endColumn - pos.startColumn) + else "^" + } + + s"$prefix|$whitespace${carets.show}" + } + + def errorMsg(pos: SourcePosition, msg: String, offset: Int)(implicit ctx: Context): String = { + val leastWhitespace = msg.lines.foldLeft(Int.MaxValue) { (minPad, line) => + val lineLength = stripColor(line).length + val padding = + math.min(math.max(0, ctx.settings.pageWidth.value - offset - lineLength), offset + pos.startColumn) + + if (padding < minPad) padding + else minPad + } + + msg.lines + .map { line => " " * (offset - 1) + "|" + (" " * (leastWhitespace - offset)) + line } + .mkString(sys.props("line.separator")) + } + + def posStr(pos: SourcePosition, diagnosticLevel: String, message: Message)(implicit ctx: Context): String = + if (pos.exists) Blue({ + val file = pos.source.file.toString + val errId = + if (message.errorId != NoExplanation.ID) + s"[E${"0" * (3 - message.errorId.toString.length) + message.errorId}] " + else "" + val kind = + if (message.kind == "") diagnosticLevel + else s"${message.kind} $diagnosticLevel" + val prefix = s"-- ${errId}${kind}: $file " + + prefix + + ("-" * math.max(ctx.settings.pageWidth.value - stripColor(prefix).length, 0)) + }).show else "" + + def explanation(m: Message)(implicit ctx: Context): String = { + val sb = new StringBuilder(hl"""| + |${Blue("Explanation")} + |${Blue("===========")}""".stripMargin) + sb.append('\n').append(m.explanation) + if (m.explanation.lastOption != Some('\n')) sb.append('\n') + sb.toString + } + + def messageAndPos(msg: Message, pos: SourcePosition, diagnosticLevel: String)(implicit ctx: Context): String = { + val sb = mutable.StringBuilder.newBuilder + sb.append(posStr(pos, diagnosticLevel, msg)).append('\n') + if (pos.exists) { + val (srcBefore, srcAfter, offset) = sourceLines(pos) + val marker = columnMarker(pos, offset) + val err = errorMsg(pos, msg.msg, offset) + sb.append((srcBefore ::: marker :: err :: srcAfter).mkString("\n")) + } else sb.append(msg.msg) + sb.toString + } + + def diagnosticLevel(cont: MessageContainer): String = { + cont match { + case m: Error => "Error" + case m: FeatureWarning => "Feature Warning" + case m: DeprecationWarning => "Deprecation Warning" + case m: UncheckedWarning => "Unchecked Warning" + case m: MigrationWarning => "Migration Warning" + case m: Warning => "Warning" + case m: Info => "Info" + } + } +} |