Skip to content

Commit

Permalink
Fix a false positive for when method's receiver/argument is not the s…
Browse files Browse the repository at this point in the history
…ame as block key argument
  • Loading branch information
fatkodima committed May 12, 2023
1 parent de330b3 commit 1fdb7d6
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 8 deletions.
1 change: 1 addition & 0 deletions changelog/fix_false_positive_for_hash_except.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#11868](https://github.com/rubocop/rubocop/issues/11868): Fix a false positive for `Style/HashExcept` when method's receiver/argument is not the same as block key argument. ([@fatkodima][])
27 changes: 19 additions & 8 deletions lib/rubocop/cop/style/hash_except.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ class HashExcept < Base
(block
(send _ _)
(args
(arg _)
$(arg _)
(arg _))
{
(send
$(send
_ {:== :!= :eql? :include?} _)
(send
(send
$(send
_ {:== :!= :eql? :include?} _) :!)
})
PATTERN
Expand All @@ -61,13 +61,13 @@ class HashExcept < Base
(block
(send _ _)
(args
(arg _)
$(arg _)
(arg _))
{
(send
$(send
_ {:== :!= :eql? :in? :include? :exclude?} _)
(send
(send
$(send
_ {:== :!= :eql? :in? :include? :exclude?} _) :!)
})
PATTERN
Expand All @@ -89,13 +89,24 @@ def on_send(node)

private

# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def bad_method?(block)
if active_support_extensions_enabled?
bad_method_with_active_support?(block)
bad_method_with_active_support?(block) do |key_arg, send_node|
if send_node.method?(:in?) && send_node.receiver&.source != key_arg.source
return false
end
return true if !send_node.method?(:include?) && !send_node.method?(:exclude?)

send_node.first_argument&.source == key_arg.source
end
else
bad_method_with_poro?(block)
bad_method_with_poro?(block) do |key_arg, send_node|
!send_node.method?(:include?) || send_node.first_argument&.source == key_arg.source
end
end
end
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

def semantically_except_method?(send, block)
body = block.body
Expand Down
48 changes: 48 additions & 0 deletions spec/rubocop/cop/style/hash_except_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,18 @@
{foo: 1, bar: 2, baz: 3}.reject { |k, v| ![1, 2].include?(v) }
RUBY
end

it 'does not register an offense when using `reject` and calling `include?` method on a key' do
expect_no_offenses(<<~RUBY)
{foo: 1, bar: 2, baz: 3}.reject { |k, v| k.include?('oo') }
RUBY
end

it 'does not register an offense when using `reject` and calling `!include?` method on a key' do
expect_no_offenses(<<~RUBY)
{foo: 1, bar: 2, baz: 3}.reject { |k, v| !k.include?('oo') }
RUBY
end
end

context 'using `exclude?`' do
Expand All @@ -180,6 +192,18 @@
{foo: 1, bar: 2, baz: 3}.reject { |k, v| !%i[foo bar].exclude?(k) }
RUBY
end

it 'does not register an offense when using `reject` and calling `exclude?` method on a key' do
expect_no_offenses(<<~RUBY)
{foo: 1, bar: 2, baz: 3}.reject { |k, v| k.exclude?('oo') }
RUBY
end

it 'does not register an offense when using `reject` and calling `!exclude?` method on a key' do
expect_no_offenses(<<~RUBY)
{foo: 1, bar: 2, baz: 3}.reject { |k, v| !k.exclude?('oo') }
RUBY
end
end

it 'does not register an offense when using `reject` and other than comparison by string and symbol using `==`' do
Expand Down Expand Up @@ -457,6 +481,18 @@
{foo: 1, bar: 2, baz: 3}.except(*array)
RUBY
end

it 'does not register an offense when using `reject` and calling `include?` method on a key' do
expect_no_offenses(<<~RUBY)
{foo: 1, bar: 2, baz: 3}.reject { |k, v| k.include?('oo') }
RUBY
end

it 'does not register an offense when using `reject` and calling `!include?` method on a key' do
expect_no_offenses(<<~RUBY)
{foo: 1, bar: 2, baz: 3}.reject { |k, v| !k.include?('oo') }
RUBY
end
end

context 'using `exclude?`' do
Expand Down Expand Up @@ -544,6 +580,18 @@
{foo: 1, bar: 2, baz: 3}.reject { |k, v| ![1, 2].exclude?(v) }
RUBY
end

it 'does not register an offense when using `reject` and calling `exclude?` method on a key' do
expect_no_offenses(<<~RUBY)
{foo: 1, bar: 2, baz: 3}.reject { |k, v| k.exclude?('oo') }
RUBY
end

it 'does not register an offense when using `reject` and calling `!exclude?` method on a key' do
expect_no_offenses(<<~RUBY)
{foo: 1, bar: 2, baz: 3}.reject { |k, v| !k.exclude?('oo') }
RUBY
end
end

it 'does not register an offense when using `reject` and other than comparison by string and symbol using `==`' do
Expand Down

0 comments on commit 1fdb7d6

Please sign in to comment.