Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#509](https://github.com/rubocop/rubocop-performance/issues/509): Fix a false positive for `Performance/RedundantMatch` when numbered capture variable is used after match. ([@5hun-s][])
30 changes: 27 additions & 3 deletions lib/rubocop/cop/performance/redundant_match.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,7 @@ class RedundantMatch < Base
PATTERN

def on_send(node)
return unless match_call?(node) &&
(!node.value_used? || only_truthiness_matters?(node)) &&
!(node.parent && node.parent.block_type?)
return unless should_register_offense?(node)

add_offense(node) do |corrector|
autocorrect(corrector, node) if autocorrectable?(node)
Expand All @@ -48,6 +46,32 @@ def on_send(node)

private

def should_register_offense?(node)
match_call?(node) &&
used_only_for_truthiness?(node) &&
!inside_block_argument?(node) &&
!special_global_variable_used_after_match?(node)
end

def used_only_for_truthiness?(node)
!node.value_used? || only_truthiness_matters?(node)
end

def inside_block_argument?(node)
node.parent&.block_type?
end

def special_global_variable_used_after_match?(node)
scope = scope_root(node) || node.ancestors.last
scope.each_node(:gvar, :back_ref, :nth_ref).any?
end

def scope_root(node)
node.each_ancestor.find do |ancestor|
ancestor.type?(:any_def, :class, :module)
end
end

def autocorrect(corrector, node)
new_source = "#{node.receiver.source} =~ #{replacement(node)}"

Expand Down
32 changes: 32 additions & 0 deletions spec/rubocop/cop/performance/redundant_match_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,38 @@ def method(str)
expect_no_offenses('match("bar")')
end

it 'does not register an error when numbered capture variable is used after match with conditional' do
expect_no_offenses(<<~RUBY)
def method(str)
puts $1 if str.match(/regex/)
end
RUBY
end

it 'does not register an error when numbered capture variable is used after match without conditional' do
expect_no_offenses(<<~RUBY)
def method(str)
str.match(/regex/)
puts $1
end
RUBY
end

it 'does not register an error when numbered capture variable is used after a match in a conditional expression' do
expect_no_offenses(<<~RUBY)
def method(str)
puts str.match(/regex/) ? $1 : ''
end
RUBY
end

it 'does not register an error when numbered capture variable is used in a subsequent statement after match' do
expect_no_offenses(<<~RUBY)
exit unless str.match(/regex/)
puts $1
RUBY
end

it 'formats error message correctly for something if str.match(/regex/)' do
expect_offense(<<~RUBY)
something if str.match(/regex/)
Expand Down