From 4dc7cabd045fe1867c7f56e6ee5dbfcd45f7fc17 Mon Sep 17 00:00:00 2001 From: 5hun-s <> Date: Wed, 29 Oct 2025 00:37:13 +0900 Subject: [PATCH] =?UTF-8?q?[Fix=C2=A0rubocop#509]=20Fix=20a=20false=20posi?= =?UTF-8?q?tive=20for=20Performance/RedundantMatch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ositive_for_performance_redundant_match.md | 1 + .../cop/performance/redundant_match.rb | 30 +++++++++++++++-- .../cop/performance/redundant_match_spec.rb | 32 +++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 changelog/fix_false_positive_for_performance_redundant_match.md diff --git a/changelog/fix_false_positive_for_performance_redundant_match.md b/changelog/fix_false_positive_for_performance_redundant_match.md new file mode 100644 index 0000000000..58f9a33562 --- /dev/null +++ b/changelog/fix_false_positive_for_performance_redundant_match.md @@ -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][]) diff --git a/lib/rubocop/cop/performance/redundant_match.rb b/lib/rubocop/cop/performance/redundant_match.rb index b36d6a2e66..2ce722fb62 100644 --- a/lib/rubocop/cop/performance/redundant_match.rb +++ b/lib/rubocop/cop/performance/redundant_match.rb @@ -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) @@ -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)}" diff --git a/spec/rubocop/cop/performance/redundant_match_spec.rb b/spec/rubocop/cop/performance/redundant_match_spec.rb index faa4a1ea79..bc26b8501b 100644 --- a/spec/rubocop/cop/performance/redundant_match_spec.rb +++ b/spec/rubocop/cop/performance/redundant_match_spec.rb @@ -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/)