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

Make Style/MapToHash aware of safe navigation operator #12408

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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#12408](https://github.com/rubocop/rubocop/pull/12408): Make `Style/MapToHash` aware of safe navigation operator. ([@koic][])
9 changes: 5 additions & 4 deletions lib/rubocop/cop/style/map_to_hash.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,29 @@ class MapToHash < Base

minimum_target_ruby_version 2.6

MSG = 'Pass a block to `to_h` instead of calling `%<method>s.to_h`.'
MSG = 'Pass a block to `to_h` instead of calling `%<method>s%<dot>sto_h`.'
RESTRICT_ON_SEND = %i[to_h].freeze

# @!method map_to_h?(node)
def_node_matcher :map_to_h?, <<~PATTERN
{
$(send ({block numblock} $(send _ {:map :collect}) ...) :to_h)
$(send $(send _ {:map :collect} (block_pass sym)) :to_h)
$(call ({block numblock} $(call _ {:map :collect}) ...) :to_h)
$(call $(call _ {:map :collect} (block_pass sym)) :to_h)
}
PATTERN

def on_send(node)
return unless (to_h_node, map_node = map_to_h?(node))

message = format(MSG, method: map_node.loc.selector.source)
message = format(MSG, method: map_node.loc.selector.source, dot: map_node.loc.dot.source)
add_offense(map_node.loc.selector, message: message) do |corrector|
# If the `to_h` call already has a block, do not autocorrect.
next if to_h_node.block_node

autocorrect(corrector, to_h_node, map_node)
end
end
alias on_csend on_send

private

Expand Down
39 changes: 39 additions & 0 deletions spec/rubocop/cop/style/map_to_hash_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,32 @@
end
end

context "for `#{method}&.to_h` with block arity 1" do
it 'registers an offense and corrects' do
expect_offense(<<~RUBY, method: method)
foo&.#{method} { |x| [x, x * 2] }&.to_h
^{method} Pass a block to `to_h` instead of calling `#{method}&.to_h`.
RUBY

expect_correction(<<~RUBY)
foo&.to_h { |x| [x, x * 2] }
RUBY
end
end

context "for `#{method}&.to_h` with block arity 2" do
it 'registers an offense and corrects' do
expect_offense(<<~RUBY, method: method)
foo&.#{method} { |x, y| [x.to_s, y.to_i] }&.to_h
^{method} Pass a block to `to_h` instead of calling `#{method}&.to_h`.
RUBY

expect_correction(<<~RUBY)
foo&.to_h { |x, y| [x.to_s, y.to_i] }
RUBY
end
end

context 'when using numbered parameters', :ruby27 do
context "for `#{method}.to_h` with block arity 1" do
it 'registers an offense and corrects' do
Expand Down Expand Up @@ -70,6 +96,19 @@
end
end

context "for `#{method}&.to_h` with symbol proc" do
it 'registers an offense and corrects' do
expect_offense(<<~RUBY, method: method)
foo&.#{method}(&:do_something)&.to_h
^{method} Pass a block to `to_h` instead of calling `#{method}&.to_h`.
RUBY

expect_correction(<<~RUBY)
foo&.to_h(&:do_something)
RUBY
end
end

context 'when the receiver is an array' do
it 'registers an offense and corrects' do
expect_offense(<<~RUBY, method: method)
Expand Down