use anyhow::Result; use log::debug; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use ruff_text_size::{Ranged, TextRange, TextSize}; use crate::Fix; #[derive(Debug, PartialEq, Eq, Clone)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct DiagnosticKind { /// The identifier of the diagnostic, used to align the diagnostic with a rule. pub name: String, /// The message body to display to the user, to explain the diagnostic. pub body: String, /// The message to display to the user, to explain the suggested fix. pub suggestion: Option, } #[derive(Debug, PartialEq, Eq, Clone)] pub struct Diagnostic { pub kind: DiagnosticKind, pub range: TextRange, pub fix: Option, pub parent: Option, } impl Diagnostic { pub fn new>(kind: T, range: TextRange) -> Self { Self { kind: kind.into(), range, fix: None, parent: None, } } /// Consumes `self` and returns a new `Diagnostic` with the given `fix`. #[inline] #[must_use] pub fn with_fix(mut self, fix: Fix) -> Self { self.set_fix(fix); self } /// Set the [`Fix`] used to fix the diagnostic. #[inline] pub fn set_fix(&mut self, fix: Fix) { self.fix = Some(fix); } /// Set the [`Fix`] used to fix the diagnostic, if the provided function returns `Ok`. /// Otherwise, log the error. #[inline] pub fn try_set_fix(&mut self, func: impl FnOnce() -> Result) { match func() { Ok(fix) => self.fix = Some(fix), Err(err) => debug!("Failed to create fix for {}: {}", self.kind.name, err), } } /// Set the [`Fix`] used to fix the diagnostic, if the provided function returns `Ok`. /// Otherwise, log the error. #[inline] pub fn try_set_optional_fix(&mut self, func: impl FnOnce() -> Result>) { match func() { Ok(None) => {} Ok(Some(fix)) => self.fix = Some(fix), Err(err) => debug!("Failed to create fix for {}: {}", self.kind.name, err), } } /// Consumes `self` and returns a new `Diagnostic` with the given parent node. #[inline] #[must_use] pub fn with_parent(mut self, parent: TextSize) -> Self { self.set_parent(parent); self } /// Set the location of the diagnostic's parent node. #[inline] pub fn set_parent(&mut self, parent: TextSize) { self.parent = Some(parent); } } impl Ranged for Diagnostic { fn range(&self) -> TextRange { self.range } }