feat(xatu): identify ordered bindings
This commit is contained in:
@@ -21,15 +21,22 @@ pub struct Finding {
|
|||||||
pub rule_id: &'static str,
|
pub rule_id: &'static str,
|
||||||
pub range: ast::SourceRange,
|
pub range: ast::SourceRange,
|
||||||
pub message: &'static str,
|
pub message: &'static str,
|
||||||
|
pub binding: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Diagnostic {
|
impl std::fmt::Display for Diagnostic {
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
formatter,
|
formatter,
|
||||||
"{}: {}",
|
"[{}] {}",
|
||||||
self.finding.rule_id, self.finding.message
|
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)])
|
.flat_map(|token| [run_token_rule::<UnquotedUri>(token)])
|
||||||
.flatten();
|
.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",
|
rule_id: "let_order",
|
||||||
range,
|
range: finding.range,
|
||||||
message: "Let bindings must follow dependency order",
|
message: "Let bindings must follow dependency order",
|
||||||
|
binding: Some(finding.binding),
|
||||||
});
|
});
|
||||||
|
|
||||||
node_diagnostics
|
node_diagnostics
|
||||||
@@ -95,6 +103,7 @@ where
|
|||||||
rule_id: R::ID,
|
rule_id: R::ID,
|
||||||
range: node.range,
|
range: node.range,
|
||||||
message,
|
message,
|
||||||
|
binding: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,5 +118,6 @@ where
|
|||||||
rule_id: R::ID,
|
rule_id: R::ID,
|
||||||
range: token.range,
|
range: token.range,
|
||||||
message,
|
message,
|
||||||
|
binding: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ use crate::{
|
|||||||
scope_graph::{LetScope, NodeId, ScopeGraph},
|
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
|
graph
|
||||||
.let_scopes()
|
.let_scopes()
|
||||||
.iter()
|
.iter()
|
||||||
@@ -24,7 +29,10 @@ pub fn check(graph: &ScopeGraph) -> Vec<ast::SourceRange> {
|
|||||||
.iter()
|
.iter()
|
||||||
.find(|(declaration, _)| *declaration == binding.declaration)
|
.find(|(declaration, _)| *declaration == binding.declaration)
|
||||||
.filter(|(_, expected_position)| position != *expected_position)
|
.filter(|(_, expected_position)| position != *expected_position)
|
||||||
.map(|_| binding.range)
|
.map(|_| Finding {
|
||||||
|
range: binding.range,
|
||||||
|
binding: binding.name.clone(),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ impl ScopeGraph {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|binding| Binding {
|
.map(|binding| Binding {
|
||||||
declaration: self.add_declaration(&binding.key.name, scope),
|
declaration: self.add_declaration(&binding.key.name, scope),
|
||||||
|
name: binding.key.name.clone(),
|
||||||
references: Vec::new(),
|
references: Vec::new(),
|
||||||
range: binding.range,
|
range: binding.range,
|
||||||
})
|
})
|
||||||
@@ -187,6 +188,7 @@ pub(crate) struct LetScope {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct Binding {
|
pub(crate) struct Binding {
|
||||||
pub(crate) declaration: NodeId,
|
pub(crate) declaration: NodeId,
|
||||||
|
pub(crate) name: String,
|
||||||
pub(crate) references: Vec<NodeId>,
|
pub(crate) references: Vec<NodeId>,
|
||||||
pub(crate) range: ast::SourceRange,
|
pub(crate) range: ast::SourceRange,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,11 +26,12 @@ impl std::fmt::Display for Report {
|
|||||||
for diagnostic in &self.diagnostics {
|
for diagnostic in &self.diagnostics {
|
||||||
let file = self.files.get(diagnostic.file_id);
|
let file = self.files.get(diagnostic.file_id);
|
||||||
let (start, end) = line_range(&file.source, diagnostic.finding.range);
|
let (start, end) = line_range(&file.source, diagnostic.finding.range);
|
||||||
writeln!(
|
let location = if start == end {
|
||||||
formatter,
|
start.to_string()
|
||||||
"{}:{start}..{end}:{diagnostic}",
|
} else {
|
||||||
file.path.display()
|
format!("{start}-{end}")
|
||||||
)?;
|
};
|
||||||
|
writeln!(formatter, "{}:{location} {diagnostic}", file.path.display())?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
Reference in New Issue
Block a user