language_reporting/
diagnostic.rs

1use crate::{ReportingSpan, Severity};
2use serde_derive::{Serialize, Deserialize};
3
4/// A style for the label
5#[derive(Copy, Clone, PartialEq, Debug, Serialize, Deserialize)]
6pub enum LabelStyle {
7    /// The main focus of the diagnostic
8    Primary,
9    /// Supporting labels that may help to isolate the cause of the diagnostic
10    Secondary,
11}
12
13/// A label describing an underlined region of code associated with a diagnostic
14#[derive(Clone, Debug, Serialize, Deserialize)]
15pub struct Label<Span: ReportingSpan> {
16    /// The span we are going to include in the final snippet.
17    pub span: Span,
18    /// A message to provide some additional information for the underlined code.
19    pub message: Option<String>,
20    /// The style to use for the label.
21    pub style: LabelStyle,
22}
23
24impl<Span: ReportingSpan> Label<Span> {
25    pub fn new(span: Span, style: LabelStyle) -> Label<Span> {
26        Label {
27            span,
28            message: None,
29            style,
30        }
31    }
32
33    pub fn new_primary(span: Span) -> Label<Span> {
34        Label::new(span, LabelStyle::Primary)
35    }
36
37    pub fn new_secondary(span: Span) -> Label<Span> {
38        Label::new(span, LabelStyle::Secondary)
39    }
40
41    pub fn with_message<S: Into<String>>(mut self, message: S) -> Label<Span> {
42        self.message = Some(message.into());
43        self
44    }
45
46    pub fn message(&self) -> &Option<String> {
47        &self.message
48    }
49}
50
51/// Represents a diagnostic message and associated child messages.
52#[derive(Clone, Debug, Deserialize, Serialize)]
53pub struct Diagnostic<Span: ReportingSpan> {
54    /// The overall severity of the diagnostic
55    pub severity: Severity,
56    /// An optional code that identifies this diagnostic.
57    pub code: Option<String>,
58    /// The main message associated with this diagnostic
59    pub message: String,
60    /// The labelled spans marking the regions of code that cause this
61    /// diagnostic to be raised
62    pub labels: Vec<Label<Span>>,
63}
64
65impl<Span: ReportingSpan> Diagnostic<Span> {
66    pub fn new<S: Into<String>>(severity: Severity, message: S) -> Diagnostic<Span> {
67        Diagnostic {
68            severity,
69            code: None,
70            message: message.into(),
71            labels: Vec::new(),
72        }
73    }
74
75    pub fn new_bug<S: Into<String>>(message: S) -> Diagnostic<Span> {
76        Diagnostic::new(Severity::Bug, message)
77    }
78
79    pub fn new_error<S: Into<String>>(message: S) -> Diagnostic<Span> {
80        Diagnostic::new(Severity::Error, message)
81    }
82
83    pub fn new_warning<S: Into<String>>(message: S) -> Diagnostic<Span> {
84        Diagnostic::new(Severity::Warning, message)
85    }
86
87    pub fn new_note<S: Into<String>>(message: S) -> Diagnostic<Span> {
88        Diagnostic::new(Severity::Note, message)
89    }
90
91    pub fn new_help<S: Into<String>>(message: S) -> Diagnostic<Span> {
92        Diagnostic::new(Severity::Help, message)
93    }
94
95    pub fn with_code<S: Into<String>>(mut self, code: S) -> Diagnostic<Span> {
96        self.code = Some(code.into());
97        self
98    }
99
100    pub fn with_label(mut self, label: Label<Span>) -> Diagnostic<Span> {
101        self.labels.push(label);
102        self
103    }
104
105    pub fn with_labels<Labels: IntoIterator<Item = Label<Span>>>(
106        mut self,
107        labels: Labels,
108    ) -> Diagnostic<Span> {
109        self.labels.extend(labels);
110        self
111    }
112}