diff --git a/src/rules/remove_unused_variable.rs b/src/rules/remove_unused_variable.rs index be4b9428..5c39e42d 100644 --- a/src/rules/remove_unused_variable.rs +++ b/src/rules/remove_unused_variable.rs @@ -129,22 +129,33 @@ impl NodeProcessor for RemoveUnusedVariableProcessor { .collect(); let length = assignments.len(); + let mut remaining_unassigned_variables = Vec::new(); + if let Some((last, value)) = assignments.last_mut() { + let remaining = + assign.iter_variables().zip(usages.iter()).skip(length); if self.evaluator.can_return_multiple_values(value) { - last.extend( - assign.iter_variables().zip(usages.iter()).skip(length), + last.extend(remaining); + } else { + remaining_unassigned_variables.extend( + remaining + .filter(|(_, used)| **used) + .map(|(identifier, _)| identifier.clone()), ); } } - let mut variables = Vec::new(); - let mut values = Vec::new(); + let mut values: Vec<_> = remaining_unassigned_variables + .iter() + .map(|_| Expression::nil()) + .collect(); + let mut variables = remaining_unassigned_variables; for (mut identifiers, value) in assignments { - if !self.evaluator.has_side_effects(value) { - while identifiers.last().filter(|(_, used)| !*used).is_some() { - identifiers.pop(); - } + let mut last_popped = None; + + while identifiers.last().filter(|(_, used)| !*used).is_some() { + last_popped = identifiers.pop(); } if !identifiers.is_empty() { @@ -154,6 +165,11 @@ impl NodeProcessor for RemoveUnusedVariableProcessor { .map(|(identifier, _)| identifier.clone()), ); values.push(value.clone()); + } else if self.evaluator.has_side_effects(value) { + if let Some((last_identifier, _)) = last_popped { + variables.push(last_identifier.clone()); + values.push(value.clone()); + } } } diff --git a/tests/rule_tests/remove_unused_variable.rs b/tests/rule_tests/remove_unused_variable.rs index 3fb344fc..b8f2c083 100644 --- a/tests/rule_tests/remove_unused_variable.rs +++ b/tests/rule_tests/remove_unused_variable.rs @@ -56,6 +56,9 @@ test_rule!( remove_unused_variable_but_keep_require_side_effect("local _requireZero = require('./requireZero.roblox.lua')") => "require('./requireZero.roblox.lua')", remove_unused_variable_but_keep_require_side_effect_in_parens("local _requireZero = (require('./requireZero.roblox.lua'))") => "require('./requireZero.roblox.lua')", remove_unused_variable_but_keep_require_side_effect_in_parens_with_type_cast("local _requireZero = (require('./requireZero.roblox.lua') :: any)") => "require('./requireZero.roblox.lua')", + remove_unused_variable_but_not_initially_assigned_variable("local a, b = true b = false") => "local b = nil b = false", + remove_unused_variable_but_not_initially_assigned_variable_with_unused_trailing_variable("local a, b, c = true b = false") => "local b = nil b = false", + keep_used_variable_bounded_by_unused_variable_with_side_effect("local a, b, c = call() b = false") => "local a, b = call() b = false", // remove variables that are used more than once, but never read // remove_if_only_assigned("local a = true a = false") => "", // remove_if_only_field_assigned("local a = {} a.foo = false") => "",