Skip to main content

driver_lang/
severity.rs

1//! How serious a [`Diagnostic`](crate::Diagnostic) is.
2
3use core::fmt;
4
5/// The seriousness of a [`Diagnostic`](crate::Diagnostic).
6///
7/// A driver runs a program through a chain of stages, and each stage reports
8/// what it found by emitting diagnostics into the [`Session`](crate::Session).
9/// The severity is what tells the driver — and the person reading the output —
10/// whether a diagnostic is a hard failure that should stop compilation, a
11/// heads-up that something looks wrong, or a neutral remark that adds context.
12///
13/// Only [`Error`](Severity::Error) counts toward
14/// [`Session::error_count`](crate::Session::error_count); a warning or a note is
15/// recorded and rendered but never trips
16/// [`Session::abort_if_errors`](crate::Session::abort_if_errors). Ordering the
17/// variants by seriousness — error first — mirrors that: `Error < Warning < Note`
18/// is *not* the intent, so the type intentionally does not derive `Ord`. Compare
19/// with [`is_error`](Severity::is_error) instead of relying on a numeric rank.
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize))]
22#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))]
23pub enum Severity {
24    /// A hard failure. Counts toward the session's error total and makes
25    /// [`Session::abort_if_errors`](crate::Session::abort_if_errors) stop the
26    /// build.
27    Error,
28    /// Something suspicious that does not by itself stop compilation.
29    Warning,
30    /// Neutral context attached to the output — a hint, a location, a reminder.
31    Note,
32}
33
34impl Severity {
35    /// Whether this is [`Severity::Error`] — the only severity that counts as a
36    /// build failure.
37    ///
38    /// # Examples
39    ///
40    /// ```
41    /// use driver_lang::Severity;
42    ///
43    /// assert!(Severity::Error.is_error());
44    /// assert!(!Severity::Warning.is_error());
45    /// assert!(!Severity::Note.is_error());
46    /// ```
47    #[must_use]
48    #[inline]
49    pub fn is_error(self) -> bool {
50        matches!(self, Severity::Error)
51    }
52
53    /// The lowercase label used when a diagnostic is rendered
54    /// (`"error"`, `"warning"`, `"note"`).
55    ///
56    /// # Examples
57    ///
58    /// ```
59    /// use driver_lang::Severity;
60    ///
61    /// assert_eq!(Severity::Error.as_str(), "error");
62    /// assert_eq!(Severity::Warning.as_str(), "warning");
63    /// assert_eq!(Severity::Note.as_str(), "note");
64    /// ```
65    #[must_use]
66    #[inline]
67    pub fn as_str(self) -> &'static str {
68        match self {
69            Severity::Error => "error",
70            Severity::Warning => "warning",
71            Severity::Note => "note",
72        }
73    }
74}
75
76impl fmt::Display for Severity {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        f.write_str(self.as_str())
79    }
80}
81
82#[cfg(test)]
83#[allow(clippy::unwrap_used, clippy::expect_used)]
84mod tests {
85    use super::*;
86    use alloc::string::ToString;
87
88    #[test]
89    fn test_is_error_only_true_for_error() {
90        assert!(Severity::Error.is_error());
91        assert!(!Severity::Warning.is_error());
92        assert!(!Severity::Note.is_error());
93    }
94
95    #[test]
96    fn test_as_str_matches_variant() {
97        assert_eq!(Severity::Error.as_str(), "error");
98        assert_eq!(Severity::Warning.as_str(), "warning");
99        assert_eq!(Severity::Note.as_str(), "note");
100    }
101
102    #[test]
103    fn test_display_matches_as_str() {
104        assert_eq!(Severity::Warning.to_string(), "warning");
105    }
106}