aboutsummaryrefslogtreecommitdiff
path: root/src/dotty/tools/dotc/reporting/diagnostic/Message.scala
blob: f19191f4fcad363456a1650a9900a4d3ef623741 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
package dotty.tools
package dotc
package reporting
package diagnostic

import util.SourcePosition
import core.Contexts.Context

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)
}

abstract class Message(val errorId: Int) { self =>
  import messages._

  /** The `msg` contains the diagnostic message e.g:
    *
    * > expected: String
    * > found:    Int
    *
    * This message wil 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

  /** It is possible to map `msg` to add details, this is at the loss of
    * precision since the type of the resulting `Message` won't be original
    * extending class
    *
    * @return a `Message` with the mapped message
    */
  def mapMsg(f: String => String) = new Message(errorId) {
    val msg = f(self.msg)
    val kind = self.kind
    val explanation = self.explanation
  }

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

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

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

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

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

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

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

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

/** The extractor for `NoExplanation` can be used to check whether any error
  * lacks an explanation
  */
object NoExplanation {
  final val ID = -1

  def unapply(m: Message): Option[Message] =
    if (m.explanation == "") Some(m)
    else None
}