From f5b77c87514372e92f99a1553d603c5cce1252a1 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Tue, 28 Jun 2022 11:39:38 +0900 Subject: [PATCH] [Fix #10754] Fix an incorrect autocorrect for `Style/HashExcept` Fixes #10754. This PR fixes an incorrect autocorrect for `Style/HashExcept` when using a non-literal collection receiver for `include?`. --- ...rrect_autocorrect_for_style_hash_except.md | 1 + lib/rubocop/cop/style/hash_except.rb | 2 +- spec/rubocop/cop/style/hash_except_spec.rb | 96 +++++++++++++++++++ 3 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_an_incorrect_autocorrect_for_style_hash_except.md diff --git a/changelog/fix_an_incorrect_autocorrect_for_style_hash_except.md b/changelog/fix_an_incorrect_autocorrect_for_style_hash_except.md new file mode 100644 index 00000000000..6961faadeb3 --- /dev/null +++ b/changelog/fix_an_incorrect_autocorrect_for_style_hash_except.md @@ -0,0 +1 @@ +* [#10754](https://github.com/rubocop/rubocop/issues/10754): Fix an incorrect autocorrect for `Style/HashExcept` when using a non-literal collection receiver for `include?`. ([@koic][]) diff --git a/lib/rubocop/cop/style/hash_except.rb b/lib/rubocop/cop/style/hash_except.rb index 6b5a489035e..4bad19d08e6 100644 --- a/lib/rubocop/cop/style/hash_except.rb +++ b/lib/rubocop/cop/style/hash_except.rb @@ -144,7 +144,7 @@ def except_key_source(key) return key.join(', ') end - key.source + key.literal? ? key.source : "*#{key.source}" end def decorate_source(value) diff --git a/spec/rubocop/cop/style/hash_except_spec.rb b/spec/rubocop/cop/style/hash_except_spec.rb index f22ad234569..265e87a2bcf 100644 --- a/spec/rubocop/cop/style/hash_except_spec.rb +++ b/spec/rubocop/cop/style/hash_except_spec.rb @@ -142,6 +142,30 @@ {foo: 1, bar: 2, baz: 3}.except("\#{foo}", 'bar') RUBY end + + it 'registers and corrects an offense when using `reject` and calling `include?` method with variable' do + expect_offense(<<~RUBY) + array = [:foo, :bar] + {foo: 1, bar: 2, baz: 3}.reject { |k, v| !array.include?(k) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `except(*array)` instead. + RUBY + + expect_correction(<<~RUBY) + array = [:foo, :bar] + {foo: 1, bar: 2, baz: 3}.except(*array) + RUBY + end + + it 'registers and corrects an offense when using `reject` and calling `include?` method with method call' do + expect_offense(<<~RUBY) + {foo: 1, bar: 2, baz: 3}.reject { |k, v| !array.include?(k) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `except(*array)` instead. + RUBY + + expect_correction(<<~RUBY) + {foo: 1, bar: 2, baz: 3}.except(*array) + RUBY + end end context 'using `exclude?`' do @@ -316,6 +340,30 @@ {foo: 1, bar: 2, baz: 3}.except("\#{foo}", 'bar') RUBY end + + it 'registers and corrects an offense when using `reject` and calling `key.in?` method with variable' do + expect_offense(<<~RUBY) + array = %i[foo bar] + {foo: 1, bar: 2, baz: 3}.reject { |k, v| k.in?(array) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `except(*array)` instead. + RUBY + + expect_correction(<<~RUBY) + array = %i[foo bar] + {foo: 1, bar: 2, baz: 3}.except(*array) + RUBY + end + + it 'registers and corrects an offense when using `reject` and calling `key.in?` method with method call' do + expect_offense(<<~RUBY) + {foo: 1, bar: 2, baz: 3}.reject { |k, v| k.in?(array) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `except(*array)` instead. + RUBY + + expect_correction(<<~RUBY) + {foo: 1, bar: 2, baz: 3}.except(*array) + RUBY + end end context 'using `include?`' do @@ -373,6 +421,30 @@ {foo: 1, bar: 2, baz: 3}.except("\#{foo}", 'bar') RUBY end + + it 'registers and corrects an offense when using `reject` and calling `include?` method with variable' do + expect_offense(<<~RUBY) + array = %i[foo bar] + {foo: 1, bar: 2, baz: 3}.reject { |k, v| !array.include?(k) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `except(*array)` instead. + RUBY + + expect_correction(<<~RUBY) + array = %i[foo bar] + {foo: 1, bar: 2, baz: 3}.except(*array) + RUBY + end + + it 'registers and corrects an offense when using `reject` and calling `include?` method with method call' do + expect_offense(<<~RUBY) + {foo: 1, bar: 2, baz: 3}.reject { |k, v| !array.include?(k) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `except(*array)` instead. + RUBY + + expect_correction(<<~RUBY) + {foo: 1, bar: 2, baz: 3}.except(*array) + RUBY + end end context 'using `exclude?`' do @@ -430,6 +502,30 @@ {foo: 1, bar: 2, baz: 3}.except("\#{foo}", 'bar') RUBY end + + it 'registers and corrects an offense when using `reject` and calling `!exclude?` method with variable' do + expect_offense(<<~RUBY) + array = %i[foo bar] + {foo: 1, bar: 2, baz: 3}.reject { |k, v| !array.exclude?(k) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `except(*array)` instead. + RUBY + + expect_correction(<<~RUBY) + array = %i[foo bar] + {foo: 1, bar: 2, baz: 3}.except(*array) + RUBY + end + + it 'registers and corrects an offense when using `reject` and calling `!exclude?` method with method call' do + expect_offense(<<~RUBY) + {foo: 1, bar: 2, baz: 3}.reject { |k, v| !array.exclude?(k) } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `except(*array)` instead. + RUBY + + expect_correction(<<~RUBY) + {foo: 1, bar: 2, baz: 3}.except(*array) + RUBY + end end it 'does not register an offense when using `reject` and other than comparison by string and symbol using `==`' do