feat(xatu): identify ordered bindings

This commit is contained in:
2026-09-26 20:02:19 -04:00
parent a295bed5c0
commit 7a54789dd2
4 changed files with 32 additions and 11 deletions

View File

@@ -21,15 +21,22 @@ pub struct Finding {
pub rule_id: &'static str,
pub range: ast::SourceRange,
pub message: &'static str,
pub binding: Option<String>,
}
impl std::fmt::Display for Diagnostic {
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
formatter,
"{}: {}",
"[{}] {}",
self.finding.rule_id, self.finding.message
)
)?;
if let Some(binding) = &self.finding.binding {
write!(formatter, ": {binding}")?;
}
Ok(())
}
}
@@ -68,10 +75,11 @@ pub fn run_rules(file: &ast::ParsedFile, graph: &ScopeGraph) -> Vec<Diagnostic>
.flat_map(|token| [run_token_rule::<UnquotedUri>(token)])
.flatten();
let let_order_diagnostics = let_order::check(graph).into_iter().map(|range| Finding {
let let_order_diagnostics = let_order::check(graph).into_iter().map(|finding| Finding {
rule_id: "let_order",
range,
range: finding.range,
message: "Let bindings must follow dependency order",
binding: Some(finding.binding),
});
node_diagnostics
@@ -95,6 +103,7 @@ where
rule_id: R::ID,
range: node.range,
message,
binding: None,
})
}
@@ -109,5 +118,6 @@ where
rule_id: R::ID,
range: token.range,
message,
binding: None,
})
}

View File

@@ -3,7 +3,12 @@ use crate::{
scope_graph::{LetScope, NodeId, ScopeGraph},
};
pub fn check(graph: &ScopeGraph) -> Vec<ast::SourceRange> {
pub struct Finding {
pub range: ast::SourceRange,
pub binding: String,
}
pub fn check(graph: &ScopeGraph) -> Vec<Finding> {
graph
.let_scopes()
.iter()
@@ -24,7 +29,10 @@ pub fn check(graph: &ScopeGraph) -> Vec<ast::SourceRange> {
.iter()
.find(|(declaration, _)| *declaration == binding.declaration)
.filter(|(_, expected_position)| position != *expected_position)
.map(|_| binding.range)
.map(|_| Finding {
range: binding.range,
binding: binding.name.clone(),
})
})
})
.collect()

View File

@@ -57,6 +57,7 @@ impl ScopeGraph {
.iter()
.map(|binding| Binding {
declaration: self.add_declaration(&binding.key.name, scope),
name: binding.key.name.clone(),
references: Vec::new(),
range: binding.range,
})
@@ -187,6 +188,7 @@ pub(crate) struct LetScope {
#[derive(Debug)]
pub(crate) struct Binding {
pub(crate) declaration: NodeId,
pub(crate) name: String,
pub(crate) references: Vec<NodeId>,
pub(crate) range: ast::SourceRange,
}

View File

@@ -26,11 +26,12 @@ impl std::fmt::Display for Report {
for diagnostic in &self.diagnostics {
let file = self.files.get(diagnostic.file_id);
let (start, end) = line_range(&file.source, diagnostic.finding.range);
writeln!(
formatter,
"{}:{start}..{end}:{diagnostic}",
file.path.display()
)?;
let location = if start == end {
start.to_string()
} else {
format!("{start}-{end}")
};
writeln!(formatter, "{}:{location} {diagnostic}", file.path.display())?;
}
Ok(())