feat(natu): ignore imported let bindings
This commit was merged in pull request #122.
This commit is contained in:
@@ -199,6 +199,24 @@ in
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gtest]
|
||||||
|
fn natu_accepts_single_use_import_binding() -> googletest::Result<()> {
|
||||||
|
let report = natu::future_sight(vec![SourceFile {
|
||||||
|
path: PathBuf::from("testdata/import_binding.nix"),
|
||||||
|
source: r#"
|
||||||
|
let
|
||||||
|
imported = import ./module.nix { };
|
||||||
|
in
|
||||||
|
imported
|
||||||
|
"#
|
||||||
|
.into(),
|
||||||
|
}])
|
||||||
|
.or_fail()?;
|
||||||
|
|
||||||
|
expect_that!(report.is_clean(), is_true());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[gtest]
|
#[gtest]
|
||||||
fn natu_reports_single_use_binding() -> googletest::Result<()> {
|
fn natu_reports_single_use_binding() -> googletest::Result<()> {
|
||||||
let report = natu::future_sight(vec![SourceFile {
|
let report = natu::future_sight(vec![SourceFile {
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ fn is_single_use(graph: &ScopeGraph, let_scope: &LetScope, binding: &Binding) ->
|
|||||||
.filter(|reference| graph.resolve(**reference).contains(&binding.declaration))
|
.filter(|reference| graph.resolve(**reference).contains(&binding.declaration))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
self_references == 0
|
!binding.is_import
|
||||||
|
&& self_references == 0
|
||||||
&& external_references.len() == 1
|
&& external_references.len() == 1
|
||||||
&& (binding.is_lambda
|
&& (binding.is_lambda
|
||||||
|| !graph.crosses_lambda_scope(*external_references[0], binding.declaration))
|
|| !graph.crosses_lambda_scope(*external_references[0], binding.declaration))
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ impl ScopeGraph {
|
|||||||
declaration: self.add_declaration(&binding.key.name, scope),
|
declaration: self.add_declaration(&binding.key.name, scope),
|
||||||
name: binding.key.name.clone(),
|
name: binding.key.name.clone(),
|
||||||
references: Vec::new(),
|
references: Vec::new(),
|
||||||
|
is_import: is_import(&binding.value),
|
||||||
is_lambda: matches!(binding.value, ast::Expr::Lambda { .. }),
|
is_lambda: matches!(binding.value, ast::Expr::Lambda { .. }),
|
||||||
range: binding.range,
|
range: binding.range,
|
||||||
})
|
})
|
||||||
@@ -191,6 +192,28 @@ impl ScopeGraph {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_import(expr: &ast::Expr) -> bool {
|
||||||
|
match unwrap_expr(expr) {
|
||||||
|
ast::Expr::Apply(application) => is_import_callee(&application.lambda),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_import_callee(expr: &ast::Expr) -> bool {
|
||||||
|
match unwrap_expr(expr) {
|
||||||
|
ast::Expr::Apply(application) => is_import_callee(&application.lambda),
|
||||||
|
ast::Expr::Ident(ident) => ident.name == "import",
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unwrap_expr(expr: &ast::Expr) -> &ast::Expr {
|
||||||
|
match expr {
|
||||||
|
ast::Expr::Other(expressions) if expressions.len() == 1 => unwrap_expr(&expressions[0]),
|
||||||
|
_ => expr,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Node {
|
enum Node {
|
||||||
Scope(ScopeKind),
|
Scope(ScopeKind),
|
||||||
@@ -237,6 +260,7 @@ pub(crate) struct Binding {
|
|||||||
pub(crate) declaration: NodeId,
|
pub(crate) declaration: NodeId,
|
||||||
pub(crate) name: String,
|
pub(crate) name: String,
|
||||||
pub(crate) references: Vec<NodeId>,
|
pub(crate) references: Vec<NodeId>,
|
||||||
|
pub(crate) is_import: bool,
|
||||||
pub(crate) is_lambda: bool,
|
pub(crate) is_lambda: bool,
|
||||||
pub(crate) range: ast::SourceRange,
|
pub(crate) range: ast::SourceRange,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user