rubocop 1.86.1 → 1.87.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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +15 -1
  3. data/lib/rubocop/cli/command/auto_generate_config.rb +27 -1
  4. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  5. data/lib/rubocop/cli/command/show_docs_url.rb +3 -7
  6. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  7. data/lib/rubocop/cli.rb +6 -7
  8. data/lib/rubocop/comment_config.rb +12 -15
  9. data/lib/rubocop/config_loader.rb +17 -2
  10. data/lib/rubocop/config_loader_resolver.rb +11 -3
  11. data/lib/rubocop/config_store.rb +1 -1
  12. data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
  13. data/lib/rubocop/cop/base.rb +8 -2
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  15. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -2
  16. data/lib/rubocop/cop/correctors.rb +28 -0
  17. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  18. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
  19. data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -4
  20. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -3
  21. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  22. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  23. data/lib/rubocop/cop/layout/class_structure.rb +1 -1
  24. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +14 -5
  25. data/lib/rubocop/cop/layout/end_alignment.rb +2 -2
  26. data/lib/rubocop/cop/layout/indentation_width.rb +13 -1
  27. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  28. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +26 -1
  29. data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
  30. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
  31. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  32. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  33. data/lib/rubocop/cop/lint/constant_reassignment.rb +36 -4
  34. data/lib/rubocop/cop/lint/constant_resolution.rb +5 -5
  35. data/lib/rubocop/cop/lint/deprecated_constants.rb +1 -1
  36. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  37. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
  38. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  39. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  40. data/lib/rubocop/cop/lint/number_conversion.rb +5 -5
  41. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  42. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
  43. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +2 -2
  44. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +3 -3
  45. data/lib/rubocop/cop/lint/require_relative_self_path.rb +3 -1
  46. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  47. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -1
  48. data/lib/rubocop/cop/lint/unreachable_code.rb +2 -2
  49. data/lib/rubocop/cop/lint/useless_assignment.rb +3 -8
  50. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  51. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +18 -7
  52. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  53. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  54. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  55. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  56. data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
  57. data/lib/rubocop/cop/mixin.rb +86 -0
  58. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
  59. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  60. data/lib/rubocop/cop/naming/predicate_method.rb +2 -2
  61. data/lib/rubocop/cop/naming/predicate_prefix.rb +1 -1
  62. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  63. data/lib/rubocop/cop/offense.rb +8 -0
  64. data/lib/rubocop/cop/registry.rb +42 -25
  65. data/lib/rubocop/cop/security/io_methods.rb +1 -1
  66. data/lib/rubocop/cop/style/alias.rb +10 -1
  67. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  68. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -0
  69. data/lib/rubocop/cop/style/copyright.rb +21 -10
  70. data/lib/rubocop/cop/style/date_time.rb +2 -2
  71. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
  72. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  73. data/lib/rubocop/cop/style/file_write.rb +18 -16
  74. data/lib/rubocop/cop/style/format_string.rb +4 -3
  75. data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
  76. data/lib/rubocop/cop/style/hash_lookup_method.rb +12 -7
  77. data/lib/rubocop/cop/style/if_inside_else.rb +15 -2
  78. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  79. data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
  80. data/lib/rubocop/cop/style/module_member_existence_check.rb +6 -3
  81. data/lib/rubocop/cop/style/reduce_to_hash.rb +16 -0
  82. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  83. data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
  84. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
  85. data/lib/rubocop/cop/style/redundant_self.rb +2 -2
  86. data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
  87. data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
  88. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  89. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
  90. data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
  91. data/lib/rubocop/cop/style/symbol_proc.rb +3 -3
  92. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
  93. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  94. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
  95. data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
  96. data/lib/rubocop/cop/team.rb +86 -35
  97. data/lib/rubocop/file_patterns.rb +9 -1
  98. data/lib/rubocop/formatter/disabled_config_formatter.rb +4 -1
  99. data/lib/rubocop/lsp/runtime.rb +1 -2
  100. data/lib/rubocop/options.rb +26 -4
  101. data/lib/rubocop/project_index_loader.rb +66 -0
  102. data/lib/rubocop/rspec/shared_contexts.rb +21 -0
  103. data/lib/rubocop/runner.rb +123 -57
  104. data/lib/rubocop/target_finder.rb +13 -6
  105. data/lib/rubocop/version.rb +20 -2
  106. data/lib/rubocop.rb +8 -96
  107. metadata +8 -3
@@ -16,7 +16,9 @@ module RuboCop
16
16
  'root of the project. RuboCop will use this path to determine which ' \
17
17
  'cops are enabled (via eg. Include/Exclude), and so that certain cops ' \
18
18
  'like Naming/FileName can be checked.'
19
- EXITING_OPTIONS = %i[version verbose_version show_cops show_docs_url lsp mcp].freeze
19
+ EXITING_OPTIONS = %i[
20
+ version verbose_version show_cops list_enabled_cops_for show_docs_url lsp mcp
21
+ ].freeze
20
22
  DEFAULT_MAXIMUM_EXCLUSION_ITEMS = 15
21
23
 
22
24
  def initialize
@@ -89,6 +91,8 @@ module RuboCop
89
91
  option(opts, '-F', '--fail-fast')
90
92
  option(opts, '--disable-pending-cops')
91
93
  option(opts, '--enable-pending-cops')
94
+ option(opts, '--disable-all-cops')
95
+ option(opts, '--enable-all-cops')
92
96
  option(opts, '--ignore-disable-comments')
93
97
  option(opts, '--force-exclusion')
94
98
  option(opts, '--only-recognized-file-types')
@@ -236,6 +240,7 @@ module RuboCop
236
240
  def add_additional_modes(opts)
237
241
  section(opts, 'Additional Modes') do
238
242
  option(opts, '-L', '--list-target-files')
243
+ option(opts, '--list-enabled-cops-for PATH')
239
244
  option(opts, '--show-cops [COP1,COP2,...]') do |list|
240
245
  @options[:show_cops] = list.nil? ? [] : list.split(',')
241
246
  end
@@ -393,6 +398,7 @@ module RuboCop
393
398
  validate_display_only_failed_and_display_only_correctable
394
399
  validate_display_only_correctable_and_autocorrect
395
400
  validate_lsp_and_editor_mode
401
+ validate_enable_all_cops_and_disable_all_cops
396
402
  disable_parallel_when_invalid_option_combo
397
403
 
398
404
  return if incompatible_options.size <= 1
@@ -446,6 +452,13 @@ module RuboCop
446
452
  raise OptionArgumentError, 'Do not specify `--editor-mode` as it is redundant in `--lsp`.'
447
453
  end
448
454
 
455
+ def validate_enable_all_cops_and_disable_all_cops
456
+ return if !@options.key?(:enable_all_cops) || !@options.key?(:disable_all_cops)
457
+
458
+ raise OptionArgumentError,
459
+ '--enable-all-cops cannot be used together with --disable-all-cops.'
460
+ end
461
+
449
462
  def validate_autocorrect
450
463
  if @options.key?(:safe_autocorrect) && @options.key?(:autocorrect_all)
451
464
  message = Rainbow(<<~MESSAGE).red
@@ -474,8 +487,7 @@ module RuboCop
474
487
  end
475
488
 
476
489
  def invalid_arguments_for_parallel
477
- [('--auto-gen-config' if @options.key?(:auto_gen_config)),
478
- ('-F/--fail-fast' if @options.key?(:fail_fast)),
490
+ [('-F/--fail-fast' if @options.key?(:fail_fast)),
479
491
  ('--profile' if @options[:profile]),
480
492
  ('--memory' if @options[:memory]),
481
493
  ('--cache false' if @options > { cache: 'false' })].compact
@@ -599,7 +611,7 @@ module RuboCop
599
611
  display_only_correctable: ['Only output correctable offense messages.'],
600
612
  display_only_safe_correctable: ['Only output safe-correctable offense messages',
601
613
  'when combined with --display-only-correctable.'],
602
- show_cops: ['Shows the given cops, or all cops by',
614
+ show_cops: ['Show the given cops, or all cops by',
603
615
  'default, and their configurations for the',
604
616
  'current directory.',
605
617
  'You can use `*` as a wildcard.'],
@@ -619,8 +631,16 @@ module RuboCop
619
631
  display_cop_names: ['Display cop names in offense messages.',
620
632
  'Default is true.'],
621
633
  disable_pending_cops: 'Run without pending cops.',
634
+ disable_all_cops: ['Run with all cops disabled by default,',
635
+ 'except `Lint/Syntax`. Overrides',
636
+ '`AllCops/EnabledByDefault` and',
637
+ '`AllCops/DisabledByDefault` in config files.'],
622
638
  display_style_guide: 'Display style guide URLs in offense messages.',
623
639
  enable_pending_cops: 'Run with pending cops.',
640
+ enable_all_cops: ['Run with all cops enabled, including those',
641
+ 'disabled by default. Overrides',
642
+ '`AllCops/EnabledByDefault` and',
643
+ '`AllCops/DisabledByDefault` in config files.'],
624
644
  extra_details: 'Display extra details in offense messages.',
625
645
  lint: 'Run only lint cops.',
626
646
  safe: 'Run only safe cops.',
@@ -628,6 +648,8 @@ module RuboCop
628
648
  'autocorrected source. This is especially useful',
629
649
  'when combined with --autocorrect and --stdin.'],
630
650
  list_target_files: 'List all files RuboCop will inspect.',
651
+ list_enabled_cops_for: ['List which cops will inspect a given file or',
652
+ 'directory.'],
631
653
  autocorrect: 'Autocorrect offenses (only when it\'s safe).',
632
654
  auto_correct: '(same, deprecated)',
633
655
  safe_auto_correct: '(same, deprecated)',
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ # Defensive loader for the optional `rubydex` gem.
5
+ #
6
+ # When `AllCops/UseProjectIndex` is enabled in the user's configuration, RuboCop builds
7
+ # a project-wide index using `Rubydex::Graph` and exposes it to cops that opt in.
8
+ # The gem is intentionally not a runtime dependency; if it is not installed,
9
+ # or if the running Ruby is older than what `rubydex` supports, RuboCop falls back to
10
+ # its standard file-local behavior.
11
+ module ProjectIndexLoader
12
+ MINIMUM_RUBY_VERSION = '3.2'
13
+
14
+ module_function
15
+
16
+ # Returns whether the `rubydex` gem can be loaded. The result is memoized
17
+ # for the lifetime of the process.
18
+ def available?
19
+ return @available if defined?(@available)
20
+
21
+ @available = supported_ruby? && try_require
22
+ end
23
+
24
+ def supported_ruby?
25
+ RUBY_VERSION >= MINIMUM_RUBY_VERSION
26
+ end
27
+
28
+ def warn_unavailable
29
+ return if @warned
30
+
31
+ @warned = true
32
+
33
+ if supported_ruby?
34
+ warn Rainbow(<<~MSG).yellow
35
+ `AllCops/UseProjectIndex` is enabled but the `rubydex` gem is not installed.
36
+ Analyses that use the project index will be skipped. Add `gem 'rubydex'` to your Gemfile.
37
+ MSG
38
+ else
39
+ warn Rainbow(<<~MSG).yellow
40
+ `AllCops/UseProjectIndex` is enabled but `rubydex` requires Ruby #{MINIMUM_RUBY_VERSION} or later (current: #{RUBY_VERSION}).
41
+ Analyses that use the project index will be skipped.
42
+ MSG
43
+ end
44
+ end
45
+
46
+ def try_require
47
+ require 'rubydex'
48
+ true
49
+ rescue LoadError
50
+ false
51
+ end
52
+
53
+ # Builds and resolves a `Rubydex::Graph` for the given file paths. Returns the resolved graph,
54
+ # or `nil` if the build fails. This is the only place in RuboCop that depends on the concrete
55
+ # `Rubydex::Graph` API, so callers (e.g. `Runner`) do not need to know which Rubydex classes
56
+ # or methods are involved.
57
+ def build_index(paths)
58
+ graph = Rubydex::Graph.new
59
+ graph.index_all(paths.map(&:to_s))
60
+ graph.resolve
61
+ graph
62
+ rescue StandardError => e
63
+ warn Rainbow("rubydex index build failed: #{e.message}. Continuing without it.").yellow
64
+ end
65
+ end
66
+ end
@@ -212,6 +212,27 @@ RSpec.shared_context 'lsp' do
212
212
  end
213
213
  end
214
214
 
215
+ RSpec.shared_context 'with exclude limit tracking' do
216
+ around do |example|
217
+ Dir.mktmpdir('rubocop-exclude-limit') do |dir|
218
+ RuboCop::ExcludeLimit.tmp_dir = Pathname.new(dir)
219
+ example.run
220
+ ensure
221
+ RuboCop::ExcludeLimit.tmp_dir = nil
222
+ end
223
+ end
224
+
225
+ # Reads exclude_limit values from the tmp files written by ExcludeLimit.
226
+ # Returns a hash like { 'Max' => 81 } or nil if no values were written.
227
+ def read_exclude_limit(cop, parameter_name = nil)
228
+ if parameter_name
229
+ read_exclude_limit(cop)[parameter_name]
230
+ else
231
+ RuboCop::ExcludeLimit.read_limits(cop.class.badge.to_s)
232
+ end
233
+ end
234
+ end
235
+
215
236
  RSpec.shared_context 'ruby 2.0' do
216
237
  # Prism supports parsing Ruby 3.3+.
217
238
  let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.0 }
@@ -62,6 +62,8 @@ module RuboCop
62
62
  @errors = []
63
63
  @warnings = []
64
64
  @aborting = false
65
+ @inspected_files = []
66
+ @report_queue = {}
65
67
  end
66
68
 
67
69
  def run(paths)
@@ -70,10 +72,11 @@ module RuboCop
70
72
  ResultCache.source_checksum
71
73
 
72
74
  target_files = find_target_files(paths)
75
+ @project_index = ProjectIndexLoader.build_index(target_files) if project_index_enabled?
76
+
73
77
  if @options[:list_target_files]
74
78
  list_files(target_files)
75
79
  else
76
- warm_cache(target_files) if @options[:parallel]
77
80
  inspect_files(target_files)
78
81
  end
79
82
  rescue Interrupt
@@ -90,21 +93,6 @@ module RuboCop
90
93
 
91
94
  private
92
95
 
93
- # Warms up the RuboCop cache by forking a suitable number of RuboCop
94
- # instances that each inspects its allotted group of files.
95
- def warm_cache(target_files)
96
- saved_options = @options.dup
97
- if target_files.length <= 1
98
- puts 'Skipping parallel inspection: only a single file needs inspection' if @options[:debug]
99
- return
100
- end
101
- puts 'Running parallel inspection' if @options[:debug]
102
- %i[autocorrect safe_autocorrect].each { |opt| @options[opt] = false }
103
- Parallel.each(target_files) { |target_file| file_offenses(target_file) }
104
- ensure
105
- @options = saved_options
106
- end
107
-
108
96
  def find_target_files(paths)
109
97
  target_finder = TargetFinder.new(@config_store, @options)
110
98
  mode = if @options[:only_recognized_file_types]
@@ -116,12 +104,26 @@ module RuboCop
116
104
  target_files.each(&:freeze).freeze
117
105
  end
118
106
 
119
- def inspect_files(files)
120
- inspected_files = []
107
+ def project_index_enabled?
108
+ return false unless @config_store.for_pwd.for_all_cops['UseProjectIndex']
121
109
 
110
+ unless ProjectIndexLoader.available?
111
+ ProjectIndexLoader.warn_unavailable
112
+ return false
113
+ end
114
+
115
+ true
116
+ end
117
+
118
+ def inspect_files(files) # rubocop:disable Metrics/AbcSize
122
119
  formatter_set.started(files)
120
+ file_iterator(files) do |file|
121
+ offenses = process_file(file)
122
+ succeeded = offenses.none? { |o| considered_failure?(o) && offense_displayed?(o) }
123
+ raise Parallel::Break if @options[:fail_fast] && !succeeded
123
124
 
124
- each_inspected_file(files) { |file| inspected_files << file }
125
+ [offenses, succeeded]
126
+ end
125
127
  ensure
126
128
  # OPTIMIZE: Calling `ResultCache.cleanup` takes time. This optimization
127
129
  # mainly targets editors that integrates RuboCop. When RuboCop is run
@@ -129,23 +131,88 @@ module RuboCop
129
131
  if files.size > 1 && cached_run?
130
132
  ResultCache.cleanup(@config_store, @options[:debug], @options[:cache_root])
131
133
  end
132
-
133
- formatter_set.finished(inspected_files.freeze)
134
+ formatter_set.finished(@inspected_files.freeze)
134
135
  formatter_set.close_output_files
135
136
  end
136
137
 
137
- def each_inspected_file(files)
138
- files.reduce(true) do |all_passed, file|
139
- offenses = process_file(file)
140
- yield file
138
+ def file_iterator(files, &block)
139
+ all_passed = true
141
140
 
142
- if offenses.any? { |o| considered_failure?(o) && offense_displayed?(o) }
143
- break false if @options[:fail_fast]
141
+ on_start = ->(file, _index) { file_started(file) }
142
+ on_finish = lambda do |file, index, (offenses, passed)|
143
+ all_passed &&= passed
144
+ finished_report(file, index, offenses)
145
+ end
144
146
 
145
- next false
146
- end
147
+ if run_in_parallel?(files)
148
+ parallel_file_iterator(files, on_start, on_finish, &block)
149
+ else
150
+ serial_file_iterator(files, on_start, on_finish, &block)
151
+ end
152
+
153
+ process_remaining_report_queue
154
+
155
+ all_passed
156
+ end
157
+
158
+ def finished_report(file, index, offenses)
159
+ @report_queue[index] = [file, offenses]
160
+ @next_index_to_report ||= 0
161
+ while @report_queue.key?(@next_index_to_report)
162
+ process_report_queue_entry(@next_index_to_report)
163
+ @next_index_to_report += 1
164
+ end
165
+ end
166
+
167
+ def process_report_queue_entry(index)
168
+ file, offenses = @report_queue.delete(index)
169
+ file_finished(file, offenses)
170
+ end
171
+
172
+ def process_remaining_report_queue
173
+ @report_queue.keys.sort.each do |index|
174
+ process_report_queue_entry(index)
175
+ end
176
+ end
147
177
 
148
- all_passed
178
+ def run_in_parallel?(files)
179
+ return false if @options[:auto_gen_config]
180
+ return false unless @options[:parallel]
181
+
182
+ if files.size <= 1
183
+ puts 'Skipping parallel inspection: only a single file needs inspection' if @options[:debug]
184
+ return false
185
+ end
186
+
187
+ return false if project_index_disables_parallel?
188
+
189
+ puts 'Running parallel inspection' if @options[:debug]
190
+
191
+ true
192
+ end
193
+
194
+ def project_index_disables_parallel?
195
+ return false if @project_index.nil? || !Gem.win_platform?
196
+
197
+ if @options[:debug]
198
+ puts 'Skipping parallel inspection: the project index is enabled and parallel ' \
199
+ 'inspection is not yet supported on Windows.'
200
+ end
201
+
202
+ true
203
+ end
204
+
205
+ def parallel_file_iterator(files, on_start, on_finish, &block)
206
+ Parallel.each(files, start: on_start, finish: on_finish, &block)
207
+ end
208
+
209
+ def serial_file_iterator(files, on_start, on_finish, &block)
210
+ files.each_with_index do |file, index|
211
+ on_start.call(file, index)
212
+ result = yield file
213
+ on_finish.call(file, index, result)
214
+ rescue Parallel::Break
215
+ break
149
216
  end
150
217
  end
151
218
 
@@ -154,16 +221,13 @@ module RuboCop
154
221
  end
155
222
 
156
223
  def process_file(file)
157
- file_started(file)
158
- offenses = file_offenses(file)
224
+ file_offenses(file)
159
225
  rescue InfiniteCorrectionLoop => e
160
226
  raise e if @options[:raise_cop_error]
161
227
 
162
228
  errors << e
163
229
  warn Rainbow(e.message).red
164
- offenses = e.offenses.compact.sort.freeze
165
- ensure
166
- file_finished(file, offenses || [])
230
+ e.offenses.compact.sort.freeze
167
231
  end
168
232
 
169
233
  def file_offenses(file)
@@ -250,6 +314,7 @@ module RuboCop
250
314
  end
251
315
 
252
316
  def file_finished(file, offenses)
317
+ @inspected_files << file
253
318
  offenses = offenses_to_report(offenses)
254
319
  formatter_set.file_finished(file, offenses)
255
320
  end
@@ -258,10 +323,6 @@ module RuboCop
258
323
  @cached_run ||=
259
324
  (@options[:cache] == 'true' ||
260
325
  (@options[:cache] != 'false' && @config_store.for_pwd.for_all_cops['UseCache'])) &&
261
- # When running --auto-gen-config, there's some processing done in the
262
- # cops related to calculating the Max parameters for Metrics cops. We
263
- # need to do that processing and cannot use caching.
264
- !@options[:auto_gen_config] &&
265
326
  # We can't cache results from code which is piped in to stdin
266
327
  !@options[:stdin]
267
328
  end
@@ -350,21 +411,9 @@ module RuboCop
350
411
 
351
412
  def inspect_file(processed_source, team = mobilize_team(processed_source))
352
413
  extracted_ruby_sources = extract_ruby_sources(processed_source)
353
- offenses = []
354
-
355
- extracted_ruby_sources.each do |extracted_ruby_source|
356
- report = team.investigate(
357
- extracted_ruby_source[:processed_source],
358
- offset: extracted_ruby_source[:offset],
359
- original: processed_source
360
- )
361
- @errors.concat(team.errors)
362
- @warnings.concat(team.warnings)
363
- offenses.concat(report.offenses)
364
-
365
- break if team.updated_source_file?
366
- end
367
-
414
+ offenses = team.investigate_fragments(extracted_ruby_sources, original: processed_source)
415
+ @errors.concat(team.errors)
416
+ @warnings.concat(team.warnings)
368
417
  [offenses, team.updated_source_file?]
369
418
  end
370
419
 
@@ -384,7 +433,15 @@ module RuboCop
384
433
 
385
434
  def mobilize_team(processed_source)
386
435
  config = @config_store.for_file(processed_source.path)
387
- Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
436
+ team = Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
437
+
438
+ if @project_index
439
+ team.cops.each do |cop|
440
+ cop.project_index = @project_index
441
+ end
442
+ end
443
+
444
+ team
388
445
  end
389
446
 
390
447
  def mobilized_cop_classes(config) # rubocop:disable Metrics/AbcSize
@@ -527,8 +584,17 @@ module RuboCop
527
584
  # level caching in ResultCache.
528
585
  def standby_team(config)
529
586
  @team_by_config ||= {}.compare_by_identity
530
- @team_by_config[config] ||=
531
- Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
587
+ @team_by_config[config] ||= begin
588
+ team = Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
589
+
590
+ if @project_index
591
+ team.cops.each do |cop|
592
+ cop.project_index = @project_index
593
+ end
594
+ end
595
+
596
+ team
597
+ end
532
598
  end
533
599
  end
534
600
  end
@@ -44,10 +44,10 @@ module RuboCop
44
44
  all_files = find_files(base_dir, File::FNM_DOTMATCH)
45
45
  base_dir_config = @config_store.for(base_dir)
46
46
 
47
- target_files = if hidden_path?(base_dir)
47
+ target_files = if hidden_dir?(base_dir)
48
48
  all_files.select { |file| ruby_file?(file) }
49
49
  else
50
- all_files.select { |file| to_inspect?(file, base_dir_config) }
50
+ all_files.select { |file| to_inspect?(file, base_dir, base_dir_config) }
51
51
  end
52
52
 
53
53
  target_files.sort_by!(&order)
@@ -72,15 +72,22 @@ module RuboCop
72
72
 
73
73
  private
74
74
 
75
- def to_inspect?(file, base_dir_config)
75
+ def to_inspect?(file, base_dir, base_dir_config)
76
76
  return false if base_dir_config.file_to_exclude?(file)
77
- return true if !hidden_path?(file) && ruby_file?(file)
77
+ return true if !hidden_file_in_dir?(file, base_dir) && ruby_file?(file)
78
78
 
79
79
  base_dir_config.file_to_include?(file)
80
80
  end
81
81
 
82
- def hidden_path?(path)
83
- path.include?(HIDDEN_PATH_SUBSTRING)
82
+ def hidden_dir?(dir)
83
+ basename = File.basename(dir)
84
+ basename.start_with?('.') && basename != '.' && basename != '..'
85
+ end
86
+
87
+ def hidden_file_in_dir?(file, base_dir)
88
+ base_dir = "#{base_dir}#{File::SEPARATOR}" unless base_dir.end_with?(File::SEPARATOR)
89
+ relative = file.delete_prefix(base_dir)
90
+ relative.start_with?('.') || relative.include?(HIDDEN_PATH_SUBSTRING)
84
91
  end
85
92
 
86
93
  def wanted_dir_patterns(base_dir, exclude_pattern, flags)
@@ -3,12 +3,13 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.86.1'
6
+ STRING = '1.87.0'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
10
10
  'analyzing as Ruby %<target_ruby_version>s, ' \
11
- 'running on %<ruby_engine>s %<ruby_version>s)%<server_mode>s [%<ruby_platform>s]'
11
+ 'running on %<ruby_engine>s %<ruby_version>s)' \
12
+ '%<rubydex_indicator>s%<server_mode>s [%<ruby_platform>s]'
12
13
 
13
14
  MINIMUM_PARSABLE_PRISM_VERSION = 3.3
14
15
 
@@ -31,6 +32,7 @@ module RuboCop
31
32
  rubocop_ast_version: RuboCop::AST::Version::STRING,
32
33
  target_ruby_version: target_ruby_version,
33
34
  ruby_engine: RUBY_ENGINE, ruby_version: RUBY_VERSION,
35
+ rubydex_indicator: rubydex_indicator(env),
34
36
  server_mode: server_mode,
35
37
  ruby_platform: RUBY_PLATFORM)
36
38
  return verbose_version unless env
@@ -152,6 +154,22 @@ module RuboCop
152
154
  STRING.match('\d+\.\d+').to_s
153
155
  end
154
156
 
157
+ # @api private
158
+ def self.rubydex_indicator(env)
159
+ env && rubydex_enabled?(env) && ProjectIndexLoader.available? ? ' +Rubydex' : ''
160
+ end
161
+
162
+ # @api private
163
+ def self.rubydex_enabled?(env)
164
+ config_for_pwd(env).for_all_cops['UseProjectIndex']
165
+ rescue StandardError
166
+ # Keep `rubocop -V` usable when the config cannot be loaded (broken YAML,
167
+ # missing `inherit_from` target, etc). It is the first command users run to
168
+ # diagnose a broken setup, so the indicator just hides rather than letting
169
+ # the version banner crash.
170
+ false
171
+ end
172
+
155
173
  # @api private
156
174
  def self.server_mode
157
175
  RuboCop.const_defined?(:Server) && Server.running? ? ' +server' : ''