Skip to main content

miniextendr_lint/
diagnostic.rs

1//! Structured diagnostic output for lint rules.
2
3use std::fmt;
4use std::path::PathBuf;
5
6use crate::lint_code::LintCode;
7
8/// Diagnostic severity level.
9#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
10pub enum Severity {
11    /// Migration hints and informational notes.
12    Info,
13    /// Default for new rules; non-blocking.
14    Warning,
15    /// CI-blocking in strict mode.
16    Error,
17}
18
19impl fmt::Display for Severity {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        match self {
22            Self::Info => f.write_str("info"),
23            Self::Warning => f.write_str("warning"),
24            Self::Error => f.write_str("error"),
25        }
26    }
27}
28
29/// A single lint diagnostic with structured metadata.
30#[derive(Clone, Debug)]
31pub struct Diagnostic {
32    /// Stable rule code (e.g. `MXL101`).
33    pub code: LintCode,
34    /// Severity level.
35    pub severity: Severity,
36    /// Source file path.
37    pub path: PathBuf,
38    /// 1-based line number (0 if unknown).
39    pub line: usize,
40    /// Primary diagnostic message.
41    pub message: String,
42    /// Optional fix guidance.
43    pub help: Option<String>,
44}
45
46impl Diagnostic {
47    /// Create a new diagnostic with the rule's default severity.
48    pub fn new(code: LintCode, path: impl Into<PathBuf>, line: usize, message: String) -> Self {
49        Self {
50            severity: code.default_severity(),
51            code,
52            path: path.into(),
53            line,
54            message,
55            help: None,
56        }
57    }
58
59    /// Attach a help message.
60    pub fn with_help(mut self, help: impl Into<String>) -> Self {
61        self.help = Some(help.into());
62        self
63    }
64
65    /// Format as a legacy error string (for backward-compatible `LintReport::errors`).
66    pub fn to_legacy_string(&self) -> String {
67        let mut s = format!("{}:{}: {}", self.path.display(), self.line, self.message);
68        if let Some(ref help) = self.help {
69            s.push(' ');
70            s.push_str(help);
71        }
72        s
73    }
74}
75
76impl fmt::Display for Diagnostic {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        write!(
79            f,
80            "[{}] {}:{}: {}",
81            self.code,
82            self.path.display(),
83            self.line,
84            self.message,
85        )?;
86        if let Some(ref help) = self.help {
87            write!(f, " Help: {}", help)?;
88        }
89        Ok(())
90    }
91}