diff --git a/src/xatu/rules.rs b/src/xatu/rules.rs index 09684ed..aa04a2f 100644 --- a/src/xatu/rules.rs +++ b/src/xatu/rules.rs @@ -4,17 +4,37 @@ use crate::rules::empty_inherit::EmptyInherit; pub mod empty_inherit; +#[derive(Debug)] pub struct Finding { + /// Identifies the rule that produced this finding. pub rule_id: &'static str, + /// Identifies the source range that triggered this finding. pub range: ast::SourceRange, + /// Describes the finding for human-readable output. pub message: &'static str, } +#[derive(Debug)] pub struct Diagnostic { + /// Identifies the file that contains this diagnostic. pub file_id: FileId, + /// Contains the node-local rule finding. pub finding: Finding, } +impl std::fmt::Display for Diagnostic { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + formatter, + "{}..{}: {}: {}", + self.finding.range.start, + self.finding.range.end, + self.finding.rule_id, + self.finding.message, + ) + } +} + pub trait NodeRule { type Node; diff --git a/src/xatu/xatu.rs b/src/xatu/xatu.rs index b48ed5c..c16c3e7 100644 --- a/src/xatu/xatu.rs +++ b/src/xatu/xatu.rs @@ -4,9 +4,38 @@ mod parser; mod rules; pub use file_store::{FileId, FileStore, SourceFile}; +pub use rules::{Diagnostic, Finding}; -pub fn run(files: Vec) -> status::Result<()> { +#[derive(Debug)] +pub struct Report { + /// Contains the analyzed source files. + pub files: FileStore, + /// Contains lint diagnostics from analyzed source files. + pub diagnostics: Vec, +} + +impl Report { + /// Returns true when Xatu found no diagnostics. + pub fn is_clean(&self) -> bool { + self.diagnostics.is_empty() + } +} + +impl std::fmt::Display for Report { + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for diagnostic in &self.diagnostics { + let file = self.files.get(diagnostic.file_id); + writeln!(formatter, "{}:{diagnostic}", file.path.display())?; + } + + Ok(()) + } +} + +/// Analyzes source files and returns the diagnostics Xatu finds. +pub fn future_sight(files: Vec) -> status::Result { let mut store = FileStore::default(); + let mut diagnostics = Vec::new(); for file in files { let file_id = store.add(file); @@ -20,17 +49,11 @@ pub fn run(files: Vec) -> status::Result<()> { ))); } - for diagnostic in rules::run_rules(&parsed) { - println!( - "{}:{}..{}: {}: {}", - file.path.display(), - diagnostic.finding.range.start, - diagnostic.finding.range.end, - diagnostic.finding.rule_id, - diagnostic.finding.message, - ); - } + diagnostics.extend(rules::run_rules(&parsed)); } - Ok(()) + Ok(Report { + files: store, + diagnostics, + }) } diff --git a/src/xatu/xatu_main.rs b/src/xatu/xatu_main.rs index 24d519e..2a5c68c 100644 --- a/src/xatu/xatu_main.rs +++ b/src/xatu/xatu_main.rs @@ -82,5 +82,8 @@ fn main() -> status::Result<()> { .flatten() .collect(); - xatu::run(files) + let report = xatu::future_sight(files)?; + print!("{report}"); + + Ok(()) }