feat(natu): detect single-use let bindings

This commit was merged in pull request #116.
This commit is contained in:
2026-09-30 10:43:05 -04:00
parent 2265dfc558
commit 78492739f3
7 changed files with 153 additions and 16 deletions

View File

@@ -0,0 +1,45 @@
use crate::{
ast,
scope_graph::{Binding, LetScope, ScopeGraph},
};
pub struct Finding {
pub range: ast::SourceRange,
pub name: String,
}
pub fn check(graph: &ScopeGraph) -> Vec<Finding> {
graph
.let_scopes()
.iter()
.flat_map(|let_scope| {
let_scope.bindings.iter().filter_map(|binding| {
is_single_use(graph, let_scope, binding).then(|| Finding {
range: binding.range,
name: binding.name.clone(),
})
})
})
.collect()
}
fn is_single_use(graph: &ScopeGraph, let_scope: &LetScope, binding: &Binding) -> bool {
let self_references = binding
.references
.iter()
.filter(|reference| graph.resolve(**reference).contains(&binding.declaration))
.count();
let external_references = let_scope
.bindings
.iter()
.filter(|candidate| candidate.declaration != binding.declaration)
.flat_map(|candidate| candidate.references.iter())
.chain(let_scope.entry_references.iter())
.filter(|reference| graph.resolve(**reference).contains(&binding.declaration))
.collect::<Vec<_>>();
self_references == 0
&& external_references.len() == 1
&& (binding.is_lambda
|| !graph.crosses_lambda_scope(*external_references[0], binding.declaration))
}