aboutsummaryrefslogblamecommitdiff
path: root/src/dotty/tools/dotc/reporting/Reporter.scala
blob: 4b11b415a2eb82586ba4b53d91d803f58d62a423 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
















                                                                                         

                                                     


                                                                       
                           














































































































                                                                                                    
package dotty.tools
package dotc
package reporting

import core.Contexts._
import core.Positions._
import core.Decorators.PhaseListDecorator
import collection.mutable
import io.{SourceFile, NoSource}
import java.lang.System.currentTimeMillis

trait Reporting { this: Context =>
  def error(msg: String, pos: Position = NoPosition): Unit = reporter.error(msg, pos)
  def warning(msg: String, pos: Position = NoPosition): Unit = reporter.warning(msg, pos)
  def inform(msg: String, pos: Position = NoPosition): Unit = reporter.info(msg, pos)

  def log(msg: => String)(implicit ctx: Context): Unit =
    if (true || // !!! for now
        this.settings.log.value.containsPhase(phase))
      inform(s"[log ${ctx.phasesStack.reverse.mkString(" -> ")}] $msg")

  def debuglog(msg: => String)(implicit ctx: Context): Unit =
    if (ctx.debug) log(msg)

  def informTime(msg: => String, start: Long)(implicit ctx: Context): Unit =
    informProgress(msg + elapsed(start))

  private def elapsed(start: Long) =
    " in " + (currentTimeMillis - start) + "ms"

  def informProgress(msg: => String)(implicit ctx: Context) =
    if (ctx.settings.verbose.value) inform("[" + msg + "]")
}

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 {

  import Reporter.Severity.{Value => Severity, _}

  protected def report(msg: String, severity: Severity, pos: Position)(implicit ctx: Context): Unit

  protected def isHidden(severity: Severity, pos: Position)(implicit ctx: Context) = false

  val count = new mutable.HashMap[Severity, Int]() {
    override def default(key: Severity) = 0
  }

  /** Whether very long lines can be truncated.  This exists so important
   *  debugging information (like printing the classpath) is not rendered
   *  invisible due to the max message length.
   */
  private var _truncationOK: Boolean = true
  def truncationOK = _truncationOK
  def withoutTruncating[T](body: => T): T = {
    val saved = _truncationOK
    _truncationOK = false
    try body
    finally _truncationOK = saved
  }

  type ErrorHandler = (String, Position, Context) => Unit
  private var incompleteHandler: ErrorHandler = error(_, _)(_)
  def withIncompleteHandler[T](handler: ErrorHandler)(op: => T): T = {
    val saved = incompleteHandler
    incompleteHandler = handler
    try op
    finally incompleteHandler = saved
  }

  def hasErrors   = count(ERROR) > 0
  def hasWarnings = count(WARNING) > 0

  /** For sending messages that are printed only if -verbose is set */
  def info(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit =
    if (ctx.settings.verbose.value) info0(msg, INFO, pos)

  /** 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: Position = NoPosition)(implicit ctx: Context): Unit =
    info0(msg, INFO, pos)

  def warning(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit =
    if (!ctx.settings.nowarn.value)
      withoutTruncating(info0(msg, WARNING, pos))

  def error(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit =
    withoutTruncating(info0(msg, ERROR, pos))

  def incompleteInputError(msg: String, pos: Position = NoPosition)(implicit ctx: Context): Unit =
    incompleteHandler(msg, pos, ctx)

  private def info0(msg: String, severity: Severity, pos: Position)(implicit ctx: Context): Unit = {
    if (!isHidden(severity, pos)) {
      count(severity) += 1
      report(msg, severity, pos)
    }
  }

  /** 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 INFO    => ""
    case ERROR   => "error: "
    case WARNING => "warning: "
  }

  protected def countString(severity: Severity) = {
    assert(severity != INFO)
    countElementsAsString(count(severity), label(severity).dropRight(2))
  }

  def flush(): Unit = {}

  def reset(): Unit = count.clear()
}