rubocop 1.50.2 → 1.62.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (339) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +7 -5
  4. data/assets/output.css.erb +159 -0
  5. data/assets/output.html.erb +1 -160
  6. data/config/default.yml +196 -28
  7. data/config/obsoletion.yml +5 -0
  8. data/lib/rubocop/cli/command/auto_generate_config.rb +22 -8
  9. data/lib/rubocop/cli/command/lsp.rb +19 -0
  10. data/lib/rubocop/cli.rb +10 -2
  11. data/lib/rubocop/config.rb +8 -2
  12. data/lib/rubocop/config_finder.rb +14 -4
  13. data/lib/rubocop/config_loader.rb +0 -1
  14. data/lib/rubocop/config_loader_resolver.rb +4 -3
  15. data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
  16. data/lib/rubocop/config_obsoletion.rb +13 -10
  17. data/lib/rubocop/config_validator.rb +14 -7
  18. data/lib/rubocop/cop/autocorrect_logic.rb +9 -2
  19. data/lib/rubocop/cop/base.rb +23 -4
  20. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
  21. data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  23. data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
  24. data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
  25. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  26. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
  27. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
  28. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
  29. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  30. data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
  31. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  32. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  33. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
  34. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
  35. data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
  36. data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
  37. data/lib/rubocop/cop/internal_affairs/example_description.rb +45 -24
  38. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
  39. data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
  40. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  41. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  42. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +127 -33
  43. data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
  44. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
  45. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
  46. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  47. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  48. data/lib/rubocop/cop/layout/class_structure.rb +7 -0
  49. data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
  50. data/lib/rubocop/cop/layout/dot_position.rb +1 -5
  51. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
  52. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
  53. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
  54. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
  55. data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
  56. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  57. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  58. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  59. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
  60. data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
  61. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  62. data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
  63. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  64. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
  65. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  66. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
  67. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
  68. data/lib/rubocop/cop/layout/redundant_line_break.rb +30 -7
  69. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  70. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  71. data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
  72. data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
  73. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
  74. data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
  75. data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
  76. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  77. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
  78. data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
  79. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
  80. data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
  81. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
  82. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  83. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  84. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  85. data/lib/rubocop/cop/lint/debugger.rb +19 -5
  86. data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
  87. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  88. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
  89. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  90. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  91. data/lib/rubocop/cop/lint/erb_new_arguments.rb +6 -7
  92. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  93. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  94. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
  95. data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
  96. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
  97. data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
  98. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  99. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  100. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  101. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  102. data/lib/rubocop/cop/lint/missing_super.rb +34 -5
  103. data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
  104. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  105. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
  106. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  107. data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
  108. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  109. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
  110. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  111. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
  112. data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
  113. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
  114. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  115. data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
  116. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  117. data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
  118. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
  119. data/lib/rubocop/cop/lint/script_permission.rb +3 -3
  120. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  121. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
  122. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  123. data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
  124. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
  125. data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
  126. data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
  127. data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
  128. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  129. data/lib/rubocop/cop/lint/to_enum_arguments.rb +12 -5
  130. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  131. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  132. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  133. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  134. data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
  135. data/lib/rubocop/cop/lint/useless_times.rb +2 -2
  136. data/lib/rubocop/cop/lint/void.rb +97 -11
  137. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  138. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  139. data/lib/rubocop/cop/metrics/class_length.rb +8 -3
  140. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  141. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  142. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
  143. data/lib/rubocop/cop/migration/department_name.rb +2 -2
  144. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  145. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  146. data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
  147. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  148. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  149. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  150. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
  151. data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
  152. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
  153. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  154. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
  155. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  156. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  157. data/lib/rubocop/cop/mixin/string_help.rb +4 -2
  158. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  159. data/lib/rubocop/cop/naming/block_forwarding.rb +13 -5
  160. data/lib/rubocop/cop/naming/constant_name.rb +2 -3
  161. data/lib/rubocop/cop/naming/file_name.rb +1 -1
  162. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
  163. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
  164. data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
  165. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  166. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  167. data/lib/rubocop/cop/registry.rb +1 -1
  168. data/lib/rubocop/cop/security/open.rb +2 -2
  169. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  170. data/lib/rubocop/cop/style/accessor_grouping.rb +6 -2
  171. data/lib/rubocop/cop/style/alias.rb +9 -8
  172. data/lib/rubocop/cop/style/arguments_forwarding.rb +411 -63
  173. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  174. data/lib/rubocop/cop/style/array_intersect.rb +13 -5
  175. data/lib/rubocop/cop/style/attr.rb +11 -1
  176. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  177. data/lib/rubocop/cop/style/begin_block.rb +1 -2
  178. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  179. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  180. data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
  181. data/lib/rubocop/cop/style/case_like_if.rb +5 -5
  182. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  183. data/lib/rubocop/cop/style/class_check.rb +1 -0
  184. data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
  185. data/lib/rubocop/cop/style/class_vars.rb +3 -3
  186. data/lib/rubocop/cop/style/collection_compact.rb +32 -12
  187. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  188. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  189. data/lib/rubocop/cop/style/combinable_loops.rb +36 -8
  190. data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
  191. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
  192. data/lib/rubocop/cop/style/conditional_assignment.rb +11 -10
  193. data/lib/rubocop/cop/style/copyright.rb +5 -2
  194. data/lib/rubocop/cop/style/date_time.rb +5 -4
  195. data/lib/rubocop/cop/style/dir.rb +1 -1
  196. data/lib/rubocop/cop/style/dir_empty.rb +8 -14
  197. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
  198. data/lib/rubocop/cop/style/documentation.rb +1 -1
  199. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  200. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  201. data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
  202. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  203. data/lib/rubocop/cop/style/eval_with_location.rb +8 -19
  204. data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
  205. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  206. data/lib/rubocop/cop/style/file_read.rb +2 -2
  207. data/lib/rubocop/cop/style/for.rb +3 -1
  208. data/lib/rubocop/cop/style/format_string.rb +24 -3
  209. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
  210. data/lib/rubocop/cop/style/guard_clause.rb +28 -0
  211. data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
  212. data/lib/rubocop/cop/style/hash_each_methods.rb +106 -33
  213. data/lib/rubocop/cop/style/hash_except.rb +21 -9
  214. data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
  215. data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
  216. data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
  217. data/lib/rubocop/cop/style/identical_conditional_branches.rb +34 -5
  218. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  219. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  220. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  221. data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
  222. data/lib/rubocop/cop/style/invertible_unless_condition.rb +54 -8
  223. data/lib/rubocop/cop/style/lambda.rb +3 -3
  224. data/lib/rubocop/cop/style/lambda_call.rb +5 -0
  225. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
  226. data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
  227. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +24 -9
  228. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  229. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  230. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  231. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  232. data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
  233. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  234. data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
  235. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
  236. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  237. data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
  238. data/lib/rubocop/cop/style/next.rb +1 -1
  239. data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
  240. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  241. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  242. data/lib/rubocop/cop/style/object_then.rb +5 -3
  243. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  244. data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
  245. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
  246. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  247. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  248. data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
  249. data/lib/rubocop/cop/style/raise_args.rb +4 -1
  250. data/lib/rubocop/cop/style/redundant_argument.rb +10 -4
  251. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  252. data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
  253. data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
  254. data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
  255. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +39 -0
  256. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
  257. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  258. data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
  259. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  260. data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
  261. data/lib/rubocop/cop/style/redundant_line_continuation.rb +32 -8
  262. data/lib/rubocop/cop/style/redundant_parentheses.rb +72 -23
  263. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
  264. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  265. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
  266. data/lib/rubocop/cop/style/redundant_return.rb +14 -3
  267. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  268. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
  269. data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
  270. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  271. data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
  272. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  273. data/lib/rubocop/cop/style/require_order.rb +11 -5
  274. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  275. data/lib/rubocop/cop/style/return_nil.rb +6 -2
  276. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
  277. data/lib/rubocop/cop/style/sample.rb +3 -4
  278. data/lib/rubocop/cop/style/select_by_regexp.rb +22 -11
  279. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  280. data/lib/rubocop/cop/style/semicolon.rb +20 -4
  281. data/lib/rubocop/cop/style/signal_exception.rb +1 -1
  282. data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
  283. data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
  284. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  285. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  286. data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -2
  287. data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
  288. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  289. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
  290. data/lib/rubocop/cop/style/strip.rb +7 -4
  291. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  292. data/lib/rubocop/cop/style/symbol_array.rb +35 -15
  293. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  294. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  295. data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
  296. data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
  297. data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
  298. data/lib/rubocop/cop/team.rb +1 -1
  299. data/lib/rubocop/cop/util.rb +1 -1
  300. data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
  301. data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
  302. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  303. data/lib/rubocop/cop/variable_force.rb +1 -0
  304. data/lib/rubocop/cops_documentation_generator.rb +16 -4
  305. data/lib/rubocop/directive_comment.rb +10 -8
  306. data/lib/rubocop/ext/regexp_node.rb +9 -4
  307. data/lib/rubocop/ext/regexp_parser.rb +4 -1
  308. data/lib/rubocop/file_finder.rb +4 -7
  309. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  310. data/lib/rubocop/formatter/html_formatter.rb +35 -14
  311. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  312. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  313. data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
  314. data/lib/rubocop/formatter.rb +1 -1
  315. data/lib/rubocop/lsp/logger.rb +22 -0
  316. data/lib/rubocop/lsp/routes.rb +246 -0
  317. data/lib/rubocop/lsp/runtime.rb +99 -0
  318. data/lib/rubocop/lsp/server.rb +71 -0
  319. data/lib/rubocop/lsp/severity.rb +27 -0
  320. data/lib/rubocop/lsp.rb +29 -0
  321. data/lib/rubocop/magic_comment.rb +13 -11
  322. data/lib/rubocop/options.rb +22 -9
  323. data/lib/rubocop/path_util.rb +6 -2
  324. data/lib/rubocop/result_cache.rb +5 -2
  325. data/lib/rubocop/rspec/cop_helper.rb +8 -2
  326. data/lib/rubocop/rspec/expect_offense.rb +8 -8
  327. data/lib/rubocop/rspec/shared_contexts.rb +42 -18
  328. data/lib/rubocop/rspec/support.rb +2 -0
  329. data/lib/rubocop/runner.rb +15 -6
  330. data/lib/rubocop/server/cache.rb +1 -1
  331. data/lib/rubocop/server/client_command/exec.rb +3 -3
  332. data/lib/rubocop/server/server_command/exec.rb +0 -1
  333. data/lib/rubocop/string_interpreter.rb +3 -3
  334. data/lib/rubocop/target_finder.rb +91 -81
  335. data/lib/rubocop/target_ruby.rb +85 -78
  336. data/lib/rubocop/version.rb +27 -8
  337. data/lib/rubocop.rb +19 -0
  338. metadata +56 -14
  339. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'language_server-protocol'
4
+ require_relative '../lsp'
5
+ require_relative 'logger'
6
+ require_relative 'routes'
7
+ require_relative 'runtime'
8
+
9
+ #
10
+ # This code is based on https://github.com/standardrb/standard.
11
+ #
12
+ # Copyright (c) 2023 Test Double, Inc.
13
+ #
14
+ # The MIT License (MIT)
15
+ #
16
+ # https://github.com/standardrb/standard/blob/main/LICENSE.txt
17
+ #
18
+ module RuboCop
19
+ module LSP
20
+ # Language Server Protocol of RuboCop.
21
+ # @api private
22
+ class Server
23
+ def initialize(config_store)
24
+ RuboCop::LSP.enable
25
+
26
+ @reader = LanguageServer::Protocol::Transport::Io::Reader.new($stdin)
27
+ @writer = LanguageServer::Protocol::Transport::Io::Writer.new($stdout)
28
+ @runtime = RuboCop::LSP::Runtime.new(config_store)
29
+ @routes = Routes.new(self)
30
+ end
31
+
32
+ def start
33
+ @reader.read do |request|
34
+ if !request.key?(:method)
35
+ @routes.handle_method_missing(request)
36
+ elsif (route = @routes.for(request[:method]))
37
+ route.call(request)
38
+ else
39
+ @routes.handle_unsupported_method(request)
40
+ end
41
+ rescue StandardError => e
42
+ Logger.log("Error #{e.class} #{e.message[0..100]}")
43
+ Logger.log(e.backtrace.inspect)
44
+ end
45
+ end
46
+
47
+ def write(response)
48
+ @writer.write(response)
49
+ end
50
+
51
+ def format(path, text, command:)
52
+ @runtime.format(path, text, command: command)
53
+ end
54
+
55
+ def offenses(path, text)
56
+ @runtime.offenses(path, text)
57
+ end
58
+
59
+ def configure(options)
60
+ @runtime.safe_autocorrect = options[:safe_autocorrect]
61
+ @runtime.lint_mode = options[:lint_mode]
62
+ @runtime.layout_mode = options[:layout_mode]
63
+ end
64
+
65
+ def stop(&block)
66
+ at_exit(&block) if block
67
+ exit
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module LSP
5
+ # Severity for Language Server Protocol of RuboCop.
6
+ # @api private
7
+ class Severity
8
+ SEVERITIES = {
9
+ fatal: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
10
+ error: LanguageServer::Protocol::Constant::DiagnosticSeverity::ERROR,
11
+ warning: LanguageServer::Protocol::Constant::DiagnosticSeverity::WARNING,
12
+ convention: LanguageServer::Protocol::Constant::DiagnosticSeverity::INFORMATION,
13
+ refactor: LanguageServer::Protocol::Constant::DiagnosticSeverity::HINT,
14
+ info: LanguageServer::Protocol::Constant::DiagnosticSeverity::HINT
15
+ }.freeze
16
+
17
+ def self.find_by(rubocop_severity)
18
+ if (severity = SEVERITIES[rubocop_severity.to_sym])
19
+ return severity
20
+ end
21
+
22
+ Logger.log("Unknown severity: #{rubocop_severity}")
23
+ LanguageServer::Protocol::Constant::DiagnosticSeverity::HINT
24
+ end
25
+ end
26
+ end
27
+ end
@@ -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
@@ -7,7 +7,7 @@ module RuboCop
7
7
  class MagicComment
8
8
  # IRB's pattern for matching magic comment tokens.
9
9
  # @see https://github.com/ruby/ruby/blob/b4a55c1/lib/irb/magic-file.rb#L5
10
- TOKEN = /[[:alnum:]\-_]+/.freeze
10
+ TOKEN = '(?<token>[[:alnum:]\-_]+)'
11
11
  KEYWORDS = {
12
12
  encoding: '(?:en)?coding',
13
13
  frozen_string_literal: 'frozen[_-]string[_-]literal',
@@ -129,7 +129,7 @@ module RuboCop
129
129
  # @return [String] if pattern matched
130
130
  # @return [nil] otherwise
131
131
  def extract(pattern)
132
- @comment[pattern, 1]
132
+ @comment[pattern, :token]
133
133
  end
134
134
 
135
135
  # Parent to Vim and Emacs magic comment handling.
@@ -157,10 +157,10 @@ module RuboCop
157
157
  # @return [String] extracted value if it is found
158
158
  # @return [nil] otherwise
159
159
  def match(keyword)
160
- pattern = /\A#{keyword}\s*#{self.class::OPERATOR}\s*(#{TOKEN})\z/
160
+ pattern = /\A#{keyword}\s*#{self.class::OPERATOR}\s*#{TOKEN}\z/
161
161
 
162
162
  tokens.each do |token|
163
- next unless (value = token[pattern, 1])
163
+ next unless (value = token[pattern, :token])
164
164
 
165
165
  return value.downcase
166
166
  end
@@ -188,7 +188,7 @@ module RuboCop
188
188
  # @see https://www.gnu.org/software/emacs/manual/html_node/emacs/Specify-Coding.html
189
189
  # @see https://github.com/ruby/ruby/blob/3f306dc/parse.y#L6873-L6892 Emacs handling in parse.y
190
190
  class EmacsComment < EditorComment
191
- REGEXP = /-\*-(.+)-\*-/.freeze
191
+ REGEXP = /-\*-(?<token>.+)-\*-/.freeze
192
192
  FORMAT = '# -*- %s -*-'
193
193
  SEPARATOR = ';'
194
194
  OPERATOR = ':'
@@ -216,7 +216,7 @@ module RuboCop
216
216
  #
217
217
  # comment.encoding # => 'ascii-8bit'
218
218
  class VimComment < EditorComment
219
- REGEXP = /#\s*vim:\s*(.+)/.freeze
219
+ REGEXP = /#\s*vim:\s*(?<token>.+)/.freeze
220
220
  FORMAT = '# vim: %s'
221
221
  SEPARATOR = ', '
222
222
  OPERATOR = '='
@@ -259,14 +259,16 @@ module RuboCop
259
259
  # comment2.frozen_string_literal # => nil
260
260
  # comment2.encoding # => 'utf-8'
261
261
  class SimpleComment < MagicComment
262
+ FSTRING_LITERAL_COMMENT = 'frozen_string_literal:\s*(true|false)'
263
+
262
264
  # Match `encoding` or `coding`
263
265
  def encoding
264
- extract(/\A\s*\#.*\b#{KEYWORDS[:encoding]}: (#{TOKEN})/io)
266
+ extract(/\A\s*\#\s*(#{FSTRING_LITERAL_COMMENT})?\s*#{KEYWORDS[:encoding]}: (#{TOKEN})/io)
265
267
  end
266
268
 
267
269
  # Rewrite the comment without a given token type
268
270
  def without(type)
269
- if @comment.match?(/\A#\s*#{self.class::KEYWORDS[type.to_sym]}/)
271
+ if @comment.match?(/\A#\s*#{self.class::KEYWORDS[type.to_sym]}/io)
270
272
  ''
271
273
  else
272
274
  @comment
@@ -283,15 +285,15 @@ module RuboCop
283
285
  # Case-insensitive and dashes/underscores are acceptable.
284
286
  # @see https://github.com/ruby/ruby/blob/78b95b4/parse.y#L7134-L7138
285
287
  def extract_frozen_string_literal
286
- extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*(#{TOKEN})\s*\z/io)
288
+ extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*#{TOKEN}\s*\z/io)
287
289
  end
288
290
 
289
291
  def extract_shareable_constant_value
290
- extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*(#{TOKEN})\s*\z/io)
292
+ extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*#{TOKEN}\s*\z/io)
291
293
  end
292
294
 
293
295
  def extract_typed
294
- extract(/\A\s*#\s*#{KEYWORDS[:typed]}:\s*(#{TOKEN})\s*\z/io)
296
+ extract(/\A\s*#\s*#{KEYWORDS[:typed]}:\s*#{TOKEN}\s*\z/io)
295
297
  end
296
298
  end
297
299
  end
@@ -16,7 +16,7 @@ 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].freeze
19
+ EXITING_OPTIONS = %i[version verbose_version show_cops show_docs_url lsp].freeze
20
20
  DEFAULT_MAXIMUM_EXCLUSION_ITEMS = 15
21
21
 
22
22
  def initialize
@@ -49,12 +49,14 @@ module RuboCop
49
49
 
50
50
  private
51
51
 
52
+ # rubocop:disable Metrics/AbcSize
52
53
  def define_options
53
54
  OptionParser.new do |opts|
54
55
  opts.banner = rainbow.wrap('Usage: rubocop [options] [file1, file2, ...]').bright
55
56
 
56
57
  add_check_options(opts)
57
58
  add_cache_options(opts)
59
+ add_lsp_option(opts)
58
60
  add_server_options(opts)
59
61
  add_output_options(opts)
60
62
  add_autocorrection_options(opts)
@@ -66,6 +68,7 @@ module RuboCop
66
68
  add_profile_options(opts) if RUBY_ENGINE == 'ruby' && !Platform.windows?
67
69
  end
68
70
  end
71
+ # rubocop:enable Metrics/AbcSize
69
72
 
70
73
  def add_check_options(opts) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
71
74
  section(opts, 'Basic Options') do # rubocop:disable Metrics/BlockLength
@@ -92,6 +95,7 @@ module RuboCop
92
95
  option(opts, '--ignore-unrecognized-cops')
93
96
  option(opts, '--force-default-config')
94
97
  option(opts, '-s', '--stdin FILE')
98
+ option(opts, '--editor-mode')
95
99
  option(opts, '-P', '--[no-]parallel')
96
100
  option(opts, '--raise-cop-error')
97
101
  add_severity_option(opts)
@@ -205,6 +209,12 @@ module RuboCop
205
209
  end
206
210
  end
207
211
 
212
+ def add_lsp_option(opts)
213
+ section(opts, 'LSP Option') do
214
+ option(opts, '--lsp')
215
+ end
216
+ end
217
+
208
218
  def add_server_options(opts)
209
219
  section(opts, 'Server Options') do
210
220
  option(opts, '--[no-]server')
@@ -355,15 +365,12 @@ module RuboCop
355
365
  raise OptionArgumentError, '-C/--cache argument must be true or false'
356
366
  end
357
367
 
358
- if display_only_fail_level_offenses_with_autocorrect?
359
- raise OptionArgumentError, '--autocorrect cannot be used with ' \
360
- '--display-only-fail-level-offenses.'
361
- end
362
368
  validate_auto_gen_config
363
369
  validate_autocorrect
364
370
  validate_display_only_failed
365
371
  validate_display_only_failed_and_display_only_correctable
366
372
  validate_display_only_correctable_and_autocorrect
373
+ validate_lsp_and_editor_mode
367
374
  disable_parallel_when_invalid_option_combo
368
375
 
369
376
  return if incompatible_options.size <= 1
@@ -411,6 +418,13 @@ module RuboCop
411
418
  format('--display-only-failed cannot be used together with other display options.')
412
419
  end
413
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
+
414
428
  def validate_autocorrect
415
429
  if @options.key?(:safe_autocorrect) && @options.key?(:autocorrect_all)
416
430
  message = Rainbow(<<~MESSAGE).red
@@ -451,10 +465,6 @@ module RuboCop
451
465
  (@options[:only] & %w[Lint/RedundantCopDisableDirective RedundantCopDisableDirective]).any?
452
466
  end
453
467
 
454
- def display_only_fail_level_offenses_with_autocorrect?
455
- @options.key?(:display_only_fail_level_offenses) && @options.key?(:autocorrect)
456
- end
457
-
458
468
  def except_syntax?
459
469
  @options.key?(:except) && (@options[:except] & %w[Lint/Syntax Syntax]).any?
460
470
  end
@@ -608,6 +618,8 @@ module RuboCop
608
618
  'parallel. Default is true.'],
609
619
  stdin: ['Pipe source from STDIN, using FILE in offense',
610
620
  'reports. This is useful for editor integration.'],
621
+ editor_mode: ['Optimize real-time feedback in editors,',
622
+ 'adjusting behaviors for editing experience.'],
611
623
  init: 'Generate a .rubocop.yml file in the current directory.',
612
624
  server: ['If a server process has not been started yet, start',
613
625
  'the server process and execute inspection with server.',
@@ -620,6 +632,7 @@ module RuboCop
620
632
  stop_server: 'Stop server process.',
621
633
  server_status: 'Show server status.',
622
634
  no_detach: 'Run the server process in the foreground.',
635
+ lsp: 'Start a language server listening on STDIN.',
623
636
  raise_cop_error: ['Raise cop-related errors with cause and location.',
624
637
  'This is used to prevent cops from failing silently.',
625
638
  'Default is false.'],
@@ -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)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'digest/sha1'
4
- require 'etc'
5
4
  require 'find'
6
5
  require 'zlib'
7
6
  require_relative 'cache_config'
@@ -83,7 +82,7 @@ module RuboCop
83
82
  config_store.for_pwd.for_all_cops['AllowSymlinksInCacheRootDirectory']
84
83
  end
85
84
 
86
- attr :path
85
+ attr_reader :path
87
86
 
88
87
  def initialize(file, team, options, config_store, cache_root = nil)
89
88
  cache_root ||= File.join(options[:cache_root], 'rubocop_cache') if options[:cache_root]
@@ -202,6 +201,10 @@ module RuboCop
202
201
  lib_root = File.join(File.dirname(__FILE__), '..')
203
202
  exe_root = File.join(lib_root, '..', 'exe')
204
203
 
204
+ # Make sure to use an absolute path to prevent errors on Windows
205
+ # when traversing the relative paths with symlinks.
206
+ exe_root = File.absolute_path(exe_root)
207
+
205
208
  # These are all the files we have `require`d plus everything in the
206
209
  # exe directory. A change to any of them could affect the cop output
207
210
  # so we include them in the cache hash.
@@ -6,7 +6,11 @@ require 'tempfile'
6
6
  module CopHelper
7
7
  extend RSpec::SharedContext
8
8
 
9
- let(:ruby_version) { 2.6 }
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(source, ruby_version, file)
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
@@ -126,7 +126,7 @@ module RuboCop
126
126
  @offenses
127
127
  end
128
128
 
129
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
129
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
130
130
  def expect_correction(correction, loop: true, source: nil)
131
131
  if source
132
132
  expected_annotations = parse_annotations(source, raise_error: false)
@@ -148,7 +148,6 @@ module RuboCop
148
148
 
149
149
  break corrected_source unless loop
150
150
  break corrected_source if @last_corrector.empty?
151
- break corrected_source if corrected_source == @processed_source.buffer.source
152
151
 
153
152
  if iteration > RuboCop::Runner::MAX_ITERATIONS
154
153
  raise RuboCop::Runner::InfiniteCorrectionLoop.new(@processed_source.path, [@offenses])
@@ -163,19 +162,20 @@ module RuboCop
163
162
 
164
163
  expect(new_source).to eq(correction)
165
164
  end
166
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
165
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity
167
166
 
168
167
  def expect_no_corrections
169
168
  raise '`expect_no_corrections` must follow `expect_offense`' unless @processed_source
170
169
 
171
170
  return if @last_corrector.empty?
172
171
 
173
- # In order to print a nice diff, e.g. what source got corrected to,
174
- # we need to run the actual corrections
175
-
172
+ # This is just here for a pretty diff if the source actually got changed
176
173
  new_source = @last_corrector.rewrite
177
-
178
174
  expect(new_source).to eq(@processed_source.buffer.source)
175
+
176
+ # There is an infinite loop if a corrector is present that did not make
177
+ # any changes. It will cause the same offense/correction on the next loop.
178
+ raise RuboCop::Runner::InfiniteCorrectionLoop.new(@processed_source.path, [@offenses])
179
179
  end
180
180
 
181
181
  def expect_no_offenses(source, file = nil)
@@ -212,7 +212,7 @@ module RuboCop
212
212
 
213
213
  # Parsed representation of code annotated with the `^^^ Message` style
214
214
  class AnnotatedSource
215
- ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) /.freeze
215
+ ANNOTATION_PATTERN = /\A\s*(\^+|\^{}) ?/.freeze
216
216
  ABBREV = "[...]\n"
217
217
 
218
218
  # @param annotated_source [String] string passed to the matchers
@@ -11,6 +11,8 @@ RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLe
11
11
  # Make sure to expand all symlinks in the path first. Otherwise we may
12
12
  # get mismatched pathnames when loading config files later on.
13
13
  tmpdir = File.realpath(tmpdir)
14
+ # Make upwards search for .rubocop.yml files stop at this directory.
15
+ RuboCop::FileFinder.root_level = tmpdir
14
16
 
15
17
  virtual_home = File.expand_path(File.join(tmpdir, 'home'))
16
18
  Dir.mkdir(virtual_home)
@@ -21,9 +23,6 @@ RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLe
21
23
  root = example.metadata[:root]
22
24
  working_dir = root ? File.join(base_dir, 'work', root) : File.join(base_dir, 'work')
23
25
 
24
- # Make upwards search for .rubocop.yml files stop at this directory.
25
- RuboCop::FileFinder.root_level = working_dir
26
-
27
26
  begin
28
27
  FileUtils.mkdir_p(working_dir)
29
28
 
@@ -101,10 +100,10 @@ RSpec.shared_context 'config' do # rubocop:disable Metrics/BlockLength
101
100
  let(:cur_cop_config) do
102
101
  RuboCop::ConfigLoader
103
102
  .default_configuration.for_cop(cop_class)
104
- .merge({
105
- 'Enabled' => true, # in case it is 'pending'
106
- 'AutoCorrect' => true # in case defaults set it to false
107
- })
103
+ .merge(
104
+ 'Enabled' => true, # in case it is 'pending'
105
+ 'AutoCorrect' => 'always' # in case defaults set it to 'disabled' or false
106
+ )
108
107
  .merge(cop_config)
109
108
  end
110
109
 
@@ -129,50 +128,75 @@ RSpec.shared_context 'mock console output' do
129
128
  end
130
129
  end
131
130
 
131
+ RSpec.shared_context 'lsp' do
132
+ before do
133
+ RuboCop::LSP.enable
134
+ end
135
+
136
+ after do
137
+ RuboCop::LSP.disable
138
+ end
139
+ end
140
+
132
141
  RSpec.shared_context 'ruby 2.0' do
133
- let(:ruby_version) { 2.0 }
142
+ # Prism supports parsing Ruby 3.3+.
143
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.0 }
134
144
  end
135
145
 
136
146
  RSpec.shared_context 'ruby 2.1' do
137
- let(:ruby_version) { 2.1 }
147
+ # Prism supports parsing Ruby 3.3+.
148
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.1 }
138
149
  end
139
150
 
140
151
  RSpec.shared_context 'ruby 2.2' do
141
- let(:ruby_version) { 2.2 }
152
+ # Prism supports parsing Ruby 3.3+.
153
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.2 }
142
154
  end
143
155
 
144
156
  RSpec.shared_context 'ruby 2.3' do
145
- let(:ruby_version) { 2.3 }
157
+ # Prism supports parsing Ruby 3.3+.
158
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.3 }
146
159
  end
147
160
 
148
161
  RSpec.shared_context 'ruby 2.4' do
149
- let(:ruby_version) { 2.4 }
162
+ # Prism supports parsing Ruby 3.3+.
163
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.4 }
150
164
  end
151
165
 
152
166
  RSpec.shared_context 'ruby 2.5' do
153
- let(:ruby_version) { 2.5 }
167
+ # Prism supports parsing Ruby 3.3+.
168
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.5 }
154
169
  end
155
170
 
156
171
  RSpec.shared_context 'ruby 2.6' do
157
- let(:ruby_version) { 2.6 }
172
+ # Prism supports parsing Ruby 3.3+.
173
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.6 }
158
174
  end
159
175
 
160
176
  RSpec.shared_context 'ruby 2.7' do
161
- let(:ruby_version) { 2.7 }
177
+ # Prism supports parsing Ruby 3.3+.
178
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.7 }
162
179
  end
163
180
 
164
181
  RSpec.shared_context 'ruby 3.0' do
165
- let(:ruby_version) { 3.0 }
182
+ # Prism supports parsing Ruby 3.3+.
183
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.0 }
166
184
  end
167
185
 
168
186
  RSpec.shared_context 'ruby 3.1' do
169
- let(:ruby_version) { 3.1 }
187
+ # Prism supports parsing Ruby 3.3+.
188
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.1 }
170
189
  end
171
190
 
172
191
  RSpec.shared_context 'ruby 3.2' do
173
- let(:ruby_version) { 3.2 }
192
+ # Prism supports parsing Ruby 3.3+.
193
+ let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 3.2 }
174
194
  end
175
195
 
176
196
  RSpec.shared_context 'ruby 3.3' do
177
197
  let(:ruby_version) { 3.3 }
178
198
  end
199
+
200
+ RSpec.shared_context 'ruby 3.4' do
201
+ let(:ruby_version) { 3.4 }
202
+ end
@@ -13,6 +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', :lsp
16
17
  config.include_context 'maintain registry', :restore_registry
17
18
  config.include_context 'ruby 2.0', :ruby20
18
19
  config.include_context 'ruby 2.1', :ruby21
@@ -26,4 +27,5 @@ RSpec.configure do |config|
26
27
  config.include_context 'ruby 3.1', :ruby31
27
28
  config.include_context 'ruby 3.2', :ruby32
28
29
  config.include_context 'ruby 3.3', :ruby33
30
+ config.include_context 'ruby 3.4', :ruby34
29
31
  end
@@ -20,7 +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
- super message
23
+ super(message)
24
24
  end
25
25
  end
26
26
 
@@ -421,10 +421,10 @@ module RuboCop
421
421
  end
422
422
 
423
423
  def considered_failure?(offense)
424
- # For :autocorrect level, any offense - corrected or not - is a failure.
425
424
  return false if offense.disabled?
426
425
 
427
- return true if @options[:fail_level] == :autocorrect
426
+ # For :autocorrect level, any correctable offense is a failure, regardless of severity
427
+ return true if @options[:fail_level] == :autocorrect && offense.correctable?
428
428
 
429
429
  !offense.corrected? && offense.severity >= minimum_severity_to_fail
430
430
  end
@@ -461,19 +461,27 @@ module RuboCop
461
461
  @minimum_severity_to_fail ||= begin
462
462
  # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
463
463
  name = @options[:fail_level] || :refactor
464
- RuboCop::Cop::Severity.new(name)
464
+
465
+ # autocorrect is a fake level - use the default
466
+ RuboCop::Cop::Severity.new(name == :autocorrect ? :refactor : name)
465
467
  end
466
468
  end
467
469
 
470
+ # rubocop:disable Metrics/MethodLength
468
471
  def get_processed_source(file)
469
472
  config = @config_store.for_file(file)
470
473
  ruby_version = config.target_ruby_version
474
+ parser_engine = config.parser_engine
471
475
 
472
476
  processed_source = if @options[:stdin]
473
- ProcessedSource.new(@options[:stdin], ruby_version, file)
477
+ ProcessedSource.new(
478
+ @options[:stdin], ruby_version, file, parser_engine: parser_engine
479
+ )
474
480
  else
475
481
  begin
476
- ProcessedSource.from_file(file, ruby_version)
482
+ ProcessedSource.from_file(
483
+ file, ruby_version, parser_engine: parser_engine
484
+ )
477
485
  rescue Errno::ENOENT
478
486
  raise RuboCop::Error, "No such file or directory: #{file}"
479
487
  end
@@ -482,6 +490,7 @@ module RuboCop
482
490
  processed_source.registry = mobilized_cop_classes(config)
483
491
  processed_source
484
492
  end
493
+ # rubocop:enable Metrics/MethodLength
485
494
 
486
495
  # A Cop::Team instance is stateful and may change when inspecting.
487
496
  # The "standby" team for a given config is an initialized but
@@ -116,7 +116,7 @@ module RuboCop
116
116
 
117
117
  def pid_running?
118
118
  Process.kill(0, pid_path.read.to_i) == 1
119
- rescue Errno::ESRCH, Errno::ENOENT, Errno::EACCES
119
+ rescue Errno::ESRCH, Errno::ENOENT, Errno::EACCES, Errno::EROFS
120
120
  false
121
121
  end
122
122