use std::fmt;
use std::sync::Arc;
pub use crate::checks::{ViolationType, lookup_rationale};
#[derive(Debug, Clone, Copy, serde::Serialize)]
pub struct CheckRationale {
pub problem: &'static str,
pub fix: &'static str,
pub exception: &'static str,
pub llm_specific: bool,
}
impl fmt::Display for CheckRationale {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "Problem: {}", self.problem)?;
writeln!(f, "Fix: {}", self.fix)?;
writeln!(f, "Exception: {}", self.exception)?;
write!(f, "LLM-specific: {}", self.llm_specific)
}
}
impl ViolationType {
pub fn pattern(&self) -> Option<&str> {
match self {
Self::ForbiddenAttribute { pattern }
| Self::ForbiddenType { pattern }
| Self::ForbiddenCall { pattern }
| Self::ForbiddenMacro { pattern } => Some(pattern),
_ => None,
}
}
}
impl fmt::Display for ViolationType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.code())
}
}
#[derive(Debug, Clone)]
pub struct Violation {
pub violation_type: ViolationType,
pub file_path: Arc<str>,
pub line: usize,
pub column: usize,
pub message: Box<str>,
}
impl Violation {
pub fn new(
violation_type: ViolationType,
file_path: Arc<str>,
line: usize,
column: usize,
message: impl Into<Box<str>>,
) -> Self {
Self {
violation_type,
file_path,
line,
column,
message: message.into(),
}
}
pub fn rationale(&self) -> CheckRationale {
self.violation_type.rationale()
}
}
impl fmt::Display for Violation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{}:{}:{}: {}: {}",
self.file_path, self.line, self.column, self.violation_type, self.message
)
}
}