rubocop 1.81.7 → 1.92.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 (621) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +626 -111
  5. data/config/obsoletion.yml +39 -1
  6. data/exe/rubocop +1 -1
  7. data/lib/rubocop/cache_config.rb +29 -0
  8. data/lib/rubocop/cached_data.rb +50 -5
  9. data/lib/rubocop/changed_files.rb +134 -0
  10. data/lib/rubocop/cli/command/auto_generate_config.rb +34 -2
  11. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  12. data/lib/rubocop/cli/command/execute_runner.rb +54 -3
  13. data/lib/rubocop/cli/command/explain.rb +34 -0
  14. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  15. data/lib/rubocop/cli/command/lsp.rb +1 -1
  16. data/lib/rubocop/cli/command/mcp.rb +19 -0
  17. data/lib/rubocop/cli/command/show_cops.rb +8 -2
  18. data/lib/rubocop/cli/command/show_docs_url.rb +8 -10
  19. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  20. data/lib/rubocop/cli.rb +41 -14
  21. data/lib/rubocop/comment_config/directive_range.rb +34 -0
  22. data/lib/rubocop/comment_config/disable_next.rb +143 -0
  23. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  24. data/lib/rubocop/comment_config.rb +97 -44
  25. data/lib/rubocop/config.rb +100 -15
  26. data/lib/rubocop/config_finder.rb +1 -1
  27. data/lib/rubocop/config_loader.rb +49 -27
  28. data/lib/rubocop/config_loader_resolver.rb +95 -20
  29. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  30. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  31. data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
  32. data/lib/rubocop/config_obsoletion.rb +1 -1
  33. data/lib/rubocop/config_store.rb +2 -2
  34. data/lib/rubocop/config_validator.rb +69 -7
  35. data/lib/rubocop/cop/autocorrect_logic.rb +24 -6
  36. data/lib/rubocop/cop/badge.rb +10 -2
  37. data/lib/rubocop/cop/base.rb +128 -35
  38. data/lib/rubocop/cop/bundler/gem_comment.rb +5 -4
  39. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  40. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -10
  41. data/lib/rubocop/cop/bundler.rb +19 -0
  42. data/lib/rubocop/cop/commissioner.rb +13 -11
  43. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  44. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  45. data/lib/rubocop/cop/corrector.rb +4 -4
  46. data/lib/rubocop/cop/correctors/alignment_corrector.rb +87 -9
  47. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  48. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +37 -7
  49. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  50. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +31 -4
  51. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +35 -5
  52. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
  53. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +70 -2
  54. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  55. data/lib/rubocop/cop/correctors.rb +28 -0
  56. data/lib/rubocop/cop/documentation.rb +3 -4
  57. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  58. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  59. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  60. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +14 -4
  61. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -8
  62. data/lib/rubocop/cop/gemspec/require_mfa.rb +9 -6
  63. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
  64. data/lib/rubocop/cop/gemspec.rb +22 -0
  65. data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
  66. data/lib/rubocop/cop/generator.rb +5 -1
  67. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  68. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  69. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  70. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  71. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +12 -16
  72. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  73. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
  74. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
  75. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  76. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  77. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
  78. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  79. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  80. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  81. data/lib/rubocop/cop/layout/argument_alignment.rb +9 -3
  82. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  83. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  84. data/lib/rubocop/cop/layout/block_alignment.rb +84 -4
  85. data/lib/rubocop/cop/layout/case_indentation.rb +28 -10
  86. data/lib/rubocop/cop/layout/class_structure.rb +156 -41
  87. data/lib/rubocop/cop/layout/comment_indentation.rb +17 -7
  88. data/lib/rubocop/cop/layout/condition_position.rb +13 -3
  89. data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
  90. data/lib/rubocop/cop/layout/dot_position.rb +26 -16
  91. data/lib/rubocop/cop/layout/else_alignment.rb +2 -14
  92. data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
  93. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +25 -7
  94. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
  95. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
  96. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +15 -2
  97. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  98. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
  99. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -0
  100. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +21 -5
  101. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  102. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  103. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  104. data/lib/rubocop/cop/layout/end_alignment.rb +23 -15
  105. data/lib/rubocop/cop/layout/extra_spacing.rb +109 -3
  106. data/lib/rubocop/cop/layout/first_argument_indentation.rb +81 -2
  107. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
  108. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +41 -0
  109. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +36 -23
  110. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  111. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  112. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  113. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  114. data/lib/rubocop/cop/layout/hash_alignment.rb +16 -11
  115. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +8 -4
  116. data/lib/rubocop/cop/layout/heredoc_indentation.rb +48 -3
  117. data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
  118. data/lib/rubocop/cop/layout/indentation_style.rb +5 -2
  119. data/lib/rubocop/cop/layout/indentation_width.rb +158 -12
  120. data/lib/rubocop/cop/layout/leading_comment_space.rb +27 -0
  121. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +10 -4
  122. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  123. data/lib/rubocop/cop/layout/line_length.rb +265 -29
  124. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +69 -57
  125. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
  126. data/lib/rubocop/cop/layout/multiline_block_layout.rb +10 -1
  127. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +65 -56
  128. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +7 -1
  129. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +268 -38
  130. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  131. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  132. data/lib/rubocop/cop/layout/redundant_line_break.rb +102 -2
  133. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +19 -5
  134. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  135. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  136. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  137. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  138. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
  139. data/lib/rubocop/cop/layout/space_around_keyword.rb +14 -2
  140. data/lib/rubocop/cop/layout/space_around_operators.rb +18 -3
  141. data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
  142. data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
  143. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  144. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +44 -34
  145. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
  146. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
  147. data/lib/rubocop/cop/layout.rb +114 -0
  148. data/lib/rubocop/cop/lazy_loader.rb +41 -0
  149. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -17
  150. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +72 -1
  151. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  152. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +3 -11
  153. data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -2
  154. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
  155. data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
  156. data/lib/rubocop/cop/lint/assignment_in_condition.rb +15 -1
  157. data/lib/rubocop/cop/lint/circular_argument_reference.rb +45 -3
  158. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  159. data/lib/rubocop/cop/lint/constant_reassignment.rb +94 -15
  160. data/lib/rubocop/cop/lint/constant_resolution.rb +31 -6
  161. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +165 -15
  162. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  163. data/lib/rubocop/cop/lint/debugger.rb +13 -2
  164. data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
  165. data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
  166. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  167. data/lib/rubocop/cop/lint/duplicate_methods.rb +405 -28
  168. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  169. data/lib/rubocop/cop/lint/empty_block.rb +4 -4
  170. data/lib/rubocop/cop/lint/empty_conditional_body.rb +9 -2
  171. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  172. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  173. data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
  174. data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -2
  175. data/lib/rubocop/cop/lint/float_comparison.rb +2 -1
  176. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
  177. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
  178. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
  179. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
  180. data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
  181. data/lib/rubocop/cop/lint/interpolation_check.rb +25 -6
  182. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  183. data/lib/rubocop/cop/lint/literal_as_condition.rb +36 -9
  184. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
  185. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +75 -37
  186. data/lib/rubocop/cop/lint/loop.rb +24 -2
  187. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
  188. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +46 -18
  189. data/lib/rubocop/cop/lint/missing_super.rb +31 -1
  190. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  191. data/lib/rubocop/cop/lint/name_typo.rb +270 -0
  192. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  193. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  194. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
  195. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  196. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  197. data/lib/rubocop/cop/lint/number_conversion.rb +22 -11
  198. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  199. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +10 -0
  200. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
  201. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
  202. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +20 -14
  203. data/lib/rubocop/cop/lint/raise_exception.rb +1 -1
  204. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  205. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +160 -39
  206. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
  207. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +28 -6
  208. data/lib/rubocop/cop/lint/redundant_require_statement.rb +5 -4
  209. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +37 -14
  210. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
  211. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +11 -5
  212. data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -3
  213. data/lib/rubocop/cop/lint/redundant_with_object.rb +5 -0
  214. data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
  215. data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
  216. data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
  217. data/lib/rubocop/cop/lint/require_range_parentheses.rb +2 -1
  218. data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
  219. data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
  220. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +24 -0
  221. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +56 -6
  222. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  223. data/lib/rubocop/cop/lint/script_permission.rb +5 -1
  224. data/lib/rubocop/cop/lint/self_assignment.rb +33 -2
  225. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
  226. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  227. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +14 -0
  228. data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -1
  229. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  230. data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
  231. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +13 -2
  232. data/lib/rubocop/cop/lint/symbol_conversion.rb +22 -4
  233. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  234. data/lib/rubocop/cop/lint/to_enum_arguments.rb +72 -4
  235. data/lib/rubocop/cop/lint/to_json.rb +20 -17
  236. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  237. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
  238. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +54 -11
  239. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  240. data/lib/rubocop/cop/lint/unreachable_code.rb +15 -9
  241. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  242. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  243. data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
  244. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -2
  245. data/lib/rubocop/cop/lint/useless_assignment.rb +61 -27
  246. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +40 -4
  247. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  248. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  249. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +10 -10
  250. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  251. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -2
  252. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +10 -4
  253. data/lib/rubocop/cop/lint/useless_setter_call.rb +11 -5
  254. data/lib/rubocop/cop/lint/useless_times.rb +22 -1
  255. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +94 -14
  256. data/lib/rubocop/cop/lint/void.rb +59 -22
  257. data/lib/rubocop/cop/lint.rb +179 -0
  258. data/lib/rubocop/cop/metrics/block_length.rb +1 -1
  259. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  260. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  261. data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
  262. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  263. data/lib/rubocop/cop/metrics/method_length.rb +2 -2
  264. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  265. data/lib/rubocop/cop/metrics/perceived_complexity.rb +37 -7
  266. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  267. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  268. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  269. data/lib/rubocop/cop/metrics.rb +31 -0
  270. data/lib/rubocop/cop/migration/department_name.rb +11 -5
  271. data/lib/rubocop/cop/migration.rb +13 -0
  272. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  273. data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
  274. data/lib/rubocop/cop/mixin/allowed_pattern.rb +5 -1
  275. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  276. data/lib/rubocop/cop/mixin/check_line_breakable.rb +47 -25
  277. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +12 -8
  278. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  279. data/lib/rubocop/cop/mixin/comments_help.rb +1 -2
  280. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
  281. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  282. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
  283. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
  284. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
  285. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
  286. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +5 -1
  287. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +58 -12
  288. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +37 -10
  289. data/lib/rubocop/cop/mixin/hash_subset.rb +9 -2
  290. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  291. data/lib/rubocop/cop/mixin/hash_transform_method.rb +14 -60
  292. data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
  293. data/lib/rubocop/cop/mixin/line_length_help.rb +28 -3
  294. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  295. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  296. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  297. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  298. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +10 -1
  299. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  300. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  301. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +79 -8
  302. data/lib/rubocop/cop/mixin/project_index_help.rb +203 -0
  303. data/lib/rubocop/cop/mixin/range_help.rb +1 -2
  304. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +181 -0
  305. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  306. data/lib/rubocop/cop/mixin/statement_modifier.rb +69 -12
  307. data/lib/rubocop/cop/mixin/trailing_comma.rb +7 -6
  308. data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
  309. data/lib/rubocop/cop/mixin.rb +93 -0
  310. data/lib/rubocop/cop/naming/accessor_method_name.rb +8 -0
  311. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +17 -1
  312. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
  313. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  314. data/lib/rubocop/cop/naming/file_name.rb +4 -3
  315. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  316. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  317. data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
  318. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +12 -5
  319. data/lib/rubocop/cop/naming/method_name.rb +6 -3
  320. data/lib/rubocop/cop/naming/predicate_method.rb +13 -2
  321. data/lib/rubocop/cop/naming/predicate_prefix.rb +30 -17
  322. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -7
  323. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  324. data/lib/rubocop/cop/naming.rb +31 -0
  325. data/lib/rubocop/cop/offense.rb +108 -9
  326. data/lib/rubocop/cop/registry.rb +232 -66
  327. data/lib/rubocop/cop/security/eval.rb +15 -2
  328. data/lib/rubocop/cop/security/io_methods.rb +2 -2
  329. data/lib/rubocop/cop/security/json_load.rb +16 -4
  330. data/lib/rubocop/cop/security/marshal_load.rb +1 -1
  331. data/lib/rubocop/cop/security.rb +19 -0
  332. data/lib/rubocop/cop/severity.rb +12 -0
  333. data/lib/rubocop/cop/style/access_modifier_declarations.rb +55 -8
  334. data/lib/rubocop/cop/style/accessor_grouping.rb +16 -5
  335. data/lib/rubocop/cop/style/alias.rb +33 -8
  336. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  337. data/lib/rubocop/cop/style/and_or.rb +8 -3
  338. data/lib/rubocop/cop/style/arguments_forwarding.rb +61 -17
  339. data/lib/rubocop/cop/style/array_first_last.rb +13 -3
  340. data/lib/rubocop/cop/style/array_intersect.rb +28 -5
  341. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +3 -0
  342. data/lib/rubocop/cop/style/array_join.rb +4 -2
  343. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  344. data/lib/rubocop/cop/style/attr.rb +8 -6
  345. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  346. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  347. data/lib/rubocop/cop/style/bitwise_predicate.rb +7 -6
  348. data/lib/rubocop/cop/style/block_delimiters.rb +74 -38
  349. data/lib/rubocop/cop/style/case_equality.rb +29 -15
  350. data/lib/rubocop/cop/style/case_like_if.rb +11 -10
  351. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  352. data/lib/rubocop/cop/style/class_and_module_children.rb +151 -35
  353. data/lib/rubocop/cop/style/class_equality_comparison.rb +21 -13
  354. data/lib/rubocop/cop/style/class_methods_definitions.rb +26 -5
  355. data/lib/rubocop/cop/style/collection_compact.rb +37 -17
  356. data/lib/rubocop/cop/style/collection_querying.rb +79 -46
  357. data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
  358. data/lib/rubocop/cop/style/combinable_loops.rb +91 -9
  359. data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
  360. data/lib/rubocop/cop/style/concat_array_literals.rb +65 -9
  361. data/lib/rubocop/cop/style/conditional_assignment.rb +34 -18
  362. data/lib/rubocop/cop/style/constant_visibility.rb +13 -7
  363. data/lib/rubocop/cop/style/copyright.rb +27 -12
  364. data/lib/rubocop/cop/style/data_inheritance.rb +18 -0
  365. data/lib/rubocop/cop/style/date_time.rb +4 -4
  366. data/lib/rubocop/cop/style/def_with_parentheses.rb +6 -2
  367. data/lib/rubocop/cop/style/dig_chain.rb +5 -0
  368. data/lib/rubocop/cop/style/dir_empty.rb +4 -0
  369. data/lib/rubocop/cop/style/directive_scope.rb +304 -0
  370. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +184 -20
  371. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  372. data/lib/rubocop/cop/style/documentation.rb +53 -6
  373. data/lib/rubocop/cop/style/documentation_method.rb +8 -12
  374. data/lib/rubocop/cop/style/double_negation.rb +11 -0
  375. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  376. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  377. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  378. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -4
  379. data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
  380. data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
  381. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  382. data/lib/rubocop/cop/style/empty_literal.rb +8 -3
  383. data/lib/rubocop/cop/style/empty_method.rb +15 -9
  384. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +74 -22
  385. data/lib/rubocop/cop/style/encoding.rb +7 -1
  386. data/lib/rubocop/cop/style/end_block.rb +3 -1
  387. data/lib/rubocop/cop/style/endless_method.rb +100 -21
  388. data/lib/rubocop/cop/style/env_home.rb +4 -0
  389. data/lib/rubocop/cop/style/even_odd.rb +11 -1
  390. data/lib/rubocop/cop/style/exact_regexp_match.rb +52 -8
  391. data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
  392. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  393. data/lib/rubocop/cop/style/file_null.rb +6 -4
  394. data/lib/rubocop/cop/style/file_open.rb +84 -0
  395. data/lib/rubocop/cop/style/file_write.rb +21 -16
  396. data/lib/rubocop/cop/style/float_division.rb +28 -14
  397. data/lib/rubocop/cop/style/for.rb +60 -1
  398. data/lib/rubocop/cop/style/format_string.rb +44 -9
  399. data/lib/rubocop/cop/style/format_string_token.rb +50 -7
  400. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  401. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  402. data/lib/rubocop/cop/style/guard_clause.rb +57 -40
  403. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +31 -9
  404. data/lib/rubocop/cop/style/hash_conversion.rb +39 -11
  405. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
  406. data/lib/rubocop/cop/style/hash_lookup_method.rb +128 -0
  407. data/lib/rubocop/cop/style/hash_slice.rb +16 -0
  408. data/lib/rubocop/cop/style/hash_syntax.rb +19 -5
  409. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  410. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  411. data/lib/rubocop/cop/style/identical_conditional_branches.rb +38 -10
  412. data/lib/rubocop/cop/style/if_inside_else.rb +36 -8
  413. data/lib/rubocop/cop/style/if_unless_modifier.rb +80 -76
  414. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +17 -14
  415. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
  416. data/lib/rubocop/cop/style/if_with_semicolon.rb +61 -8
  417. data/lib/rubocop/cop/style/inline_comment.rb +5 -2
  418. data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
  419. data/lib/rubocop/cop/style/invertible_unless_condition.rb +25 -5
  420. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  421. data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
  422. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
  423. data/lib/rubocop/cop/style/keyword_parameters_order.rb +10 -4
  424. data/lib/rubocop/cop/style/lambda.rb +45 -2
  425. data/lib/rubocop/cop/style/lambda_call.rb +24 -8
  426. data/lib/rubocop/cop/style/magic_comment_format.rb +4 -4
  427. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
  428. data/lib/rubocop/cop/style/map_into_array.rb +2 -3
  429. data/lib/rubocop/cop/style/map_join.rb +123 -0
  430. data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
  431. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +102 -20
  432. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  433. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +42 -6
  434. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +36 -8
  435. data/lib/rubocop/cop/style/method_def_parentheses.rb +36 -8
  436. data/lib/rubocop/cop/style/min_max_comparison.rb +4 -1
  437. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  438. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
  439. data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
  440. data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
  441. data/lib/rubocop/cop/style/module_function.rb +4 -2
  442. data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
  443. data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
  444. data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
  445. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  446. data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
  447. data/lib/rubocop/cop/style/multiline_method_signature.rb +14 -13
  448. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  449. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  450. data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
  451. data/lib/rubocop/cop/style/mutable_constant.rb +158 -14
  452. data/lib/rubocop/cop/style/negated_if_else_condition.rb +3 -3
  453. data/lib/rubocop/cop/style/negative_array_index.rb +228 -0
  454. data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
  455. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  456. data/lib/rubocop/cop/style/next.rb +24 -10
  457. data/lib/rubocop/cop/style/nil_comparison.rb +50 -12
  458. data/lib/rubocop/cop/style/nil_lambda.rb +9 -1
  459. data/lib/rubocop/cop/style/non_nil_check.rb +21 -11
  460. data/lib/rubocop/cop/style/not.rb +12 -3
  461. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  462. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  463. data/lib/rubocop/cop/style/numeric_predicate.rb +22 -6
  464. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  465. data/lib/rubocop/cop/style/one_line_conditional.rb +18 -6
  466. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  467. data/lib/rubocop/cop/style/operator_method_call.rb +10 -2
  468. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  469. data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
  470. data/lib/rubocop/cop/style/parallel_assignment.rb +26 -7
  471. data/lib/rubocop/cop/style/parentheses_around_condition.rb +7 -2
  472. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  473. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +18 -3
  474. data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
  475. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  476. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  477. data/lib/rubocop/cop/style/proc.rb +3 -2
  478. data/lib/rubocop/cop/style/raise_args.rb +20 -10
  479. data/lib/rubocop/cop/style/reduce_to_hash.rb +216 -0
  480. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  481. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  482. data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
  483. data/lib/rubocop/cop/style/redundant_begin.rb +25 -7
  484. data/lib/rubocop/cop/style/redundant_condition.rb +41 -23
  485. data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
  486. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +13 -1
  487. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -3
  488. data/lib/rubocop/cop/style/redundant_each.rb +4 -5
  489. data/lib/rubocop/cop/style/redundant_exception.rb +21 -3
  490. data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
  491. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
  492. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  493. data/lib/rubocop/cop/style/redundant_format.rb +43 -7
  494. data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
  495. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
  496. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +49 -10
  497. data/lib/rubocop/cop/style/redundant_line_continuation.rb +82 -115
  498. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  499. data/lib/rubocop/cop/style/redundant_parentheses.rb +105 -83
  500. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  501. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +13 -2
  502. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  503. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +27 -7
  504. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -4
  505. data/lib/rubocop/cop/style/redundant_return.rb +4 -3
  506. data/lib/rubocop/cop/style/redundant_self.rb +11 -2
  507. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -2
  508. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +27 -4
  509. data/lib/rubocop/cop/style/redundant_sort.rb +45 -11
  510. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
  511. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
  512. data/lib/rubocop/cop/style/regexp_literal.rb +106 -28
  513. data/lib/rubocop/cop/style/require_order.rb +25 -8
  514. data/lib/rubocop/cop/style/rescue_modifier.rb +15 -14
  515. data/lib/rubocop/cop/style/return_nil.rb +17 -2
  516. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  517. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  518. data/lib/rubocop/cop/style/safe_navigation.rb +18 -9
  519. data/lib/rubocop/cop/style/sample.rb +19 -13
  520. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  521. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  522. data/lib/rubocop/cop/style/select_by_regexp.rb +52 -23
  523. data/lib/rubocop/cop/style/self_assignment.rb +13 -16
  524. data/lib/rubocop/cop/style/semicolon.rb +39 -13
  525. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
  526. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  527. data/lib/rubocop/cop/style/single_line_do_end_block.rb +19 -7
  528. data/lib/rubocop/cop/style/single_line_methods.rb +24 -5
  529. data/lib/rubocop/cop/style/sole_nested_conditional.rb +25 -7
  530. data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
  531. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +31 -5
  532. data/lib/rubocop/cop/style/static_class.rb +21 -0
  533. data/lib/rubocop/cop/style/string_concatenation.rb +25 -6
  534. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
  535. data/lib/rubocop/cop/style/struct_inheritance.rb +36 -1
  536. data/lib/rubocop/cop/style/super_arguments.rb +6 -4
  537. data/lib/rubocop/cop/style/symbol_proc.rb +32 -14
  538. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  539. data/lib/rubocop/cop/style/ternary_parentheses.rb +34 -1
  540. data/lib/rubocop/cop/style/time_now.rb +41 -0
  541. data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
  542. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  543. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  544. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +35 -32
  545. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  546. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  547. data/lib/rubocop/cop/style/while_until_do.rb +7 -0
  548. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -0
  549. data/lib/rubocop/cop/style/word_array.rb +1 -0
  550. data/lib/rubocop/cop/style/yoda_condition.rb +26 -12
  551. data/lib/rubocop/cop/style/yoda_expression.rb +11 -2
  552. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
  553. data/lib/rubocop/cop/style.rb +311 -0
  554. data/lib/rubocop/cop/team.rb +171 -48
  555. data/lib/rubocop/cop/util.rb +5 -8
  556. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  557. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  558. data/lib/rubocop/cop/variable_force/variable.rb +33 -9
  559. data/lib/rubocop/cops_documentation_generator.rb +27 -9
  560. data/lib/rubocop/directive_comment.rb +116 -7
  561. data/lib/rubocop/feature_loader.rb +0 -6
  562. data/lib/rubocop/file_patterns.rb +9 -1
  563. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  564. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  565. data/lib/rubocop/formatter/disabled_config_formatter.rb +39 -10
  566. data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
  567. data/lib/rubocop/formatter/formatter_set.rb +7 -2
  568. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  569. data/lib/rubocop/formatter/html_formatter.rb +2 -4
  570. data/lib/rubocop/formatter/json_formatter.rb +82 -7
  571. data/lib/rubocop/formatter/junit_formatter.rb +27 -10
  572. data/lib/rubocop/formatter/offense_count_formatter.rb +4 -3
  573. data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
  574. data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
  575. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -5
  576. data/lib/rubocop/formatter/tap_formatter.rb +8 -3
  577. data/lib/rubocop/formatter/worst_offenders_formatter.rb +5 -4
  578. data/lib/rubocop/formatter.rb +23 -21
  579. data/lib/rubocop/lockfile.rb +18 -0
  580. data/lib/rubocop/lsp/diagnostic.rb +22 -42
  581. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  582. data/lib/rubocop/lsp/routes.rb +130 -83
  583. data/lib/rubocop/lsp/runtime.rb +64 -15
  584. data/lib/rubocop/lsp/server.rb +6 -2
  585. data/lib/rubocop/lsp/stdin_runner.rb +35 -2
  586. data/lib/rubocop/lsp.rb +5 -2
  587. data/lib/rubocop/magic_comment.rb +47 -0
  588. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  589. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  590. data/lib/rubocop/mcp/scope.rb +65 -0
  591. data/lib/rubocop/mcp/server.rb +307 -0
  592. data/lib/rubocop/mcp/source_files.rb +35 -0
  593. data/lib/rubocop/offense_limit.rb +30 -0
  594. data/lib/rubocop/options.rb +141 -13
  595. data/lib/rubocop/path_util.rb +16 -5
  596. data/lib/rubocop/pending_cops_reporter.rb +1 -6
  597. data/lib/rubocop/plugin/configuration_integrator.rb +13 -3
  598. data/lib/rubocop/plugin/loader.rb +2 -2
  599. data/lib/rubocop/project_index_loader.rb +82 -0
  600. data/lib/rubocop/rake_task.rb +2 -3
  601. data/lib/rubocop/remote_config.rb +18 -13
  602. data/lib/rubocop/result_cache.rb +102 -59
  603. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  604. data/lib/rubocop/rspec/expect_offense.rb +2 -4
  605. data/lib/rubocop/rspec/shared_contexts.rb +53 -5
  606. data/lib/rubocop/rspec/support.rb +2 -1
  607. data/lib/rubocop/runner.rb +362 -106
  608. data/lib/rubocop/server/cache.rb +21 -40
  609. data/lib/rubocop/server/cli.rb +2 -4
  610. data/lib/rubocop/server/core.rb +8 -0
  611. data/lib/rubocop/server.rb +14 -0
  612. data/lib/rubocop/target_finder.rb +18 -8
  613. data/lib/rubocop/target_ruby.rb +42 -22
  614. data/lib/rubocop/todo_audit.rb +111 -0
  615. data/lib/rubocop/unified_diff.rb +257 -0
  616. data/lib/rubocop/util.rb +69 -0
  617. data/lib/rubocop/version.rb +23 -7
  618. data/lib/rubocop.rb +34 -701
  619. data/lib/ruby_lsp/rubocop/addon.rb +1 -2
  620. metadata +80 -14
  621. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module LSP
5
+ # Builds LSP text edits for rubocop:disable comments.
6
+ # @api private
7
+ class DisableCommentEdits
8
+ def initialize(offense:, document_encoding:, processed_source:)
9
+ @offense = offense
10
+ @document_encoding = document_encoding
11
+ @processed_source = processed_source
12
+ end
13
+
14
+ def edits
15
+ literal_range = multiline_literal_range
16
+ return block_disable_comments(literal_range) if literal_range
17
+
18
+ inline_disable_comment
19
+ end
20
+
21
+ private
22
+
23
+ def inline_disable_comment
24
+ eol = position(@offense.line - 1, @offense.source_line.length, @offense.source_line)
25
+ [text_edit(eol, inline_comment_text)]
26
+ end
27
+
28
+ def inline_comment_text
29
+ if @offense.source_line.include?(' # rubocop:disable ')
30
+ ",#{@offense.cop_name}"
31
+ else
32
+ " # rubocop:disable #{@offense.cop_name}"
33
+ end
34
+ end
35
+
36
+ def block_disable_comments(range)
37
+ full_line_range = range_by_lines(range)
38
+ leading_whitespace = full_line_range.source_line[/^\s*/].to_s
39
+ [
40
+ disable_edit(full_line_range.first_line, leading_whitespace),
41
+ enable_edit(full_line_range, leading_whitespace)
42
+ ]
43
+ end
44
+
45
+ def disable_edit(first_line, leading_whitespace)
46
+ position = position(first_line - 1, 0, '')
47
+ text_edit(position, "#{leading_whitespace}# rubocop:disable #{@offense.cop_name}\n")
48
+ end
49
+
50
+ def enable_edit(full_line_range, leading_whitespace)
51
+ last_line = full_line_range.last_line
52
+ last_line_text = full_line_range.source_buffer.source_line(last_line)
53
+ position = position(last_line - 1, last_line_text.length, last_line_text)
54
+ text_edit(position, "\n#{leading_whitespace}# rubocop:enable #{@offense.cop_name}")
55
+ end
56
+
57
+ def text_edit(position, new_text)
58
+ range = LanguageServer::Protocol::Interface::Range.new(start: position, end: position)
59
+ LanguageServer::Protocol::Interface::TextEdit.new(range: range, new_text: new_text)
60
+ end
61
+
62
+ def position(line, utf8_index, line_text)
63
+ LanguageServer::Protocol::Interface::Position.new(
64
+ line: line,
65
+ character: position_character(utf8_index, line_text)
66
+ )
67
+ end
68
+
69
+ def position_character(utf8_index, line_text)
70
+ str = line_text[0, utf8_index]
71
+ if @document_encoding == Encoding::UTF_16LE || @document_encoding.nil?
72
+ str.length + str.b.count("\xf0-\xff".b)
73
+ else
74
+ str.length
75
+ end
76
+ end
77
+
78
+ def multiline_literal_range
79
+ return unless @processed_source&.ast
80
+
81
+ offense_range = @offense.location
82
+ multiline_ranges&.find do |range|
83
+ eol_comment_would_be_inside_literal?(offense_range, range)
84
+ end
85
+ end
86
+
87
+ def multiline_ranges
88
+ @processed_source.ast.each_node.filter_map do |node|
89
+ if surrounding_heredoc?(node)
90
+ heredoc_range(node)
91
+ elsif string_continuation?(node)
92
+ range_by_lines(node.source_range)
93
+ elsif surrounding_percent_array?(node) || multiline_string?(node)
94
+ node.source_range
95
+ end
96
+ end
97
+ end
98
+
99
+ def eol_comment_would_be_inside_literal?(offense_range, literal_range)
100
+ offense_line = offense_range.line
101
+ offense_line >= literal_range.first_line && offense_line < literal_range.last_line
102
+ end
103
+
104
+ def surrounding_heredoc?(node)
105
+ node.any_str_type? && node.heredoc?
106
+ end
107
+
108
+ def heredoc_range(node)
109
+ node.source_range.join(node.loc.heredoc_end)
110
+ end
111
+
112
+ def surrounding_percent_array?(node)
113
+ node.array_type? && node.percent_literal?
114
+ end
115
+
116
+ def string_continuation?(node)
117
+ node.any_str_type? && node.source.match?(/\\\s*$/)
118
+ end
119
+
120
+ def multiline_string?(node)
121
+ node.dstr_type? && node.multiline?
122
+ end
123
+
124
+ def range_by_lines(range)
125
+ begin_of_first_line = range.begin_pos - range.column
126
+
127
+ last_line = range.source_buffer.source_line(range.last_line)
128
+ last_line_offset = last_line.length - range.last_column
129
+ end_of_last_line = range.end_pos + last_line_offset
130
+
131
+ Parser::Source::Range.new(range.source_buffer, begin_of_first_line, end_of_last_line)
132
+ end
133
+ end
134
+ end
135
+ end
@@ -15,17 +15,15 @@ module RuboCop
15
15
  module LSP
16
16
  # Routes for Language Server Protocol of RuboCop.
17
17
  # @api private
18
- class Routes # rubocop:disable Metrics/ClassLength
18
+ class Routes
19
19
  CONFIGURATION_FILE_PATTERNS = [
20
20
  RuboCop::ConfigFinder::DOTFILE,
21
21
  RuboCop::CLI::Command::AutoGenerateConfig::AUTO_GENERATED_FILE
22
22
  ].freeze
23
23
 
24
- def self.handle(name, &block)
25
- define_method(:"handle_#{name}", &block)
26
- end
27
-
28
- private_class_method :handle
24
+ # Commands handled by `workspace/executeCommand`. Advertised to the client
25
+ # via `executeCommandProvider` so it knows which commands it can invoke.
26
+ EXECUTE_COMMANDS = %w[rubocop.formatAutocorrects rubocop.formatAutocorrectsAll].freeze
29
27
 
30
28
  def initialize(server)
31
29
  @server = server
@@ -40,9 +38,31 @@ module RuboCop
40
38
  method(name)
41
39
  end
42
40
 
41
+ def handle_unsupported_method(request, method = request[:method])
42
+ @server.write(
43
+ id: request[:id],
44
+ error: LanguageServer::Protocol::Interface::ResponseError.new(
45
+ code: LanguageServer::Protocol::Constant::ErrorCodes::METHOD_NOT_FOUND,
46
+ message: "Unsupported Method: #{method}"
47
+ )
48
+ )
49
+ Logger.log("Unsupported Method: #{method}")
50
+ end
51
+
52
+ def handle_method_missing(request)
53
+ return unless request.key?(:id)
54
+
55
+ @server.write(id: request[:id], result: nil)
56
+ end
57
+
58
+ def self.handle(name, &block)
59
+ define_method(:"handle_#{name}", &block)
60
+ end
61
+
62
+ private_class_method :handle
63
+
43
64
  handle 'initialize' do |request|
44
65
  initialization_options = extract_initialization_options_from(request)
45
- @position_encoding = initialization_options[:position_encoding]
46
66
 
47
67
  @server.configure(initialization_options)
48
68
 
@@ -51,11 +71,16 @@ module RuboCop
51
71
  result: LanguageServer::Protocol::Interface::InitializeResult.new(
52
72
  capabilities: LanguageServer::Protocol::Interface::ServerCapabilities.new(
53
73
  document_formatting_provider: true,
74
+ code_action_provider: LanguageServer::Protocol::Interface::CodeActionOptions.new(
75
+ code_action_kinds: [LanguageServer::Protocol::Constant::CodeActionKind::QUICK_FIX]
76
+ ),
77
+ execute_command_provider: LanguageServer::Protocol::Interface::ExecuteCommandOptions.new(
78
+ commands: EXECUTE_COMMANDS
79
+ ),
54
80
  text_document_sync: LanguageServer::Protocol::Interface::TextDocumentSyncOptions.new(
55
81
  change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::INCREMENTAL,
56
82
  open_close: true
57
- ),
58
- position_encoding: @position_encoding
83
+ )
59
84
  )
60
85
  )
61
86
  )
@@ -63,9 +88,16 @@ module RuboCop
63
88
 
64
89
  handle 'initialized' do |_request|
65
90
  version = RuboCop::Version::STRING
66
- yjit = Object.const_defined?('RubyVM::YJIT') && RubyVM::YJIT.enabled? ? ' +YJIT' : ''
67
-
68
- Logger.log("RuboCop #{version} language server#{yjit} initialized, PID #{Process.pid}")
91
+ # Only one JIT can be enabled at the same time, since YJIT and ZJIT are mutually exclusive.
92
+ jit = if Object.const_defined?('RubyVM::YJIT') && RubyVM::YJIT.enabled?
93
+ '+YJIT'
94
+ elsif Object.const_defined?('RubyVM::ZJIT') && RubyVM::ZJIT.enabled?
95
+ '+ZJIT'
96
+ else
97
+ ''
98
+ end
99
+
100
+ Logger.log("RuboCop #{version} language server#{jit} initialized, PID #{Process.pid}")
69
101
  end
70
102
 
71
103
  handle 'shutdown' do |request|
@@ -102,18 +134,26 @@ module RuboCop
102
134
  @server.write(id: request[:id], result: format_file(uri))
103
135
  end
104
136
 
137
+ handle 'textDocument/codeAction' do |request|
138
+ @server.write(id: request[:id], result: code_actions_for(request[:params]))
139
+ end
140
+
105
141
  handle 'workspace/didChangeConfiguration' do |_request|
106
142
  Logger.log('Ignoring workspace/didChangeConfiguration')
107
143
  end
108
144
 
109
145
  handle 'workspace/didChangeWatchedFiles' do |request|
110
- changed = request[:params][:changes].any? do |change|
146
+ config_changed = request[:params][:changes].any? do |change|
111
147
  CONFIGURATION_FILE_PATTERNS.any? { |path| change[:uri].end_with?(path) }
112
148
  end
113
149
 
114
- if changed
150
+ if config_changed
115
151
  Logger.log('Configuration file changed; restart required')
116
152
  @server.stop
153
+ else
154
+ # A watched source file changed on disk, so the project index may be
155
+ # stale; drop it so the next diagnostics run rebuilds it.
156
+ @server.reset_project_index
117
157
  end
118
158
  end
119
159
 
@@ -128,25 +168,13 @@ module RuboCop
128
168
  return
129
169
  end
130
170
 
131
- uri = request[:params][:arguments][0][:uri]
132
- formatted = nil
133
-
134
- # The `workspace/executeCommand` is an LSP method triggered by intentional user actions,
135
- # so the user's intention for autocorrection is respected.
136
- LSP.disable { formatted = format_file(uri, command: command) }
137
-
138
- @server.write(
139
- id: request[:id],
140
- method: 'workspace/applyEdit',
141
- params: {
142
- label: label,
143
- edit: {
144
- changes: {
145
- uri => formatted
146
- }
147
- }
148
- }
149
- )
171
+ # Clients such as Eglot can invoke a command without arguments, so respond with
172
+ # an error instead of letting the server crash on a missing URI.
173
+ if (uri = document_uri_from(request))
174
+ write_formatting_edits(request, uri: uri, command: command, label: label)
175
+ else
176
+ write_invalid_arguments_error(request, command)
177
+ end
150
178
  end
151
179
 
152
180
  handle 'textDocument/willSave' do |_request|
@@ -154,7 +182,9 @@ module RuboCop
154
182
  end
155
183
 
156
184
  handle 'textDocument/didSave' do |_request|
157
- # Nothing to do
185
+ # The buffer's contents are now on disk, so the project index may be
186
+ # stale; drop it so the next diagnostics run rebuilds it.
187
+ @server.reset_project_index
158
188
  end
159
189
 
160
190
  handle '$/cancelRequest' do |_request|
@@ -165,45 +195,57 @@ module RuboCop
165
195
  # No-op, we log everything
166
196
  end
167
197
 
168
- def handle_unsupported_method(request, method = request[:method])
169
- @server.write(
170
- id: request[:id],
171
- error: LanguageServer::Protocol::Interface::ResponseError.new(
172
- code: LanguageServer::Protocol::Constant::ErrorCodes::METHOD_NOT_FOUND,
173
- message: "Unsupported Method: #{method}"
174
- )
175
- )
176
- Logger.log("Unsupported Method: #{method}")
177
- end
178
-
179
- def handle_method_missing(request)
180
- return unless request.key?(:id)
181
-
182
- @server.write(id: request[:id], result: nil)
183
- end
184
-
185
198
  private
186
199
 
187
200
  def extract_initialization_options_from(request)
188
201
  safe_autocorrect = request.dig(:params, :initializationOptions, :safeAutocorrect)
189
- position_encodings = request.dig(:params, :capabilities, :general, :positionEncodings)
190
202
 
191
203
  {
192
204
  safe_autocorrect: safe_autocorrect.nil? || safe_autocorrect == true,
193
205
  lint_mode: request.dig(:params, :initializationOptions, :lintMode) == true,
194
- layout_mode: request.dig(:params, :initializationOptions, :layoutMode) == true,
195
- position_encoding: position_encoding(position_encodings)
206
+ layout_mode: request.dig(:params, :initializationOptions, :layoutMode) == true
196
207
  }
197
208
  end
198
209
 
199
- def position_encoding(position_encodings)
200
- if position_encodings&.include?('utf-8')
201
- 'utf-8'
202
- elsif position_encodings&.include?('utf-32')
203
- 'utf-32'
204
- else
205
- 'utf-16'
206
- end
210
+ def document_uri_from(request)
211
+ argument = request.dig(:params, :arguments, 0)
212
+
213
+ argument[:uri] if argument.is_a?(Hash)
214
+ end
215
+
216
+ def write_formatting_edits(request, uri:, command:, label:)
217
+ formatted = nil
218
+
219
+ # The `workspace/executeCommand` is an LSP method triggered by intentional user actions,
220
+ # so the user's intention for autocorrection is respected.
221
+ LSP.disable { formatted = format_file(uri, command: command) }
222
+
223
+ @server.write(
224
+ id: request[:id],
225
+ method: 'workspace/applyEdit',
226
+ params: {
227
+ label: label,
228
+ edit: {
229
+ changes: {
230
+ uri => formatted
231
+ }
232
+ }
233
+ }
234
+ )
235
+ end
236
+
237
+ def write_invalid_arguments_error(request, command)
238
+ message = "Missing document URI in arguments for #{command}"
239
+
240
+ @server.write(
241
+ id: request[:id],
242
+ error: LanguageServer::Protocol::Interface::ResponseError.new(
243
+ code: LanguageServer::Protocol::Constant::ErrorCodes::INVALID_PARAMS,
244
+ message: message
245
+ )
246
+ )
247
+
248
+ Logger.log(message)
207
249
  end
208
250
 
209
251
  def format_file(file_uri, command: nil)
@@ -217,13 +259,31 @@ module RuboCop
217
259
 
218
260
  return [] if new_text == text
219
261
 
220
- [
262
+ [{
221
263
  newText: new_text,
222
264
  range: {
223
265
  start: { line: 0, character: 0 },
224
266
  end: { line: text.count("\n") + 1, character: 0 }
225
267
  }
226
- ]
268
+ }]
269
+ end
270
+
271
+ # Returns the quickfix code actions for a `textDocument/codeAction` request.
272
+ #
273
+ # RuboCop attaches each offense's autocorrect and disable-line actions to
274
+ # the diagnostic it publishes, under the diagnostic's `data` (see
275
+ # `Diagnostic#to_lsp_diagnostic`). The LSP spec preserves that `data`
276
+ # between `textDocument/publishDiagnostics` and `textDocument/codeAction`,
277
+ # so the client hands the diagnostics back in the request's context and we
278
+ # can surface their actions without re-analyzing the file. This makes the
279
+ # actions available to clients that request code actions rather than
280
+ # reading them off the diagnostic (Eglot, Helix, Flycheck, ...).
281
+ def code_actions_for(params)
282
+ diagnostics = params.dig(:context, :diagnostics) || []
283
+ only = params.dig(:context, :only)
284
+
285
+ diagnostics.flat_map { |diagnostic| diagnostic.dig(:data, :code_actions) || [] }
286
+ .select { |action| only.nil? || only.include?(action[:kind]) }
227
287
  end
228
288
 
229
289
  def diagnostic(file_uri, text)
@@ -233,8 +293,7 @@ module RuboCop
233
293
  method: 'textDocument/publishDiagnostics',
234
294
  params: {
235
295
  uri: file_uri,
236
- diagnostics: @server.offenses(convert_file_uri_to_path(file_uri),
237
- text, @position_encoding)
296
+ diagnostics: @server.offenses(convert_file_uri_to_path(file_uri), text)
238
297
  }
239
298
  }
240
299
  end
@@ -244,8 +303,9 @@ module RuboCop
244
303
 
245
304
  start_pos = text_pos(orig_text, range[:start])
246
305
  end_pos = text_pos(orig_text, range[:end])
247
- orig_text[start_pos...end_pos] = text
248
- orig_text
306
+ text_bin = orig_text.b
307
+ text_bin[start_pos...end_pos] = text.b
308
+ text_bin.force_encoding(orig_text.encoding)
249
309
  end
250
310
 
251
311
  def text_pos(text, range)
@@ -254,27 +314,14 @@ module RuboCop
254
314
  pos = 0
255
315
  text.each_line.with_index do |l, i|
256
316
  if i == line
257
- pos += line_pos(l, char)
317
+ pos += l.encode('utf-16be').b[0, char * 2].encode('utf-8', 'utf-16be').bytesize
258
318
  return pos
259
319
  end
260
- pos += l.size
320
+ pos += l.bytesize
261
321
  end
262
322
  pos
263
323
  end
264
324
 
265
- def line_pos(line, char)
266
- case @position_encoding
267
- when 'utf-8'
268
- line.byteslice(0, char).size
269
- when 'utf-32'
270
- char
271
- else # 'utf-16'
272
- # utf-16 is default position encoding on LSP
273
- # https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/
274
- line.encode('utf-16be').byteslice(0, char * 2).size
275
- end
276
- end
277
-
278
325
  def convert_file_uri_to_path(uri)
279
326
  URI.decode_www_form_component(uri.delete_prefix('file://'))
280
327
  end
@@ -17,47 +17,96 @@ module RuboCop
17
17
  # Runtime for Language Server Protocol of RuboCop.
18
18
  # @api private
19
19
  class Runtime
20
- attr_writer :safe_autocorrect, :lint_mode, :layout_mode
20
+ attr_writer :safe_autocorrect, :lint_mode, :layout_mode, :raise_cop_error
21
21
 
22
- def initialize(config_store)
23
- RuboCop::LSP.enable
22
+ # Without `lsp_mode`, offenses keep the locations and messages the
23
+ # command line gives them, rather than the ones meant for an editor.
24
+ def initialize(config_store, lsp_mode: true)
25
+ RuboCop::LSP.enable if lsp_mode
24
26
 
25
27
  @runner = RuboCop::Lsp::StdinRunner.new(config_store)
26
- @cop_registry = RuboCop::Cop::Registry.global.to_h
27
28
 
28
29
  @safe_autocorrect = true
29
30
  @lint_mode = false
30
31
  @layout_mode = false
32
+ @raise_cop_error = true
31
33
  end
32
34
 
33
- def format(path, text, command:, prism_result: nil)
35
+ def format(path, text, command:, prism_result: nil, options: {})
34
36
  safe_autocorrect = if command
35
37
  command == 'rubocop.formatAutocorrects'
36
38
  else
37
39
  @safe_autocorrect
38
40
  end
39
41
 
40
- formatting_options = { autocorrect: true, safe_autocorrect: safe_autocorrect }
41
- formatting_options[:only] = config_only_options if @lint_mode || @layout_mode
42
+ formatting_options = {
43
+ autocorrect: true, safe_autocorrect: safe_autocorrect, raise_cop_error: @raise_cop_error
44
+ }.merge(call_options(options))
42
45
 
43
46
  @runner.run(path, text, formatting_options, prism_result: prism_result)
44
47
  @runner.formatted_source
45
48
  end
46
49
 
47
- def offenses(path, text, position_encoding, prism_result: nil)
48
- diagnostic_options = {}
49
- diagnostic_options[:only] = config_only_options if @lint_mode || @layout_mode
50
+ def reset_project_index
51
+ @runner.reset_project_index
52
+ end
50
53
 
51
- @runner.run(path, text, diagnostic_options, prism_result: prism_result)
52
- @runner.offenses.map do |offense|
53
- Diagnostic.new(
54
- position_encoding, offense, path, @cop_registry[offense.cop_name]&.first
55
- ).to_lsp_diagnostic(@runner.config_for_working_directory)
54
+ def offenses(path, text, document_encoding = nil, prism_result: nil)
55
+ found = raw_offenses(path, text, prism_result: prism_result)
56
+ processed_source = @runner.processed_source
57
+ config = @runner.config_for_working_directory
58
+ found.map do |offense|
59
+ build_diagnostic(offense, path, document_encoding, processed_source, config)
56
60
  end
57
61
  end
58
62
 
63
+ # The offenses before they are converted to LSP diagnostics, for callers
64
+ # that do not speak LSP.
65
+ def raw_offenses(path, text, prism_result: nil, options: {})
66
+ diagnostic_options = { raise_cop_error: @raise_cop_error }.merge(call_options(options))
67
+
68
+ @runner.run(path, text, diagnostic_options, prism_result: prism_result)
69
+ @runner.offenses
70
+ end
71
+
72
+ # The offenses the last `format` found but didn't correct, located in the
73
+ # source it returned.
74
+ def uncorrected_offenses
75
+ @runner.offenses.reject(&:corrected?)
76
+ end
77
+
78
+ # What went wrong in the last run. Cop errors only end up here when
79
+ # `raise_cop_error` is off; otherwise they are raised.
80
+ def errors
81
+ @runner.errors
82
+ end
83
+
84
+ def warnings
85
+ @runner.warnings
86
+ end
87
+
59
88
  private
60
89
 
90
+ def build_diagnostic(offense, path, document_encoding, processed_source, config)
91
+ Diagnostic.new(
92
+ document_encoding,
93
+ offense,
94
+ path,
95
+ RuboCop::Cop::Registry.global.find_by_cop_name(offense.cop_name),
96
+ processed_source
97
+ ).to_lsp_diagnostic(config)
98
+ end
99
+
100
+ # What a caller adds for one call, such as `only` and `except` to select
101
+ # the cops, or `editing` to hold back the corrections of cops with
102
+ # `AutoCorrect: contextual`, as LSP mode does. Without `only`, the cops
103
+ # are the departments a lint or layout mode limits the server to.
104
+ def call_options(options)
105
+ return options if options[:only] || !(@lint_mode || @layout_mode)
106
+
107
+ options.merge(only: config_only_options)
108
+ end
109
+
61
110
  def config_only_options
62
111
  only_options = []
63
112
  only_options << 'Lint' if @lint_mode
@@ -51,8 +51,8 @@ module RuboCop
51
51
  @runtime.format(path, text, command: command)
52
52
  end
53
53
 
54
- def offenses(path, text, position_encoding)
55
- @runtime.offenses(path, text, position_encoding)
54
+ def offenses(path, text)
55
+ @runtime.offenses(path, text)
56
56
  end
57
57
 
58
58
  def configure(options)
@@ -61,6 +61,10 @@ module RuboCop
61
61
  @runtime.layout_mode = options[:layout_mode]
62
62
  end
63
63
 
64
+ def reset_project_index
65
+ @runtime.reset_project_index
66
+ end
67
+
64
68
  def stop(&block)
65
69
  at_exit(&block) if block
66
70
  exit
@@ -17,13 +17,12 @@ module RuboCop
17
17
  class StdinRunner < RuboCop::Runner
18
18
  class ConfigurationError < StandardError; end
19
19
 
20
- attr_reader :offenses, :config_for_working_directory
20
+ attr_reader :offenses, :config_for_working_directory, :processed_source
21
21
 
22
22
  DEFAULT_RUBOCOP_OPTIONS = {
23
23
  stderr: true,
24
24
  force_exclusion: true,
25
25
  formatters: ['RuboCop::Formatter::BaseFormatter'],
26
- raise_cop_error: true,
27
26
  todo_file: nil,
28
27
  todo_ignore_files: []
29
28
  }.freeze
@@ -41,10 +40,18 @@ module RuboCop
41
40
  end
42
41
 
43
42
  def run(path, contents, options, prism_result: nil)
43
+ # The cops mobilized for a configuration are cached, which only holds while
44
+ # every run asks for the same ones.
45
+ selection = options.values_at(:only, :except)
46
+ unless selection == @cop_selection
47
+ forget_mobilized_cops
48
+ @cop_selection = selection
49
+ end
44
50
  @options = options.merge(DEFAULT_RUBOCOP_OPTIONS)
45
51
  @options[:stdin] = contents
46
52
 
47
53
  @prism_result = prism_result
54
+ @processed_source = nil
48
55
 
49
56
  @offenses = []
50
57
  @warnings = []
@@ -59,11 +66,37 @@ module RuboCop
59
66
  @options[:stdin]
60
67
  end
61
68
 
69
+ # Drop the cached project index so the next run rebuilds it. Called when a
70
+ # file is saved or a watched file changes, i.e. when the on-disk state the
71
+ # index is derived from may have changed.
72
+ def reset_project_index
73
+ @project_index = nil
74
+ @project_index_built = false
75
+ end
76
+
62
77
  private
63
78
 
79
+ # The project index is built from files on disk, not from the in-memory
80
+ # buffer, so it does not change while the user is typing. Build it once and
81
+ # reuse it across runs instead of re-walking and re-indexing the whole
82
+ # project on every request; `reset_project_index` drops the cache when the
83
+ # on-disk state changes.
84
+ def build_project_index(target_files)
85
+ return if @project_index_built
86
+
87
+ super
88
+ @project_index_built = true
89
+ end
90
+
64
91
  def file_finished(_file, offenses)
65
92
  @offenses = offenses
66
93
  end
94
+
95
+ def do_inspection_loop(file, source = nil)
96
+ processed_source, offenses = super
97
+ @processed_source = processed_source
98
+ [processed_source, offenses]
99
+ end
67
100
  end
68
101
  end
69
102
  end
data/lib/rubocop/lsp.rb CHANGED
@@ -26,8 +26,11 @@ module RuboCop
26
26
  if block
27
27
  original = @enabled
28
28
  @enabled = false
29
- yield
30
- @enabled = original
29
+ begin
30
+ yield
31
+ ensure
32
+ @enabled = original
33
+ end
31
34
  else
32
35
  @enabled = false
33
36
  end