-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
In Ruby >= 3.0, interpolated strings are always unfrozen: https://bugs.ruby-lang.org/issues/17104 On Ruby 2.7 they followed the magic comment literal which made it necessary to sometimes unfreeze them manually. This could also apply on Ruby 2.7 by looking at the magic comment but it doesn't seem worth the effort. RuboCop itself has 5 offenses: ``` Offenses: lib/rubocop/cop/lint/unused_method_argument.rb:99:21: C: [Correctable] Style/RedundantInterpolationUnfreeze: Don't unfreeze interpolated strings as they are already unfrozen message = +"Unused method argument - `#{variable.name}`." ^ lib/rubocop/cops_documentation_generator.rb:133:15: C: [Correctable] Style/RedundantInterpolationUnfreeze: Don't unfreeze interpolated strings as they are already unfrozen content = +"==== #{title}\n" ^ lib/rubocop/cops_documentation_generator.rb:259:15: C: [Correctable] Style/RedundantInterpolationUnfreeze: Don't unfreeze interpolated strings as they are already unfrozen content = +<<~HEADER ^ lib/rubocop/cops_documentation_generator.rb:307:15: C: [Correctable] Style/RedundantInterpolationUnfreeze: Don't unfreeze interpolated strings as they are already unfrozen content = +"=== Department xref:#{filename}[#{type_title}]\n\n" ^ spec/rubocop/cop/layout/end_of_line_spec.rb:21:16: C: [Correctable] Style/RedundantInterpolationUnfreeze: Don't unfreeze interpolated strings as they are already unfrozen input = (+<<~RUBY).force_encoding(encoding) ^ 1546 files inspected, 5 offenses detected, 5 offenses autocorrectable ```
- Loading branch information
Showing
6 changed files
with
174 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* [#13061](https://github.com/rubocop/rubocop/issues/13061): Add new `Style/RedundantInterpolationUnfreeze` cop to check for `dup` and `@+` on interpolated strings in Ruby >= 3.0. ([@earlopain][]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Style | ||
# Before Ruby 3.0, interpolated strings followed the frozen string literal | ||
# magic comment which sometimes made it necessary to explicitly unfreeze them. | ||
# Ruby 3.0 changed interpolated strings to always be unfrozen which makes | ||
# unfreezing them redundant. | ||
# | ||
# @example | ||
# # bad | ||
# +"#{foo} bar" | ||
# | ||
# # bad | ||
# "#{foo} bar".dup | ||
# | ||
# # good | ||
# "#{foo} bar" | ||
# | ||
class RedundantInterpolationUnfreeze < Base | ||
include FrozenStringLiteral | ||
extend AutoCorrector | ||
extend TargetRubyVersion | ||
|
||
MSG = "Don't unfreeze interpolated strings as they are already unfrozen." | ||
|
||
RESTRICT_ON_SEND = %i[+@ dup].freeze | ||
|
||
minimum_target_ruby_version 3.0 | ||
|
||
def on_send(node) | ||
return if node.arguments? | ||
return unless (receiver = node.receiver) | ||
return unless receiver.dstr_type? | ||
return if uninterpolated_string?(receiver) || uninterpolated_heredoc?(receiver) | ||
|
||
add_offense(node.loc.selector) do |corrector| | ||
corrector.remove(node.loc.selector) | ||
corrector.remove(node.loc.dot) unless node.unary_operation? | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
118 changes: 118 additions & 0 deletions
118
spec/rubocop/cop/style/redundant_interpolation_unfreeze_spec.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::Style::RedundantInterpolationUnfreeze, :config do | ||
context 'target_ruby_version >= 3.0', :ruby30 do | ||
it 'registers an offense for `@+`' do | ||
expect_offense(<<~'RUBY') | ||
+"#{foo} bar" | ||
^ Don't unfreeze interpolated strings as they are already unfrozen. | ||
RUBY | ||
|
||
expect_correction(<<~'RUBY') | ||
"#{foo} bar" | ||
RUBY | ||
end | ||
|
||
it 'registers an offense for `@+` as a normal method call' do | ||
expect_offense(<<~'RUBY') | ||
"#{foo} bar".+@ | ||
^^ Don't unfreeze interpolated strings as they are already unfrozen. | ||
RUBY | ||
|
||
expect_correction(<<~'RUBY') | ||
"#{foo} bar" | ||
RUBY | ||
end | ||
|
||
it 'registers an offense for `dup`' do | ||
expect_offense(<<~'RUBY') | ||
"#{foo} bar".dup | ||
^^^ Don't unfreeze interpolated strings as they are already unfrozen. | ||
RUBY | ||
|
||
expect_correction(<<~'RUBY') | ||
"#{foo} bar" | ||
RUBY | ||
end | ||
|
||
it 'registers an offense for interpolated heredoc with `@+`' do | ||
expect_offense(<<~'RUBY') | ||
foo(+<<~MSG) | ||
^ Don't unfreeze interpolated strings as they are already unfrozen. | ||
foo #{bar} | ||
baz | ||
MSG | ||
RUBY | ||
|
||
expect_correction(<<~'RUBY') | ||
foo(<<~MSG) | ||
foo #{bar} | ||
baz | ||
MSG | ||
RUBY | ||
end | ||
|
||
it 'registers an offense for interpolated heredoc with `dup`' do | ||
expect_offense(<<~'RUBY') | ||
foo(<<~MSG.dup) | ||
^^^ Don't unfreeze interpolated strings as they are already unfrozen. | ||
foo #{bar} | ||
baz | ||
MSG | ||
RUBY | ||
|
||
expect_correction(<<~'RUBY') | ||
foo(<<~MSG) | ||
foo #{bar} | ||
baz | ||
MSG | ||
RUBY | ||
end | ||
|
||
it 'registers no offense for uninterpolated heredoc' do | ||
expect_no_offenses(<<~'RUBY') | ||
foo(+<<~'MSG') | ||
foo #{bar} | ||
baz | ||
MSG | ||
RUBY | ||
end | ||
|
||
it 'registers no offense for plain string literals' do | ||
expect_no_offenses(<<~RUBY) | ||
"foo".dup | ||
RUBY | ||
end | ||
|
||
it 'registers no offense for other types' do | ||
expect_no_offenses(<<~RUBY) | ||
local.dup | ||
RUBY | ||
end | ||
|
||
it 'registers no offense when the method has arguments' do | ||
expect_no_offenses(<<~'RUBY') | ||
"#{foo} bar".dup(baz) | ||
RUBY | ||
end | ||
|
||
it 'registers no offense for multiline string literals' do | ||
expect_no_offenses(<<~RUBY) | ||
+'foo' \ | ||
'bar' | ||
RUBY | ||
end | ||
|
||
it 'registers no offense when there is no receiver' do | ||
expect_no_offenses(<<~RUBY) | ||
dup | ||
RUBY | ||
end | ||
end | ||
|
||
context 'target_ruby_version < 3.0', :ruby27, unsupported_on: :prism do | ||
it 'accepts unfreezing an interpolated string' do | ||
expect_no_offenses('+"#{foo} bar"') | ||
end | ||
end | ||
end |