tiger_lib/report/report_struct.rs
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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
use serde::Serialize;
use strum_macros::{Display, EnumIter, EnumString, IntoStaticStr};
use crate::report::ErrorKey;
use crate::token::Loc;
/// Describes a report about a potentially problematic situation that can be logged.
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct LogReport {
/// Used for choosing output colors and for filtering reports.
pub severity: Severity,
/// Mostly used for filtering reports.
pub confidence: Confidence,
/// Defines the problem category. Used for filtering reports.
pub key: ErrorKey,
/// The primary error message. A short description of the problem.
pub msg: String,
/// Optional info message to be printed at the end.
pub info: Option<String>,
/// Should contain one or more elements.
pub pointers: Vec<PointedMessage>,
}
impl LogReport {
/// Returns the primary pointer.
///
/// # Panics
/// May panic if this is an invalid `LogReport` with no pointers.
pub fn primary(&self) -> &PointedMessage {
self.pointers.first().expect("A LogReport must always have at least one PointedMessage.")
}
/// Returns the length of the longest line number.
pub fn indentation(&self) -> usize {
self.pointers.iter().map(|pointer| pointer.loc.line.to_string().len()).max().unwrap_or(0)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct PointedMessage {
/// Which file and where in the file the error occurs.
/// Might point to a whole file, rather than a specific location in the file.
pub loc: Loc,
/// The length of the offending phrase in characters.
/// Set this to 0 if the length cannot be determined.
/// This will determine the number of carets that are printed at the given location.
/// e.g.: ^^^^^^^^^
/// TODO: If we end up adding length to Loc, this field can be deleted.
pub length: usize,
/// A short message that will be printed at the caret location.
pub msg: Option<String>,
}
impl PointedMessage {
pub fn new(loc: Loc) -> Self {
Self { loc, msg: None, length: 0 }
}
}
/// Determines the output colour.
/// User can also filter by minimum severity level: e.g. don't show me Info-level messages.
///
/// The order of these enum values determines the level of severity they denote.
/// Do not change the order unless you mean to change the logic of the program!
#[derive(
Default,
Debug,
Display,
Clone,
Copy,
Ord,
PartialOrd,
Eq,
PartialEq,
Hash,
IntoStaticStr,
EnumString,
EnumIter,
Serialize,
)]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum Severity {
/// These are things that aren't necessarily wrong, but there may be a better, more
/// idiomatic way to do it. This may also include performance issues.
Tips,
/// This code smells.
/// The player is unlikely to be impacted directly, but developers working on this codebase
/// will likely experience maintenance headaches.
Untidy,
/// This will result in glitches that will noticeably impact the player's gaming experience.
/// Missing translations are an example.
#[default]
Warning,
/// This code probably doesn't work as intended. The player may experience bugs.
Error,
/// This is likely to cause crashes.
Fatal,
}
impl Severity {
/// Reduce the severity to at most `max_sev`, unless severity is `Fatal`, then stays `Fatal`.
#[must_use]
pub fn at_most(self, max_sev: Severity) -> Severity {
if self == Severity::Fatal {
Severity::Fatal
} else {
self.min(max_sev)
}
}
}
/// Mostly invisible in the output.
/// User can filter by minimum confidence level.
/// This would be a dial for how many false positives they're willing to put up with.
///
/// The order of these enum values determines the level of confidence they denote.
/// Do not change the order unless you mean to change the logic of the program!
#[derive(
Default,
Debug,
Clone,
Copy,
Ord,
PartialOrd,
Eq,
PartialEq,
Hash,
IntoStaticStr,
EnumIter,
EnumString,
Serialize,
)]
#[serde(rename_all = "kebab-case")]
#[strum(serialize_all = "kebab-case")]
pub enum Confidence {
/// Quite likely to be a false positive.
Weak,
/// Reasonably confident that the problem is real.
#[default]
Reasonable,
/// Very confident that this problem is real.
Strong,
}