feat(xatu): identify ordered bindings
This commit is contained in:
@@ -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,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
Reference in New Issue
Block a user