rubocop 1.71.1 → 1.92.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (705) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -19
  4. data/config/default.yml +885 -168
  5. data/config/internal_affairs.yml +20 -0
  6. data/config/obsoletion.yml +47 -4
  7. data/exe/rubocop +2 -9
  8. data/lib/rubocop/cache_config.rb +29 -0
  9. data/lib/rubocop/cached_data.rb +50 -5
  10. data/lib/rubocop/changed_files.rb +134 -0
  11. data/lib/rubocop/cli/command/auto_generate_config.rb +36 -4
  12. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  13. data/lib/rubocop/cli/command/execute_runner.rb +54 -3
  14. data/lib/rubocop/cli/command/explain.rb +34 -0
  15. data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
  16. data/lib/rubocop/cli/command/lsp.rb +1 -1
  17. data/lib/rubocop/cli/command/mcp.rb +19 -0
  18. data/lib/rubocop/cli/command/show_cops.rb +8 -2
  19. data/lib/rubocop/cli/command/show_docs_url.rb +8 -10
  20. data/lib/rubocop/cli/command/suggest_extensions.rb +8 -2
  21. data/lib/rubocop/cli.rb +59 -17
  22. data/lib/rubocop/comment_config/directive_range.rb +34 -0
  23. data/lib/rubocop/comment_config/disable_next.rb +143 -0
  24. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  25. data/lib/rubocop/comment_config.rb +98 -45
  26. data/lib/rubocop/config.rb +137 -19
  27. data/lib/rubocop/config_finder.rb +1 -1
  28. data/lib/rubocop/config_loader.rb +75 -49
  29. data/lib/rubocop/config_loader_resolver.rb +124 -33
  30. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  31. data/lib/rubocop/config_obsoletion/extracted_cop.rb +6 -3
  32. data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
  33. data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
  34. data/lib/rubocop/config_obsoletion.rb +47 -3
  35. data/lib/rubocop/config_store.rb +7 -2
  36. data/lib/rubocop/config_validator.rb +75 -12
  37. data/lib/rubocop/cop/autocorrect_logic.rb +43 -17
  38. data/lib/rubocop/cop/badge.rb +9 -1
  39. data/lib/rubocop/cop/base.rb +128 -35
  40. data/lib/rubocop/cop/bundler/gem_comment.rb +5 -4
  41. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  42. data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -11
  43. data/lib/rubocop/cop/bundler.rb +19 -0
  44. data/lib/rubocop/cop/commissioner.rb +13 -11
  45. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  46. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  47. data/lib/rubocop/cop/corrector.rb +4 -4
  48. data/lib/rubocop/cop/correctors/alignment_corrector.rb +92 -11
  49. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  50. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +22 -7
  51. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  52. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
  53. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +29 -2
  54. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
  55. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
  56. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +73 -2
  57. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  58. data/lib/rubocop/cop/correctors.rb +28 -0
  59. data/lib/rubocop/cop/documentation.rb +3 -4
  60. data/lib/rubocop/cop/exclude_limit.rb +31 -5
  61. data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
  62. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  63. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  64. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +49 -17
  65. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +2 -9
  66. data/lib/rubocop/cop/gemspec/require_mfa.rb +22 -5
  67. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
  68. data/lib/rubocop/cop/gemspec.rb +22 -0
  69. data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
  70. data/lib/rubocop/cop/generator.rb +5 -1
  71. data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
  72. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  73. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  74. data/lib/rubocop/cop/internal_affairs/location_exists.rb +142 -0
  75. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
  76. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +16 -20
  77. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  78. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
  79. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
  80. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +85 -0
  81. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +2 -2
  82. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  83. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  84. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
  85. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
  86. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  87. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
  88. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  89. data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
  90. data/lib/rubocop/cop/internal_affairs.rb +3 -16
  91. data/lib/rubocop/cop/layout/argument_alignment.rb +4 -2
  92. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  93. data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
  94. data/lib/rubocop/cop/layout/block_alignment.rb +86 -4
  95. data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
  96. data/lib/rubocop/cop/layout/case_indentation.rb +28 -10
  97. data/lib/rubocop/cop/layout/class_structure.rb +172 -36
  98. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
  99. data/lib/rubocop/cop/layout/comment_indentation.rb +17 -7
  100. data/lib/rubocop/cop/layout/condition_position.rb +13 -3
  101. data/lib/rubocop/cop/layout/def_end_alignment.rb +5 -1
  102. data/lib/rubocop/cop/layout/dot_position.rb +2 -2
  103. data/lib/rubocop/cop/layout/else_alignment.rb +3 -15
  104. data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
  105. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +27 -9
  106. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
  107. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +14 -5
  108. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +46 -21
  109. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  110. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
  111. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
  112. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
  113. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -0
  114. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +14 -3
  115. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +17 -3
  116. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  117. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  118. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  119. data/lib/rubocop/cop/layout/end_alignment.rb +20 -8
  120. data/lib/rubocop/cop/layout/extra_spacing.rb +109 -3
  121. data/lib/rubocop/cop/layout/first_argument_indentation.rb +57 -3
  122. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
  123. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  124. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +25 -18
  125. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  126. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  127. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  128. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  129. data/lib/rubocop/cop/layout/hash_alignment.rb +20 -18
  130. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +5 -3
  131. data/lib/rubocop/cop/layout/heredoc_indentation.rb +48 -3
  132. data/lib/rubocop/cop/layout/indentation_style.rb +5 -2
  133. data/lib/rubocop/cop/layout/indentation_width.rb +159 -12
  134. data/lib/rubocop/cop/layout/leading_comment_space.rb +40 -1
  135. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +10 -4
  136. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  137. data/lib/rubocop/cop/layout/line_length.rb +201 -30
  138. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +69 -57
  139. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
  140. data/lib/rubocop/cop/layout/multiline_block_layout.rb +11 -1
  141. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +63 -56
  142. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +7 -1
  143. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +259 -40
  144. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  145. data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
  146. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
  147. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  148. data/lib/rubocop/cop/layout/redundant_line_break.rb +111 -7
  149. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +29 -9
  150. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  151. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  152. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  153. data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
  154. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
  155. data/lib/rubocop/cop/layout/space_around_keyword.rb +20 -3
  156. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  157. data/lib/rubocop/cop/layout/space_around_operators.rb +30 -4
  158. data/lib/rubocop/cop/layout/space_before_block_braces.rb +5 -1
  159. data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -39
  160. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  161. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +55 -36
  162. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +32 -8
  163. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
  164. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  165. data/lib/rubocop/cop/layout.rb +114 -0
  166. data/lib/rubocop/cop/lazy_loader.rb +41 -0
  167. data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -17
  168. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +72 -1
  169. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  170. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +3 -11
  171. data/lib/rubocop/cop/lint/ambiguous_range.rb +6 -2
  172. data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
  173. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
  174. data/lib/rubocop/cop/lint/assignment_in_condition.rb +15 -1
  175. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  176. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -8
  177. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
  178. data/lib/rubocop/cop/lint/constant_reassignment.rb +94 -15
  179. data/lib/rubocop/cop/lint/constant_resolution.rb +31 -6
  180. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +240 -0
  181. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  182. data/lib/rubocop/cop/lint/debugger.rb +13 -4
  183. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
  184. data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
  185. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
  186. data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
  187. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  188. data/lib/rubocop/cop/lint/duplicate_methods.rb +506 -41
  189. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
  190. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  191. data/lib/rubocop/cop/lint/empty_block.rb +4 -4
  192. data/lib/rubocop/cop/lint/empty_conditional_body.rb +22 -65
  193. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  194. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  195. data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
  196. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  197. data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
  198. data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -8
  199. data/lib/rubocop/cop/lint/float_comparison.rb +33 -10
  200. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  201. data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
  202. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
  203. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
  204. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
  205. data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
  206. data/lib/rubocop/cop/lint/interpolation_check.rb +25 -6
  207. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  208. data/lib/rubocop/cop/lint/literal_as_condition.rb +152 -11
  209. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
  210. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +75 -37
  211. data/lib/rubocop/cop/lint/loop.rb +24 -2
  212. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
  213. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +60 -23
  214. data/lib/rubocop/cop/lint/missing_super.rb +31 -1
  215. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  216. data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
  217. data/lib/rubocop/cop/lint/name_typo.rb +270 -0
  218. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  219. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  220. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
  221. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
  222. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +4 -4
  223. data/lib/rubocop/cop/lint/number_conversion.rb +20 -11
  224. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
  225. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +11 -0
  226. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
  227. data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
  228. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
  229. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +20 -14
  230. data/lib/rubocop/cop/lint/raise_exception.rb +30 -11
  231. data/lib/rubocop/cop/lint/rand_one.rb +1 -1
  232. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +160 -39
  233. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
  234. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +28 -6
  235. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  236. data/lib/rubocop/cop/lint/redundant_require_statement.rb +5 -25
  237. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +134 -12
  238. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
  239. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +267 -0
  240. data/lib/rubocop/cop/lint/redundant_with_index.rb +5 -3
  241. data/lib/rubocop/cop/lint/redundant_with_object.rb +8 -0
  242. data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
  243. data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
  244. data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
  245. data/lib/rubocop/cop/lint/require_range_parentheses.rb +3 -2
  246. data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
  247. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  248. data/lib/rubocop/cop/lint/rescue_type.rb +2 -2
  249. data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
  250. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +28 -4
  251. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +9 -5
  252. data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
  253. data/lib/rubocop/cop/lint/script_permission.rb +5 -1
  254. data/lib/rubocop/cop/lint/self_assignment.rb +63 -6
  255. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
  256. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  257. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  258. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +27 -1
  259. data/lib/rubocop/cop/lint/shared_mutable_default.rb +14 -1
  260. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  261. data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
  262. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  263. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +122 -0
  264. data/lib/rubocop/cop/lint/symbol_conversion.rb +21 -4
  265. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  266. data/lib/rubocop/cop/lint/to_enum_arguments.rb +73 -5
  267. data/lib/rubocop/cop/lint/to_json.rb +20 -17
  268. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
  269. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
  270. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +54 -11
  271. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
  272. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -1
  273. data/lib/rubocop/cop/lint/unreachable_code.rb +16 -9
  274. data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
  275. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  276. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  277. data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
  278. data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
  279. data/lib/rubocop/cop/lint/useless_access_modifier.rb +31 -6
  280. data/lib/rubocop/cop/lint/useless_assignment.rb +63 -27
  281. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +107 -0
  282. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +92 -0
  283. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  284. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +11 -10
  285. data/lib/rubocop/cop/lint/useless_or.rb +111 -0
  286. data/lib/rubocop/cop/lint/useless_rescue.rb +2 -3
  287. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +13 -7
  288. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -1
  289. data/lib/rubocop/cop/lint/useless_times.rb +22 -1
  290. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +201 -0
  291. data/lib/rubocop/cop/lint/void.rb +68 -22
  292. data/lib/rubocop/cop/lint.rb +179 -0
  293. data/lib/rubocop/cop/message_annotator.rb +7 -3
  294. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  295. data/lib/rubocop/cop/metrics/block_length.rb +2 -1
  296. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  297. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  298. data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
  299. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  300. data/lib/rubocop/cop/metrics/method_length.rb +3 -2
  301. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  302. data/lib/rubocop/cop/metrics/perceived_complexity.rb +37 -7
  303. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  304. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
  305. data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
  306. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  307. data/lib/rubocop/cop/metrics.rb +31 -0
  308. data/lib/rubocop/cop/migration/department_name.rb +11 -5
  309. data/lib/rubocop/cop/migration.rb +13 -0
  310. data/lib/rubocop/cop/mixin/alignment.rb +7 -3
  311. data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
  312. data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -5
  313. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  314. data/lib/rubocop/cop/mixin/check_line_breakable.rb +44 -23
  315. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +10 -8
  316. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  317. data/lib/rubocop/cop/mixin/comments_help.rb +2 -3
  318. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
  319. data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
  320. data/lib/rubocop/cop/mixin/def_node.rb +1 -1
  321. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +13 -2
  322. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
  323. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +69 -0
  324. data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
  325. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
  326. data/lib/rubocop/cop/mixin/forbidden_pattern.rb +20 -0
  327. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
  328. data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
  329. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +59 -17
  330. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +52 -25
  331. data/lib/rubocop/cop/mixin/hash_subset.rb +28 -6
  332. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  333. data/lib/rubocop/cop/mixin/hash_transform_method.rb +32 -78
  334. data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
  335. data/lib/rubocop/cop/mixin/line_length_help.rb +52 -11
  336. data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
  337. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  338. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  339. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
  340. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +10 -1
  341. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +2 -2
  342. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  343. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  344. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +79 -8
  345. data/lib/rubocop/cop/mixin/project_index_help.rb +203 -0
  346. data/lib/rubocop/cop/mixin/range_help.rb +16 -5
  347. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +181 -0
  348. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  349. data/lib/rubocop/cop/mixin/statement_modifier.rb +66 -10
  350. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  351. data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
  352. data/lib/rubocop/cop/mixin/trailing_comma.rb +23 -6
  353. data/lib/rubocop/cop/mixin.rb +93 -0
  354. data/lib/rubocop/cop/naming/accessor_method_name.rb +8 -0
  355. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +17 -1
  356. data/lib/rubocop/cop/naming/block_forwarding.rb +7 -4
  357. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  358. data/lib/rubocop/cop/naming/file_name.rb +6 -5
  359. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  360. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  361. data/lib/rubocop/cop/naming/inclusive_language.rb +8 -2
  362. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +13 -6
  363. data/lib/rubocop/cop/naming/method_name.rb +190 -15
  364. data/lib/rubocop/cop/naming/predicate_method.rb +330 -0
  365. data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +65 -8
  366. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -6
  367. data/lib/rubocop/cop/naming/variable_name.rb +51 -6
  368. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  369. data/lib/rubocop/cop/naming.rb +31 -0
  370. data/lib/rubocop/cop/offense.rb +108 -9
  371. data/lib/rubocop/cop/registry.rb +234 -65
  372. data/lib/rubocop/cop/security/eval.rb +17 -3
  373. data/lib/rubocop/cop/security/io_methods.rb +2 -2
  374. data/lib/rubocop/cop/security/json_load.rb +45 -11
  375. data/lib/rubocop/cop/security/marshal_load.rb +1 -1
  376. data/lib/rubocop/cop/security/open.rb +1 -0
  377. data/lib/rubocop/cop/security.rb +19 -0
  378. data/lib/rubocop/cop/severity.rb +12 -0
  379. data/lib/rubocop/cop/style/access_modifier_declarations.rb +54 -13
  380. data/lib/rubocop/cop/style/accessor_grouping.rb +47 -10
  381. data/lib/rubocop/cop/style/alias.rb +33 -8
  382. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  383. data/lib/rubocop/cop/style/and_or.rb +6 -1
  384. data/lib/rubocop/cop/style/arguments_forwarding.rb +52 -37
  385. data/lib/rubocop/cop/style/array_first_last.rb +13 -3
  386. data/lib/rubocop/cop/style/array_intersect.rb +136 -38
  387. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +50 -0
  388. data/lib/rubocop/cop/style/array_join.rb +4 -2
  389. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  390. data/lib/rubocop/cop/style/attr.rb +8 -6
  391. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  392. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  393. data/lib/rubocop/cop/style/bitwise_predicate.rb +13 -5
  394. data/lib/rubocop/cop/style/block_delimiters.rb +71 -40
  395. data/lib/rubocop/cop/style/case_equality.rb +29 -15
  396. data/lib/rubocop/cop/style/case_like_if.rb +12 -11
  397. data/lib/rubocop/cop/style/character_literal.rb +2 -2
  398. data/lib/rubocop/cop/style/class_and_module_children.rb +179 -27
  399. data/lib/rubocop/cop/style/class_equality_comparison.rb +22 -14
  400. data/lib/rubocop/cop/style/class_methods_definitions.rb +19 -5
  401. data/lib/rubocop/cop/style/collection_compact.rb +37 -17
  402. data/lib/rubocop/cop/style/collection_methods.rb +1 -0
  403. data/lib/rubocop/cop/style/collection_querying.rb +167 -0
  404. data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
  405. data/lib/rubocop/cop/style/combinable_loops.rb +88 -9
  406. data/lib/rubocop/cop/style/command_literal.rb +1 -1
  407. data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
  408. data/lib/rubocop/cop/style/comparable_between.rb +78 -0
  409. data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
  410. data/lib/rubocop/cop/style/concat_array_literals.rb +53 -9
  411. data/lib/rubocop/cop/style/conditional_assignment.rb +58 -24
  412. data/lib/rubocop/cop/style/constant_visibility.rb +23 -12
  413. data/lib/rubocop/cop/style/copyright.rb +27 -12
  414. data/lib/rubocop/cop/style/data_inheritance.rb +25 -0
  415. data/lib/rubocop/cop/style/date_time.rb +4 -4
  416. data/lib/rubocop/cop/style/def_with_parentheses.rb +22 -5
  417. data/lib/rubocop/cop/style/dig_chain.rb +6 -1
  418. data/lib/rubocop/cop/style/dir_empty.rb +4 -0
  419. data/lib/rubocop/cop/style/directive_scope.rb +304 -0
  420. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +184 -20
  421. data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
  422. data/lib/rubocop/cop/style/documentation.rb +53 -6
  423. data/lib/rubocop/cop/style/documentation_method.rb +8 -12
  424. data/lib/rubocop/cop/style/double_negation.rb +14 -3
  425. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  426. data/lib/rubocop/cop/style/each_with_object.rb +4 -3
  427. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  428. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -4
  429. data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
  430. data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
  431. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  432. data/lib/rubocop/cop/style/empty_literal.rb +12 -3
  433. data/lib/rubocop/cop/style/empty_method.rb +15 -9
  434. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +110 -0
  435. data/lib/rubocop/cop/style/encoding.rb +7 -1
  436. data/lib/rubocop/cop/style/end_block.rb +3 -1
  437. data/lib/rubocop/cop/style/endless_method.rb +252 -19
  438. data/lib/rubocop/cop/style/env_home.rb +4 -0
  439. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  440. data/lib/rubocop/cop/style/even_odd.rb +11 -1
  441. data/lib/rubocop/cop/style/exact_regexp_match.rb +52 -8
  442. data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
  443. data/lib/rubocop/cop/style/explicit_block_argument.rb +62 -9
  444. data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
  445. data/lib/rubocop/cop/style/fetch_env_var.rb +33 -7
  446. data/lib/rubocop/cop/style/file_null.rb +6 -4
  447. data/lib/rubocop/cop/style/file_open.rb +84 -0
  448. data/lib/rubocop/cop/style/file_write.rb +21 -16
  449. data/lib/rubocop/cop/style/float_division.rb +43 -15
  450. data/lib/rubocop/cop/style/for.rb +48 -1
  451. data/lib/rubocop/cop/style/format_string.rb +44 -9
  452. data/lib/rubocop/cop/style/format_string_token.rb +86 -16
  453. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +5 -3
  454. data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
  455. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  456. data/lib/rubocop/cop/style/guard_clause.rb +41 -24
  457. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  458. data/lib/rubocop/cop/style/hash_conversion.rb +52 -16
  459. data/lib/rubocop/cop/style/hash_each_methods.rb +4 -4
  460. data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
  461. data/lib/rubocop/cop/style/hash_lookup_method.rb +128 -0
  462. data/lib/rubocop/cop/style/hash_slice.rb +16 -0
  463. data/lib/rubocop/cop/style/hash_syntax.rb +23 -6
  464. data/lib/rubocop/cop/style/hash_transform_keys.rb +19 -9
  465. data/lib/rubocop/cop/style/hash_transform_values.rb +19 -9
  466. data/lib/rubocop/cop/style/identical_conditional_branches.rb +39 -11
  467. data/lib/rubocop/cop/style/if_inside_else.rb +46 -21
  468. data/lib/rubocop/cop/style/if_unless_modifier.rb +90 -66
  469. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +19 -19
  470. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -2
  471. data/lib/rubocop/cop/style/if_with_semicolon.rb +61 -8
  472. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  473. data/lib/rubocop/cop/style/inline_comment.rb +5 -2
  474. data/lib/rubocop/cop/style/inverse_methods.rb +34 -8
  475. data/lib/rubocop/cop/style/invertible_unless_condition.rb +27 -7
  476. data/lib/rubocop/cop/style/ip_addresses.rb +3 -4
  477. data/lib/rubocop/cop/style/it_assignment.rb +69 -12
  478. data/lib/rubocop/cop/style/it_block_parameter.rb +150 -0
  479. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
  480. data/lib/rubocop/cop/style/keyword_parameters_order.rb +23 -11
  481. data/lib/rubocop/cop/style/lambda.rb +30 -1
  482. data/lib/rubocop/cop/style/lambda_call.rb +31 -10
  483. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  484. data/lib/rubocop/cop/style/magic_comment_format.rb +4 -4
  485. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
  486. data/lib/rubocop/cop/style/map_into_array.rb +6 -4
  487. data/lib/rubocop/cop/style/map_join.rb +123 -0
  488. data/lib/rubocop/cop/style/map_to_hash.rb +13 -5
  489. data/lib/rubocop/cop/style/map_to_set.rb +1 -3
  490. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +75 -24
  491. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  492. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +58 -6
  493. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +36 -8
  494. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
  495. data/lib/rubocop/cop/style/method_def_parentheses.rb +36 -8
  496. data/lib/rubocop/cop/style/min_max_comparison.rb +17 -6
  497. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  498. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
  499. data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
  500. data/lib/rubocop/cop/style/module_function.rb +4 -2
  501. data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
  502. data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
  503. data/lib/rubocop/cop/style/multiline_if_modifier.rb +47 -5
  504. data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
  505. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  506. data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
  507. data/lib/rubocop/cop/style/multiline_method_signature.rb +15 -22
  508. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  509. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  510. data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
  511. data/lib/rubocop/cop/style/mutable_constant.rb +139 -13
  512. data/lib/rubocop/cop/style/negated_if_else_condition.rb +3 -3
  513. data/lib/rubocop/cop/style/negative_array_index.rb +228 -0
  514. data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
  515. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  516. data/lib/rubocop/cop/style/next.rb +68 -10
  517. data/lib/rubocop/cop/style/nil_comparison.rb +53 -13
  518. data/lib/rubocop/cop/style/nil_lambda.rb +9 -1
  519. data/lib/rubocop/cop/style/non_nil_check.rb +21 -11
  520. data/lib/rubocop/cop/style/not.rb +12 -3
  521. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  522. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  523. data/lib/rubocop/cop/style/numeric_predicate.rb +22 -6
  524. data/lib/rubocop/cop/style/object_then.rb +1 -0
  525. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  526. data/lib/rubocop/cop/style/one_line_conditional.rb +35 -15
  527. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  528. data/lib/rubocop/cop/style/operator_method_call.rb +10 -2
  529. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  530. data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
  531. data/lib/rubocop/cop/style/parallel_assignment.rb +58 -27
  532. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  533. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  534. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +18 -3
  535. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  536. data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
  537. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  538. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  539. data/lib/rubocop/cop/style/proc.rb +4 -2
  540. data/lib/rubocop/cop/style/raise_args.rb +9 -9
  541. data/lib/rubocop/cop/style/reduce_to_hash.rb +216 -0
  542. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  543. data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
  544. data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
  545. data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
  546. data/lib/rubocop/cop/style/redundant_begin.rb +58 -6
  547. data/lib/rubocop/cop/style/redundant_condition.rb +93 -18
  548. data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
  549. data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +26 -4
  550. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -3
  551. data/lib/rubocop/cop/style/redundant_each.rb +4 -5
  552. data/lib/rubocop/cop/style/redundant_exception.rb +22 -4
  553. data/lib/rubocop/cop/style/redundant_fetch_block.rb +11 -11
  554. data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
  555. data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
  556. data/lib/rubocop/cop/style/redundant_format.rb +319 -0
  557. data/lib/rubocop/cop/style/redundant_freeze.rb +12 -3
  558. data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
  559. data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
  560. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  561. data/lib/rubocop/cop/style/redundant_line_continuation.rb +83 -119
  562. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  563. data/lib/rubocop/cop/style/redundant_parentheses.rb +176 -83
  564. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  565. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +15 -0
  566. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  567. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +27 -7
  568. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +16 -0
  569. data/lib/rubocop/cop/style/redundant_return.rb +4 -3
  570. data/lib/rubocop/cop/style/redundant_self.rb +20 -7
  571. data/lib/rubocop/cop/style/redundant_self_assignment.rb +2 -3
  572. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  573. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  574. data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
  575. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
  576. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
  577. data/lib/rubocop/cop/style/regexp_literal.rb +107 -29
  578. data/lib/rubocop/cop/style/require_order.rb +9 -0
  579. data/lib/rubocop/cop/style/rescue_modifier.rb +10 -12
  580. data/lib/rubocop/cop/style/return_nil.rb +19 -4
  581. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  582. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  583. data/lib/rubocop/cop/style/safe_navigation.rb +76 -20
  584. data/lib/rubocop/cop/style/sample.rb +19 -13
  585. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  586. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  587. data/lib/rubocop/cop/style/select_by_regexp.rb +54 -22
  588. data/lib/rubocop/cop/style/self_assignment.rb +13 -16
  589. data/lib/rubocop/cop/style/semicolon.rb +56 -14
  590. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  591. data/lib/rubocop/cop/style/single_line_do_end_block.rb +22 -8
  592. data/lib/rubocop/cop/style/single_line_methods.rb +28 -11
  593. data/lib/rubocop/cop/style/sole_nested_conditional.rb +96 -104
  594. data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
  595. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +32 -6
  596. data/lib/rubocop/cop/style/static_class.rb +21 -0
  597. data/lib/rubocop/cop/style/string_concatenation.rb +38 -16
  598. data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
  599. data/lib/rubocop/cop/style/struct_inheritance.rb +38 -2
  600. data/lib/rubocop/cop/style/super_arguments.rb +7 -6
  601. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  602. data/lib/rubocop/cop/style/symbol_proc.rb +34 -14
  603. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  604. data/lib/rubocop/cop/style/ternary_parentheses.rb +34 -1
  605. data/lib/rubocop/cop/style/time_now.rb +41 -0
  606. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -2
  607. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
  608. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  609. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +2 -2
  610. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  611. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  612. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +35 -32
  613. data/lib/rubocop/cop/style/trivial_accessors.rb +2 -2
  614. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  615. data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
  616. data/lib/rubocop/cop/style/while_until_do.rb +7 -0
  617. data/lib/rubocop/cop/style/while_until_modifier.rb +16 -1
  618. data/lib/rubocop/cop/style/word_array.rb +1 -0
  619. data/lib/rubocop/cop/style/yoda_condition.rb +26 -12
  620. data/lib/rubocop/cop/style/yoda_expression.rb +11 -2
  621. data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
  622. data/lib/rubocop/cop/style.rb +311 -0
  623. data/lib/rubocop/cop/team.rb +172 -49
  624. data/lib/rubocop/cop/util.rb +7 -10
  625. data/lib/rubocop/cop/utils/format_string.rb +20 -5
  626. data/lib/rubocop/cop/variable_force/assignment.rb +8 -4
  627. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  628. data/lib/rubocop/cop/variable_force/scope.rb +1 -1
  629. data/lib/rubocop/cop/variable_force/variable.rb +42 -11
  630. data/lib/rubocop/cop/variable_force.rb +26 -9
  631. data/lib/rubocop/cops_documentation_generator.rb +49 -15
  632. data/lib/rubocop/directive_comment.rb +147 -5
  633. data/lib/rubocop/ext/regexp_node.rb +0 -1
  634. data/lib/rubocop/feature_loader.rb +0 -6
  635. data/lib/rubocop/file_patterns.rb +9 -1
  636. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  637. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  638. data/lib/rubocop/formatter/disabled_config_formatter.rb +57 -14
  639. data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
  640. data/lib/rubocop/formatter/formatter_set.rb +7 -2
  641. data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
  642. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  643. data/lib/rubocop/formatter/html_formatter.rb +3 -5
  644. data/lib/rubocop/formatter/json_formatter.rb +82 -7
  645. data/lib/rubocop/formatter/junit_formatter.rb +27 -10
  646. data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
  647. data/lib/rubocop/formatter/offense_count_formatter.rb +5 -4
  648. data/lib/rubocop/formatter/pacman_formatter.rb +5 -2
  649. data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
  650. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -5
  651. data/lib/rubocop/formatter/tap_formatter.rb +8 -3
  652. data/lib/rubocop/formatter/worst_offenders_formatter.rb +5 -4
  653. data/lib/rubocop/formatter.rb +23 -21
  654. data/lib/rubocop/lockfile.rb +18 -0
  655. data/lib/rubocop/lsp/diagnostic.rb +22 -41
  656. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  657. data/lib/rubocop/lsp/routes.rb +136 -33
  658. data/lib/rubocop/lsp/runtime.rb +66 -15
  659. data/lib/rubocop/lsp/server.rb +4 -2
  660. data/lib/rubocop/lsp/stdin_runner.rb +38 -19
  661. data/lib/rubocop/lsp.rb +5 -2
  662. data/lib/rubocop/magic_comment.rb +55 -0
  663. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  664. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  665. data/lib/rubocop/mcp/scope.rb +65 -0
  666. data/lib/rubocop/mcp/server.rb +307 -0
  667. data/lib/rubocop/mcp/source_files.rb +35 -0
  668. data/lib/rubocop/offense_limit.rb +30 -0
  669. data/lib/rubocop/options.rb +166 -23
  670. data/lib/rubocop/path_util.rb +20 -5
  671. data/lib/rubocop/pending_cops_reporter.rb +51 -0
  672. data/lib/rubocop/plugin/configuration_integrator.rb +153 -0
  673. data/lib/rubocop/plugin/load_error.rb +26 -0
  674. data/lib/rubocop/plugin/loader.rb +100 -0
  675. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  676. data/lib/rubocop/plugin.rb +46 -0
  677. data/lib/rubocop/project_index_loader.rb +82 -0
  678. data/lib/rubocop/rake_task.rb +6 -4
  679. data/lib/rubocop/remote_config.rb +18 -13
  680. data/lib/rubocop/result_cache.rb +110 -65
  681. data/lib/rubocop/rspec/cop_helper.rb +21 -1
  682. data/lib/rubocop/rspec/expect_offense.rb +11 -7
  683. data/lib/rubocop/rspec/shared_contexts.rb +85 -3
  684. data/lib/rubocop/rspec/support.rb +4 -0
  685. data/lib/rubocop/runner.rb +368 -106
  686. data/lib/rubocop/server/cache.rb +67 -48
  687. data/lib/rubocop/server/cli.rb +2 -4
  688. data/lib/rubocop/server/client_command/base.rb +10 -0
  689. data/lib/rubocop/server/client_command/exec.rb +2 -1
  690. data/lib/rubocop/server/client_command/start.rb +11 -1
  691. data/lib/rubocop/server/core.rb +8 -0
  692. data/lib/rubocop/server.rb +14 -0
  693. data/lib/rubocop/target_finder.rb +25 -11
  694. data/lib/rubocop/target_ruby.rb +31 -14
  695. data/lib/rubocop/todo_audit.rb +111 -0
  696. data/lib/rubocop/unified_diff.rb +257 -0
  697. data/lib/rubocop/util.rb +69 -0
  698. data/lib/rubocop/version.rb +48 -10
  699. data/lib/rubocop.rb +35 -682
  700. data/lib/ruby_lsp/rubocop/addon.rb +28 -17
  701. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
  702. metadata +129 -21
  703. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
  704. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
  705. data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +0 -50
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'language_server-protocol'
4
+ require_relative 'disable_comment_edits'
3
5
  require_relative 'severity'
4
6
 
5
7
  #
@@ -16,11 +18,12 @@ module RuboCop
16
18
  # Diagnostic for Language Server Protocol of RuboCop.
17
19
  # @api private
18
20
  class Diagnostic
19
- def initialize(document_encoding, offense, uri, cop_class)
21
+ def initialize(document_encoding, offense, uri, cop_class, processed_source = nil)
20
22
  @document_encoding = document_encoding
21
23
  @offense = offense
22
24
  @uri = uri
23
25
  @cop_class = cop_class
26
+ @processed_source = processed_source
24
27
  end
25
28
 
26
29
  def to_lsp_code_actions
@@ -32,7 +35,7 @@ module RuboCop
32
35
  code_actions
33
36
  end
34
37
 
35
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
38
+ # rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
36
39
  def to_lsp_diagnostic(config)
37
40
  highlighted = @offense.highlighted_area
38
41
 
@@ -45,11 +48,11 @@ module RuboCop
45
48
  range: LanguageServer::Protocol::Interface::Range.new(
46
49
  start: LanguageServer::Protocol::Interface::Position.new(
47
50
  line: @offense.line - 1,
48
- character: highlighted.begin_pos
51
+ character: to_position_character(highlighted.begin_pos)
49
52
  ),
50
53
  end: LanguageServer::Protocol::Interface::Position.new(
51
54
  line: @offense.line - 1,
52
- character: highlighted.end_pos
55
+ character: to_position_character(highlighted.end_pos)
53
56
  )
54
57
  ),
55
58
  data: {
@@ -58,7 +61,6 @@ module RuboCop
58
61
  }
59
62
  )
60
63
  end
61
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
62
64
 
63
65
  private
64
66
 
@@ -79,7 +81,7 @@ module RuboCop
79
81
  LanguageServer::Protocol::Interface::CodeDescription.new(href: doc_url)
80
82
  end
81
83
 
82
- # rubocop:disable Layout/LineLength, Metrics/MethodLength
84
+ # rubocop:disable-next Metrics/MethodLength
83
85
  def autocorrect_action
84
86
  LanguageServer::Protocol::Interface::CodeAction.new(
85
87
  title: "Autocorrect #{@offense.cop_name}",
@@ -98,29 +100,27 @@ module RuboCop
98
100
  is_preferred: true
99
101
  )
100
102
  end
101
- # rubocop:enable Layout/LineLength, Metrics/MethodLength
102
103
 
103
- # rubocop:disable Metrics/MethodLength
104
+ # rubocop:disable-next Metrics/MethodLength
104
105
  def offense_replacements
105
106
  @offense.corrector.as_replacements.map do |range, replacement|
106
107
  LanguageServer::Protocol::Interface::TextEdit.new(
107
108
  range: LanguageServer::Protocol::Interface::Range.new(
108
109
  start: LanguageServer::Protocol::Interface::Position.new(
109
110
  line: range.line - 1,
110
- character: range.column
111
+ character: to_position_character(range.column)
111
112
  ),
112
113
  end: LanguageServer::Protocol::Interface::Position.new(
113
114
  line: range.last_line - 1,
114
- character: range.last_column
115
+ character: to_position_character(range.last_column)
115
116
  )
116
117
  ),
117
118
  new_text: replacement
118
119
  )
119
120
  end
120
121
  end
121
- # rubocop:enable Metrics/MethodLength
122
122
 
123
- # rubocop:disable Layout/LineLength, Metrics/MethodLength
123
+ # rubocop:disable-next Metrics/MethodLength
124
124
  def disable_line_action
125
125
  LanguageServer::Protocol::Interface::CodeAction.new(
126
126
  title: "Disable #{@offense.cop_name} for this line",
@@ -138,40 +138,21 @@ module RuboCop
138
138
  )
139
139
  )
140
140
  end
141
- # rubocop:enable Layout/LineLength, Metrics/MethodLength
142
141
 
143
142
  def line_disable_comment
144
- new_text = if @offense.source_line.include?(' # rubocop:disable ')
145
- ",#{@offense.cop_name}"
146
- else
147
- " # rubocop:disable #{@offense.cop_name}"
148
- end
149
-
150
- eol = LanguageServer::Protocol::Interface::Position.new(
151
- line: @offense.line - 1,
152
- character: length_of_line(@offense.source_line)
153
- )
154
-
155
- # TODO: fails for multiline strings - may be preferable to use block
156
- # comments to disable some offenses
157
- inline_comment = LanguageServer::Protocol::Interface::TextEdit.new(
158
- range: LanguageServer::Protocol::Interface::Range.new(start: eol, end: eol),
159
- new_text: new_text
160
- )
161
-
162
- [inline_comment]
143
+ DisableCommentEdits.new(
144
+ offense: @offense,
145
+ document_encoding: @document_encoding,
146
+ processed_source: @processed_source
147
+ ).edits
163
148
  end
164
149
 
165
- def length_of_line(line)
166
- if @document_encoding == Encoding::UTF_16LE
167
- line_length = 0
168
- line.codepoints.each do |codepoint|
169
- line_length += 1
170
- line_length += 1 if codepoint > RubyLsp::Document::Scanner::SURROGATE_PAIR_START
171
- end
172
- line_length
150
+ def to_position_character(utf8_index)
151
+ str = @offense.source_line[0, utf8_index]
152
+ if @document_encoding == Encoding::UTF_16LE || @document_encoding.nil?
153
+ str.length + str.b.count("\xf0-\xff".b)
173
154
  else
174
- line.length
155
+ str.length
175
156
  end
176
157
  end
177
158
 
@@ -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
@@ -21,6 +21,10 @@ module RuboCop
21
21
  RuboCop::CLI::Command::AutoGenerateConfig::AUTO_GENERATED_FILE
22
22
  ].freeze
23
23
 
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
27
+
24
28
  def self.handle(name, &block)
25
29
  define_method(:"handle_#{name}", &block)
26
30
  end
@@ -50,8 +54,14 @@ module RuboCop
50
54
  result: LanguageServer::Protocol::Interface::InitializeResult.new(
51
55
  capabilities: LanguageServer::Protocol::Interface::ServerCapabilities.new(
52
56
  document_formatting_provider: true,
57
+ code_action_provider: LanguageServer::Protocol::Interface::CodeActionOptions.new(
58
+ code_action_kinds: [LanguageServer::Protocol::Constant::CodeActionKind::QUICK_FIX]
59
+ ),
60
+ execute_command_provider: LanguageServer::Protocol::Interface::ExecuteCommandOptions.new(
61
+ commands: EXECUTE_COMMANDS
62
+ ),
53
63
  text_document_sync: LanguageServer::Protocol::Interface::TextDocumentSyncOptions.new(
54
- change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::FULL,
64
+ change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::INCREMENTAL,
55
65
  open_close: true
56
66
  )
57
67
  )
@@ -61,9 +71,16 @@ module RuboCop
61
71
 
62
72
  handle 'initialized' do |_request|
63
73
  version = RuboCop::Version::STRING
64
- yjit = Object.const_defined?('RubyVM::YJIT') && RubyVM::YJIT.enabled? ? ' +YJIT' : ''
65
-
66
- Logger.log("RuboCop #{version} language server#{yjit} initialized, PID #{Process.pid}")
74
+ # Only one JIT can be enabled at the same time, since YJIT and ZJIT are mutually exclusive.
75
+ jit = if Object.const_defined?('RubyVM::YJIT') && RubyVM::YJIT.enabled?
76
+ '+YJIT'
77
+ elsif Object.const_defined?('RubyVM::ZJIT') && RubyVM::ZJIT.enabled?
78
+ '+ZJIT'
79
+ else
80
+ ''
81
+ end
82
+
83
+ Logger.log("RuboCop #{version} language server#{jit} initialized, PID #{Process.pid}")
67
84
  end
68
85
 
69
86
  handle 'shutdown' do |request|
@@ -76,7 +93,12 @@ module RuboCop
76
93
 
77
94
  handle 'textDocument/didChange' do |request|
78
95
  params = request[:params]
79
- result = diagnostic(params[:textDocument][:uri], params[:contentChanges][0][:text])
96
+ file_uri = params[:textDocument][:uri]
97
+ text = @text_cache[file_uri]
98
+ params[:contentChanges].each do |content|
99
+ text = change_text(text, content[:text], content[:range])
100
+ end
101
+ result = diagnostic(file_uri, text)
80
102
  @server.write(result)
81
103
  end
82
104
 
@@ -95,18 +117,26 @@ module RuboCop
95
117
  @server.write(id: request[:id], result: format_file(uri))
96
118
  end
97
119
 
120
+ handle 'textDocument/codeAction' do |request|
121
+ @server.write(id: request[:id], result: code_actions_for(request[:params]))
122
+ end
123
+
98
124
  handle 'workspace/didChangeConfiguration' do |_request|
99
125
  Logger.log('Ignoring workspace/didChangeConfiguration')
100
126
  end
101
127
 
102
128
  handle 'workspace/didChangeWatchedFiles' do |request|
103
- changed = request[:params][:changes].any? do |change|
129
+ config_changed = request[:params][:changes].any? do |change|
104
130
  CONFIGURATION_FILE_PATTERNS.any? { |path| change[:uri].end_with?(path) }
105
131
  end
106
132
 
107
- if changed
133
+ if config_changed
108
134
  Logger.log('Configuration file changed; restart required')
109
135
  @server.stop
136
+ else
137
+ # A watched source file changed on disk, so the project index may be
138
+ # stale; drop it so the next diagnostics run rebuilds it.
139
+ @server.reset_project_index
110
140
  end
111
141
  end
112
142
 
@@ -121,25 +151,13 @@ module RuboCop
121
151
  return
122
152
  end
123
153
 
124
- uri = request[:params][:arguments][0][:uri]
125
- formatted = nil
126
-
127
- # The `workspace/executeCommand` is an LSP method triggered by intentional user actions,
128
- # so the user's intention for autocorrection is respected.
129
- LSP.disable { formatted = format_file(uri, command: command) }
130
-
131
- @server.write(
132
- id: request[:id],
133
- method: 'workspace/applyEdit',
134
- params: {
135
- label: label,
136
- edit: {
137
- changes: {
138
- uri => formatted
139
- }
140
- }
141
- }
142
- )
154
+ # Clients such as Eglot can invoke a command without arguments, so respond with
155
+ # an error instead of letting the server crash on a missing URI.
156
+ if (uri = document_uri_from(request))
157
+ write_formatting_edits(request, uri: uri, command: command, label: label)
158
+ else
159
+ write_invalid_arguments_error(request, command)
160
+ end
143
161
  end
144
162
 
145
163
  handle 'textDocument/willSave' do |_request|
@@ -147,7 +165,9 @@ module RuboCop
147
165
  end
148
166
 
149
167
  handle 'textDocument/didSave' do |_request|
150
- # Nothing to do
168
+ # The buffer's contents are now on disk, so the project index may be
169
+ # stale; drop it so the next diagnostics run rebuilds it.
170
+ @server.reset_project_index
151
171
  end
152
172
 
153
173
  handle '$/cancelRequest' do |_request|
@@ -187,6 +207,47 @@ module RuboCop
187
207
  }
188
208
  end
189
209
 
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)
249
+ end
250
+
190
251
  def format_file(file_uri, command: nil)
191
252
  unless (text = @text_cache[file_uri])
192
253
  Logger.log("Format request arrived before text synchronized; skipping: `#{file_uri}'")
@@ -194,17 +255,35 @@ module RuboCop
194
255
  return []
195
256
  end
196
257
 
197
- new_text = @server.format(remove_file_protocol_from(file_uri), text, command: command)
258
+ new_text = @server.format(convert_file_uri_to_path(file_uri), text, command: command)
198
259
 
199
260
  return [] if new_text == text
200
261
 
201
- [
262
+ [{
202
263
  newText: new_text,
203
264
  range: {
204
265
  start: { line: 0, character: 0 },
205
266
  end: { line: text.count("\n") + 1, character: 0 }
206
267
  }
207
- ]
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]) }
208
287
  end
209
288
 
210
289
  def diagnostic(file_uri, text)
@@ -214,13 +293,37 @@ module RuboCop
214
293
  method: 'textDocument/publishDiagnostics',
215
294
  params: {
216
295
  uri: file_uri,
217
- diagnostics: @server.offenses(remove_file_protocol_from(file_uri), text)
296
+ diagnostics: @server.offenses(convert_file_uri_to_path(file_uri), text)
218
297
  }
219
298
  }
220
299
  end
221
300
 
222
- def remove_file_protocol_from(uri)
223
- uri.delete_prefix('file://')
301
+ def change_text(orig_text, text, range)
302
+ return text unless range
303
+
304
+ start_pos = text_pos(orig_text, range[:start])
305
+ end_pos = text_pos(orig_text, range[:end])
306
+ text_bin = orig_text.b
307
+ text_bin[start_pos...end_pos] = text.b
308
+ text_bin.force_encoding(orig_text.encoding)
309
+ end
310
+
311
+ def text_pos(text, range)
312
+ line = range[:line]
313
+ char = range[:character]
314
+ pos = 0
315
+ text.each_line.with_index do |l, i|
316
+ if i == line
317
+ pos += l.encode('utf-16be').b[0, char * 2].encode('utf-8', 'utf-16be').bytesize
318
+ return pos
319
+ end
320
+ pos += l.bytesize
321
+ end
322
+ pos
323
+ end
324
+
325
+ def convert_file_uri_to_path(uri)
326
+ URI.decode_www_form_component(uri.delete_prefix('file://'))
224
327
  end
225
328
  end
226
329
  end
@@ -17,45 +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
+
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
21
26
 
22
- def initialize(config_store)
23
27
  @runner = RuboCop::Lsp::StdinRunner.new(config_store)
24
- @cop_registry = RuboCop::Cop::Registry.global.to_h
25
28
 
26
29
  @safe_autocorrect = true
27
30
  @lint_mode = false
28
31
  @layout_mode = false
32
+ @raise_cop_error = true
29
33
  end
30
34
 
31
- def format(path, text, command:)
35
+ def format(path, text, command:, prism_result: nil, options: {})
32
36
  safe_autocorrect = if command
33
37
  command == 'rubocop.formatAutocorrects'
34
38
  else
35
39
  @safe_autocorrect
36
40
  end
37
41
 
38
- formatting_options = { autocorrect: true, safe_autocorrect: safe_autocorrect }
39
- 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))
40
45
 
41
- @runner.run(path, text, formatting_options)
46
+ @runner.run(path, text, formatting_options, prism_result: prism_result)
42
47
  @runner.formatted_source
43
48
  end
44
49
 
45
- def offenses(path, text, document_encoding = nil)
46
- diagnostic_options = {}
47
- diagnostic_options[:only] = config_only_options if @lint_mode || @layout_mode
50
+ def reset_project_index
51
+ @runner.reset_project_index
52
+ end
48
53
 
49
- @runner.run(path, text, diagnostic_options)
50
- @runner.offenses.map do |offense|
51
- Diagnostic.new(
52
- document_encoding, offense, path, @cop_registry[offense.cop_name]&.first
53
- ).to_lsp_diagnostic(@runner.config_for_working_directory)
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)
54
60
  end
55
61
  end
56
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
+
57
88
  private
58
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
+
59
110
  def config_only_options
60
111
  only_options = []
61
112
  only_options << 'Lint' if @lint_mode
@@ -22,8 +22,6 @@ module RuboCop
22
22
  def initialize(config_store)
23
23
  $PROGRAM_NAME = "rubocop --lsp #{ConfigFinder.project_root}"
24
24
 
25
- RuboCop::LSP.enable
26
-
27
25
  @reader = LanguageServer::Protocol::Transport::Io::Reader.new($stdin)
28
26
  @writer = LanguageServer::Protocol::Transport::Io::Writer.new($stdout)
29
27
  @runtime = RuboCop::LSP::Runtime.new(config_store)
@@ -63,6 +61,10 @@ module RuboCop
63
61
  @runtime.layout_mode = options[:layout_mode]
64
62
  end
65
63
 
64
+ def reset_project_index
65
+ @runtime.reset_project_index
66
+ end
67
+
66
68
  def stop(&block)
67
69
  at_exit(&block) if block
68
70
  exit