usage: become aware of shadowed bindings

This commit is contained in:
Astro 2021-12-07 20:58:02 +01:00
parent 99ea26c6ee
commit e754ef4e7f
2 changed files with 45 additions and 1 deletions

View File

@ -36,6 +36,13 @@ fn let_in_dead_recursive() {
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn let_in_shadowed() {
let results = run("let dead = true; in let dead = false; in dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn let_in_inherit_alive() {
let results = run("let alive = {}; inherit (alive) key; in key");
@ -49,6 +56,13 @@ fn let_in_inherit_dead() {
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn let_in_inherit_shadowed() {
let results = run("let inherit (dead) dead; in let inherit (alive) dead; in dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn lambda_arg_alive() {
let results = run("alive: alive");
@ -68,6 +82,13 @@ fn lambda_arg_dead() {
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn lambda_arg_shadowed() {
let results = run("dead: dead: dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn lambda_at_alive() {
let results = run("alive@{ ... }: alive");
@ -87,6 +108,13 @@ fn lambda_at_dead() {
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn lambda_at_shadowed() {
let results = run("dead@{ ... }: dead@{ ... }: dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn lambda_pattern_alive() {
let results = run("{ alive, ... }: alive");
@ -106,6 +134,13 @@ fn lambda_pattern_no_ellipsis() {
assert_eq!(0, results.len());
}
#[test]
fn lambda_pattern_shadowed() {
let results = run("{ dead, ... }: { dead, ... }: dead");
assert_eq!(1, results.len());
assert_eq!(results[0].binding.name.as_str(), "dead");
}
#[test]
fn looped() {
let results = run("let dead1 = dead2; dead2 = {}; in false");

View File

@ -8,10 +8,19 @@ use rnix::{
TypedNode,
},
};
use crate::scope::Scope;
/// find out if `name` is used in `node`
pub fn find_usage(name: &Ident, node: SyntaxNode<NixLanguage>) -> bool {
// TODO: return false if shadowed by other let/rec/param binding
if let Some(scope) = Scope::new(&node) {
for binding in scope.bindings() {
if binding.name.as_str() == name.as_str() {
// shadowed by a a new child scope that redefines the
// variable with the same name
return false;
}
}
}
if node.kind() == SyntaxKind::NODE_IDENT {
Ident::cast(node).expect("Ident::cast").as_str() == name.as_str()