Skip to content

Commit

Permalink
Recover Ruby 2.3 code analysis using TargetRubyVersion: 2.3
Browse files Browse the repository at this point in the history
Follow up rubocop#10632 (comment).

Reverts part of rubocop#7869 and rubocop#8056.

Only the Ruby version (2.3) to runtime should have been dropped, not
code analysis.
This PR makes Ruby 2.3 code analysis with `TargetRubyVersion: 2.3`.
It aims to solve essentially the same problem as rubocop#10626 and 10632.

And this change requires RuboCop AST 1.18 or later:
rubocop/rubocop-ast#233
  • Loading branch information
koic committed May 16, 2022
1 parent 58c56bf commit 4a92f98
Show file tree
Hide file tree
Showing 12 changed files with 322 additions and 263 deletions.
1 change: 1 addition & 0 deletions changelog/fix_recover_ruby_23_code_analysis.md
@@ -0,0 +1 @@
* [#10640](https://github.com/rubocop/rubocop/pull/10640): Recover Ruby 2.3 code analysis using `TargetRubyVersion: 2.3`. ([@koic][])
2 changes: 2 additions & 0 deletions lib/rubocop/cop/lint/unified_integer.rb
Expand Up @@ -33,6 +33,8 @@ def on_const(node)
return unless klass

add_offense(node, message: format(MSG, klass: klass)) do |corrector|
next if target_ruby_version <= 2.3

corrector.replace(node.loc.name, 'Integer')
end
end
Expand Down
3 changes: 3 additions & 0 deletions lib/rubocop/cop/style/hash_transform_values.rb
Expand Up @@ -26,6 +26,9 @@ module Style
class HashTransformValues < Base
include HashTransformMethod
extend AutoCorrector
extend TargetRubyVersion

minimum_target_ruby_version 2.4

# @!method on_bad_each_with_object(node)
def_node_matcher :on_bad_each_with_object, <<~PATTERN
Expand Down
3 changes: 3 additions & 0 deletions lib/rubocop/cop/style/unpack_first.rb
Expand Up @@ -19,6 +19,9 @@ module Style
#
class UnpackFirst < Base
extend AutoCorrector
extend TargetRubyVersion

minimum_target_ruby_version 2.4

MSG = 'Use `%<receiver>s.unpack1(%<format>s)` instead of '\
'`%<receiver>s.unpack(%<format>s)%<method>s`.'
Expand Down
4 changes: 4 additions & 0 deletions lib/rubocop/rspec/shared_contexts.rb
Expand Up @@ -116,6 +116,10 @@ def source_range(range, buffer: source_buffer)
end
end

RSpec.shared_context 'ruby 2.3', :ruby23 do
let(:ruby_version) { 2.3 }
end

RSpec.shared_context 'ruby 2.4', :ruby24 do
let(:ruby_version) { 2.4 }
end
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/target_ruby.rb
Expand Up @@ -4,7 +4,7 @@ module RuboCop
# The kind of Ruby that code inspected by RuboCop is written in.
# @api private
class TargetRuby
KNOWN_RUBIES = [2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2].freeze
KNOWN_RUBIES = [2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2].freeze
DEFAULT_VERSION = 2.6

OBSOLETE_RUBIES = {
Expand Down
2 changes: 1 addition & 1 deletion rubocop.gemspec
Expand Up @@ -36,7 +36,7 @@ Gem::Specification.new do |s|
s.add_runtime_dependency('rainbow', '>= 2.2.2', '< 4.0')
s.add_runtime_dependency('regexp_parser', '>= 1.8', '< 3.0')
s.add_runtime_dependency('rexml', '>= 3.2.5', '< 4.0')
s.add_runtime_dependency('rubocop-ast', '>= 1.17.0', '< 2.0')
s.add_runtime_dependency('rubocop-ast', '>= 1.18.0', '< 2.0')
s.add_runtime_dependency('ruby-progressbar', '~> 1.7')
s.add_runtime_dependency('unicode-display_width', '>= 1.4.0', '< 3.0')

Expand Down
4 changes: 2 additions & 2 deletions spec/rubocop/cli_spec.rb
Expand Up @@ -1724,7 +1724,7 @@ def method(foo, bar, qux, fred, arg5, f) end #{'#' * 85}
'Error: RuboCop found unknown Ruby version 4.0 in `TargetRubyVersion`'
)
expect($stderr.string.strip).to match(
/Supported versions: 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2/
/Supported versions: 2.3, 2.4, 2.5, 2.6, 2.7, 3.0, 3.1, 3.2/
)
end
end
Expand All @@ -1746,7 +1746,7 @@ def method(foo, bar, qux, fred, arg5, f) end #{'#' * 85}
/2\.0-compatible analysis was dropped after version 0\.50/
)

expect($stderr.string.strip).to match(/Supported versions: 2.4/)
expect($stderr.string.strip).to match(/Supported versions: 2.3/)
end
end
end
Expand Down
4 changes: 2 additions & 2 deletions spec/rubocop/config_loader_spec.rb
Expand Up @@ -1188,7 +1188,7 @@ class Loop < Base
end

context 'when the specified version is obsolete' do
let(:inherited_version) { '2.3' }
let(:inherited_version) { '2.2' }

context 'and it is not overridden' do
before do
Expand All @@ -1199,7 +1199,7 @@ class Loop < Base

it 'raises a validation error' do
expect { configuration_from_file }.to raise_error(RuboCop::ValidationError) do |error|
expect(error.message).to start_with('RuboCop found unsupported Ruby version 2.3')
expect(error.message).to start_with('RuboCop found unsupported Ruby version 2.2')
end
end
end
Expand Down
84 changes: 60 additions & 24 deletions spec/rubocop/cop/lint/unified_integer_spec.rb
Expand Up @@ -2,36 +2,72 @@

RSpec.describe RuboCop::Cop::Lint::UnifiedInteger, :config do
shared_examples 'registers an offense' do |klass|
context "when #{klass}" do
context 'without any decorations' do
it 'registers an offense and autocorrects' do
expect_offense(<<~RUBY, klass: klass)
1.is_a?(%{klass})
^{klass} Use `Integer` instead of `#{klass}`.
RUBY

expect_correction(<<~RUBY)
1.is_a?(Integer)
RUBY
context 'target ruby version < 2.4', :ruby23 do
context "when #{klass}" do
context 'without any decorations' do
it 'registers an offense and autocorrects' do
expect_offense(<<~RUBY, klass: klass)
1.is_a?(%{klass})
^{klass} Use `Integer` instead of `#{klass}`.
RUBY

expect_no_corrections
end
end
end

context 'when explicitly specified as toplevel constant' do
it 'registers an offense' do
expect_offense(<<~RUBY, klass: klass)
1.is_a?(::%{klass})
^^^{klass} Use `Integer` instead of `#{klass}`.
RUBY
context 'when explicitly specified as toplevel constant' do
let(:source) { "1.is_a?(::#{klass})" }

it 'registers an offense' do
expect_offense(<<~RUBY, klass: klass)
1.is_a?(::%{klass})
^^^{klass} Use `Integer` instead of `#{klass}`.
RUBY

expect_correction(<<~RUBY)
1.is_a?(::Integer)
RUBY
expect_no_corrections
end
end

context 'with MyNamespace' do
it 'does not register an offense' do
expect_no_offenses("1.is_a?(MyNamespace::#{klass})")
end
end
end
end

context 'target ruby version >= 2.4', :ruby24 do
context "when #{klass}" do
context 'without any decorations' do
it 'registers an offense' do
expect_offense(<<~RUBY, klass: klass)
1.is_a?(#{klass})
^{klass} Use `Integer` instead of `#{klass}`.
RUBY

expect_correction(<<~RUBY)
1.is_a?(Integer)
RUBY
end
end

context 'when explicitly specified as toplevel constant' do
it 'registers an offense' do
expect_offense(<<~RUBY, klass: klass)
1.is_a?(::#{klass})
^^^{klass} Use `Integer` instead of `#{klass}`.
RUBY

expect_correction(<<~RUBY)
1.is_a?(::Integer)
RUBY
end
end

context 'with MyNamespace' do
it 'does not register an offense' do
expect_no_offenses("1.is_a?(MyNamespace::#{klass})")
context 'with MyNamespace' do
it 'does not register an offense' do
expect_no_offenses("1.is_a?(MyNamespace::#{klass})")
end
end
end
end
Expand Down

0 comments on commit 4a92f98

Please sign in to comment.