diff --git a/changelog/fix_fix_styleredundantself_to_allow.md b/changelog/fix_fix_styleredundantself_to_allow.md new file mode 100644 index 00000000000..f9aef5146a9 --- /dev/null +++ b/changelog/fix_fix_styleredundantself_to_allow.md @@ -0,0 +1 @@ +* [#9843](https://github.com/rubocop/rubocop/issues/9843): Fix `Style/RedundantSelf` to allow conditional nodes to use `self` in the condition when a variable named is shadowed inside. ([@dvandersluis][]) diff --git a/lib/rubocop/cop/style/redundant_self.rb b/lib/rubocop/cop/style/redundant_self.rb index da54c27c138..1539b1673b5 100644 --- a/lib/rubocop/cop/style/redundant_self.rb +++ b/lib/rubocop/cop/style/redundant_self.rb @@ -92,7 +92,7 @@ def on_blockarg(node) def on_masgn(node) lhs, rhs = *node - lhs.children.each { |child| add_lhs_to_local_variables_scopes(rhs, child.to_a.first) } + add_masgn_lhs_variables(rhs, lhs) end def on_lvasgn(node) @@ -116,6 +116,22 @@ def on_block(node) add_scope(node, @local_variables_scopes[node]) end + def on_if(node) + # Allow conditional nodes to use `self` in the condition if that variable + # name is used in an `lvasgn` or `masgn` within the `if`. + node.child_nodes.each do |child_node| + lhs, _rhs = *child_node + + if child_node.lvasgn_type? + add_lhs_to_local_variables_scopes(node.condition, lhs) + elsif child_node.masgn_type? + add_masgn_lhs_variables(node.condition, lhs) + end + end + end + alias on_while on_if + alias on_until on_if + private def add_scope(node, local_variables = []) @@ -163,6 +179,12 @@ def add_lhs_to_local_variables_scopes(rhs, lhs) @local_variables_scopes[rhs] << lhs end end + + def add_masgn_lhs_variables(rhs, lhs) + lhs.children.each do |child| + add_lhs_to_local_variables_scopes(rhs, child.to_a.first) + end + end end end end diff --git a/spec/rubocop/cop/style/redundant_self_spec.rb b/spec/rubocop/cop/style/redundant_self_spec.rb index 4999f241fc2..7d4d6f975fc 100644 --- a/spec/rubocop/cop/style/redundant_self_spec.rb +++ b/spec/rubocop/cop/style/redundant_self_spec.rb @@ -24,6 +24,56 @@ expect_no_offenses('a, b = self.a') end + it 'does not report an offense when lvasgn name is used in `if`' do + expect_no_offenses('a = self.a if self.a') + end + + it 'does not report an offense when masgn name is used in `if`' do + expect_no_offenses('a, b = self.a if self.a') + end + + it 'does not report an offense when lvasgn name is used in `unless`' do + expect_no_offenses('a = self.a unless self.a') + end + + it 'does not report an offense when masgn name is used in `unless`' do + expect_no_offenses('a, b = self.a unless self.a') + end + + it 'does not report an offense when lvasgn name is used in `while`' do + expect_no_offenses('a = self.a while self.a') + end + + it 'does not report an offense when masgn name is used in `while`' do + expect_no_offenses('a, b = self.a while self.a') + end + + it 'does not report an offense when lvasgn name is used in `until`' do + expect_no_offenses('a = self.a until self.a') + end + + it 'does not report an offense when masgn name is used in `until`' do + expect_no_offenses('a, b = self.a until self.a') + end + + it 'does not report an offense when lvasgn name is nested below `if`' do + expect_no_offenses('a = self.a if foo(self.a)') + end + + it 'reports an offense when a different lvasgn name is used in `if`' do + expect_offense(<<~RUBY) + a = x if self.b + ^^^^ Redundant `self` detected. + RUBY + end + + it 'reports an offense when a different masgn name is used in `if`' do + expect_offense(<<~RUBY) + a, b, c = x if self.d + ^^^^ Redundant `self` detected. + RUBY + end + it 'does not report an offense when self receiver in a method argument and ' \ 'lvalue have the same name' do expect_no_offenses('a = do_something(self.a)')