rubocop 1.60.2 → 1.63.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/assets/output.css.erb +159 -0
- data/assets/output.html.erb +1 -160
- data/config/default.yml +64 -15
- data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli.rb +6 -1
- data/lib/rubocop/config.rb +37 -10
- data/lib/rubocop/config_finder.rb +12 -2
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_validator.rb +14 -5
- data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
- data/lib/rubocop/cop/base.rb +52 -6
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +122 -28
- data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +11 -3
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -4
- data/lib/rubocop/cop/lint/debugger.rb +27 -2
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +14 -9
- data/lib/rubocop/cop/lint/redundant_with_index.rb +4 -0
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
- data/lib/rubocop/cop/lint/script_permission.rb +3 -3
- data/lib/rubocop/cop/lint/syntax.rb +1 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -2
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +6 -1
- data/lib/rubocop/cop/mixin/code_length.rb +12 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +31 -12
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/style/alias.rb +1 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +29 -8
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/class_vars.rb +3 -3
- data/lib/rubocop/cop/style/collection_compact.rb +3 -3
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -5
- data/lib/rubocop/cop/style/copyright.rb +16 -11
- data/lib/rubocop/cop/style/eval_with_location.rb +2 -0
- data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/format_string.rb +9 -9
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +8 -8
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -5
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +5 -8
- data/lib/rubocop/cop/style/map_into_array.rb +175 -0
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
- data/lib/rubocop/cop/style/map_to_set.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +4 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
- data/lib/rubocop/cop/style/object_then.rb +5 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
- data/lib/rubocop/cop/style/raise_args.rb +4 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +25 -2
- data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +5 -4
- data/lib/rubocop/cop/style/redundant_each.rb +1 -1
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +5 -0
- data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
- data/lib/rubocop/cop/style/redundant_return.rb +6 -0
- data/lib/rubocop/cop/style/sample.rb +1 -3
- data/lib/rubocop/cop/team.rb +3 -0
- data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +4 -2
- data/lib/rubocop/directive_comment.rb +10 -8
- data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
- data/lib/rubocop/formatter/html_formatter.rb +30 -10
- data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
- data/lib/rubocop/formatter/tap_formatter.rb +3 -7
- data/lib/rubocop/lockfile.rb +34 -4
- data/lib/rubocop/lsp/logger.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/lsp/runtime.rb +1 -1
- data/lib/rubocop/lsp/server.rb +5 -2
- data/lib/rubocop/lsp/severity.rb +1 -1
- data/lib/rubocop/lsp.rb +29 -0
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/options.rb +11 -0
- data/lib/rubocop/path_util.rb +6 -2
- data/lib/rubocop/rspec/cop_helper.rb +8 -2
- data/lib/rubocop/rspec/expect_offense.rb +16 -8
- data/lib/rubocop/rspec/shared_contexts.rb +49 -18
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +12 -2
- data/lib/rubocop/target_finder.rb +84 -78
- data/lib/rubocop/target_ruby.rb +82 -80
- data/lib/rubocop/version.rb +19 -4
- data/lib/rubocop.rb +1 -0
- metadata +10 -6
data/lib/rubocop/lsp.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# The RuboCop's built-in LSP module.
|
5
|
+
module LSP
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# Returns true when LSP is enabled, false when disabled.
|
9
|
+
#
|
10
|
+
# @return [Boolean]
|
11
|
+
def enabled?
|
12
|
+
@enabled ||= false
|
13
|
+
end
|
14
|
+
|
15
|
+
# Enable LSP.
|
16
|
+
#
|
17
|
+
# @return [void]
|
18
|
+
def enable
|
19
|
+
@enabled = true
|
20
|
+
end
|
21
|
+
|
22
|
+
# Disable LSP.
|
23
|
+
#
|
24
|
+
# @return [void]
|
25
|
+
def disable
|
26
|
+
@enabled = false
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -268,7 +268,7 @@ module RuboCop
|
|
268
268
|
|
269
269
|
# Rewrite the comment without a given token type
|
270
270
|
def without(type)
|
271
|
-
if @comment.match?(/\A#\s*#{self.class::KEYWORDS[type.to_sym]}/)
|
271
|
+
if @comment.match?(/\A#\s*#{self.class::KEYWORDS[type.to_sym]}/io)
|
272
272
|
''
|
273
273
|
else
|
274
274
|
@comment
|
data/lib/rubocop/options.rb
CHANGED
@@ -95,6 +95,7 @@ module RuboCop
|
|
95
95
|
option(opts, '--ignore-unrecognized-cops')
|
96
96
|
option(opts, '--force-default-config')
|
97
97
|
option(opts, '-s', '--stdin FILE')
|
98
|
+
option(opts, '--editor-mode')
|
98
99
|
option(opts, '-P', '--[no-]parallel')
|
99
100
|
option(opts, '--raise-cop-error')
|
100
101
|
add_severity_option(opts)
|
@@ -369,6 +370,7 @@ module RuboCop
|
|
369
370
|
validate_display_only_failed
|
370
371
|
validate_display_only_failed_and_display_only_correctable
|
371
372
|
validate_display_only_correctable_and_autocorrect
|
373
|
+
validate_lsp_and_editor_mode
|
372
374
|
disable_parallel_when_invalid_option_combo
|
373
375
|
|
374
376
|
return if incompatible_options.size <= 1
|
@@ -416,6 +418,13 @@ module RuboCop
|
|
416
418
|
format('--display-only-failed cannot be used together with other display options.')
|
417
419
|
end
|
418
420
|
|
421
|
+
def validate_lsp_and_editor_mode
|
422
|
+
return if !@options.key?(:lsp) || !@options.key?(:editor_mode)
|
423
|
+
|
424
|
+
raise OptionArgumentError,
|
425
|
+
format('Do not specify `--editor-mode` as it is redundant in `--lsp`.')
|
426
|
+
end
|
427
|
+
|
419
428
|
def validate_autocorrect
|
420
429
|
if @options.key?(:safe_autocorrect) && @options.key?(:autocorrect_all)
|
421
430
|
message = Rainbow(<<~MESSAGE).red
|
@@ -609,6 +618,8 @@ module RuboCop
|
|
609
618
|
'parallel. Default is true.'],
|
610
619
|
stdin: ['Pipe source from STDIN, using FILE in offense',
|
611
620
|
'reports. This is useful for editor integration.'],
|
621
|
+
editor_mode: ['Optimize real-time feedback in editors,',
|
622
|
+
'adjusting behaviors for editing experience.'],
|
612
623
|
init: 'Generate a .rubocop.yml file in the current directory.',
|
613
624
|
server: ['If a server process has not been started yet, start',
|
614
625
|
'the server process and execute inspection with server.',
|
data/lib/rubocop/path_util.rb
CHANGED
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
|
-
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
47
|
+
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
48
48
|
def match_path?(pattern, path)
|
49
49
|
case pattern
|
50
50
|
when String
|
@@ -52,6 +52,10 @@ module RuboCop
|
|
52
52
|
if pattern == path
|
53
53
|
true
|
54
54
|
elsif glob?(pattern)
|
55
|
+
# File name matching doesn't really work with relative patterns that start with "..". We
|
56
|
+
# get around that problem by converting the pattern to an absolute path.
|
57
|
+
pattern = File.expand_path(pattern) if pattern.start_with?('..')
|
58
|
+
|
55
59
|
File.fnmatch?(pattern, path, File::FNM_PATHNAME | File::FNM_EXTGLOB)
|
56
60
|
end
|
57
61
|
|
@@ -66,7 +70,7 @@ module RuboCop
|
|
66
70
|
end
|
67
71
|
end
|
68
72
|
end
|
69
|
-
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
73
|
+
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
70
74
|
|
71
75
|
# Returns true for an absolute Unix or Windows path.
|
72
76
|
def absolute?(path)
|
@@ -6,7 +6,11 @@ require 'tempfile'
|
|
6
6
|
module CopHelper
|
7
7
|
extend RSpec::SharedContext
|
8
8
|
|
9
|
-
let(:ruby_version)
|
9
|
+
let(:ruby_version) do
|
10
|
+
# The minimum version Prism can parse is 3.3.
|
11
|
+
ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : RuboCop::TargetRuby::DEFAULT_VERSION
|
12
|
+
end
|
13
|
+
let(:parser_engine) { ENV.fetch('PARSER_ENGINE', :parser_whitequark).to_sym }
|
10
14
|
let(:rails_version) { false }
|
11
15
|
|
12
16
|
def inspect_source(source, file = nil)
|
@@ -28,7 +32,9 @@ module CopHelper
|
|
28
32
|
file = file.path
|
29
33
|
end
|
30
34
|
|
31
|
-
processed_source = RuboCop::ProcessedSource.new(
|
35
|
+
processed_source = RuboCop::ProcessedSource.new(
|
36
|
+
source, ruby_version, file, parser_engine: parser_engine
|
37
|
+
)
|
32
38
|
processed_source.config = configuration
|
33
39
|
processed_source.registry = registry
|
34
40
|
processed_source
|
@@ -111,6 +111,7 @@ module RuboCop
|
|
111
111
|
source
|
112
112
|
end
|
113
113
|
|
114
|
+
# rubocop:disable Metrics/AbcSize
|
114
115
|
def expect_offense(source, file = nil, severity: nil, chomp: false, **replacements)
|
115
116
|
expected_annotations = parse_annotations(source, **replacements)
|
116
117
|
source = expected_annotations.plain_source
|
@@ -123,10 +124,17 @@ module RuboCop
|
|
123
124
|
expect(actual_annotations).to eq(expected_annotations), ''
|
124
125
|
expect(@offenses.map(&:severity).uniq).to eq([severity]) if severity
|
125
126
|
|
127
|
+
# Validate that all offenses have a range that formatters can display
|
128
|
+
expect do
|
129
|
+
@offenses.each { |offense| offense.location.source_line }
|
130
|
+
end.not_to raise_error, 'One of the offenses has a misconstructed range, for ' \
|
131
|
+
'example if the offense is on line 1 and the source is empty'
|
132
|
+
|
126
133
|
@offenses
|
127
134
|
end
|
135
|
+
# rubocop:enable Metrics/AbcSize
|
128
136
|
|
129
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
137
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
130
138
|
def expect_correction(correction, loop: true, source: nil)
|
131
139
|
if source
|
132
140
|
expected_annotations = parse_annotations(source, raise_error: false)
|
@@ -148,7 +156,6 @@ module RuboCop
|
|
148
156
|
|
149
157
|
break corrected_source unless loop
|
150
158
|
break corrected_source if @last_corrector.empty?
|
151
|
-
break corrected_source if corrected_source == @processed_source.buffer.source
|
152
159
|
|
153
160
|
if iteration > RuboCop::Runner::MAX_ITERATIONS
|
154
161
|
raise RuboCop::Runner::InfiniteCorrectionLoop.new(@processed_source.path, [@offenses])
|
@@ -163,19 +170,20 @@ module RuboCop
|
|
163
170
|
|
164
171
|
expect(new_source).to eq(correction)
|
165
172
|
end
|
166
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
173
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
|
167
174
|
|
168
175
|
def expect_no_corrections
|
169
176
|
raise '`expect_no_corrections` must follow `expect_offense`' unless @processed_source
|
170
177
|
|
171
178
|
return if @last_corrector.empty?
|
172
179
|
|
173
|
-
#
|
174
|
-
# we need to run the actual corrections
|
175
|
-
|
180
|
+
# This is just here for a pretty diff if the source actually got changed
|
176
181
|
new_source = @last_corrector.rewrite
|
177
|
-
|
178
182
|
expect(new_source).to eq(@processed_source.buffer.source)
|
183
|
+
|
184
|
+
# There is an infinite loop if a corrector is present that did not make
|
185
|
+
# any changes. It will cause the same offense/correction on the next loop.
|
186
|
+
raise RuboCop::Runner::InfiniteCorrectionLoop.new(@processed_source.path, [@offenses])
|
179
187
|
end
|
180
188
|
|
181
189
|
def expect_no_offenses(source, file = nil)
|
@@ -212,7 +220,7 @@ module RuboCop
|
|
212
220
|
|
213
221
|
# Parsed representation of code annotated with the `^^^ Message` style
|
214
222
|
class AnnotatedSource
|
215
|
-
ANNOTATION_PATTERN = /\A\s*(\^+|\^{})
|
223
|
+
ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) ?/.freeze
|
216
224
|
ABBREV = "[...]\n"
|
217
225
|
|
218
226
|
# @param annotated_source [String] string passed to the matchers
|
@@ -100,17 +100,29 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
|
|
100
100
|
let(:cur_cop_config) do
|
101
101
|
RuboCop::ConfigLoader
|
102
102
|
.default_configuration.for_cop(cop_class)
|
103
|
-
.merge(
|
104
|
-
|
105
|
-
|
106
|
-
|
103
|
+
.merge(
|
104
|
+
'Enabled' => true, # in case it is 'pending'
|
105
|
+
'AutoCorrect' => 'always' # in case defaults set it to 'disabled' or false
|
106
|
+
)
|
107
107
|
.merge(cop_config)
|
108
108
|
end
|
109
109
|
|
110
110
|
let(:config) do
|
111
111
|
hash = { 'AllCops' => all_cops_config, cop_class.cop_name => cur_cop_config }.merge!(other_cops)
|
112
112
|
|
113
|
-
RuboCop::Config.new(hash, "#{Dir.pwd}/.rubocop.yml")
|
113
|
+
config = RuboCop::Config.new(hash, "#{Dir.pwd}/.rubocop.yml")
|
114
|
+
|
115
|
+
rails_version_in_gemfile = Gem::Version.new(
|
116
|
+
rails_version || RuboCop::Config::DEFAULT_RAILS_VERSION
|
117
|
+
)
|
118
|
+
|
119
|
+
allow(config).to receive(:gem_versions_in_target).and_return(
|
120
|
+
{
|
121
|
+
'railties' => rails_version_in_gemfile
|
122
|
+
}
|
123
|
+
)
|
124
|
+
|
125
|
+
config
|
114
126
|
end
|
115
127
|
|
116
128
|
let(:cop) { cop_class.new(config, cop_options) }
|
@@ -128,56 +140,75 @@ RSpec.shared_context 'mock console output' do
|
|
128
140
|
end
|
129
141
|
end
|
130
142
|
|
131
|
-
RSpec.shared_context 'lsp
|
143
|
+
RSpec.shared_context 'lsp' do
|
132
144
|
before do
|
133
|
-
|
145
|
+
RuboCop::LSP.enable
|
146
|
+
end
|
147
|
+
|
148
|
+
after do
|
149
|
+
RuboCop::LSP.disable
|
134
150
|
end
|
135
151
|
end
|
136
152
|
|
137
153
|
RSpec.shared_context 'ruby 2.0' do
|
138
|
-
|
154
|
+
# Prism supports parsing Ruby 3.3+.
|
155
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.0 }
|
139
156
|
end
|
140
157
|
|
141
158
|
RSpec.shared_context 'ruby 2.1' do
|
142
|
-
|
159
|
+
# Prism supports parsing Ruby 3.3+.
|
160
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.1 }
|
143
161
|
end
|
144
162
|
|
145
163
|
RSpec.shared_context 'ruby 2.2' do
|
146
|
-
|
164
|
+
# Prism supports parsing Ruby 3.3+.
|
165
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.2 }
|
147
166
|
end
|
148
167
|
|
149
168
|
RSpec.shared_context 'ruby 2.3' do
|
150
|
-
|
169
|
+
# Prism supports parsing Ruby 3.3+.
|
170
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.3 }
|
151
171
|
end
|
152
172
|
|
153
173
|
RSpec.shared_context 'ruby 2.4' do
|
154
|
-
|
174
|
+
# Prism supports parsing Ruby 3.3+.
|
175
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.4 }
|
155
176
|
end
|
156
177
|
|
157
178
|
RSpec.shared_context 'ruby 2.5' do
|
158
|
-
|
179
|
+
# Prism supports parsing Ruby 3.3+.
|
180
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.5 }
|
159
181
|
end
|
160
182
|
|
161
183
|
RSpec.shared_context 'ruby 2.6' do
|
162
|
-
|
184
|
+
# Prism supports parsing Ruby 3.3+.
|
185
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.6 }
|
163
186
|
end
|
164
187
|
|
165
188
|
RSpec.shared_context 'ruby 2.7' do
|
166
|
-
|
189
|
+
# Prism supports parsing Ruby 3.3+.
|
190
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.7 }
|
167
191
|
end
|
168
192
|
|
169
193
|
RSpec.shared_context 'ruby 3.0' do
|
170
|
-
|
194
|
+
# Prism supports parsing Ruby 3.3+.
|
195
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.0 }
|
171
196
|
end
|
172
197
|
|
173
198
|
RSpec.shared_context 'ruby 3.1' do
|
174
|
-
|
199
|
+
# Prism supports parsing Ruby 3.3+.
|
200
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.1 }
|
175
201
|
end
|
176
202
|
|
177
203
|
RSpec.shared_context 'ruby 3.2' do
|
178
|
-
|
204
|
+
# Prism supports parsing Ruby 3.3+.
|
205
|
+
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.2 }
|
179
206
|
end
|
180
207
|
|
181
208
|
RSpec.shared_context 'ruby 3.3' do
|
182
209
|
let(:ruby_version) { 3.3 }
|
183
210
|
end
|
211
|
+
|
212
|
+
RSpec.shared_context 'ruby 3.4' do
|
213
|
+
let(:ruby_version) { 3.4 }
|
214
|
+
end
|
@@ -13,7 +13,7 @@ RSpec.configure do |config|
|
|
13
13
|
config.include HostEnvironmentSimulatorHelper
|
14
14
|
config.include_context 'config', :config
|
15
15
|
config.include_context 'isolated environment', :isolated_environment
|
16
|
-
config.include_context 'lsp
|
16
|
+
config.include_context 'lsp', :lsp
|
17
17
|
config.include_context 'maintain registry', :restore_registry
|
18
18
|
config.include_context 'ruby 2.0', :ruby20
|
19
19
|
config.include_context 'ruby 2.1', :ruby21
|
@@ -27,4 +27,5 @@ RSpec.configure do |config|
|
|
27
27
|
config.include_context 'ruby 3.1', :ruby31
|
28
28
|
config.include_context 'ruby 3.2', :ruby32
|
29
29
|
config.include_context 'ruby 3.3', :ruby33
|
30
|
+
config.include_context 'ruby 3.4', :ruby34
|
30
31
|
end
|
data/lib/rubocop/runner.rb
CHANGED
@@ -20,6 +20,9 @@ module RuboCop
|
|
20
20
|
message = 'Infinite loop detected'
|
21
21
|
message += " in #{path}" if path
|
22
22
|
message += " and caused by #{root_cause}" if root_cause
|
23
|
+
message += ' Hint: Please update to the latest RuboCop version if not already in use,'
|
24
|
+
message += ' and report a bug if the issue still occurs on this version.'
|
25
|
+
message += ' Please check the latest version at https://rubygems.org/gems/rubocop'
|
23
26
|
super(message)
|
24
27
|
end
|
25
28
|
end
|
@@ -467,15 +470,21 @@ module RuboCop
|
|
467
470
|
end
|
468
471
|
end
|
469
472
|
|
473
|
+
# rubocop:disable Metrics/MethodLength
|
470
474
|
def get_processed_source(file)
|
471
475
|
config = @config_store.for_file(file)
|
472
476
|
ruby_version = config.target_ruby_version
|
477
|
+
parser_engine = config.parser_engine
|
473
478
|
|
474
479
|
processed_source = if @options[:stdin]
|
475
|
-
ProcessedSource.new(
|
480
|
+
ProcessedSource.new(
|
481
|
+
@options[:stdin], ruby_version, file, parser_engine: parser_engine
|
482
|
+
)
|
476
483
|
else
|
477
484
|
begin
|
478
|
-
ProcessedSource.from_file(
|
485
|
+
ProcessedSource.from_file(
|
486
|
+
file, ruby_version, parser_engine: parser_engine
|
487
|
+
)
|
479
488
|
rescue Errno::ENOENT
|
480
489
|
raise RuboCop::Error, "No such file or directory: #{file}"
|
481
490
|
end
|
@@ -484,6 +493,7 @@ module RuboCop
|
|
484
493
|
processed_source.registry = mobilized_cop_classes(config)
|
485
494
|
processed_source
|
486
495
|
end
|
496
|
+
# rubocop:enable Metrics/MethodLength
|
487
497
|
|
488
498
|
# A Cop::Team instance is stateful and may change when inspecting.
|
489
499
|
# The "standby" team for a given config is an initialized but
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module RuboCop
|
4
|
-
# This class finds target files to inspect by scanning the directory tree
|
5
|
-
# and picking ruby files.
|
4
|
+
# This class finds target files to inspect by scanning the directory tree and picking ruby files.
|
6
5
|
# @api private
|
7
6
|
class TargetFinder
|
8
7
|
HIDDEN_PATH_SUBSTRING = "#{File::SEPARATOR}."
|
@@ -12,21 +11,8 @@ module RuboCop
|
|
12
11
|
@options = options
|
13
12
|
end
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
def debug?
|
20
|
-
@options[:debug]
|
21
|
-
end
|
22
|
-
|
23
|
-
def fail_fast?
|
24
|
-
@options[:fail_fast]
|
25
|
-
end
|
26
|
-
|
27
|
-
# Generate a list of target files by expanding globbing patterns
|
28
|
-
# (if any). If args is empty, recursively find all Ruby source
|
29
|
-
# files under the current directory
|
14
|
+
# Generate a list of target files by expanding globbing patterns (if any). If args is empty,
|
15
|
+
# recursively find all Ruby source files under the current directory
|
30
16
|
# @return [Array] array of file paths
|
31
17
|
def find(args, mode)
|
32
18
|
return target_files_in_dir if args.empty?
|
@@ -44,12 +30,11 @@ module RuboCop
|
|
44
30
|
files.map { |f| File.expand_path(f) }.uniq
|
45
31
|
end
|
46
32
|
|
47
|
-
# Finds all Ruby source files under the current or other supplied
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
# so you can include other Ruby files like Rakefiles and gemspecs.
|
33
|
+
# Finds all Ruby source files under the current or other supplied directory. A Ruby source file
|
34
|
+
# is defined as a file with the `.rb` extension or a file with no extension that has a ruby
|
35
|
+
# shebang line as its first line.
|
36
|
+
# It is possible to specify includes and excludes using the config file, so you can include
|
37
|
+
# other Ruby files like Rakefiles and gemspecs.
|
53
38
|
# @param base_dir Root directory under which to search for
|
54
39
|
# ruby source files
|
55
40
|
# @return [Array] Array of filenames
|
@@ -66,20 +51,10 @@ module RuboCop
|
|
66
51
|
target_files.sort_by!(&order)
|
67
52
|
end
|
68
53
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
end && ruby_file?(file)
|
74
|
-
|
75
|
-
base_dir_config.file_to_include?(file)
|
76
|
-
end
|
77
|
-
|
78
|
-
# Search for files recursively starting at the given base directory using
|
79
|
-
# the given flags that determine how the match is made. Excluded files will
|
80
|
-
# be removed later by the caller, but as an optimization find_files removes
|
81
|
-
# the top level directories that are excluded in configuration in the
|
82
|
-
# normal way (dir/**/*).
|
54
|
+
# Search for files recursively starting at the given base directory using the given flags that
|
55
|
+
# determine how the match is made. Excluded files will be removed later by the caller, but as an
|
56
|
+
# optimization find_files removes the top level directories that are excluded in configuration
|
57
|
+
# in the normal way (dir/**/*).
|
83
58
|
def find_files(base_dir, flags)
|
84
59
|
# get all wanted directories first to improve speed of finding all files
|
85
60
|
exclude_pattern = combined_exclude_glob_patterns(base_dir)
|
@@ -93,6 +68,17 @@ module RuboCop
|
|
93
68
|
Dir.glob(patterns, flags).select { |path| FileTest.file?(path) }
|
94
69
|
end
|
95
70
|
|
71
|
+
private
|
72
|
+
|
73
|
+
def to_inspect?(file, hidden_files, base_dir_config)
|
74
|
+
return false if base_dir_config.file_to_exclude?(file)
|
75
|
+
return true if !hidden_files.bsearch do |hidden_file|
|
76
|
+
file <=> hidden_file
|
77
|
+
end && ruby_file?(file)
|
78
|
+
|
79
|
+
base_dir_config.file_to_include?(file)
|
80
|
+
end
|
81
|
+
|
96
82
|
def wanted_dir_patterns(base_dir, exclude_pattern, flags)
|
97
83
|
# Escape glob characters in base_dir to avoid unwanted behavior.
|
98
84
|
base_dir = base_dir.gsub(/[\\\{\}\[\]\*\?]/) do |reserved_glob_character|
|
@@ -124,21 +110,6 @@ module RuboCop
|
|
124
110
|
"#{base_dir}/{#{patterns.join(',')}}"
|
125
111
|
end
|
126
112
|
|
127
|
-
def ruby_extension?(file)
|
128
|
-
ruby_extensions.include?(File.extname(file))
|
129
|
-
end
|
130
|
-
|
131
|
-
def ruby_extensions
|
132
|
-
@ruby_extensions ||= begin
|
133
|
-
ext_patterns = all_cops_include.select { |pattern| pattern.start_with?('**/*.') }
|
134
|
-
ext_patterns.map { |pattern| pattern.sub('**/*', '') }
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def ruby_filename?(file)
|
139
|
-
ruby_filenames.include?(File.basename(file))
|
140
|
-
end
|
141
|
-
|
142
113
|
def ruby_filenames
|
143
114
|
@ruby_filenames ||= begin
|
144
115
|
file_patterns = all_cops_include.reject { |pattern| pattern.start_with?('**/*.') }
|
@@ -150,53 +121,72 @@ module RuboCop
|
|
150
121
|
@all_cops_include ||= @config_store.for_pwd.for_all_cops['Include'].map(&:to_s)
|
151
122
|
end
|
152
123
|
|
153
|
-
def
|
154
|
-
|
124
|
+
def process_explicit_path(path, mode)
|
125
|
+
files = path.include?('*') ? Dir[path] : [path]
|
155
126
|
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
warn("Unprocessable file #{file}: #{e.class}, #{e.message}") if debug?
|
127
|
+
if mode == :only_recognized_file_types || force_exclusion?
|
128
|
+
files.select! { |file| included_file?(file) }
|
129
|
+
end
|
160
130
|
|
161
|
-
|
131
|
+
force_exclusion? ? without_excluded(files) : files
|
162
132
|
end
|
163
133
|
|
164
|
-
def
|
165
|
-
|
134
|
+
def without_excluded(files)
|
135
|
+
files.reject do |file|
|
136
|
+
# When --ignore-parent-exclusion is given, we must look at the configuration associated with
|
137
|
+
# the file, but in the default case when --ignore-parent-exclusion is not given, can safely
|
138
|
+
# look only at the configuration for the current directory, since it's only the Exclude
|
139
|
+
# parameters we're going to check.
|
140
|
+
config = @config_store.for(ignore_parent_exclusion? ? file : '.')
|
141
|
+
config.file_to_exclude?(file)
|
142
|
+
end
|
166
143
|
end
|
167
144
|
|
168
|
-
def
|
169
|
-
|
145
|
+
def included_file?(file)
|
146
|
+
ruby_file?(file) || configured_include?(file)
|
170
147
|
end
|
171
148
|
|
172
149
|
def ruby_file?(file)
|
173
150
|
stdin? || ruby_extension?(file) || ruby_filename?(file) || ruby_executable?(file)
|
174
151
|
end
|
175
152
|
|
176
|
-
def
|
177
|
-
@
|
153
|
+
def stdin?
|
154
|
+
@options.key?(:stdin)
|
178
155
|
end
|
179
156
|
|
180
|
-
def
|
181
|
-
|
157
|
+
def ruby_extension?(file)
|
158
|
+
ruby_extensions.include?(File.extname(file))
|
182
159
|
end
|
183
160
|
|
184
|
-
def
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
files.select! { |file| included_file?(file) }
|
161
|
+
def ruby_extensions
|
162
|
+
@ruby_extensions ||= begin
|
163
|
+
ext_patterns = all_cops_include.select { |pattern| pattern.start_with?('**/*.') }
|
164
|
+
ext_patterns.map { |pattern| pattern.sub('**/*', '') }
|
189
165
|
end
|
166
|
+
end
|
190
167
|
|
191
|
-
|
168
|
+
def ruby_filename?(file)
|
169
|
+
ruby_filenames.include?(File.basename(file))
|
170
|
+
end
|
192
171
|
|
193
|
-
|
194
|
-
|
195
|
-
config.file_to_exclude?(file)
|
196
|
-
end
|
172
|
+
def configured_include?(file)
|
173
|
+
@config_store.for_pwd.file_to_include?(file)
|
197
174
|
end
|
198
175
|
|
199
|
-
|
176
|
+
def ruby_executable?(file)
|
177
|
+
return false unless File.extname(file).empty? && File.exist?(file)
|
178
|
+
|
179
|
+
first_line = File.open(file, &:readline)
|
180
|
+
/#!.*(#{ruby_interpreters(file).join('|')})/.match?(first_line)
|
181
|
+
rescue EOFError, ArgumentError => e
|
182
|
+
warn("Unprocessable file #{file}: #{e.class}, #{e.message}") if debug?
|
183
|
+
|
184
|
+
false
|
185
|
+
end
|
186
|
+
|
187
|
+
def ruby_interpreters(file)
|
188
|
+
@config_store.for(file).for_all_cops['RubyInterpreters']
|
189
|
+
end
|
200
190
|
|
201
191
|
def order
|
202
192
|
if fail_fast?
|
@@ -206,5 +196,21 @@ module RuboCop
|
|
206
196
|
:itself
|
207
197
|
end
|
208
198
|
end
|
199
|
+
|
200
|
+
def force_exclusion?
|
201
|
+
@options[:force_exclusion]
|
202
|
+
end
|
203
|
+
|
204
|
+
def ignore_parent_exclusion?
|
205
|
+
@options[:ignore_parent_exclusion]
|
206
|
+
end
|
207
|
+
|
208
|
+
def debug?
|
209
|
+
@options[:debug]
|
210
|
+
end
|
211
|
+
|
212
|
+
def fail_fast?
|
213
|
+
@options[:fail_fast]
|
214
|
+
end
|
209
215
|
end
|
210
216
|
end
|