1e73685ebSopenharmony_ci//! Diagnostic data structures.
2e73685ebSopenharmony_ci
3e73685ebSopenharmony_ci#[cfg(feature = "serialization")]
4e73685ebSopenharmony_ciuse serde::{Deserialize, Serialize};
5e73685ebSopenharmony_ciuse std::ops::Range;
6e73685ebSopenharmony_ci
7e73685ebSopenharmony_ci/// A severity level for diagnostic messages.
8e73685ebSopenharmony_ci///
9e73685ebSopenharmony_ci/// These are ordered in the following way:
10e73685ebSopenharmony_ci///
11e73685ebSopenharmony_ci/// ```rust
12e73685ebSopenharmony_ci/// use codespan_reporting::diagnostic::Severity;
13e73685ebSopenharmony_ci///
14e73685ebSopenharmony_ci/// assert!(Severity::Bug > Severity::Error);
15e73685ebSopenharmony_ci/// assert!(Severity::Error > Severity::Warning);
16e73685ebSopenharmony_ci/// assert!(Severity::Warning > Severity::Note);
17e73685ebSopenharmony_ci/// assert!(Severity::Note > Severity::Help);
18e73685ebSopenharmony_ci/// ```
19e73685ebSopenharmony_ci#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
20e73685ebSopenharmony_ci#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
21e73685ebSopenharmony_cipub enum Severity {
22e73685ebSopenharmony_ci    /// An unexpected bug.
23e73685ebSopenharmony_ci    Bug,
24e73685ebSopenharmony_ci    /// An error.
25e73685ebSopenharmony_ci    Error,
26e73685ebSopenharmony_ci    /// A warning.
27e73685ebSopenharmony_ci    Warning,
28e73685ebSopenharmony_ci    /// A note.
29e73685ebSopenharmony_ci    Note,
30e73685ebSopenharmony_ci    /// A help message.
31e73685ebSopenharmony_ci    Help,
32e73685ebSopenharmony_ci}
33e73685ebSopenharmony_ci
34e73685ebSopenharmony_ciimpl Severity {
35e73685ebSopenharmony_ci    /// We want bugs to be the maximum severity, errors next, etc...
36e73685ebSopenharmony_ci    fn to_cmp_int(self) -> u8 {
37e73685ebSopenharmony_ci        match self {
38e73685ebSopenharmony_ci            Severity::Bug => 5,
39e73685ebSopenharmony_ci            Severity::Error => 4,
40e73685ebSopenharmony_ci            Severity::Warning => 3,
41e73685ebSopenharmony_ci            Severity::Note => 2,
42e73685ebSopenharmony_ci            Severity::Help => 1,
43e73685ebSopenharmony_ci        }
44e73685ebSopenharmony_ci    }
45e73685ebSopenharmony_ci}
46e73685ebSopenharmony_ci
47e73685ebSopenharmony_ciimpl PartialOrd for Severity {
48e73685ebSopenharmony_ci    fn partial_cmp(&self, other: &Severity) -> Option<std::cmp::Ordering> {
49e73685ebSopenharmony_ci        u8::partial_cmp(&self.to_cmp_int(), &other.to_cmp_int())
50e73685ebSopenharmony_ci    }
51e73685ebSopenharmony_ci}
52e73685ebSopenharmony_ci
53e73685ebSopenharmony_ci#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd)]
54e73685ebSopenharmony_ci#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
55e73685ebSopenharmony_cipub enum LabelStyle {
56e73685ebSopenharmony_ci    /// Labels that describe the primary cause of a diagnostic.
57e73685ebSopenharmony_ci    Primary,
58e73685ebSopenharmony_ci    /// Labels that provide additional context for a diagnostic.
59e73685ebSopenharmony_ci    Secondary,
60e73685ebSopenharmony_ci}
61e73685ebSopenharmony_ci
62e73685ebSopenharmony_ci/// A label describing an underlined region of code associated with a diagnostic.
63e73685ebSopenharmony_ci#[derive(Clone, Debug, PartialEq, Eq)]
64e73685ebSopenharmony_ci#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
65e73685ebSopenharmony_cipub struct Label<FileId> {
66e73685ebSopenharmony_ci    /// The style of the label.
67e73685ebSopenharmony_ci    pub style: LabelStyle,
68e73685ebSopenharmony_ci    /// The file that we are labelling.
69e73685ebSopenharmony_ci    pub file_id: FileId,
70e73685ebSopenharmony_ci    /// The range in bytes we are going to include in the final snippet.
71e73685ebSopenharmony_ci    pub range: Range<usize>,
72e73685ebSopenharmony_ci    /// An optional message to provide some additional information for the
73e73685ebSopenharmony_ci    /// underlined code. These should not include line breaks.
74e73685ebSopenharmony_ci    pub message: String,
75e73685ebSopenharmony_ci}
76e73685ebSopenharmony_ci
77e73685ebSopenharmony_ciimpl<FileId> Label<FileId> {
78e73685ebSopenharmony_ci    /// Create a new label.
79e73685ebSopenharmony_ci    pub fn new(
80e73685ebSopenharmony_ci        style: LabelStyle,
81e73685ebSopenharmony_ci        file_id: FileId,
82e73685ebSopenharmony_ci        range: impl Into<Range<usize>>,
83e73685ebSopenharmony_ci    ) -> Label<FileId> {
84e73685ebSopenharmony_ci        Label {
85e73685ebSopenharmony_ci            style,
86e73685ebSopenharmony_ci            file_id,
87e73685ebSopenharmony_ci            range: range.into(),
88e73685ebSopenharmony_ci            message: String::new(),
89e73685ebSopenharmony_ci        }
90e73685ebSopenharmony_ci    }
91e73685ebSopenharmony_ci
92e73685ebSopenharmony_ci    /// Create a new label with a style of [`LabelStyle::Primary`].
93e73685ebSopenharmony_ci    ///
94e73685ebSopenharmony_ci    /// [`LabelStyle::Primary`]: LabelStyle::Primary
95e73685ebSopenharmony_ci    pub fn primary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
96e73685ebSopenharmony_ci        Label::new(LabelStyle::Primary, file_id, range)
97e73685ebSopenharmony_ci    }
98e73685ebSopenharmony_ci
99e73685ebSopenharmony_ci    /// Create a new label with a style of [`LabelStyle::Secondary`].
100e73685ebSopenharmony_ci    ///
101e73685ebSopenharmony_ci    /// [`LabelStyle::Secondary`]: LabelStyle::Secondary
102e73685ebSopenharmony_ci    pub fn secondary(file_id: FileId, range: impl Into<Range<usize>>) -> Label<FileId> {
103e73685ebSopenharmony_ci        Label::new(LabelStyle::Secondary, file_id, range)
104e73685ebSopenharmony_ci    }
105e73685ebSopenharmony_ci
106e73685ebSopenharmony_ci    /// Add a message to the diagnostic.
107e73685ebSopenharmony_ci    pub fn with_message(mut self, message: impl Into<String>) -> Label<FileId> {
108e73685ebSopenharmony_ci        self.message = message.into();
109e73685ebSopenharmony_ci        self
110e73685ebSopenharmony_ci    }
111e73685ebSopenharmony_ci}
112e73685ebSopenharmony_ci
113e73685ebSopenharmony_ci/// Represents a diagnostic message that can provide information like errors and
114e73685ebSopenharmony_ci/// warnings to the user.
115e73685ebSopenharmony_ci///
116e73685ebSopenharmony_ci/// The position of a Diagnostic is considered to be the position of the [`Label`] that has the earliest starting position and has the highest style which appears in all the labels of the diagnostic.
117e73685ebSopenharmony_ci#[derive(Clone, Debug, PartialEq, Eq)]
118e73685ebSopenharmony_ci#[cfg_attr(feature = "serialization", derive(Serialize, Deserialize))]
119e73685ebSopenharmony_cipub struct Diagnostic<FileId> {
120e73685ebSopenharmony_ci    /// The overall severity of the diagnostic
121e73685ebSopenharmony_ci    pub severity: Severity,
122e73685ebSopenharmony_ci    /// An optional code that identifies this diagnostic.
123e73685ebSopenharmony_ci    pub code: Option<String>,
124e73685ebSopenharmony_ci    /// The main message associated with this diagnostic.
125e73685ebSopenharmony_ci    ///
126e73685ebSopenharmony_ci    /// These should not include line breaks, and in order support the 'short'
127e73685ebSopenharmony_ci    /// diagnostic display mod, the message should be specific enough to make
128e73685ebSopenharmony_ci    /// sense on its own, without additional context provided by labels and notes.
129e73685ebSopenharmony_ci    pub message: String,
130e73685ebSopenharmony_ci    /// Source labels that describe the cause of the diagnostic.
131e73685ebSopenharmony_ci    /// The order of the labels inside the vector does not have any meaning.
132e73685ebSopenharmony_ci    /// The labels are always arranged in the order they appear in the source code.
133e73685ebSopenharmony_ci    pub labels: Vec<Label<FileId>>,
134e73685ebSopenharmony_ci    /// Notes that are associated with the primary cause of the diagnostic.
135e73685ebSopenharmony_ci    /// These can include line breaks for improved formatting.
136e73685ebSopenharmony_ci    pub notes: Vec<String>,
137e73685ebSopenharmony_ci}
138e73685ebSopenharmony_ci
139e73685ebSopenharmony_ciimpl<FileId> Diagnostic<FileId> {
140e73685ebSopenharmony_ci    /// Create a new diagnostic.
141e73685ebSopenharmony_ci    pub fn new(severity: Severity) -> Diagnostic<FileId> {
142e73685ebSopenharmony_ci        Diagnostic {
143e73685ebSopenharmony_ci            severity,
144e73685ebSopenharmony_ci            code: None,
145e73685ebSopenharmony_ci            message: String::new(),
146e73685ebSopenharmony_ci            labels: Vec::new(),
147e73685ebSopenharmony_ci            notes: Vec::new(),
148e73685ebSopenharmony_ci        }
149e73685ebSopenharmony_ci    }
150e73685ebSopenharmony_ci
151e73685ebSopenharmony_ci    /// Create a new diagnostic with a severity of [`Severity::Bug`].
152e73685ebSopenharmony_ci    ///
153e73685ebSopenharmony_ci    /// [`Severity::Bug`]: Severity::Bug
154e73685ebSopenharmony_ci    pub fn bug() -> Diagnostic<FileId> {
155e73685ebSopenharmony_ci        Diagnostic::new(Severity::Bug)
156e73685ebSopenharmony_ci    }
157e73685ebSopenharmony_ci
158e73685ebSopenharmony_ci    /// Create a new diagnostic with a severity of [`Severity::Error`].
159e73685ebSopenharmony_ci    ///
160e73685ebSopenharmony_ci    /// [`Severity::Error`]: Severity::Error
161e73685ebSopenharmony_ci    pub fn error() -> Diagnostic<FileId> {
162e73685ebSopenharmony_ci        Diagnostic::new(Severity::Error)
163e73685ebSopenharmony_ci    }
164e73685ebSopenharmony_ci
165e73685ebSopenharmony_ci    /// Create a new diagnostic with a severity of [`Severity::Warning`].
166e73685ebSopenharmony_ci    ///
167e73685ebSopenharmony_ci    /// [`Severity::Warning`]: Severity::Warning
168e73685ebSopenharmony_ci    pub fn warning() -> Diagnostic<FileId> {
169e73685ebSopenharmony_ci        Diagnostic::new(Severity::Warning)
170e73685ebSopenharmony_ci    }
171e73685ebSopenharmony_ci
172e73685ebSopenharmony_ci    /// Create a new diagnostic with a severity of [`Severity::Note`].
173e73685ebSopenharmony_ci    ///
174e73685ebSopenharmony_ci    /// [`Severity::Note`]: Severity::Note
175e73685ebSopenharmony_ci    pub fn note() -> Diagnostic<FileId> {
176e73685ebSopenharmony_ci        Diagnostic::new(Severity::Note)
177e73685ebSopenharmony_ci    }
178e73685ebSopenharmony_ci
179e73685ebSopenharmony_ci    /// Create a new diagnostic with a severity of [`Severity::Help`].
180e73685ebSopenharmony_ci    ///
181e73685ebSopenharmony_ci    /// [`Severity::Help`]: Severity::Help
182e73685ebSopenharmony_ci    pub fn help() -> Diagnostic<FileId> {
183e73685ebSopenharmony_ci        Diagnostic::new(Severity::Help)
184e73685ebSopenharmony_ci    }
185e73685ebSopenharmony_ci
186e73685ebSopenharmony_ci    /// Add an error code to the diagnostic.
187e73685ebSopenharmony_ci    pub fn with_code(mut self, code: impl Into<String>) -> Diagnostic<FileId> {
188e73685ebSopenharmony_ci        self.code = Some(code.into());
189e73685ebSopenharmony_ci        self
190e73685ebSopenharmony_ci    }
191e73685ebSopenharmony_ci
192e73685ebSopenharmony_ci    /// Add a message to the diagnostic.
193e73685ebSopenharmony_ci    pub fn with_message(mut self, message: impl Into<String>) -> Diagnostic<FileId> {
194e73685ebSopenharmony_ci        self.message = message.into();
195e73685ebSopenharmony_ci        self
196e73685ebSopenharmony_ci    }
197e73685ebSopenharmony_ci
198e73685ebSopenharmony_ci    /// Add some labels to the diagnostic.
199e73685ebSopenharmony_ci    pub fn with_labels(mut self, labels: Vec<Label<FileId>>) -> Diagnostic<FileId> {
200e73685ebSopenharmony_ci        self.labels = labels;
201e73685ebSopenharmony_ci        self
202e73685ebSopenharmony_ci    }
203e73685ebSopenharmony_ci
204e73685ebSopenharmony_ci    /// Add some notes to the diagnostic.
205e73685ebSopenharmony_ci    pub fn with_notes(mut self, notes: Vec<String>) -> Diagnostic<FileId> {
206e73685ebSopenharmony_ci        self.notes = notes;
207e73685ebSopenharmony_ci        self
208e73685ebSopenharmony_ci    }
209e73685ebSopenharmony_ci}
210