diff --git a/changelog/fix_an_incorrect_autocorrect_for_style_and_or.md b/changelog/fix_an_incorrect_autocorrect_for_style_and_or.md new file mode 100644 index 000000000000..61d49cea87de --- /dev/null +++ b/changelog/fix_an_incorrect_autocorrect_for_style_and_or.md @@ -0,0 +1 @@ +* [#8053](https://github.com/rubocop-hq/rubocop/issues/8053): Fix an incorrect auto-correct for `Style/AndOr` when `or` precedes `and`. ([@koic][]) diff --git a/lib/rubocop/cop/style/and_or.rb b/lib/rubocop/cop/style/and_or.rb index e98f22f01fa7..52c349b0780a 100644 --- a/lib/rubocop/cop/style/and_or.rb +++ b/lib/rubocop/cop/style/and_or.rb @@ -72,6 +72,8 @@ def process_logical_operator(node) end corrector.replace(node.loc.operator, node.alternate_operator) + + keep_operator_precedence(corrector, node) end end @@ -123,6 +125,14 @@ def correct_other(node, corrector) corrector.wrap(node, '(', ')') end + def keep_operator_precedence(corrector, node) + if node.or_type? && node.parent&.and_type? + corrector.wrap(node, '(', ')') + elsif node.and_type? && node.rhs.or_type? + corrector.wrap(node.rhs, '(', ')') + end + end + def correctable_send?(node) !node.parenthesized? && node.arguments? && !node.method?(:[]) end diff --git a/spec/rubocop/cop/style/and_or_spec.rb b/spec/rubocop/cop/style/and_or_spec.rb index c08ce4156273..756637a56421 100644 --- a/spec/rubocop/cop/style/and_or_spec.rb +++ b/spec/rubocop/cop/style/and_or_spec.rb @@ -508,6 +508,60 @@ def y end end + context 'when `or` precedes `and`' do + it 'registers an offense and corrects' do + expect_offense(<<~RUBY) + foo or bar and baz + ^^ Use `||` instead of `or`. + ^^^ Use `&&` instead of `and`. + RUBY + + expect_correction(<<~RUBY) + (foo || bar) && baz + RUBY + end + end + + context 'when `or` precedes `&&`' do + it 'registers an offense and corrects' do + expect_offense(<<~RUBY) + foo or bar && baz + ^^ Use `||` instead of `or`. + RUBY + + expect_correction(<<~RUBY) + foo || bar && baz + RUBY + end + end + + context 'when `and` precedes `or`' do + it 'registers an offense and corrects' do + expect_offense(<<~RUBY) + foo and bar or baz + ^^^ Use `&&` instead of `and`. + ^^ Use `||` instead of `or`. + RUBY + + expect_correction(<<~RUBY) + foo && bar || baz + RUBY + end + end + + context 'when `and` precedes `||`' do + it 'registers an offense and corrects' do + expect_offense(<<~RUBY) + foo and bar || baz + ^^^ Use `&&` instead of `and`. + RUBY + + expect_correction(<<~RUBY) + foo && (bar || baz) + RUBY + end + end + context 'within a nested begin node with one child only' do # regression test; see GH issue 2531 it 'autocorrects "and" with && and adds parens' do