rubocop 1.80.2 → 1.86.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 (310) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -2
  4. data/config/default.yml +170 -19
  5. data/config/obsoletion.yml +9 -0
  6. data/lib/rubocop/cache_config.rb +29 -0
  7. data/lib/rubocop/cli/command/auto_generate_config.rb +3 -3
  8. data/lib/rubocop/cli/command/lsp.rb +1 -1
  9. data/lib/rubocop/cli/command/mcp.rb +19 -0
  10. data/lib/rubocop/cli/command/show_cops.rb +2 -2
  11. data/lib/rubocop/cli/command/show_docs_url.rb +1 -1
  12. data/lib/rubocop/cli.rb +28 -6
  13. data/lib/rubocop/comment_config.rb +62 -17
  14. data/lib/rubocop/config.rb +14 -10
  15. data/lib/rubocop/config_finder.rb +1 -1
  16. data/lib/rubocop/config_loader.rb +20 -21
  17. data/lib/rubocop/config_loader_resolver.rb +9 -7
  18. data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
  19. data/lib/rubocop/config_store.rb +6 -1
  20. data/lib/rubocop/config_validator.rb +1 -1
  21. data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
  22. data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
  23. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
  24. data/lib/rubocop/cop/correctors/alignment_corrector.rb +22 -6
  25. data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
  26. data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
  27. data/lib/rubocop/cop/documentation.rb +2 -3
  28. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
  29. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  30. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  31. data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
  32. data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
  33. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  34. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +9 -9
  35. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  36. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
  37. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  38. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
  39. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  40. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -2
  41. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  42. data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
  43. data/lib/rubocop/cop/layout/class_structure.rb +13 -6
  44. data/lib/rubocop/cop/layout/dot_position.rb +2 -2
  45. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +12 -2
  46. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +31 -13
  47. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  48. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  49. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
  50. data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
  51. data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
  52. data/lib/rubocop/cop/layout/end_alignment.rb +8 -1
  53. data/lib/rubocop/cop/layout/first_argument_indentation.rb +34 -1
  54. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
  55. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
  56. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
  57. data/lib/rubocop/cop/layout/hash_alignment.rb +3 -6
  58. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  59. data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
  60. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  61. data/lib/rubocop/cop/layout/indentation_width.rb +111 -7
  62. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  63. data/lib/rubocop/cop/layout/line_length.rb +26 -9
  64. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
  65. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
  66. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  67. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
  68. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +204 -39
  69. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +6 -4
  70. data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
  71. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  72. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
  73. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  74. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  75. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  76. data/lib/rubocop/cop/layout/space_around_keyword.rb +4 -2
  77. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
  78. data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
  79. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  80. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
  81. data/lib/rubocop/cop/lint/constant_reassignment.rb +59 -9
  82. data/lib/rubocop/cop/lint/constant_resolution.rb +1 -1
  83. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
  84. data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
  85. data/lib/rubocop/cop/lint/debugger.rb +0 -2
  86. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
  87. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  88. data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -12
  89. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  90. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  91. data/lib/rubocop/cop/lint/empty_conditional_body.rb +6 -1
  92. data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
  93. data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
  94. data/lib/rubocop/cop/lint/empty_when.rb +8 -1
  95. data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
  96. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  97. data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
  98. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  99. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +16 -6
  100. data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
  101. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  102. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -1
  103. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  104. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  105. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +0 -9
  106. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  107. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +23 -6
  108. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -2
  109. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
  110. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +17 -0
  111. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
  112. data/lib/rubocop/cop/lint/self_assignment.rb +10 -2
  113. data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
  114. data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
  115. data/lib/rubocop/cop/lint/syntax.rb +25 -1
  116. data/lib/rubocop/cop/lint/to_json.rb +12 -16
  117. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -0
  118. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
  119. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  120. data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
  121. data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
  122. data/lib/rubocop/cop/lint/useless_assignment.rb +45 -17
  123. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
  124. data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
  125. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  126. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +24 -9
  127. data/lib/rubocop/cop/lint/void.rb +39 -12
  128. data/lib/rubocop/cop/message_annotator.rb +1 -1
  129. data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
  130. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  131. data/lib/rubocop/cop/migration/department_name.rb +12 -1
  132. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  133. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +4 -6
  134. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  135. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -5
  136. data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
  137. data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
  138. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  139. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  140. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  141. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  142. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  143. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  144. data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
  145. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  146. data/lib/rubocop/cop/naming/method_name.rb +4 -2
  147. data/lib/rubocop/cop/naming/predicate_method.rb +27 -4
  148. data/lib/rubocop/cop/naming/predicate_prefix.rb +11 -11
  149. data/lib/rubocop/cop/offense.rb +9 -1
  150. data/lib/rubocop/cop/registry.rb +20 -13
  151. data/lib/rubocop/cop/security/eval.rb +15 -2
  152. data/lib/rubocop/cop/security/json_load.rb +33 -11
  153. data/lib/rubocop/cop/style/access_modifier_declarations.rb +15 -4
  154. data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
  155. data/lib/rubocop/cop/style/alias.rb +4 -1
  156. data/lib/rubocop/cop/style/and_or.rb +1 -0
  157. data/lib/rubocop/cop/style/arguments_forwarding.rb +25 -7
  158. data/lib/rubocop/cop/style/array_intersect.rb +2 -2
  159. data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
  160. data/lib/rubocop/cop/style/array_join.rb +4 -2
  161. data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
  162. data/lib/rubocop/cop/style/attr.rb +5 -2
  163. data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
  164. data/lib/rubocop/cop/style/begin_block.rb +3 -1
  165. data/lib/rubocop/cop/style/block_delimiters.rb +27 -34
  166. data/lib/rubocop/cop/style/case_equality.rb +15 -13
  167. data/lib/rubocop/cop/style/class_and_module_children.rb +11 -2
  168. data/lib/rubocop/cop/style/collection_compact.rb +36 -16
  169. data/lib/rubocop/cop/style/colon_method_call.rb +3 -1
  170. data/lib/rubocop/cop/style/concat_array_literals.rb +2 -0
  171. data/lib/rubocop/cop/style/conditional_assignment.rb +8 -18
  172. data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
  173. data/lib/rubocop/cop/style/copyright.rb +1 -1
  174. data/lib/rubocop/cop/style/documentation.rb +6 -6
  175. data/lib/rubocop/cop/style/documentation_method.rb +8 -8
  176. data/lib/rubocop/cop/style/double_negation.rb +1 -1
  177. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  178. data/lib/rubocop/cop/style/each_with_object.rb +2 -0
  179. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  180. data/lib/rubocop/cop/style/empty_class_definition.rb +119 -0
  181. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  182. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  183. data/lib/rubocop/cop/style/encoding.rb +7 -1
  184. data/lib/rubocop/cop/style/end_block.rb +3 -1
  185. data/lib/rubocop/cop/style/endless_method.rb +23 -5
  186. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  187. data/lib/rubocop/cop/style/file_open.rb +84 -0
  188. data/lib/rubocop/cop/style/float_division.rb +15 -1
  189. data/lib/rubocop/cop/style/for.rb +3 -0
  190. data/lib/rubocop/cop/style/format_string_token.rb +49 -5
  191. data/lib/rubocop/cop/style/global_vars.rb +5 -2
  192. data/lib/rubocop/cop/style/guard_clause.rb +27 -22
  193. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
  194. data/lib/rubocop/cop/style/hash_lookup_method.rb +101 -0
  195. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  196. data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
  197. data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
  198. data/lib/rubocop/cop/style/if_inside_else.rb +1 -5
  199. data/lib/rubocop/cop/style/if_unless_modifier.rb +57 -17
  200. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
  201. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
  202. data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
  203. data/lib/rubocop/cop/style/inline_comment.rb +4 -1
  204. data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
  205. data/lib/rubocop/cop/style/lambda_call.rb +8 -8
  206. data/lib/rubocop/cop/style/magic_comment_format.rb +2 -2
  207. data/lib/rubocop/cop/style/map_join.rb +123 -0
  208. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
  209. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  210. data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -4
  211. data/lib/rubocop/cop/style/module_member_existence_check.rb +107 -0
  212. data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
  213. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  214. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  215. data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
  216. data/lib/rubocop/cop/style/nil_comparison.rb +11 -10
  217. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  218. data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
  219. data/lib/rubocop/cop/style/not.rb +2 -0
  220. data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
  221. data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
  222. data/lib/rubocop/cop/style/one_line_conditional.rb +21 -12
  223. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  224. data/lib/rubocop/cop/style/parallel_assignment.rb +6 -2
  225. data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
  226. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
  227. data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
  228. data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
  229. data/lib/rubocop/cop/style/proc.rb +3 -2
  230. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  231. data/lib/rubocop/cop/style/reduce_to_hash.rb +184 -0
  232. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  233. data/lib/rubocop/cop/style/redundant_begin.rb +3 -3
  234. data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
  235. data/lib/rubocop/cop/style/redundant_each.rb +3 -3
  236. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  237. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  238. data/lib/rubocop/cop/style/redundant_format.rb +26 -5
  239. data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
  240. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
  241. data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
  242. data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
  243. data/lib/rubocop/cop/style/redundant_parentheses.rb +26 -22
  244. data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
  245. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
  246. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
  247. data/lib/rubocop/cop/style/redundant_return.rb +3 -1
  248. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +0 -5
  249. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  250. data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +114 -0
  251. data/lib/rubocop/cop/style/reverse_find.rb +51 -0
  252. data/lib/rubocop/cop/style/safe_navigation.rb +7 -7
  253. data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
  254. data/lib/rubocop/cop/style/select_by_range.rb +197 -0
  255. data/lib/rubocop/cop/style/select_by_regexp.rb +51 -21
  256. data/lib/rubocop/cop/style/semicolon.rb +25 -7
  257. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  258. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
  259. data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
  260. data/lib/rubocop/cop/style/sole_nested_conditional.rb +8 -1
  261. data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
  262. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  263. data/lib/rubocop/cop/style/symbol_proc.rb +4 -3
  264. data/lib/rubocop/cop/style/tally_method.rb +181 -0
  265. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  266. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  267. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
  268. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  269. data/lib/rubocop/cop/style/unless_else.rb +10 -9
  270. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  271. data/lib/rubocop/cop/team.rb +4 -4
  272. data/lib/rubocop/cop/util.rb +2 -3
  273. data/lib/rubocop/cop/utils/format_string.rb +10 -0
  274. data/lib/rubocop/cop/variable_force/branch.rb +30 -6
  275. data/lib/rubocop/cops_documentation_generator.rb +4 -4
  276. data/lib/rubocop/directive_comment.rb +48 -4
  277. data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
  278. data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
  279. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  280. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  281. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
  282. data/lib/rubocop/formatter/tap_formatter.rb +5 -2
  283. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
  284. data/lib/rubocop/formatter.rb +22 -21
  285. data/lib/rubocop/lsp/diagnostic.rb +18 -33
  286. data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
  287. data/lib/rubocop/lsp/routes.rb +12 -5
  288. data/lib/rubocop/lsp/runtime.rb +13 -3
  289. data/lib/rubocop/lsp/stdin_runner.rb +8 -17
  290. data/lib/rubocop/magic_comment.rb +20 -0
  291. data/lib/rubocop/mcp/server.rb +200 -0
  292. data/lib/rubocop/options.rb +10 -1
  293. data/lib/rubocop/path_util.rb +14 -2
  294. data/lib/rubocop/plugin/loader.rb +1 -1
  295. data/lib/rubocop/rake_task.rb +1 -1
  296. data/lib/rubocop/remote_config.rb +10 -8
  297. data/lib/rubocop/result_cache.rb +60 -37
  298. data/lib/rubocop/rspec/cop_helper.rb +8 -0
  299. data/lib/rubocop/rspec/shared_contexts.rb +18 -5
  300. data/lib/rubocop/rspec/support.rb +2 -1
  301. data/lib/rubocop/runner.rb +12 -3
  302. data/lib/rubocop/server/cache.rb +6 -29
  303. data/lib/rubocop/server/core.rb +2 -0
  304. data/lib/rubocop/target_finder.rb +1 -1
  305. data/lib/rubocop/target_ruby.rb +31 -14
  306. data/lib/rubocop/version.rb +2 -2
  307. data/lib/rubocop.rb +20 -0
  308. data/lib/ruby_lsp/rubocop/addon.rb +23 -8
  309. data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
  310. metadata +33 -9
@@ -95,10 +95,20 @@ module RuboCop
95
95
  return unless variable.method_argument?
96
96
  return if variable.keyword_argument? && cop_config['AllowUnusedKeywordArguments']
97
97
  return if ignored_method?(variable.scope.node.body)
98
+ return if block_argument_with_yield?(variable)
98
99
 
99
100
  super
100
101
  end
101
102
 
103
+ def block_argument_with_yield?(variable)
104
+ return false unless variable.declaration_node.blockarg_type?
105
+
106
+ method_body = variable.scope.node.body
107
+ return false unless method_body
108
+
109
+ method_body.yield_type? || method_body.each_descendant(:yield).any?
110
+ end
111
+
102
112
  def ignored_method?(body)
103
113
  (cop_config['IgnoreEmptyMethods'] && body.nil?) ||
104
114
  (cop_config['IgnoreNotImplementedMethods'] && not_implemented?(body))
@@ -52,32 +52,39 @@ module RuboCop
52
52
  scope.variables.each_value { |variable| check_for_unused_assignments(variable) }
53
53
  end
54
54
 
55
- # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
56
55
  def check_for_unused_assignments(variable)
57
56
  return if variable.should_be_unused?
58
57
 
59
58
  variable.assignments.reverse_each do |assignment|
60
- assignment_node = assignment.node
61
- next if assignment.used? || part_of_ignored_node?(assignment_node)
59
+ check_for_unused_assignment(variable, assignment)
60
+ end
61
+ end
62
62
 
63
- message = message_for_useless_assignment(assignment)
64
- range = offense_range(assignment)
63
+ def check_for_unused_assignment(variable, assignment)
64
+ assignment_node = assignment.node
65
65
 
66
- add_offense(range, message: message) do |corrector|
67
- # In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
68
- # and where changing `x ||= 1` to `x = 1` would cause `NameError`,
69
- # the autocorrect will be skipped, even if the variable is unused.
70
- if sequential_assignment?(assignment_node) || assignment_node.parent&.or_asgn_type?
71
- next
72
- end
66
+ return if ignored_assignment?(variable, assignment_node, assignment)
73
67
 
74
- autocorrect(corrector, assignment)
75
- end
68
+ message = message_for_useless_assignment(assignment)
69
+ range = offense_range(assignment)
76
70
 
77
- ignore_node(assignment_node) if chained_assignment?(assignment_node)
71
+ add_offense(range, message: message) do |corrector|
72
+ # In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
73
+ # and where changing `x ||= 1` to `x = 1` would cause `NameError`,
74
+ # the autocorrect will be skipped, even if the variable is unused.
75
+ next if sequential_assignment?(assignment_node) ||
76
+ assignment_node.parent&.or_asgn_type?
77
+
78
+ autocorrect(corrector, assignment)
78
79
  end
80
+
81
+ ignore_node(assignment_node) if chained_assignment?(assignment_node)
82
+ end
83
+
84
+ def ignored_assignment?(variable, assignment_node, assignment)
85
+ assignment.used? || part_of_ignored_node?(assignment_node) ||
86
+ variable_in_loop_condition?(assignment_node, variable)
79
87
  end
80
- # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
81
88
 
82
89
  def message_for_useless_assignment(assignment)
83
90
  variable = assignment.variable
@@ -206,7 +213,28 @@ module RuboCop
206
213
  end
207
214
 
208
215
  def remove_local_variable_assignment_part(corrector, node)
209
- corrector.replace(node, node.expression.source)
216
+ corrector.remove(node.loc.name.begin.join(node.expression.source_range.begin))
217
+ end
218
+
219
+ def variable_in_loop_condition?(assignment_node, variable)
220
+ return false if assignment_node.each_ancestor(:any_def).any?
221
+
222
+ loop_node = assignment_node.each_ancestor.find do |ancestor|
223
+ ancestor.type?(*VariableForce::LOOP_TYPES)
224
+ end
225
+
226
+ return false unless loop_node.respond_to?(:condition)
227
+
228
+ condition_node = loop_node.condition
229
+ variable_name = variable.name
230
+
231
+ return true if condition_node.lvar_type? && condition_node.children.first == variable_name
232
+
233
+ condition_node.each_descendant(:lvar) do |lvar_node|
234
+ return true if lvar_node.children.first == variable_name
235
+ end
236
+
237
+ false
210
238
  end
211
239
  end
212
240
  end
@@ -48,12 +48,12 @@ module RuboCop
48
48
 
49
49
  def after_private_modifier?(left_siblings)
50
50
  access_modifier_candidates = left_siblings.compact.select do |left_sibling|
51
- left_sibling.respond_to?(:send_type?) && left_sibling.send_type?
51
+ left_sibling.respond_to?(:bare_access_modifier?) && left_sibling.bare_access_modifier?
52
52
  end
53
53
 
54
- access_modifier_candidates.any? do |candidate|
55
- candidate.command?(:private) && candidate.arguments.none?
56
- end
54
+ return false if access_modifier_candidates.empty?
55
+
56
+ access_modifier_candidates.last.command?(:private)
57
57
  end
58
58
 
59
59
  def private_constantize?(right_siblings, const_value)
@@ -67,6 +67,8 @@ module RuboCop
67
67
  PATTERN
68
68
 
69
69
  def on_send(node)
70
+ return unless node.receiver
71
+
70
72
  unless (prev_arg_node, default_value_node = default_value_argument_and_block(node.parent))
71
73
  return
72
74
  end
@@ -9,6 +9,13 @@ module RuboCop
9
9
  # on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
10
10
  # appended after these methods will never evaluate.
11
11
  #
12
+ # @safety
13
+ # As shown in the examples below, there are generally two possible ways to correct the
14
+ # offense, but this cop's autocorrection always chooses the option that preserves the
15
+ # current behavior. While this does not change how the code behaves, that option is not
16
+ # necessarily the appropriate fix in every situation. For this reason, the autocorrection
17
+ # provided by this cop is considered unsafe.
18
+ #
12
19
  # @example
13
20
  #
14
21
  # # bad
@@ -64,6 +71,8 @@ module RuboCop
64
71
  # x&.to_s or fallback
65
72
  #
66
73
  class UselessOr < Base
74
+ extend AutoCorrector
75
+
67
76
  MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
68
77
 
69
78
  TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
@@ -89,8 +98,12 @@ module RuboCop
89
98
  private
90
99
 
91
100
  def report_offense(or_node, truthy_node)
92
- add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
93
- message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
101
+ add_offense(
102
+ or_node.loc.operator.join(or_node.rhs.source_range),
103
+ message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source)
104
+ ) do |corrector|
105
+ corrector.replace(or_node, or_node.lhs.source)
106
+ end
94
107
  end
95
108
  end
96
109
  end
@@ -31,7 +31,7 @@ module RuboCop
31
31
  @checked_nodes[node] = true
32
32
 
33
33
  case node.type
34
- when :def, :class, :module, :sclass
34
+ when :def, :defs, :class, :module, :sclass
35
35
  return false
36
36
  when :send
37
37
  return non_nil_method?(node.method_name) if node.receiver == receiver
@@ -53,7 +53,7 @@ module RuboCop
53
53
  return true
54
54
  end
55
55
  when :when
56
- node.each_condition do |condition|
56
+ node.conditions.each do |condition|
57
57
  return true if _cant_be_nil?(condition, receiver)
58
58
  end
59
59
  when :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
@@ -82,28 +82,35 @@ module RuboCop
82
82
  !NIL_METHODS.include?(method_name) && !@additional_nil_methods.include?(method_name)
83
83
  end
84
84
 
85
- # rubocop:disable Metrics/PerceivedComplexity
85
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
86
86
  def sole_condition_of_parent_if?(node)
87
+ child = node
87
88
  parent = node.parent
88
89
 
89
90
  while parent
90
91
  if parent.if_type?
91
- if parent.condition == node
92
- return true
93
- elsif parent.elsif?
94
- parent = find_top_if(parent)
95
- end
92
+ condition = parent.condition
93
+ return true if !child.equal?(condition) && non_nil_condition?(condition, node)
94
+
95
+ parent = find_top_if(parent) if parent.elsif?
96
96
  elsif else_branch?(parent)
97
97
  # Find the top `if` for `else`.
98
98
  parent = parent.parent
99
99
  end
100
100
 
101
+ child = parent
101
102
  parent = parent&.parent
102
103
  end
103
104
 
104
105
  false
105
106
  end
106
- # rubocop:enable Metrics/PerceivedComplexity
107
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
108
+
109
+ def non_nil_condition?(condition, node)
110
+ return true if condition == node
111
+
112
+ condition.csend_type? && csend_root_receiver(condition) == node
113
+ end
107
114
 
108
115
  def else_branch?(node)
109
116
  node.parent&.if_type? && node.parent.else_branch == node
@@ -114,6 +121,14 @@ module RuboCop
114
121
 
115
122
  node
116
123
  end
124
+
125
+ def csend_root_receiver(node)
126
+ return unless (receiver = node.receiver)
127
+
128
+ receiver = receiver.receiver while receiver.call_type? && receiver.receiver
129
+
130
+ receiver
131
+ end
117
132
  end
118
133
  end
119
134
  end
@@ -16,6 +16,12 @@ module RuboCop
16
16
  # enumerator.each { |item| item >= 2 } #=> [2, 3]
17
17
  # ----
18
18
  #
19
+ # NOTE: Return values in assignment method definitions such as `def foo=(arg)` are
20
+ # detected because they are in a void context. However, autocorrection does not remove
21
+ # the return value, as that would change behavior. In such cases, whether to remove
22
+ # the return value or rename the method to something more appropriate should be left to
23
+ # the user.
24
+ #
19
25
  # @example CheckForMethodsWithNoSideEffects: false (default)
20
26
  # # bad
21
27
  # def some_method
@@ -81,8 +87,9 @@ module RuboCop
81
87
  def on_block(node)
82
88
  return unless node.body && !node.body.begin_type?
83
89
  return unless in_void_context?(node.body)
90
+ return if node.method?(:each)
84
91
 
85
- check_void_op(node.body) { node.method?(:each) }
92
+ check_void_op(node.body)
86
93
  check_expression(node.body)
87
94
  end
88
95
  alias on_numblock on_block
@@ -101,22 +108,23 @@ module RuboCop
101
108
 
102
109
  def check_begin(node)
103
110
  expressions = *node
104
- expressions.pop unless in_void_context?(node)
111
+ inside_each_block = node.each_ancestor(:any_block).first&.method?(:each)
112
+ expressions.pop if !in_void_context?(node) || inside_each_block
105
113
  expressions.each do |expr|
106
- check_void_op(expr) do
107
- block_node = node.each_ancestor(:any_block).first
108
-
109
- block_node&.method?(:each)
110
- end
111
-
114
+ check_void_op(expr) { inside_each_block }
112
115
  check_expression(expr)
113
116
  end
114
117
  end
115
118
 
116
119
  def check_expression(expr)
117
- expr = expr.body if expr.if_type?
118
- return unless expr
120
+ return check_if_expression(expr) if expr.if_type?
121
+ return check_case_expression(expr) if expr.case_type?
122
+ return check_case_match_expression(expr) if expr.case_match_type?
119
123
 
124
+ check_void_expression_nodes(expr)
125
+ end
126
+
127
+ def check_void_expression_nodes(expr)
120
128
  check_literal(expr)
121
129
  check_var(expr)
122
130
  check_self(expr)
@@ -126,6 +134,22 @@ module RuboCop
126
134
  check_nonmutating(expr)
127
135
  end
128
136
 
137
+ def check_if_expression(if_node)
138
+ check_void_expression_nodes(if_node.body) if if_node.body
139
+ end
140
+
141
+ def check_case_expression(case_node)
142
+ case_node.each_when { |when_node| check_expression(when_node.body) if when_node.body }
143
+ check_expression(case_node.else_branch) if case_node.else_branch
144
+ end
145
+
146
+ def check_case_match_expression(case_node)
147
+ case_node.each_in_pattern do |in_pattern_node|
148
+ check_expression(in_pattern_node.body) if in_pattern_node.body
149
+ end
150
+ check_expression(case_node.else_branch) if case_node.else_branch
151
+ end
152
+
129
153
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
130
154
  def check_void_op(node, &block)
131
155
  node = node.children.first while node&.begin_type?
@@ -162,7 +186,9 @@ module RuboCop
162
186
  end
163
187
 
164
188
  def check_literal(node)
165
- return if !entirely_literal?(node) || node.xstr_type? || node.range_type?
189
+ if !entirely_literal?(node) || node.xstr_type? || node.range_type? || node.nil_type?
190
+ return
191
+ end
166
192
 
167
193
  add_offense(node, message: format(LIT_MSG, lit: node.source)) do |corrector|
168
194
  autocorrect_void_expression(corrector, node)
@@ -232,7 +258,8 @@ module RuboCop
232
258
  end
233
259
 
234
260
  def autocorrect_void_expression(corrector, node)
235
- return if node.parent.if_type?
261
+ return if node.parent.type?(:if, :case, :when, :case_match, :in_pattern)
262
+ return if (def_node = node.each_ancestor(:any_def).first) && def_node.assignment_method?
236
263
 
237
264
  corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
238
265
  end
@@ -102,7 +102,7 @@ module RuboCop
102
102
  def reference_urls
103
103
  urls = cop_config
104
104
  .values_at('References', 'Reference') # Support legacy Reference key
105
- .flat_map { Array(_1) }
105
+ .flat_map { |url| Array(url) }
106
106
  .reject(&:empty?)
107
107
 
108
108
  urls unless urls.empty?
@@ -4,6 +4,8 @@ module RuboCop
4
4
  module Cop
5
5
  module Metrics
6
6
  # Checks for excessive nesting of conditional and looping constructs.
7
+ # Deeply nested code is harder to read, understand, and maintain.
8
+ # Extracting nested logic into methods improves clarity.
7
9
  #
8
10
  # You can configure if blocks are considered using the `CountBlocks` and `CountModifierForms`
9
11
  # options. When both are set to `false` (the default) blocks and modifier forms are not
@@ -11,6 +13,27 @@ module RuboCop
11
13
  # calculation as well.
12
14
  #
13
15
  # The maximum level of nesting allowed is configurable.
16
+ #
17
+ # @example Max: 3 (default)
18
+ # # bad
19
+ # if condition1
20
+ # if condition2
21
+ # if condition3
22
+ # if condition4
23
+ # do_something
24
+ # end
25
+ # end
26
+ # end
27
+ # end
28
+ #
29
+ # # good
30
+ # if condition1
31
+ # if condition2
32
+ # if condition3
33
+ # do_something
34
+ # end
35
+ # end
36
+ # end
14
37
  class BlockNesting < Base
15
38
  NESTING_BLOCKS = %i[case case_match if while while_post until until_post for resbody].freeze
16
39
 
@@ -84,7 +84,10 @@ module RuboCop
84
84
  end
85
85
 
86
86
  def assignment?(node)
87
- return compound_assignment(node) if node.masgn_type? || node.shorthand_asgn?
87
+ if node.masgn_type? || node.shorthand_asgn?
88
+ compound_assignment(node)
89
+ return false
90
+ end
88
91
 
89
92
  node.for_type? ||
90
93
  (node.respond_to?(:setter_method?) && node.setter_method?) ||
@@ -101,8 +104,6 @@ module RuboCop
101
104
  child.respond_to?(:setter_method?) && !child.setter_method?
102
105
  end
103
106
  @assignment += will_be_miscounted
104
-
105
- false
106
107
  end
107
108
 
108
109
  def simple_assignment?(node)
@@ -1,10 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # Lint/RedundantCopDisableDirective needs to be disabled so as
4
+ # to be able to provide examples of rubocop:disable comments.
5
+ # rubocop:disable Lint/RedundantCopDisableDirective
3
6
  module RuboCop
4
7
  module Cop
5
8
  module Migration
6
- # Check that cop names in rubocop:disable comments are given with
9
+ # Checks that cop names in rubocop:disable comments are given with
7
10
  # department name.
11
+ #
12
+ # @example
13
+ # # bad
14
+ # # rubocop:disable AbcSize
15
+ #
16
+ # # good
17
+ # # rubocop:disable Metrics/AbcSize
8
18
  class DepartmentName < Base
9
19
  include RangeHelp
10
20
  extend AutoCorrector
@@ -79,3 +89,4 @@ module RuboCop
79
89
  end
80
90
  end
81
91
  end
92
+ # rubocop:enable Lint/RedundantCopDisableDirective
@@ -222,12 +222,12 @@ module RuboCop
222
222
  def already_on_multiple_lines?(node)
223
223
  return node.first_line != node.last_argument.last_line if node.any_def_type?
224
224
 
225
- !node.single_line?
225
+ node.multiline?
226
226
  end
227
227
 
228
228
  def chained_to_heredoc?(node)
229
229
  while (node = node.receiver)
230
- return true if node.type?(:str, :dstr, :xstr) && node.heredoc?
230
+ return true if node.any_str_type? && node.heredoc?
231
231
  end
232
232
 
233
233
  false
@@ -14,6 +14,8 @@ module RuboCop
14
14
  private
15
15
 
16
16
  def too_long?(node)
17
+ return false unless max_line_length
18
+
17
19
  lines = processed_source.lines[(node.first_line - 1)...node.last_line]
18
20
  to_single_line(lines.join("\n")).length > max_line_length
19
21
  end
@@ -27,10 +29,6 @@ module RuboCop
27
29
  .gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
28
30
  end
29
31
 
30
- def max_line_length
31
- config.for_cop('Layout/LineLength')['Max']
32
- end
33
-
34
32
  def comment_within?(node)
35
33
  comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
36
34
 
@@ -40,9 +38,9 @@ module RuboCop
40
38
  end
41
39
 
42
40
  def safe_to_split?(node)
43
- node.each_descendant(:if, :case, :kwbegin, :any_def).none? &&
41
+ node.each_descendant(:if, :case, :kwbegin, :any_def, :rescue, :ensure).none? &&
44
42
  node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
45
- node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
43
+ node.each_descendant(:begin, :sym).none?(&:multiline?)
46
44
  end
47
45
  end
48
46
  end
@@ -59,7 +59,7 @@ module RuboCop
59
59
  return node.loc.name if node.casgn_type?
60
60
 
61
61
  if LSP.enabled?
62
- end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
62
+ end_range = node.loc?(:name) ? node.loc.name : node.loc.begin
63
63
  node.source_range.begin.join(end_range)
64
64
  else
65
65
  node.source_range
@@ -13,7 +13,7 @@ module RuboCop
13
13
 
14
14
  DefNode = Struct.new(:node) do
15
15
  def selector
16
- if node.loc.respond_to?(:selector)
16
+ if node.loc?(:selector)
17
17
  node.loc.selector
18
18
  else
19
19
  node.loc.keyword
@@ -125,7 +125,7 @@ module RuboCop
125
125
  return if dispatch_node.assignment_method?
126
126
  return if dispatch_node.parenthesized?
127
127
  return if dispatch_node.parent && parentheses?(dispatch_node.parent)
128
- return if last_expression?(dispatch_node) && !method_dispatch_as_argument?(dispatch_node)
128
+ return if last_expression?(dispatch_node) && !requires_parentheses_context?(dispatch_node)
129
129
 
130
130
  def_node = node.each_ancestor(:call, :super, :yield).first
131
131
 
@@ -164,11 +164,11 @@ module RuboCop
164
164
  !assignment_node.right_sibling
165
165
  end
166
166
 
167
- def method_dispatch_as_argument?(method_dispatch_node)
168
- parent = method_dispatch_node.parent
167
+ def requires_parentheses_context?(node)
168
+ parent = node.parent
169
169
  return false unless parent
170
170
 
171
- parent.type?(:call, :super, :yield)
171
+ parent.type?(:call, :if, :super, :until, :while, :yield)
172
172
  end
173
173
 
174
174
  def breakdown_value_types_of_hash(hash_node)
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module HashTransformMethod
6
+ # Internal helper class to hold autocorrect data
7
+ Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
8
+ def self.from_each_with_object(node, match)
9
+ new(match, node, 0, 0)
10
+ end
11
+
12
+ def self.from_hash_brackets_map(node, match)
13
+ new(match, node.children.last, 'Hash['.length, ']'.length)
14
+ end
15
+
16
+ def self.from_map_to_h(node, match)
17
+ if node.parent&.block_type? && node.parent.send_node == node
18
+ strip_trailing_chars = 0
19
+ else
20
+ map_range = node.children.first.source_range
21
+ node_range = node.source_range
22
+ strip_trailing_chars = node_range.end_pos - map_range.end_pos
23
+ end
24
+
25
+ new(match, node.children.first, 0, strip_trailing_chars)
26
+ end
27
+
28
+ def self.from_to_h(node, match)
29
+ new(match, node, 0, 0)
30
+ end
31
+
32
+ def strip_prefix_and_suffix(node, corrector)
33
+ expression = node.source_range
34
+ corrector.remove_leading(expression, leading)
35
+ corrector.remove_trailing(expression, trailing)
36
+ end
37
+
38
+ def set_new_method_name(new_method_name, corrector)
39
+ range = block_node.send_node.loc.selector
40
+ if (send_end = block_node.send_node.loc.end)
41
+ # If there are arguments (only true in the `each_with_object`
42
+ # case)
43
+ range = range.begin.join(send_end)
44
+ end
45
+ corrector.replace(range, new_method_name)
46
+ end
47
+
48
+ def set_new_arg_name(transformed_argname, corrector)
49
+ corrector.replace(block_node.arguments, "|#{transformed_argname}|")
50
+ end
51
+
52
+ def set_new_body_expression(transforming_body_expr, corrector)
53
+ body_source = transforming_body_expr.source
54
+ if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
55
+ body_source = "{ #{body_source} }"
56
+ end
57
+
58
+ corrector.replace(block_node.body, body_source)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end