Skip to content

Commit

Permalink
[Fix #407] Make Performance/DoubleStartEndWith aware of safe naviga…
Browse files Browse the repository at this point in the history
…tion

In case of inconsistent safe navigation, it keeps the dot from the first receiver.

This shouldn't change anything:
Depending on the order, it was either not needed or it will continue raising.

`Lint/SafeNavigationConsistency` takes care of this anyways
  • Loading branch information
Earlopain committed Sep 14, 2024
1 parent 082d635 commit 767f2c9
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 10 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#407](https://github.com/rubocop/rubocop-performance/issues/407): Make `Performance/DoubleStartEndWith` aware of safe navigation. ([@earlopain][])
20 changes: 10 additions & 10 deletions lib/rubocop/cop/performance/double_start_end_with.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ module Performance
class DoubleStartEndWith < Base
extend AutoCorrector

MSG = 'Use `%<receiver>s.%<method>s(%<combined_args>s)` instead of `%<original_code>s`.'
MSG = 'Use `%<replacement>s` instead of `%<original_code>s`.'

def on_or(node)
receiver, method, first_call_args, second_call_args = process_source(node)
Expand All @@ -50,7 +50,7 @@ def on_or(node)

combined_args = combine_args(first_call_args, second_call_args)

add_offense(node, message: message(node, receiver, method, combined_args)) do |corrector|
add_offense(node, message: message(node, receiver, first_call_args, method, combined_args)) do |corrector|
autocorrect(corrector, first_call_args, second_call_args, combined_args)
end
end
Expand All @@ -73,10 +73,10 @@ def process_source(node)
end
end

def message(node, receiver, method, combined_args)
format(
MSG, receiver: receiver.source, method: method, combined_args: combined_args, original_code: node.source
)
def message(node, receiver, first_call_args, method, combined_args)
dot = first_call_args.first.parent.send_type? ? '.' : '&.'
replacement = "#{receiver.source}#{dot}#{method}(#{combined_args})"
format(MSG, replacement: replacement, original_code: node.source)
end

def combine_args(first_call_args, second_call_args)
Expand All @@ -89,16 +89,16 @@ def check_for_active_support_aliases?

def_node_matcher :two_start_end_with_calls, <<~PATTERN
(or
(send $_recv [{:start_with? :end_with?} $_method] $...)
(send _recv _method $...))
(call $_recv [{:start_with? :end_with?} $_method] $...)
(call _recv _method $...))
PATTERN

def_node_matcher :check_with_active_support_aliases, <<~PATTERN
(or
(send $_recv
(call $_recv
[{:start_with? :starts_with? :end_with? :ends_with?} $_method]
$...)
(send _recv _method $...))
(call _recv _method $...))
PATTERN
end
end
Expand Down
35 changes: 35 additions & 0 deletions spec/rubocop/cop/performance/double_start_end_with_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,41 @@
expect_no_offenses('x.start_with?(a, "b") || x.start_with?(C, d)')
end
end

context 'with safe navigation' do
it 'registers an offense' do
expect_offense(<<~RUBY)
x&.start_with?(a, b) || x&.start_with?("c", D)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `x&.start_with?(a, b, "c", D)` instead of `x&.start_with?(a, b) || x&.start_with?("c", D)`.
RUBY

expect_correction(<<~RUBY)
x&.start_with?(a, b, "c", D)
RUBY
end

it 'registers an offense when the first start_with uses no safe navigation' do
expect_offense(<<~RUBY)
x.start_with?(a, b) || x&.start_with?("c", D)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `x.start_with?(a, b, "c", D)` instead of `x.start_with?(a, b) || x&.start_with?("c", D)`.
RUBY

expect_correction(<<~RUBY)
x.start_with?(a, b, "c", D)
RUBY
end

it 'registers an offense when the second start_with uses no safe navigation' do
expect_offense(<<~RUBY)
x&.start_with?(a, b) || x.start_with?("c", D)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `x&.start_with?(a, b, "c", D)` instead of `x&.start_with?(a, b) || x.start_with?("c", D)`.
RUBY

expect_correction(<<~RUBY)
x&.start_with?(a, b, "c", D)
RUBY
end
end
end

context 'with different receivers' do
Expand Down

0 comments on commit 767f2c9

Please sign in to comment.