Skip to content

Commit

Permalink
Find used variables that start with an underscore
Browse files Browse the repository at this point in the history
Fixes Github issue #90
  • Loading branch information
astro committed Jan 3, 2025
1 parent 682aa27 commit a8c3e26
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 23 deletions.
2 changes: 2 additions & 0 deletions example.nix
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ let
used4 = { t = used_inherit; };
shadowed = 42;
_unused = unused: false;
_used = 23;
in {
x = { unusedArg2, x ? args.y, ... }@args: used1 + x;
inherit used2;
"${used3}" = true;
y = used4.t;
z = let shadowed = 23; in shadowed;
inherit _used;
}
52 changes: 33 additions & 19 deletions src/dead_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@ pub struct DeadCode {
pub scope: Scope,
/// The [`Binding`] that is found to be unused
pub binding: Binding,
/// Used or unused?
unused: bool,
}

impl fmt::Display for DeadCode {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "Unused {}: {}", self.scope, self.binding.name)
if self.unused {
write!(fmt, "Unused {}: {}", self.scope, self.binding.name)
} else {
write!(fmt, "Used {}: {}", self.scope, self.binding.name)
}
}
}

Expand All @@ -32,6 +38,8 @@ pub struct Settings {
pub no_lambda_pattern_names: bool,
/// Ignore all `Binding` that start with `_`
pub no_underscore: bool,
/// Warn on used binding that starts with `_`
pub warn_used_underscore: bool,
}

impl Settings {
Expand Down Expand Up @@ -71,25 +79,31 @@ impl Settings {
continue;
}

if binding.is_mortal()
&& scope.bodies().all(|body|
// remove this binding's own node
body == binding.decl_node
// excluding already unused results
|| dead.contains(&body)
|| is_dead_inherit(dead, &body)
// or not used anywhere
|| ! usage::find(&binding.name, &body)
)
&& ! binding.has_pragma_skip() {
dead.insert(binding.decl_node.clone());
results.insert(
binding.decl_node.clone(),
DeadCode {
scope: scope.clone(),
binding,
},
if binding.is_mortal() && ! binding.has_pragma_skip() {
let unused = scope.bodies().all(|body|
// remove this binding's own node
body == binding.decl_node
// excluding already unused results
|| dead.contains(&body)
|| is_dead_inherit(dead, &body)
// or not used anywhere
|| ! usage::find(&binding.name, &body)
);
if unused || (
self.warn_used_underscore &&
binding.name.syntax().text().char_at(0.into()) == Some('_') &&
! unused
) {
dead.insert(binding.decl_node.clone());
results.insert(
binding.decl_node.clone(),
DeadCode {
scope: scope.clone(),
binding,
unused,
},
);
}
}
}
}
Expand Down
26 changes: 22 additions & 4 deletions src/dead_code_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@
use rowan::ast::AstNode;
use crate::dead_code::{DeadCode, Settings};

fn run(content: &str) -> Vec<DeadCode> {
fn run_settings(content: &str, settings: Settings) -> Vec<DeadCode> {
let ast = rnix::Root::parse(content);
assert_eq!(0, ast.errors().len());

Settings {
settings.find_dead_code(&ast.syntax())
}

fn run(content: &str) -> Vec<DeadCode> {
run_settings(content, Settings {
no_lambda_arg: false,
no_lambda_pattern_names: false,
no_underscore: false,
}
.find_dead_code(&ast.syntax())
warn_used_underscore: false,
})
}

#[test]
Expand Down Expand Up @@ -482,3 +486,17 @@ fn let_args_string_splice() {
");
assert_eq!(0, results.len());
}

#[test]
fn used_underscore_let() {
let results = run_settings("
let _x = 23;
in _x
", Settings {
no_lambda_arg: false,
no_lambda_pattern_names: false,
no_underscore: false,
warn_used_underscore: true,
});
assert_eq!(1, results.len());
}
1 change: 1 addition & 0 deletions src/edit_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ fn run(content: &str) -> (String, bool) {
no_lambda_arg: false,
no_lambda_pattern_names: false,
no_underscore: false,
warn_used_underscore: false,
}
.find_dead_code(&ast.syntax());
crate::edit::edit_dead_code(content, results.into_iter())
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
//! no_lambda_arg: false,
//! no_lambda_pattern_names: false,
//! no_underscore: false,
//! warn_used_underscore: false,
//! }.find_dead_code(&ast.syntax());
//!
//! for dead_code in &results {
Expand Down
8 changes: 8 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ fn main() {
(Lambda arguments starting with _ are not checked anyway.)"
),
)
.arg(
Arg::new("WARN_USED_UNDERSCORE")
.action(ArgAction::SetTrue)
.short('W')
.long("warn-used-underscore")
.help("Warn if bindings are referenced that start with '_'"),
)
.arg(
Arg::new("QUIET")
.action(ArgAction::SetTrue)
Expand Down Expand Up @@ -112,6 +119,7 @@ fn main() {
no_lambda_arg: matches.get_flag("NO_LAMBDA_ARG"),
no_lambda_pattern_names: matches.get_flag("NO_LAMBDA_PATTERN_NAMES"),
no_underscore: matches.get_flag("NO_UNDERSCORE"),
warn_used_underscore: matches.get_flag("WARN_USED_UNDERSCORE"),
};
let quiet = matches.get_flag("QUIET");
let edit = matches.get_flag("EDIT");
Expand Down

0 comments on commit a8c3e26

Please sign in to comment.