Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Re-add autocorrect support for Style/SafeNavigationChain #10817

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/change_add_autocorrect_support_for.md
@@ -0,0 +1 @@
* [#10817](https://github.com/rubocop/rubocop/pull/10817): Add autocorrect support for `Style/SafeNavigationChain`. ([@r7kamura][])
36 changes: 35 additions & 1 deletion lib/rubocop/cop/lint/safe_navigation_chain.rb
Expand Up @@ -25,6 +25,7 @@ module Lint
# x&.foo || bar
class SafeNavigationChain < Base
include NilMethods
extend AutoCorrector
extend TargetRubyVersion

minimum_target_ruby_version 2.3
Expand All @@ -48,12 +49,45 @@ def on_send(node)
Parser::Source::Range.new(node.source_range.source_buffer,
safe_nav.source_range.end_pos,
method_chain.source_range.end_pos)
add_offense(location)
add_offense(location) do |corrector|
autocorrect(corrector, offense_range: location, send_node: method_chain)
end
end
end

private

# @param [Parser::Source::Range] offense_range
# @param [RuboCop::AST::SendNode] send_node
# @return [String]
def add_safe_navigation_operator(offense_range:, send_node:)
source = \
if send_node.method?(:[]) || send_node.method?(:[]=)
format(
'%<method_name>s(%<arguments>s)',
arguments: send_node.arguments.map(&:source).join(', '),
method_name: send_node.method_name
)
else
offense_range.source.dup
end
source.prepend('.') unless send_node.dot?
source.prepend('&')
end

# @param [RuboCop::Cop::Corrector] corrector
# @param [Parser::Source::Range] offense_range
# @param [RuboCop::AST::SendNode] send_node
def autocorrect(corrector, offense_range:, send_node:)
corrector.replace(
offense_range,
add_safe_navigation_operator(
offense_range: offense_range,
send_node: send_node
)
)
end

def method_chain(node)
chain = node
chain = chain.parent if chain.send_type? && chain.parent&.call_type?
Expand Down
86 changes: 86 additions & 0 deletions spec/rubocop/cop/lint/safe_navigation_chain_spec.rb
Expand Up @@ -39,6 +39,10 @@
x&.foo.bar
^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&.bar
RUBY
end

it 'registers an offense for ordinary method call exists after ' \
Expand All @@ -47,6 +51,10 @@
x&.foo(x).bar(y)
^^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo(x)&.bar(y)
RUBY
end

it 'registers an offense for ordinary method chain exists after safe navigation method call' do
Expand All @@ -55,6 +63,11 @@
x&.foo.bar.baz
^^^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
something
x&.foo&.bar&.baz
RUBY
end

it 'registers an offense for ordinary method chain exists after ' \
Expand All @@ -63,6 +76,10 @@
x&.foo(x).bar(y).baz(z)
^^^^^^^^^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo(x)&.bar(y)&.baz(z)
RUBY
end

it 'registers an offense for ordinary method chain exists after ' \
Expand All @@ -72,6 +89,11 @@
x&.select(&:foo).bar
^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
something
x&.select(&:foo)&.bar
RUBY
end

it 'registers an offense for ordinary method chain exists after ' \
Expand All @@ -81,55 +103,88 @@
x&.select { |x| foo(x) }.bar
^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
something
x&.select { |x| foo(x) }&.bar
RUBY
end

it 'registers an offense for safe navigation with < operator' do
expect_offense(<<~RUBY)
x&.foo < bar
^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&. < bar
RUBY
end

it 'registers an offense for safe navigation with > operator' do
expect_offense(<<~RUBY)
x&.foo > bar
^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&. > bar
RUBY
end

it 'registers an offense for safe navigation with <= operator' do
expect_offense(<<~RUBY)
x&.foo <= bar
^^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&. <= bar
RUBY
end

it 'registers an offense for safe navigation with >= operator' do
expect_offense(<<~RUBY)
x&.foo >= bar
^^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&. >= bar
RUBY
end

it 'registers an offense for safe navigation with + operator' do
expect_offense(<<~RUBY)
x&.foo + bar
^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&. + bar
RUBY
end

it 'registers an offense for safe navigation with [] operator' do
expect_offense(<<~RUBY)
x&.foo[bar]
^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&.[](bar)
RUBY
end

it 'registers an offense for safe navigation with []= operator' do
expect_offense(<<~RUBY)
x&.foo[bar] = baz
^^^^^^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&.[]=(bar, baz)
RUBY
end

context 'proper highlighting' do
Expand All @@ -139,6 +194,11 @@
x&.foo.bar.baz
^^^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
something
x&.foo&.bar&.baz
RUBY
end

it 'when there are methods after' do
Expand All @@ -147,6 +207,11 @@
^^^^^^^^ Do not chain ordinary method call after safe navigation operator.
something
RUBY

expect_correction(<<~RUBY)
x&.foo&.bar&.baz
something
RUBY
end

it 'when in a method' do
Expand All @@ -156,6 +221,12 @@ def something
^^^^^^^^ Do not chain ordinary method call after safe navigation operator.
end
RUBY

expect_correction(<<~RUBY)
def something
x&.foo&.bar&.baz
end
RUBY
end

it 'when in a begin' do
Expand All @@ -165,13 +236,23 @@ def something
^^^^^^^^ Do not chain ordinary method call after safe navigation operator.
end
RUBY

expect_correction(<<~RUBY)
begin
x&.foo&.bar&.baz
end
RUBY
end

it 'when used with a modifier if' do
expect_offense(<<~RUBY)
x&.foo.bar.baz if something
^^^^^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
x&.foo&.bar&.baz if something
RUBY
end
end
end
Expand All @@ -184,6 +265,11 @@ def something
x&.select { foo(_1) }.bar
^^^^ Do not chain ordinary method call after safe navigation operator.
RUBY

expect_correction(<<~RUBY)
something
x&.select { foo(_1) }&.bar
RUBY
end
end
end