rubocop 1.69.2 → 1.71.1

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 (248) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +36 -2
  5. data/lib/rubocop/cli/command/execute_runner.rb +3 -3
  6. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  7. data/lib/rubocop/comment_config.rb +1 -1
  8. data/lib/rubocop/config.rb +13 -4
  9. data/lib/rubocop/config_loader.rb +4 -0
  10. data/lib/rubocop/config_loader_resolver.rb +14 -3
  11. data/lib/rubocop/config_validator.rb +18 -8
  12. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  13. data/lib/rubocop/cop/base.rb +6 -0
  14. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  15. data/lib/rubocop/cop/bundler/gem_comment.rb +1 -1
  16. data/lib/rubocop/cop/internal_affairs/cop_enabled.rb +85 -0
  17. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  18. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  19. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  20. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  21. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  22. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  23. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  24. data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +4 -3
  25. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  26. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  27. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  28. data/lib/rubocop/cop/internal_affairs.rb +4 -0
  29. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -8
  31. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  32. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  33. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  34. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -5
  35. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -0
  36. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  37. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  38. data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
  39. data/lib/rubocop/cop/layout/first_argument_indentation.rb +3 -8
  40. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -7
  41. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -7
  42. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  43. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  44. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -4
  45. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -0
  46. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +7 -1
  47. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -2
  48. data/lib/rubocop/cop/layout/line_length.rb +1 -0
  49. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  50. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +25 -0
  51. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  52. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  53. data/lib/rubocop/cop/layout/redundant_line_break.rb +7 -6
  54. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  55. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  56. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  57. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  58. data/lib/rubocop/cop/layout/space_after_method_name.rb +1 -1
  59. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  60. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  61. data/lib/rubocop/cop/layout/space_around_operators.rb +3 -3
  62. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  63. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  64. data/lib/rubocop/cop/layout/trailing_whitespace.rb +5 -3
  65. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  66. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  67. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  68. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  69. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  70. data/lib/rubocop/cop/lint/constant_reassignment.rb +148 -0
  71. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  72. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  73. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  74. data/lib/rubocop/cop/lint/duplicate_set_element.rb +20 -7
  75. data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
  76. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  77. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  78. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  79. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +24 -6
  80. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  81. data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
  82. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  83. data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -4
  84. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  85. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +4 -3
  86. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  87. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +18 -31
  88. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  89. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  90. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  91. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  92. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  93. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
  94. data/lib/rubocop/cop/lint/shared_mutable_default.rb +65 -0
  95. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  96. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  97. data/lib/rubocop/cop/lint/syntax.rb +4 -1
  98. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +1 -4
  99. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  100. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  101. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  102. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  103. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  104. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  105. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  106. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  107. data/lib/rubocop/cop/lint/void.rb +4 -3
  108. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  109. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  110. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  111. data/lib/rubocop/cop/metrics/method_length.rb +8 -1
  112. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  113. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  114. data/lib/rubocop/cop/mixin/check_line_breakable.rb +11 -11
  115. data/lib/rubocop/cop/mixin/comments_help.rb +3 -1
  116. data/lib/rubocop/cop/mixin/dig_help.rb +1 -1
  117. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  118. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -4
  119. data/lib/rubocop/cop/mixin/hash_subset.rb +188 -0
  120. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  121. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +48 -24
  122. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  123. data/lib/rubocop/cop/mixin/statement_modifier.rb +8 -3
  124. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  125. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -1
  126. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -3
  127. data/lib/rubocop/cop/naming/block_forwarding.rb +19 -15
  128. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  129. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  130. data/lib/rubocop/cop/style/access_modifier_declarations.rb +34 -5
  131. data/lib/rubocop/cop/style/and_or.rb +1 -1
  132. data/lib/rubocop/cop/style/arguments_forwarding.rb +39 -23
  133. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  134. data/lib/rubocop/cop/style/block_delimiters.rb +7 -20
  135. data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
  136. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  137. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  138. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  139. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  140. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -4
  141. data/lib/rubocop/cop/style/documentation.rb +1 -1
  142. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  143. data/lib/rubocop/cop/style/each_for_simple_loop.rb +4 -7
  144. data/lib/rubocop/cop/style/empty_else.rb +4 -2
  145. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  146. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  147. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  148. data/lib/rubocop/cop/style/exact_regexp_match.rb +3 -10
  149. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  150. data/lib/rubocop/cop/style/exponential_notation.rb +1 -1
  151. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  152. data/lib/rubocop/cop/style/float_division.rb +8 -4
  153. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  154. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -6
  155. data/lib/rubocop/cop/style/hash_except.rb +24 -148
  156. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  157. data/lib/rubocop/cop/style/hash_syntax.rb +6 -3
  158. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  159. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  160. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  161. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  162. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  163. data/lib/rubocop/cop/style/inverse_methods.rb +6 -6
  164. data/lib/rubocop/cop/style/it_assignment.rb +36 -0
  165. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  166. data/lib/rubocop/cop/style/map_into_array.rb +1 -1
  167. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  168. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  169. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +19 -12
  170. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -0
  171. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  172. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  173. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  174. data/lib/rubocop/cop/style/missing_else.rb +2 -0
  175. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  176. data/lib/rubocop/cop/style/multiple_comparison.rb +26 -20
  177. data/lib/rubocop/cop/style/mutable_constant.rb +3 -3
  178. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  179. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  180. data/lib/rubocop/cop/style/object_then.rb +13 -15
  181. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  182. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  183. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  184. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  185. data/lib/rubocop/cop/style/proc.rb +1 -2
  186. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  187. data/lib/rubocop/cop/style/raise_args.rb +6 -4
  188. data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
  189. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  190. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  191. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +2 -1
  192. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  193. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  194. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  195. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  196. data/lib/rubocop/cop/style/redundant_initialize.rb +12 -3
  197. data/lib/rubocop/cop/style/redundant_line_continuation.rb +34 -13
  198. data/lib/rubocop/cop/style/redundant_parentheses.rb +10 -10
  199. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +3 -0
  200. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  201. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  202. data/lib/rubocop/cop/style/redundant_self_assignment.rb +14 -28
  203. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  204. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  205. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  206. data/lib/rubocop/cop/style/safe_navigation.rb +2 -2
  207. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  208. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +2 -1
  209. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  210. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  211. data/lib/rubocop/cop/style/single_line_methods.rb +3 -4
  212. data/lib/rubocop/cop/style/slicing_with_range.rb +40 -11
  213. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -2
  214. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  215. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  216. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  217. data/lib/rubocop/cop/style/super_arguments.rb +65 -17
  218. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  219. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  220. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  221. data/lib/rubocop/cop/style/yoda_condition.rb +8 -4
  222. data/lib/rubocop/cop/style/yoda_expression.rb +2 -1
  223. data/lib/rubocop/cop/util.rb +11 -4
  224. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  225. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  226. data/lib/rubocop/cops_documentation_generator.rb +13 -13
  227. data/lib/rubocop/directive_comment.rb +9 -8
  228. data/lib/rubocop/formatter/formatter_set.rb +1 -1
  229. data/lib/rubocop/lsp/diagnostic.rb +189 -0
  230. data/lib/rubocop/lsp/logger.rb +2 -2
  231. data/lib/rubocop/lsp/routes.rb +7 -23
  232. data/lib/rubocop/lsp/runtime.rb +15 -49
  233. data/lib/rubocop/lsp/stdin_runner.rb +83 -0
  234. data/lib/rubocop/options.rb +2 -1
  235. data/lib/rubocop/path_util.rb +11 -8
  236. data/lib/rubocop/result_cache.rb +13 -13
  237. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  238. data/lib/rubocop/rspec/shared_contexts.rb +4 -1
  239. data/lib/rubocop/rspec/support.rb +1 -2
  240. data/lib/rubocop/runner.rb +5 -6
  241. data/lib/rubocop/target_finder.rb +1 -0
  242. data/lib/rubocop/target_ruby.rb +15 -0
  243. data/lib/rubocop/version.rb +1 -1
  244. data/lib/rubocop.rb +6 -0
  245. data/lib/ruby_lsp/rubocop/addon.rb +78 -0
  246. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +50 -0
  247. metadata +23 -11
  248. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -16,6 +16,11 @@ module RuboCop
16
16
  # Routes for Language Server Protocol of RuboCop.
17
17
  # @api private
18
18
  class Routes
19
+ CONFIGURATION_FILE_PATTERNS = [
20
+ RuboCop::ConfigFinder::DOTFILE,
21
+ RuboCop::CLI::Command::AutoGenerateConfig::AUTO_GENERATED_FILE
22
+ ].freeze
23
+
19
24
  def self.handle(name, &block)
20
25
  define_method(:"handle_#{name}", &block)
21
26
  end
@@ -96,7 +101,7 @@ module RuboCop
96
101
 
97
102
  handle 'workspace/didChangeWatchedFiles' do |request|
98
103
  changed = request[:params][:changes].any? do |change|
99
- change[:uri].end_with?(RuboCop::ConfigFinder::DOTFILE)
104
+ CONFIGURATION_FILE_PATTERNS.any? { |path| change[:uri].end_with?(path) }
100
105
  end
101
106
 
102
107
  if changed
@@ -204,14 +209,12 @@ module RuboCop
204
209
 
205
210
  def diagnostic(file_uri, text)
206
211
  @text_cache[file_uri] = text
207
- offenses = @server.offenses(remove_file_protocol_from(file_uri), text)
208
- diagnostics = offenses.map { |offense| to_diagnostic(offense) }
209
212
 
210
213
  {
211
214
  method: 'textDocument/publishDiagnostics',
212
215
  params: {
213
216
  uri: file_uri,
214
- diagnostics: diagnostics
217
+ diagnostics: @server.offenses(remove_file_protocol_from(file_uri), text)
215
218
  }
216
219
  }
217
220
  end
@@ -219,25 +222,6 @@ module RuboCop
219
222
  def remove_file_protocol_from(uri)
220
223
  uri.delete_prefix('file://')
221
224
  end
222
-
223
- def to_diagnostic(offense)
224
- code = offense[:cop_name]
225
- message = offense[:message]
226
- loc = offense[:location]
227
- rubocop_severity = offense[:severity]
228
- severity = Severity.find_by(rubocop_severity)
229
-
230
- {
231
- code: code, message: message, range: to_range(loc), severity: severity, source: 'rubocop'
232
- }
233
- end
234
-
235
- def to_range(location)
236
- {
237
- start: { character: location[:start_column] - 1, line: location[:start_line] - 1 },
238
- end: { character: location[:last_column], line: location[:last_line] - 1 }
239
- }
240
- end
241
225
  end
242
226
  end
243
227
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'stringio'
3
+ require_relative 'diagnostic'
4
+ require_relative 'stdin_runner'
4
5
 
5
6
  #
6
7
  # This code is based on https://github.com/standardrb/standard.
@@ -19,24 +20,14 @@ module RuboCop
19
20
  attr_writer :safe_autocorrect, :lint_mode, :layout_mode
20
21
 
21
22
  def initialize(config_store)
22
- @config_store = config_store
23
- @logged_paths = []
23
+ @runner = RuboCop::Lsp::StdinRunner.new(config_store)
24
+ @cop_registry = RuboCop::Cop::Registry.global.to_h
25
+
24
26
  @safe_autocorrect = true
25
27
  @lint_mode = false
26
28
  @layout_mode = false
27
29
  end
28
30
 
29
- # This abuses the `--stdin` option of rubocop and reads the formatted text
30
- # from the `options[:stdin]` that rubocop mutates. This depends on
31
- # `parallel: false` as well as the fact that RuboCop doesn't otherwise dup
32
- # or reassign that options object. Risky business!
33
- #
34
- # Reassigning `options[:stdin]` is done here:
35
- # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cop/team.rb#L131
36
- # Printing `options[:stdin]`
37
- # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cli/command/execute_runner.rb#L95
38
- # Setting `parallel: true` would break this here:
39
- # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/runner.rb#L72
40
31
  def format(path, text, command:)
41
32
  safe_autocorrect = if command
42
33
  command == 'rubocop.formatAutocorrects'
@@ -44,34 +35,23 @@ module RuboCop
44
35
  @safe_autocorrect
45
36
  end
46
37
 
47
- formatting_options = {
48
- stdin: text, force_exclusion: true, autocorrect: true, safe_autocorrect: safe_autocorrect
49
- }
38
+ formatting_options = { autocorrect: true, safe_autocorrect: safe_autocorrect }
50
39
  formatting_options[:only] = config_only_options if @lint_mode || @layout_mode
51
40
 
52
- redirect_stdout { run_rubocop(formatting_options, path) }
53
-
54
- formatting_options[:stdin]
41
+ @runner.run(path, text, formatting_options)
42
+ @runner.formatted_source
55
43
  end
56
44
 
57
- def offenses(path, text)
58
- diagnostic_options = {
59
- stdin: text, force_exclusion: true, formatters: ['json'], format: 'json'
60
- }
45
+ def offenses(path, text, document_encoding = nil)
46
+ diagnostic_options = {}
61
47
  diagnostic_options[:only] = config_only_options if @lint_mode || @layout_mode
62
48
 
63
- json = redirect_stdout { run_rubocop(diagnostic_options, path) }
64
- results = JSON.parse(json, symbolize_names: true)
65
-
66
- if results[:files].empty?
67
- unless @logged_paths.include?(path)
68
- Logger.log "Ignoring file, per configuration: #{path}"
69
- @logged_paths << path
70
- end
71
- return []
49
+ @runner.run(path, text, diagnostic_options)
50
+ @runner.offenses.map do |offense|
51
+ Diagnostic.new(
52
+ document_encoding, offense, path, @cop_registry[offense.cop_name]&.first
53
+ ).to_lsp_diagnostic(@runner.config_for_working_directory)
72
54
  end
73
-
74
- results.dig(:files, 0, :offenses)
75
55
  end
76
56
 
77
57
  private
@@ -82,20 +62,6 @@ module RuboCop
82
62
  only_options << 'Layout' if @layout_mode
83
63
  only_options
84
64
  end
85
-
86
- def redirect_stdout(&block)
87
- stdout = StringIO.new
88
-
89
- RuboCop::Server::Helper.redirect(stdout: stdout, &block)
90
-
91
- stdout.string
92
- end
93
-
94
- def run_rubocop(options, path)
95
- runner = RuboCop::Runner.new(options, @config_store)
96
-
97
- runner.run([path])
98
- end
99
65
  end
100
66
  end
101
67
  end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # This code is based on https://github.com/standardrb/standard.
5
+ #
6
+ # Copyright (c) 2023 Test Double, Inc.
7
+ #
8
+ # The MIT License (MIT)
9
+ #
10
+ # https://github.com/standardrb/standard/blob/main/LICENSE.txt
11
+ #
12
+ module RuboCop
13
+ module Lsp
14
+ # Originally lifted from:
15
+ # https://github.com/Shopify/ruby-lsp/blob/8d4c17efce4e8ecc8e7c557ab2981db6b22c0b6d/lib/ruby_lsp/requests/support/rubocop_runner.rb#L20
16
+ # @api private
17
+ class StdinRunner < RuboCop::Runner
18
+ class ConfigurationError < StandardError; end
19
+
20
+ attr_reader :offenses, :config_for_working_directory
21
+
22
+ DEFAULT_RUBOCOP_OPTIONS = {
23
+ stderr: true,
24
+ force_exclusion: true,
25
+ formatters: ['RuboCop::Formatter::BaseFormatter'],
26
+ raise_cop_error: true,
27
+ todo_file: nil,
28
+ todo_ignore_files: []
29
+ }.freeze
30
+
31
+ def initialize(config_store)
32
+ @options = {}
33
+
34
+ @offenses = []
35
+ @warnings = []
36
+ @errors = []
37
+
38
+ @config_for_working_directory = config_store.for_pwd
39
+
40
+ super(@options, config_store)
41
+ end
42
+
43
+ # rubocop:disable Metrics/MethodLength
44
+ def run(path, contents, options)
45
+ @options = options.merge(DEFAULT_RUBOCOP_OPTIONS)
46
+ @options[:stdin] = contents
47
+
48
+ @offenses = []
49
+ @warnings = []
50
+ @errors = []
51
+
52
+ super([path])
53
+
54
+ raise Interrupt if aborting?
55
+ rescue RuboCop::Runner::InfiniteCorrectionLoop => e
56
+ if defined?(::RubyLsp::Requests::Formatting::Error)
57
+ raise ::RubyLsp::Requests::Formatting::Error, e.message
58
+ end
59
+
60
+ raise e
61
+ rescue RuboCop::ValidationError => e
62
+ raise ConfigurationError, e.message
63
+ rescue StandardError => e
64
+ if defined?(::RubyLsp::Requests::Formatting::Error)
65
+ raise ::RubyLsp::Requests::Support::InternalRuboCopError, e
66
+ end
67
+
68
+ raise e
69
+ end
70
+ # rubocop:enable Metrics/MethodLength
71
+
72
+ def formatted_source
73
+ @options[:stdin]
74
+ end
75
+
76
+ private
77
+
78
+ def file_finished(_file, offenses)
79
+ @offenses = offenses
80
+ end
81
+ end
82
+ end
83
+ end
@@ -579,7 +579,8 @@ module RuboCop
579
579
  'when combined with --display-only-correctable.'],
580
580
  show_cops: ['Shows the given cops, or all cops by',
581
581
  'default, and their configurations for the',
582
- 'current directory.'],
582
+ 'current directory.',
583
+ 'You can use `*` as a wildcard.'],
583
584
  show_docs_url: ['Display url to documentation for the given',
584
585
  'cops, or base url by default.'],
585
586
  fail_fast: ['Inspect files in order of modification',
@@ -32,16 +32,19 @@ module RuboCop
32
32
  private_constant :SMART_PATH_CACHE
33
33
 
34
34
  def smart_path(path)
35
- SMART_PATH_CACHE[path] ||= begin
36
- # Ideally, we calculate this relative to the project root.
37
- base_dir = Dir.pwd
38
-
39
- if path.start_with? base_dir
40
- relative_path(path, base_dir)
35
+ SMART_PATH_CACHE[path] ||=
36
+ if path.is_a?(RemoteConfig)
37
+ path.uri.to_s
41
38
  else
42
- path
39
+ # Ideally, we calculate this relative to the project root.
40
+ base_dir = Dir.pwd
41
+
42
+ if path.start_with? base_dir
43
+ relative_path(path, base_dir)
44
+ else
45
+ path
46
+ end
43
47
  end
44
- end
45
48
  end
46
49
 
47
50
  # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -25,16 +25,16 @@ module RuboCop
25
25
  # cleaning should be done relatively seldom, since there is a slight risk
26
26
  # that some other RuboCop process was just about to read the file, when
27
27
  # there's parallel execution and the cache is shared.
28
- def self.cleanup(config_store, verbose, cache_root = nil)
28
+ def self.cleanup(config_store, verbose, cache_root_override = nil)
29
29
  return if inhibit_cleanup # OPTIMIZE: For faster testing
30
30
 
31
- cache_root ||= cache_root(config_store)
32
- return unless File.exist?(cache_root)
31
+ rubocop_cache_dir = cache_root(config_store, cache_root_override)
32
+ return unless File.exist?(rubocop_cache_dir)
33
33
 
34
- files, dirs = Find.find(cache_root).partition { |path| File.file?(path) }
34
+ files, dirs = Find.find(rubocop_cache_dir).partition { |path| File.file?(path) }
35
35
  return unless requires_file_removal?(files.length, config_store)
36
36
 
37
- remove_oldest_files(files, dirs, cache_root, verbose)
37
+ remove_oldest_files(files, dirs, rubocop_cache_dir, verbose)
38
38
  end
39
39
 
40
40
  class << self
@@ -49,11 +49,11 @@ module RuboCop
49
49
  file_count > 1 && file_count > config_store.for_pwd.for_all_cops['MaxFilesInCache']
50
50
  end
51
51
 
52
- def remove_oldest_files(files, dirs, cache_root, verbose)
52
+ def remove_oldest_files(files, dirs, rubocop_cache_dir, verbose)
53
53
  # Add 1 to half the number of files, so that we remove the file if
54
54
  # there's only 1 left.
55
55
  remove_count = (files.length / 2) + 1
56
- puts "Removing the #{remove_count} oldest files from #{cache_root}" if verbose
56
+ puts "Removing the #{remove_count} oldest files from #{rubocop_cache_dir}" if verbose
57
57
  sorted = files.sort_by { |path| File.mtime(path) }
58
58
  remove_files(sorted, dirs, remove_count)
59
59
  rescue Errno::ENOENT
@@ -72,9 +72,9 @@ module RuboCop
72
72
  end
73
73
  end
74
74
 
75
- def self.cache_root(config_store)
75
+ def self.cache_root(config_store, cache_root_override = nil)
76
76
  CacheConfig.root_dir do
77
- config_store.for_pwd.for_all_cops['CacheRootDirectory']
77
+ cache_root_override || config_store.for_pwd.for_all_cops['CacheRootDirectory']
78
78
  end
79
79
  end
80
80
 
@@ -84,12 +84,12 @@ module RuboCop
84
84
 
85
85
  attr_reader :path
86
86
 
87
- def initialize(file, team, options, config_store, cache_root = nil)
88
- cache_root ||= File.join(options[:cache_root], 'rubocop_cache') if options[:cache_root]
89
- cache_root ||= ResultCache.cache_root(config_store)
87
+ def initialize(file, team, options, config_store, cache_root_override = nil)
88
+ cache_root_override ||= options[:cache_root] if options[:cache_root]
89
+ rubocop_cache_dir = ResultCache.cache_root(config_store, cache_root_override)
90
90
  @allow_symlinks_in_cache_location =
91
91
  ResultCache.allow_symlinks_in_cache_location?(config_store)
92
- @path = File.join(cache_root,
92
+ @path = File.join(rubocop_cache_dir,
93
93
  rubocop_checksum,
94
94
  context_checksum(team, options),
95
95
  file_checksum(file, config_store))
@@ -190,7 +190,10 @@ module RuboCop
190
190
  def expect_no_offenses(source, file = nil)
191
191
  offenses = inspect_source(source, file)
192
192
 
193
- expected_annotations = AnnotatedSource.parse(source)
193
+ # Since source given `expect_no_offenses` does not have annotations, we do not need to parse
194
+ # for them, and can just build an `AnnotatedSource` object from the source lines.
195
+ # This also prevents treating source lines that begin with a caret as an annotation.
196
+ expected_annotations = AnnotatedSource.new(source.each_line.to_a, [])
194
197
  actual_annotations = expected_annotations.with_offense_annotations(offenses)
195
198
  expect(actual_annotations.to_s).to eq(source)
196
199
  end
@@ -221,7 +224,8 @@ module RuboCop
221
224
 
222
225
  # Parsed representation of code annotated with the `^^^ Message` style
223
226
  class AnnotatedSource
224
- ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) ?/.freeze
227
+ # Ignore escaped carets, don't treat as annotations
228
+ ANNOTATION_PATTERN = /\A\s*((?<!\\)\^+|\^{}) ?/.freeze
225
229
  ABBREV = "[...]\n"
226
230
 
227
231
  # @param annotated_source [String] string passed to the matchers
@@ -98,6 +98,8 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
98
98
 
99
99
  let(:cop_options) { {} }
100
100
 
101
+ let(:gem_versions) { {} }
102
+
101
103
  ### Utilities
102
104
 
103
105
  def source_range(range, buffer: source_buffer)
@@ -138,7 +140,8 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
138
140
 
139
141
  allow(config).to receive(:gem_versions_in_target).and_return(
140
142
  {
141
- 'railties' => rails_version_in_gemfile
143
+ 'railties' => rails_version_in_gemfile,
144
+ **gem_versions.transform_values { |value| Gem::Version.new(value) }
142
145
  }
143
146
  )
144
147
 
@@ -4,13 +4,12 @@
4
4
 
5
5
  require_relative 'cop_helper'
6
6
  require_relative 'expect_offense'
7
- require_relative 'host_environment_simulation_helper'
8
7
  require_relative 'parallel_formatter'
9
8
  require_relative 'shared_contexts'
10
9
 
11
10
  RSpec.configure do |config|
12
11
  config.include CopHelper
13
- config.include HostEnvironmentSimulatorHelper
12
+ config.include RuboCop::RSpec::ExpectOffense
14
13
  config.include_context 'config', :config
15
14
  config.include_context 'isolated environment', :isolated_environment
16
15
  config.include_context 'isolated bundler', :isolated_bundler
@@ -20,11 +20,7 @@ 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 += "\n"
24
- hint = 'Hint: Please update to the latest RuboCop version if not already in use, ' \
25
- "and report a bug if the issue still occurs on this version.\n" \
26
- 'Please check the latest version at https://rubygems.org/gems/rubocop.'
27
- super(Rainbow(message).red + Rainbow(hint).yellow)
23
+ super(message)
28
24
  end
29
25
  end
30
26
 
@@ -157,8 +153,11 @@ module RuboCop
157
153
  file_started(file)
158
154
  offenses = file_offenses(file)
159
155
  rescue InfiniteCorrectionLoop => e
156
+ raise e if @options[:raise_cop_error]
157
+
158
+ errors << e
159
+ warn Rainbow(e.message).red
160
160
  offenses = e.offenses.compact.sort.freeze
161
- raise
162
161
  ensure
163
162
  file_finished(file, offenses || [])
164
163
  end
@@ -127,6 +127,7 @@ module RuboCop
127
127
  if mode == :only_recognized_file_types || force_exclusion?
128
128
  files.select! { |file| included_file?(file) }
129
129
  end
130
+ files.reject! { |file| FileTest.directory?(file) }
130
131
 
131
132
  force_exclusion? ? without_excluded(files) : files
132
133
  end
@@ -34,6 +34,20 @@ module RuboCop
34
34
  end
35
35
  end
36
36
 
37
+ # The target ruby version may be configured by setting the
38
+ # `RUBOCOP_TARGET_RUBY_VERSION` environment variable.
39
+ class RuboCopEnvVar < Source
40
+ def name
41
+ '`RUBOCOP_TARGET_RUBY_VERSION` environment variable'
42
+ end
43
+
44
+ private
45
+
46
+ def find_version
47
+ ENV.fetch('RUBOCOP_TARGET_RUBY_VERSION', nil)&.to_f
48
+ end
49
+ end
50
+
37
51
  # The target ruby version may be configured in RuboCop's config.
38
52
  # @api private
39
53
  class RuboCopConfig < Source
@@ -246,6 +260,7 @@ module RuboCop
246
260
  end
247
261
 
248
262
  SOURCES = [
263
+ RuboCopEnvVar,
249
264
  RuboCopConfig,
250
265
  GemspecFile,
251
266
  RubyVersionFile,
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.69.2'
6
+ STRING = '1.71.1'
7
7
 
8
8
  MSG = '%<version>s (using %<parser_version>s, ' \
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
data/lib/rubocop.rb CHANGED
@@ -100,6 +100,7 @@ require_relative 'rubocop/cop/mixin/frozen_string_literal'
100
100
  require_relative 'rubocop/cop/mixin/gem_declaration'
101
101
  require_relative 'rubocop/cop/mixin/gemspec_help'
102
102
  require_relative 'rubocop/cop/mixin/hash_alignment_styles'
103
+ require_relative 'rubocop/cop/mixin/hash_subset'
103
104
  require_relative 'rubocop/cop/mixin/hash_transform_method'
104
105
  require_relative 'rubocop/cop/mixin/integer_node'
105
106
  require_relative 'rubocop/cop/mixin/interpolation'
@@ -293,6 +294,7 @@ require_relative 'rubocop/cop/lint/ambiguous_operator'
293
294
  require_relative 'rubocop/cop/lint/ambiguous_operator_precedence'
294
295
  require_relative 'rubocop/cop/lint/ambiguous_range'
295
296
  require_relative 'rubocop/cop/lint/ambiguous_regexp_literal'
297
+ require_relative 'rubocop/cop/lint/array_literal_in_regexp'
296
298
  require_relative 'rubocop/cop/lint/assignment_in_condition'
297
299
  require_relative 'rubocop/cop/lint/big_decimal_new'
298
300
  require_relative 'rubocop/cop/lint/binary_operator_with_identical_operands'
@@ -300,6 +302,7 @@ require_relative 'rubocop/cop/lint/boolean_symbol'
300
302
  require_relative 'rubocop/cop/lint/circular_argument_reference'
301
303
  require_relative 'rubocop/cop/lint/constant_definition_in_block'
302
304
  require_relative 'rubocop/cop/lint/constant_overwritten_in_rescue'
305
+ require_relative 'rubocop/cop/lint/constant_reassignment'
303
306
  require_relative 'rubocop/cop/lint/constant_resolution'
304
307
  require_relative 'rubocop/cop/lint/debugger'
305
308
  require_relative 'rubocop/cop/lint/deprecated_class_methods'
@@ -329,6 +332,7 @@ require_relative 'rubocop/cop/lint/empty_in_pattern'
329
332
  require_relative 'rubocop/cop/lint/empty_interpolation'
330
333
  require_relative 'rubocop/cop/lint/empty_when'
331
334
  require_relative 'rubocop/cop/lint/ensure_return'
335
+ require_relative 'rubocop/cop/lint/shared_mutable_default'
332
336
  require_relative 'rubocop/cop/lint/erb_new_arguments'
333
337
  require_relative 'rubocop/cop/lint/flip_flop'
334
338
  require_relative 'rubocop/cop/lint/float_comparison'
@@ -557,6 +561,7 @@ require_relative 'rubocop/cop/style/hash_conversion'
557
561
  require_relative 'rubocop/cop/style/hash_each_methods'
558
562
  require_relative 'rubocop/cop/style/hash_except'
559
563
  require_relative 'rubocop/cop/style/hash_like_case'
564
+ require_relative 'rubocop/cop/style/hash_slice'
560
565
  require_relative 'rubocop/cop/style/hash_syntax'
561
566
  require_relative 'rubocop/cop/style/hash_transform_keys'
562
567
  require_relative 'rubocop/cop/style/hash_transform_values'
@@ -573,6 +578,7 @@ require_relative 'rubocop/cop/style/inverse_methods'
573
578
  require_relative 'rubocop/cop/style/inline_comment'
574
579
  require_relative 'rubocop/cop/style/invertible_unless_condition'
575
580
  require_relative 'rubocop/cop/style/ip_addresses'
581
+ require_relative 'rubocop/cop/style/it_assignment'
576
582
  require_relative 'rubocop/cop/style/keyword_arguments_merging'
577
583
  require_relative 'rubocop/cop/style/keyword_parameters_order'
578
584
  require_relative 'rubocop/cop/style/lambda'
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../rubocop'
4
+ require_relative '../../rubocop/lsp/logger'
5
+ require_relative 'wraps_built_in_lsp_runtime'
6
+
7
+ module RubyLsp
8
+ module RuboCop
9
+ # A Ruby LSP add-on for RuboCop.
10
+ class Addon < RubyLsp::Addon
11
+ def initializer
12
+ @wraps_built_in_lsp_runtime = nil
13
+ end
14
+
15
+ def name
16
+ 'RuboCop'
17
+ end
18
+
19
+ def activate(global_state, message_queue)
20
+ ::RuboCop::LSP::Logger.log(
21
+ "Activating RuboCop LSP addon #{::RuboCop::Version::STRING}.", prefix: '[RuboCop]'
22
+ )
23
+
24
+ ::RuboCop::LSP.enable
25
+ @wraps_built_in_lsp_runtime = WrapsBuiltinLspRuntime.new
26
+
27
+ global_state.register_formatter('rubocop', @wraps_built_in_lsp_runtime)
28
+
29
+ register_additional_file_watchers(global_state, message_queue)
30
+
31
+ ::RuboCop::LSP::Logger.log(
32
+ "Initialized RuboCop LSP addon #{::RuboCop::Version::STRING}.", prefix: '[RuboCop]'
33
+ )
34
+ end
35
+
36
+ def deactivate
37
+ @wraps_built_in_lsp_runtime = nil
38
+ end
39
+
40
+ # rubocop:disable Layout/LineLength, Metrics/MethodLength
41
+ def register_additional_file_watchers(global_state, message_queue)
42
+ return unless global_state.supports_watching_files
43
+
44
+ message_queue << Request.new(
45
+ id: 'rubocop-file-watcher',
46
+ method: 'client/registerCapability',
47
+ params: Interface::RegistrationParams.new(
48
+ registrations: [
49
+ Interface::Registration.new(
50
+ id: 'workspace/didChangeWatchedFilesRuboCop',
51
+ method: 'workspace/didChangeWatchedFiles',
52
+ register_options: Interface::DidChangeWatchedFilesRegistrationOptions.new(
53
+ watchers: [
54
+ Interface::FileSystemWatcher.new(
55
+ glob_pattern: '**/.rubocop{,_todo}.yml',
56
+ kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE
57
+ )
58
+ ]
59
+ )
60
+ )
61
+ ]
62
+ )
63
+ )
64
+ end
65
+ # rubocop:enable Layout/LineLength, Metrics/MethodLength
66
+
67
+ def workspace_did_change_watched_files(changes)
68
+ return unless changes.any? { |change| change[:uri].end_with?('.rubocop.yml') }
69
+
70
+ @wraps_built_in_lsp_runtime.init!
71
+
72
+ ::RuboCop::LSP::Logger(<<~MESSAGE, prefix: '[RuboCop]')
73
+ Re-initialized RuboCop LSP addon #{::RuboCop::Version::STRING} due to .rubocop.yml file change.
74
+ MESSAGE
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../rubocop/lsp/runtime'
4
+
5
+ module RubyLsp
6
+ module RuboCop
7
+ # Wrap RuboCop's built-in runtime for Ruby LSP's add-on.
8
+ class WrapsBuiltinLspRuntime
9
+ include RubyLsp::Requests::Support::Formatter
10
+
11
+ def initialize
12
+ init!
13
+ end
14
+
15
+ def init!
16
+ config = ::RuboCop::ConfigStore.new
17
+
18
+ @runtime = ::RuboCop::LSP::Runtime.new(config)
19
+ end
20
+
21
+ def run_diagnostic(uri, document)
22
+ @runtime.offenses(uri_to_path(uri), document.source, document.encoding)
23
+ end
24
+
25
+ def run_formatting(uri, document)
26
+ @runtime.format(uri_to_path(uri), document.source, command: 'rubocop.formatAutocorrects')
27
+ end
28
+
29
+ def run_range_formatting(_uri, _partial_source, _base_indentation)
30
+ # Not yet supported. Should return the formatted version of `partial_source` which is
31
+ # a partial selection of the entire document. For example, it should not try to add
32
+ # a frozen_string_literal magic comment and all style corrections should start from
33
+ # the `base_indentation`.
34
+ nil
35
+ end
36
+
37
+ private
38
+
39
+ # duplicated from: lib/standard/lsp/routes.rb
40
+ # modified to incorporate Ruby LSP's to_standardized_path method
41
+ def uri_to_path(uri)
42
+ if uri.respond_to?(:to_standardized_path) && (standardized_path = uri.to_standardized_path)
43
+ standardized_path
44
+ else
45
+ uri.to_s.delete_prefix('file://')
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end