tiger_lib/report/
report_struct.rs

1use serde::Serialize;
2use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
3
4use crate::report::ErrorKey;
5use crate::token::Loc;
6
7/// Describes a report about a potentially problematic situation that can be logged.
8#[derive(Debug, Clone, Hash, PartialEq, Eq)]
9pub struct LogReport {
10    /// Used for choosing output colors and for filtering reports.
11    pub severity: Severity,
12    /// Mostly used for filtering reports.
13    pub confidence: Confidence,
14    /// Defines the problem category. Used for filtering reports.
15    pub key: ErrorKey,
16    /// The primary error message. A short description of the problem.
17    pub msg: String,
18    /// Optional info message to be printed at the end.
19    pub info: Option<String>,
20    /// Should contain one or more elements.
21    pub pointers: Vec<PointedMessage>,
22}
23
24impl LogReport {
25    /// Returns the primary pointer.
26    ///
27    /// # Panics
28    /// May panic if this is an invalid `LogReport` with no pointers.
29    pub fn primary(&self) -> &PointedMessage {
30        self.pointers.first().expect("A LogReport must always have at least one PointedMessage.")
31    }
32
33    /// Returns the length of the longest line number.
34    pub fn indentation(&self) -> usize {
35        self.pointers.iter().map(|pointer| pointer.loc.line.to_string().len()).max().unwrap_or(0)
36    }
37}
38
39#[derive(Debug, Clone, Hash, PartialEq, Eq)]
40pub struct PointedMessage {
41    /// Which file and where in the file the error occurs.
42    /// Might point to a whole file, rather than a specific location in the file.
43    pub loc: Loc,
44    /// The length of the offending phrase in characters.
45    /// Set this to 0 if the length cannot be determined.
46    /// This will determine the number of carets that are printed at the given location.
47    /// e.g.:     ^^^^^^^^^
48    /// TODO: If we end up adding length to Loc, this field can be deleted.
49    pub length: usize,
50    /// A short message that will be printed at the caret location.
51    pub msg: Option<String>,
52}
53
54impl PointedMessage {
55    pub fn new(loc: Loc) -> Self {
56        Self { loc, msg: None, length: 0 }
57    }
58}
59
60/// Determines the output colour.
61/// User can also filter by minimum severity level: e.g. don't show me Info-level messages.
62///
63/// The order of these enum values determines the level of severity they denote.
64/// Do not change the order unless you mean to change the logic of the program!
65#[derive(
66    Default,
67    Debug,
68    Display,
69    Clone,
70    Copy,
71    Ord,
72    PartialOrd,
73    Eq,
74    PartialEq,
75    Hash,
76    IntoStaticStr,
77    EnumString,
78    EnumIter,
79    Serialize,
80)]
81#[serde(rename_all = "kebab-case")]
82#[strum(serialize_all = "kebab-case")]
83pub enum Severity {
84    /// These are things that aren't necessarily wrong, but there may be a better, more
85    /// idiomatic way to do it. This may also include performance issues.
86    Tips,
87    /// This code smells.
88    /// The player is unlikely to be impacted directly, but developers working on this codebase
89    /// will likely experience maintenance headaches.
90    Untidy,
91    /// This will result in glitches that will noticeably impact the player's gaming experience.
92    /// Missing translations are an example.
93    #[default]
94    Warning,
95    /// This code probably doesn't work as intended. The player may experience bugs.
96    Error,
97    /// This is likely to cause crashes.
98    Fatal,
99}
100
101impl Severity {
102    /// Reduce the severity to at most `max_sev`, unless severity is `Fatal`, then stays `Fatal`.
103    #[must_use]
104    pub fn at_most(self, max_sev: Severity) -> Severity {
105        if self == Severity::Fatal {
106            Severity::Fatal
107        } else {
108            self.min(max_sev)
109        }
110    }
111}
112
113/// Mostly invisible in the output.
114/// User can filter by minimum confidence level.
115/// This would be a dial for how many false positives they're willing to put up with.
116///
117/// The order of these enum values determines the level of confidence they denote.
118/// Do not change the order unless you mean to change the logic of the program!
119#[derive(
120    Default,
121    Debug,
122    Clone,
123    Copy,
124    Ord,
125    PartialOrd,
126    Eq,
127    PartialEq,
128    Hash,
129    IntoStaticStr,
130    EnumIter,
131    EnumString,
132    Serialize,
133)]
134#[serde(rename_all = "kebab-case")]
135#[strum(serialize_all = "kebab-case")]
136pub enum Confidence {
137    /// Quite likely to be a false positive.
138    Weak,
139    /// Reasonably confident that the problem is real.
140    #[default]
141    Reasonable,
142    /// Very confident that this problem is real.
143    Strong,
144}