All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dotty.tools.dotc.reporting.diagnostic.Message.scala Maven / Gradle / Ivy

The newest version!
package dotty.tools
package dotc
package reporting
package diagnostic

import util.SourcePosition

import messages._

object Message {
  /** This implicit conversion provides a fallback for error messages that have
    * not yet been ported to the new scheme. Comment out this `implicit def` to
    * see where old errors still exist
    */
  implicit def toNoExplanation(str: String): Message =
    new NoExplanation(str)
}

/** A `Message` contains all semantic information necessary to easily
  * comprehend what caused the message to be logged. Each message can be turned
  * into a `MessageContainer` which contains the log level and can later be
  * consumed by a subclass of `Reporter`. However, the error position is only
  * part of `MessageContainer`, not `Message`.
  *
  * NOTE: you should not be persisting  Most messages take an implicit
  * `Context` and these contexts weigh in at about 4mb per instance, as such
  * persisting these will result in a memory leak.
  *
  * Instead use the `persist` method to create an instance that does not keep a
  * reference to these contexts.
  *
  * @param errorId a unique id identifying the message, this will later be
  *                used to reference documentation online
  */
abstract class Message(val errorId: ErrorMessageID) { self =>

  /** The `msg` contains the diagnostic message e.g:
    *
    * > expected: String
    * > found:    Int
    *
    * This message will be placed underneath the position given by the enclosing
    * `MessageContainer`
    */
  def msg: String

  /** The kind of the error message is something like "Syntax" or "Type
    * Mismatch"
    */
  def kind: String

  /** The explanation should provide a detailed description of why the error
    * occurred and use examples from the user's own code to illustrate how to
    * avoid these errors.
    */
  def explanation: String

  /** The implicit `Context` in messages is a large thing that we don't want
    * persisted. This method gets around that by duplicating the message
    * without the implicit context being passed along.
    */
  def persist: Message = new Message (errorId) {
    val msg         = self.msg
    val kind        = self.kind
    val explanation = self.explanation
  }

  def append(suffix: => String): Message = new Message(errorId) {
    val msg         = self.msg ++ suffix
    val kind        = self.kind
    val explanation = self.explanation
  }
}

/** An extended message keeps the contained message from being evaluated, while
  * allowing for extension for the `msg` string
  *
  * This is useful when we need to add additional information to an existing
  * message.
  */
class ExtendMessage(_msg: () => Message)(f: String => String) { self =>
  lazy val msg: String = f(_msg().msg)
  lazy val kind: String = _msg().kind
  lazy val explanation: String = _msg().explanation
  lazy val errorId: ErrorMessageID = _msg().errorId

  private def toMessage = new Message(errorId) {
    val msg = self.msg
    val kind = self.kind
    val explanation = self.explanation
  }

  /** Enclose this message in an `Error` container */
  def error(pos: SourcePosition): Error =
    new Error(toMessage, pos)

  /** Enclose this message in an `Warning` container */
  def warning(pos: SourcePosition): Warning =
    new Warning(toMessage, pos)

  /** Enclose this message in an `Info` container */
  def info(pos: SourcePosition): Info =
    new Info(toMessage, pos)

  /** Enclose this message in an `FeatureWarning` container */
  def featureWarning(pos: SourcePosition): FeatureWarning =
    new FeatureWarning(toMessage, pos)

  /** Enclose this message in an `UncheckedWarning` container */
  def uncheckedWarning(pos: SourcePosition): UncheckedWarning =
    new UncheckedWarning(toMessage, pos)

  /** Enclose this message in an `DeprecationWarning` container */
  def deprecationWarning(pos: SourcePosition): DeprecationWarning =
    new DeprecationWarning(toMessage, pos)

  /** Enclose this message in an `MigrationWarning` container */
  def migrationWarning(pos: SourcePosition): MigrationWarning =
    new MigrationWarning(toMessage, pos)
}

/** The fallback `Message` containing no explanation and having no `kind` */
class NoExplanation(val msg: String) extends Message(ErrorMessageID.NoExplanationID) {
  val explanation: String = ""
  val kind: String = ""

  override def toString(): String = s"NoExplanation($msg)"
}

/** The extractor for `NoExplanation` can be used to check whether any error
  * lacks an explanation
  */
object NoExplanation {
  def unapply(m: Message): Option[Message] =
    if (m.explanation == "") Some(m)
    else None
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy