diff --git a/changelog/fix_false_negative_for_layout_hash_alignment.md b/changelog/fix_false_negative_for_layout_hash_alignment.md new file mode 100644 index 00000000000..d945e103be7 --- /dev/null +++ b/changelog/fix_false_negative_for_layout_hash_alignment.md @@ -0,0 +1 @@ +* [#9805](https://github.com/rubocop/rubocop/pull/9805): Fix a false negative for `Layout/HashAlignment` when set `EnforcedStyle: with_fixed_indentation` of `ArgumentAlignment`. ([@koic][]) diff --git a/lib/rubocop/cop/layout/hash_alignment.rb b/lib/rubocop/cop/layout/hash_alignment.rb index 0daded023e5..e8b3af0cfe3 100644 --- a/lib/rubocop/cop/layout/hash_alignment.rb +++ b/lib/rubocop/cop/layout/hash_alignment.rb @@ -201,7 +201,7 @@ def on_send(node) alias on_yield on_send def on_hash(node) - return if enforce_first_argument_with_fixed_indentation? || ignored_node?(node) || + return if autocorrect_incompatible_with_other_cops?(node) || ignored_node?(node) || node.pairs.empty? || node.single_line? proc = ->(a) { a.checkable_layout?(node) } @@ -214,6 +214,10 @@ def on_hash(node) private + def autocorrect_incompatible_with_other_cops?(node) + enforce_first_argument_with_fixed_indentation? && node.parent&.call_type? + end + def reset! self.offences_by = {} self.column_deltas = Hash.new { |hash, key| hash[key] = {} } diff --git a/spec/rubocop/cli/autocorrect_spec.rb b/spec/rubocop/cli/autocorrect_spec.rb index 904bcbf5b60..ca63408999d 100644 --- a/spec/rubocop/cli/autocorrect_spec.rb +++ b/spec/rubocop/cli/autocorrect_spec.rb @@ -1839,6 +1839,38 @@ def do_even_more_stuff RUBY end + it 'corrects when specifying `EnforcedStyle: with_fixed_indentation` of `Layout/ArgumentAlignment` and ' \ + '`Layout/HashAlignment`' do + create_file('example.rb', <<~RUBY) + update(foo: bar, + baz: boo, + pony: party) + + self&.update(foo: bar, + baz: boo, + pony: party) + RUBY + + create_file('.rubocop.yml', <<~YAML) + Layout/ArgumentAlignment: + EnforcedStyle: with_fixed_indentation + YAML + + expect( + cli.run(['--auto-correct', '--only', 'Layout/ArgumentAlignment,Layout/HashAlignment']) + ).to eq(0) + expect($stderr.string).to eq('') + expect(File.read('example.rb')).to eq(<<~RUBY) + update(foo: bar, + baz: boo, + pony: party) + + self&.update(foo: bar, + baz: boo, + pony: party) + RUBY + end + it 'does not crash Lint/SafeNavigationWithEmpty and offenses and accepts Style/SafeNavigation ' \ 'when checking `foo&.empty?` in a conditional' do create_file('example.rb', <<~RUBY) diff --git a/spec/rubocop/cop/layout/hash_alignment_spec.rb b/spec/rubocop/cop/layout/hash_alignment_spec.rb index c8f2db6b475..2ef6f99e3f4 100644 --- a/spec/rubocop/cop/layout/hash_alignment_spec.rb +++ b/spec/rubocop/cop/layout/hash_alignment_spec.rb @@ -1,7 +1,15 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Layout::HashAlignment, :config do - let(:cop_config) { { 'EnforcedHashRocketStyle' => 'key', 'EnforcedColonStyle' => 'key' } } + let(:config) do + RuboCop::Config.new( + 'Layout/HashAlignment' => default_cop_config.merge(cop_config), + 'Layout/ArgumentAlignment' => argument_alignment_config + ) + end + + let(:default_cop_config) { { 'EnforcedHashRocketStyle' => 'key', 'EnforcedColonStyle' => 'key' } } + let(:argument_alignment_config) { { 'EnforcedStyle' => 'with_first_argument' } } shared_examples 'not on separate lines' do it 'accepts single line hash' do @@ -112,6 +120,27 @@ def example end end + context 'when `EnforcedStyle: with_fixed_indentation` of `ArgumentAlignment`' do + let(:argument_alignment_config) { { 'EnforcedStyle' => 'with_fixed_indentation' } } + + it 'register and corrects an offense' do + expect_offense(<<~RUBY) + THINGS = { + oh: :io, + hi: 'neat' + ^^^^^^^^^^ Align the keys of a hash literal if they span more than one line. + } + RUBY + + expect_correction(<<~RUBY) + THINGS = { + oh: :io, + hi: 'neat' + } + RUBY + end + end + context 'always ignore last argument hash' do let(:cop_config) { { 'EnforcedLastArgumentHashStyle' => 'always_ignore' } }