rubocop 1.90.0 → 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 (303) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +241 -11
  4. data/config/obsoletion.yml +9 -0
  5. data/lib/rubocop/cached_data.rb +47 -7
  6. data/lib/rubocop/changed_files.rb +134 -0
  7. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  8. data/lib/rubocop/cli/command/execute_runner.rb +23 -3
  9. data/lib/rubocop/cli/command/explain.rb +34 -0
  10. data/lib/rubocop/cli/command/show_cops.rb +6 -0
  11. data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
  12. data/lib/rubocop/cli.rb +11 -4
  13. data/lib/rubocop/comment_config/directive_range.rb +3 -1
  14. data/lib/rubocop/comment_config/disable_next.rb +49 -3
  15. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  16. data/lib/rubocop/comment_config.rb +32 -53
  17. data/lib/rubocop/config.rb +10 -0
  18. data/lib/rubocop/config_loader.rb +18 -7
  19. data/lib/rubocop/config_loader_resolver.rb +79 -12
  20. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  21. data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
  22. data/lib/rubocop/config_obsoletion.rb +1 -1
  23. data/lib/rubocop/config_validator.rb +29 -3
  24. data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
  25. data/lib/rubocop/cop/badge.rb +1 -1
  26. data/lib/rubocop/cop/base.rb +57 -24
  27. data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
  28. data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
  29. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  30. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  31. data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
  32. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +22 -7
  33. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  34. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +23 -2
  35. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
  36. data/lib/rubocop/cop/correctors.rb +2 -2
  37. data/lib/rubocop/cop/documentation.rb +1 -1
  38. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  39. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
  40. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  41. data/lib/rubocop/cop/generator.rb +1 -1
  42. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
  43. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
  44. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  45. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  46. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  47. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
  48. data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
  49. data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
  50. data/lib/rubocop/cop/layout/class_structure.rb +9 -1
  51. data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
  52. data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
  53. data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
  54. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +14 -5
  55. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  56. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  57. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  58. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -1
  59. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  60. data/lib/rubocop/cop/layout/end_alignment.rb +16 -10
  61. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -0
  62. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
  63. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
  64. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +5 -3
  65. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  66. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  67. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  68. data/lib/rubocop/cop/layout/hash_alignment.rb +15 -10
  69. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -0
  70. data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
  71. data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
  72. data/lib/rubocop/cop/layout/indentation_width.rb +4 -4
  73. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
  74. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  75. data/lib/rubocop/cop/layout/line_length.rb +71 -19
  76. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
  77. data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
  78. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +7 -0
  79. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
  80. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +14 -0
  81. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  82. data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
  83. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +15 -2
  84. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  85. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  86. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
  87. data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
  88. data/lib/rubocop/cop/layout/space_around_operators.rb +5 -1
  89. data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
  90. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
  91. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
  92. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  93. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
  94. data/lib/rubocop/cop/lint/argument_mismatch.rb +14 -4
  95. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
  96. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +88 -14
  97. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  98. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  99. data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
  100. data/lib/rubocop/cop/lint/literal_as_condition.rb +23 -2
  101. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
  102. data/lib/rubocop/cop/lint/loop.rb +24 -2
  103. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
  104. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +19 -4
  105. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  106. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  107. data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
  108. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
  109. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +42 -17
  110. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
  111. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
  112. data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
  113. data/lib/rubocop/cop/lint/void.rb +8 -1
  114. data/lib/rubocop/cop/lint.rb +1 -0
  115. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  116. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  117. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  118. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  119. data/lib/rubocop/cop/mixin/alignment.rb +5 -1
  120. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  121. data/lib/rubocop/cop/mixin/check_line_breakable.rb +17 -14
  122. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -1
  123. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  124. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
  125. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +69 -0
  126. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
  127. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +26 -2
  128. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +31 -3
  129. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  130. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  131. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  132. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
  133. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  134. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  135. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +29 -3
  136. data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
  137. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
  138. data/lib/rubocop/cop/mixin/statement_modifier.rb +22 -2
  139. data/lib/rubocop/cop/mixin.rb +4 -2
  140. data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
  141. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
  142. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  143. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  144. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  145. data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
  146. data/lib/rubocop/cop/offense.rb +59 -3
  147. data/lib/rubocop/cop/registry.rb +10 -2
  148. data/lib/rubocop/cop/security/json_load.rb +16 -4
  149. data/lib/rubocop/cop/severity.rb +12 -0
  150. data/lib/rubocop/cop/style/access_modifier_declarations.rb +10 -2
  151. data/lib/rubocop/cop/style/alias.rb +18 -5
  152. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  153. data/lib/rubocop/cop/style/and_or.rb +4 -0
  154. data/lib/rubocop/cop/style/arguments_forwarding.rb +6 -3
  155. data/lib/rubocop/cop/style/attr.rb +3 -4
  156. data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
  157. data/lib/rubocop/cop/style/block_delimiters.rb +29 -3
  158. data/lib/rubocop/cop/style/case_like_if.rb +9 -6
  159. data/lib/rubocop/cop/style/class_and_module_children.rb +54 -16
  160. data/lib/rubocop/cop/style/class_methods_definitions.rb +8 -0
  161. data/lib/rubocop/cop/style/combinable_loops.rb +85 -11
  162. data/lib/rubocop/cop/style/concat_array_literals.rb +46 -7
  163. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
  164. data/lib/rubocop/cop/style/constant_visibility.rb +6 -2
  165. data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
  166. data/lib/rubocop/cop/style/directive_scope.rb +154 -21
  167. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +118 -18
  168. data/lib/rubocop/cop/style/documentation_method.rb +1 -9
  169. data/lib/rubocop/cop/style/double_negation.rb +11 -0
  170. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  171. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  172. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  173. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  174. data/lib/rubocop/cop/style/empty_method.rb +15 -3
  175. data/lib/rubocop/cop/style/endless_method.rb +91 -11
  176. data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
  177. data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
  178. data/lib/rubocop/cop/style/file_null.rb +2 -2
  179. data/lib/rubocop/cop/style/float_division.rb +28 -14
  180. data/lib/rubocop/cop/style/for.rb +44 -1
  181. data/lib/rubocop/cop/style/format_string.rb +28 -6
  182. data/lib/rubocop/cop/style/format_string_token.rb +1 -1
  183. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  184. data/lib/rubocop/cop/style/guard_clause.rb +13 -1
  185. data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
  186. data/lib/rubocop/cop/style/hash_lookup_method.rb +35 -9
  187. data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
  188. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  189. data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
  190. data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -20
  191. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
  192. data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
  193. data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
  194. data/lib/rubocop/cop/style/it_block_parameter.rb +32 -3
  195. data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
  196. data/lib/rubocop/cop/style/lambda.rb +18 -0
  197. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  198. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  199. data/lib/rubocop/cop/style/map_into_array.rb +1 -2
  200. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +45 -10
  201. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -2
  202. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
  203. data/lib/rubocop/cop/style/method_def_parentheses.rb +29 -3
  204. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  205. data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
  206. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  207. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
  208. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  209. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  210. data/lib/rubocop/cop/style/mutable_constant.rb +28 -1
  211. data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
  212. data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
  213. data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
  214. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  215. data/lib/rubocop/cop/style/next.rb +24 -10
  216. data/lib/rubocop/cop/style/nil_comparison.rb +48 -8
  217. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  218. data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
  219. data/lib/rubocop/cop/style/not.rb +10 -3
  220. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  221. data/lib/rubocop/cop/style/numeric_predicate.rb +21 -5
  222. data/lib/rubocop/cop/style/one_line_conditional.rb +14 -3
  223. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
  224. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  225. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
  226. data/lib/rubocop/cop/style/reduce_to_hash.rb +17 -1
  227. data/lib/rubocop/cop/style/redundant_begin.rb +20 -3
  228. data/lib/rubocop/cop/style/redundant_condition.rb +34 -17
  229. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -1
  230. data/lib/rubocop/cop/style/redundant_exception.rb +15 -3
  231. data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
  232. data/lib/rubocop/cop/style/redundant_freeze.rb +10 -1
  233. data/lib/rubocop/cop/style/redundant_parentheses.rb +23 -2
  234. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
  235. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  236. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +25 -5
  237. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
  238. data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
  239. data/lib/rubocop/cop/style/require_order.rb +9 -0
  240. data/lib/rubocop/cop/style/rescue_modifier.rb +5 -9
  241. data/lib/rubocop/cop/style/return_nil.rb +17 -2
  242. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  243. data/lib/rubocop/cop/style/sample.rb +9 -8
  244. data/lib/rubocop/cop/style/self_assignment.rb +12 -15
  245. data/lib/rubocop/cop/style/semicolon.rb +16 -5
  246. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  247. data/lib/rubocop/cop/style/single_line_methods.rb +16 -4
  248. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  249. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
  250. data/lib/rubocop/cop/style/string_concatenation.rb +9 -3
  251. data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
  252. data/lib/rubocop/cop/style/super_arguments.rb +3 -0
  253. data/lib/rubocop/cop/style/symbol_proc.rb +23 -5
  254. data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
  255. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  256. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
  257. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  258. data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
  259. data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
  260. data/lib/rubocop/cop/style.rb +0 -1
  261. data/lib/rubocop/cop/team.rb +10 -5
  262. data/lib/rubocop/cop/util.rb +1 -1
  263. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  264. data/lib/rubocop/cop/variable_force/variable.rb +14 -1
  265. data/lib/rubocop/cops_documentation_generator.rb +23 -2
  266. data/lib/rubocop/directive_comment.rb +37 -8
  267. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  268. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
  269. data/lib/rubocop/formatter/formatter_set.rb +6 -1
  270. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  271. data/lib/rubocop/formatter/html_formatter.rb +2 -2
  272. data/lib/rubocop/formatter/json_formatter.rb +71 -1
  273. data/lib/rubocop/formatter/junit_formatter.rb +1 -1
  274. data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
  275. data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
  276. data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
  277. data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
  278. data/lib/rubocop/formatter.rb +1 -0
  279. data/lib/rubocop/lsp/runtime.rb +47 -11
  280. data/lib/rubocop/lsp/stdin_runner.rb +11 -5
  281. data/lib/rubocop/lsp.rb +5 -2
  282. data/lib/rubocop/magic_comment.rb +27 -0
  283. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  284. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  285. data/lib/rubocop/mcp/scope.rb +65 -0
  286. data/lib/rubocop/mcp/server.rb +184 -76
  287. data/lib/rubocop/mcp/source_files.rb +35 -0
  288. data/lib/rubocop/offense_limit.rb +30 -0
  289. data/lib/rubocop/options.rb +97 -4
  290. data/lib/rubocop/path_util.rb +1 -1
  291. data/lib/rubocop/plugin/configuration_integrator.rb +12 -5
  292. data/lib/rubocop/plugin/loader.rb +1 -1
  293. data/lib/rubocop/rake_task.rb +1 -1
  294. data/lib/rubocop/remote_config.rb +8 -5
  295. data/lib/rubocop/result_cache.rb +36 -18
  296. data/lib/rubocop/runner.rb +160 -49
  297. data/lib/rubocop/server/cache.rb +2 -2
  298. data/lib/rubocop/unified_diff.rb +257 -0
  299. data/lib/rubocop/util.rb +69 -0
  300. data/lib/rubocop/version.rb +1 -1
  301. data/lib/rubocop.rb +9 -1
  302. metadata +21 -6
  303. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RuboCop
4
- module Cop # rubocop:disable Style/Documentation
4
+ module Cop # rubocop:disable Style/Documentation -- a namespace that only autoloads the mixins below
5
5
  # Autoloads mixin modules included by cops. Mixins are autoloaded to reduce the number of
6
6
  # requires because they're used only when the relevant cop class is loaded.
7
7
 
@@ -14,7 +14,7 @@ module RuboCop
14
14
  autoload :AllowedReceivers, "#{__dir__}/mixin/allowed_receivers"
15
15
  autoload :ForbiddenIdentifiers, "#{__dir__}/mixin/forbidden_identifiers"
16
16
  autoload :ForbiddenPattern, "#{__dir__}/mixin/forbidden_pattern"
17
- autoload :AutoCorrector, "#{__dir__}/mixin/auto_corrector" # rubocop:todo Naming/InclusiveLanguage
17
+ autoload :AutoCorrector, "#{__dir__}/mixin/auto_corrector" # rubocop:todo Naming/InclusiveLanguage -- the file is named `auto_corrector.rb`
18
18
  autoload :CheckAssignment, "#{__dir__}/mixin/check_assignment"
19
19
  autoload :CheckLineBreakable, "#{__dir__}/mixin/check_line_breakable"
20
20
  autoload :CheckSingleLineSuitability, "#{__dir__}/mixin/check_single_line_suitability"
@@ -32,6 +32,7 @@ module RuboCop
32
32
  autoload :AnnotationComment, "#{__dir__}/mixin/annotation_comment"
33
33
  autoload :EmptyParameter, "#{__dir__}/mixin/empty_parameter"
34
34
  autoload :EndKeywordAlignment, "#{__dir__}/mixin/end_keyword_alignment"
35
+ autoload :EndlessMethodBodyHelp, "#{__dir__}/mixin/endless_method_body_help"
35
36
  autoload :EndlessMethodRewriter, "#{__dir__}/mixin/endless_method_rewriter"
36
37
  autoload :EnforceSuperclass, "#{__dir__}/mixin/enforce_superclass"
37
38
  autoload :FirstElementLineBreak, "#{__dir__}/mixin/first_element_line_break"
@@ -64,6 +65,7 @@ module RuboCop
64
65
  autoload :OnNormalIfUnless, "#{__dir__}/mixin/on_normal_if_unless"
65
66
  autoload :OrderedGemNode, "#{__dir__}/mixin/ordered_gem_node"
66
67
  autoload :Parentheses, "#{__dir__}/mixin/parentheses"
68
+ autoload :PatternMatchingHelp, "#{__dir__}/mixin/pattern_matching_help"
67
69
  autoload :PercentArray, "#{__dir__}/mixin/percent_array"
68
70
  autoload :PercentLiteral, "#{__dir__}/mixin/percent_literal"
69
71
  autoload :PrecedingFollowingAlignment, "#{__dir__}/mixin/preceding_following_alignment"
@@ -80,22 +80,6 @@ module RuboCop
80
80
  node.arguments.one? &&
81
81
  node.first_argument.arg_type?
82
82
  end
83
-
84
- # When `AllCops/UseProjectIndex` is enabled, methods that override a
85
- # method defined by an ancestor elsewhere in the project are not
86
- # reported: renaming an override breaks the inherited contract.
87
- def overrides_inherited_method?(node)
88
- return false unless project_index
89
- return false unless (namespace_node = node.each_ancestor(:class, :module).first)
90
-
91
- declaration = resolve_constant_in_index(namespace_node.identifier)
92
- return false unless declaration.is_a?(Rubydex::Namespace)
93
-
94
- scope = node.defs_type? ? indexed_singleton_of(declaration) : declaration
95
- !scope.nil? && inherited_index_member?(scope, "#{node.method_name}()")
96
- rescue StandardError
97
- false
98
- end
99
83
  end
100
84
  end
101
85
  end
@@ -62,7 +62,10 @@ module RuboCop
62
62
  MSG = 'Use %<style>s block forwarding.'
63
63
 
64
64
  def self.autocorrect_incompatible_with
65
- [Lint::AmbiguousOperator, Style::ArgumentsForwarding, Style::ExplicitBlockArgument]
65
+ [
66
+ Lint::AmbiguousOperator, Style::ArgumentsForwarding, Style::EndlessMethod,
67
+ Style::ExplicitBlockArgument, Style::MethodDefParentheses
68
+ ]
66
69
  end
67
70
 
68
71
  def on_def(node)
@@ -38,7 +38,7 @@ module RuboCop
38
38
  class BlockParameterName < Base
39
39
  include UncommunicativeName
40
40
 
41
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
41
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- there are no parameter names to check
42
42
  return unless node.arguments?
43
43
 
44
44
  check(node, node.arguments)
@@ -35,7 +35,7 @@ module RuboCop
35
35
  MSG = 'Use %<style>s heredoc delimiters.'
36
36
 
37
37
  def on_heredoc(node)
38
- return if correct_case_delimiters?(node)
38
+ return if correct_case_delimiters?(node) || corrected_delimiter_in_body?(node)
39
39
 
40
40
  add_offense(node.loc.heredoc_end) do |corrector|
41
41
  expr = node.source_range
@@ -52,7 +52,14 @@ module RuboCop
52
52
  end
53
53
 
54
54
  def correct_case_delimiters?(node)
55
- delimiter_string(node) == correct_delimiters(delimiter_string(node))
55
+ delimiters = delimiter_string(node)
56
+ delimiters == correct_delimiters(delimiters)
57
+ end
58
+
59
+ def corrected_delimiter_in_body?(node)
60
+ corrected = correct_delimiters(delimiter_string(node))
61
+
62
+ node.loc.heredoc_body.source.each_line.any? { |line| line.strip == corrected }
56
63
  end
57
64
 
58
65
  def correct_delimiters(source)
@@ -43,9 +43,11 @@ module RuboCop
43
43
 
44
44
  return false unless /\w/.match?(delimiters)
45
45
 
46
- forbidden_delimiters.none? do |forbidden_delimiter|
47
- Regexp.new(forbidden_delimiter).match?(delimiters)
48
- end
46
+ forbidden_delimiter_regexps.none? { |regexp| regexp.match?(delimiters) }
47
+ end
48
+
49
+ def forbidden_delimiter_regexps
50
+ @forbidden_delimiter_regexps ||= forbidden_delimiters.map { |d| Regexp.new(d) }
49
51
  end
50
52
 
51
53
  def forbidden_delimiters
@@ -142,12 +142,6 @@ module RuboCop
142
142
  end
143
143
  end
144
144
 
145
- def offending_prefixes_for(node, method_name)
146
- predicate_prefixes.reject do |prefix|
147
- allowed_method_name?(method_name, prefix) ||
148
- (use_sorbet_sigs? && !sorbet_sig?(node, return_type: 'T::Boolean'))
149
- end
150
- end
151
145
  alias on_defs on_def
152
146
 
153
147
  def validate_config
@@ -162,6 +156,13 @@ module RuboCop
162
156
 
163
157
  private
164
158
 
159
+ def offending_prefixes_for(node, method_name)
160
+ prefixes = predicate_prefixes.reject { |p| allowed_method_name?(method_name, p) }
161
+ return prefixes if prefixes.empty? || !use_sorbet_sigs?
162
+
163
+ sorbet_sig?(node, return_type: 'T::Boolean') ? prefixes : []
164
+ end
165
+
165
166
  # @!method sorbet_return_type(node)
166
167
  def_node_matcher :sorbet_return_type, <<~PATTERN
167
168
  (block (send nil? :sig) args (send _ :returns $_type))
@@ -210,22 +211,6 @@ module RuboCop
210
211
  def method_definition_macro?(macro_name)
211
212
  cop_config['MethodDefinitionMacros'].include?(macro_name.to_s)
212
213
  end
213
-
214
- # When `AllCops/UseProjectIndex` is enabled, methods that override a
215
- # method defined by an ancestor elsewhere in the project are not
216
- # reported: renaming an override breaks the inherited contract.
217
- def overrides_inherited_method?(node)
218
- return false unless project_index
219
- return false unless (namespace_node = node.each_ancestor(:class, :module).first)
220
-
221
- declaration = resolve_constant_in_index(namespace_node.identifier)
222
- return false unless declaration.is_a?(Rubydex::Namespace)
223
-
224
- scope = node.defs_type? ? indexed_singleton_of(declaration) : declaration
225
- !scope.nil? && inherited_index_member?(scope, "#{node.method_name}()")
226
- rescue StandardError
227
- false
228
- end
229
214
  end
230
215
  end
231
216
  end
@@ -86,6 +86,9 @@ module RuboCop
86
86
 
87
87
  NO_LOCATION = PseudoSourceRange.new(1, 0, '', 0, 0).freeze
88
88
 
89
+ EMPTY_CORRECTIONS = [].freeze
90
+ private_constant :EMPTY_CORRECTIONS
91
+
89
92
  # @api public
90
93
  #
91
94
  # @!attribute [r] justification
@@ -96,9 +99,43 @@ module RuboCop
96
99
  # or the directive carries no reason
97
100
  attr_reader :justification
98
101
 
102
+ # @api public
103
+ #
104
+ # @!attribute [r] corrections
105
+ #
106
+ # @return [Array<Correction>]
107
+ # the individual edits that autocorrecting this offense would make, in
108
+ # source order. Empty when the offense has no correction. Unlike
109
+ # {#corrector}, this survives serialization, so it is available on a
110
+ # cache hit and in parallel runs.
111
+ attr_reader :corrections
112
+
113
+ # @api public
114
+ #
115
+ # @!attribute [r] correction_safe
116
+ #
117
+ # @return [Boolean]
118
+ # whether autocorrection would apply {#corrections} in a normal `-a`
119
+ # run. A cop marked `Safe: false` or `SafeAutoCorrect: false` still
120
+ # builds its correction, but only `-A` applies it, so a consumer that
121
+ # applies edits itself has to make the same distinction.
122
+ attr_reader :correction_safe
123
+
124
+ # A single edit of an autocorrection: the source range it replaces and
125
+ # the text it replaces it with. An insertion has an empty range, a
126
+ # removal an empty replacement.
127
+ #
128
+ # @api public
129
+ Correction = Struct.new(:begin_pos, :end_pos, :replacement) do
130
+ def length
131
+ end_pos - begin_pos
132
+ end
133
+ end
134
+
99
135
  # @api private
100
136
  def initialize(severity, location, message, cop_name, # rubocop:disable Metrics/ParameterLists
101
- status = :uncorrected, corrector = nil, justification: nil)
137
+ status = :uncorrected, corrector = nil, justification: nil,
138
+ corrections: nil, correction_safe: true)
102
139
  @severity = RuboCop::Cop::Severity.new(severity)
103
140
  @location = location
104
141
 
@@ -112,15 +149,21 @@ module RuboCop
112
149
  @status = status
113
150
  @corrector = corrector
114
151
  @justification = justification.freeze
152
+ @corrections = (corrections || corrections_from(corrector)).freeze
153
+ @correction_safe = correction_safe
115
154
  freeze
116
155
  end
117
156
 
118
157
  def marshal_dump
119
- [@severity, @location, @message, @cop_name, @status, @justification]
158
+ [@severity, @location, @message, @cop_name, @status, @justification, @corrections,
159
+ @correction_safe]
120
160
  end
121
161
 
122
162
  def marshal_load(array)
123
- @severity, @location, @message, @cop_name, @status, @justification = array
163
+ @severity, @location, @message, @cop_name, @status, @justification, @corrections,
164
+ @correction_safe = array
165
+ @corrections ||= EMPTY_CORRECTIONS
166
+ @correction_safe = true if @correction_safe.nil?
124
167
  @line = @location.line
125
168
  @column = @location.column
126
169
  end
@@ -276,6 +319,19 @@ module RuboCop
276
319
  end
277
320
  0
278
321
  end
322
+
323
+ private
324
+
325
+ # Extracted eagerly rather than on demand because the offense is frozen,
326
+ # and because a corrector cannot be serialized - the cache and parallel
327
+ # workers would otherwise hand back offenses that have lost their edits.
328
+ def corrections_from(corrector)
329
+ return EMPTY_CORRECTIONS unless corrector
330
+
331
+ corrector.as_replacements.map do |range, replacement|
332
+ Correction.new(range.begin_pos, range.end_pos, replacement.freeze).freeze
333
+ end
334
+ end
279
335
  end
280
336
  end
281
337
  end
@@ -43,7 +43,7 @@ module RuboCop
43
43
 
44
44
  def self.qualified_cop?(name)
45
45
  badge = Badge.parse(name)
46
- global.qualify_badge(badge).first == badge
46
+ global.qualify_badge(badge).include?(badge)
47
47
  end
48
48
 
49
49
  attr_reader :options, :warnings
@@ -280,6 +280,12 @@ module RuboCop
280
280
  config.enabled_new_cop?(cop_name)
281
281
  end
282
282
 
283
+ # Preview cops are opt-in and stay silent otherwise, so unlike pending cops
284
+ # they are never reported as needing a decision.
285
+ def enabled_preview_cop?(cop_cfg, config)
286
+ cop_cfg.fetch('Enabled') == 'preview' && config.preview?(@options)
287
+ end
288
+
283
289
  def names
284
290
  clear_enrollment_queue
285
291
  @cops_by_badge.keys.map(&:to_s)
@@ -420,7 +426,9 @@ module RuboCop
420
426
  # caching which expects cop names or cop classes as keys.
421
427
  cfg = config.for_cop(cop_name)
422
428
 
423
- cop_enabled = cfg.fetch('Enabled') == true || enabled_pending_cop?(cfg, config, cop_name)
429
+ cop_enabled = cfg.fetch('Enabled') == true ||
430
+ enabled_pending_cop?(cfg, config, cop_name) ||
431
+ enabled_preview_cop?(cfg, config)
424
432
 
425
433
  if options.fetch(:safe, false)
426
434
  cop_enabled && cfg.fetch('Safe', true)
@@ -22,6 +22,13 @@ module RuboCop
22
22
  # passing the `create_additions` keyword argument emits a deprecation warning, with the
23
23
  # goal of being secure by default in the next major version 3.0.0.
24
24
  #
25
+ # NOTE: Before `json` gem version 2.17.0, `JSON.load` only takes options as its third
26
+ # argument. A hash passed as the second argument is taken as the `proc` argument, so
27
+ # its `create_additions` option is ignored. Which `json` version runs can't be told
28
+ # statically (the lockfile may resolve a newer one than the default gem loaded in
29
+ # production), so options passed as the second argument are always reported. Pass
30
+ # `nil` as the second argument instead.
31
+ #
25
32
  # @safety
26
33
  # This cop's autocorrection is unsafe because it's potentially dangerous.
27
34
  # If using a stream, like `JSON.load(open('file'))`, you will need to call
@@ -33,13 +40,16 @@ module RuboCop
33
40
  # JSON.load('{}')
34
41
  # JSON.restore('{}')
35
42
  #
43
+ # # bad - ignored by `json` older than 2.17.0
44
+ # JSON.load('{}', create_additions: false)
45
+ #
36
46
  # # good
37
47
  # JSON.parse('{}')
38
48
  # JSON.unsafe_load('{}')
39
49
  #
40
50
  # # good - explicit use of `create_additions` option
41
- # JSON.load('{}', create_additions: true)
42
- # JSON.load('{}', create_additions: false)
51
+ # JSON.load('{}', nil, create_additions: true)
52
+ # JSON.load('{}', nil, create_additions: false)
43
53
  #
44
54
  class JSONLoad < Base
45
55
  extend AutoCorrector
@@ -51,8 +61,10 @@ module RuboCop
51
61
  def_node_matcher :insecure_json_load, <<~PATTERN
52
62
  (
53
63
  send (const {nil? cbase} :JSON) ${:load :restore}
54
- ...
55
- !`(pair (sym :create_additions) _)
64
+ {
65
+ _ hash
66
+ | ... !`(pair (sym :create_additions) _)
67
+ }
56
68
  )
57
69
  PATTERN
58
70
 
@@ -21,6 +21,18 @@ module RuboCop
21
21
  # any of `:info`, `:refactor`, `:convention`, `:warning`, `:error` or `:fatal`.
22
22
  attr_reader :name
23
23
 
24
+ # The lowest severity that makes a run fail: `--fail-level` when given,
25
+ # otherwise `AllCops: FailLevel`. `autocorrect` is a pseudo level on the
26
+ # command line that gates on corrections instead, so it leaves the
27
+ # threshold at the configured one.
28
+ def self.minimum_to_fail(options, config)
29
+ name = options[:fail_level]
30
+ if name.nil? || name == :autocorrect
31
+ name = (config&.for_all_cops&.[]('FailLevel') || :refactor).to_sym
32
+ end
33
+ new(name)
34
+ end
35
+
24
36
  def self.name_from_code(code)
25
37
  name = code.to_sym
26
38
  CODE_TABLE[name] || name
@@ -187,11 +187,18 @@ module RuboCop
187
187
  def allowed?(node)
188
188
  !node.access_modifier? ||
189
189
  node.parent&.type?(:pair, :any_block) ||
190
+ dynamic_method_list?(node) ||
190
191
  allow_modifiers_on_symbols?(node) ||
191
192
  allow_modifiers_on_attrs?(node) ||
192
193
  allow_modifiers_on_alias_method?(node)
193
194
  end
194
195
 
196
+ # `private(*names)` with a list computed at runtime names no definition
197
+ # the modifier could be grouped with.
198
+ def dynamic_method_list?(node)
199
+ node.arguments.any?(&:splat_type?) && !access_modifier_with_symbol?(node)
200
+ end
201
+
195
202
  def autocorrect(corrector, node)
196
203
  case style
197
204
  when :group
@@ -316,7 +323,7 @@ module RuboCop
316
323
  end
317
324
 
318
325
  def select_grouped_def_nodes(node)
319
- node.right_siblings.take_while do |sibling|
326
+ node.right_siblings.compact.take_while do |sibling|
320
327
  !(sibling.send_type? && sibling.bare_access_modifier_declaration?)
321
328
  end.select(&:def_type?)
322
329
  end
@@ -347,7 +354,8 @@ module RuboCop
347
354
  end
348
355
 
349
356
  def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
350
- def_node = begin_node.children[begin_node.children.index(modifier_node) + 1]
357
+ modifier_index = begin_node.children.find_index { |child| child.equal?(modifier_node) }
358
+ def_node = begin_node.children[modifier_index + 1]
351
359
  # Stop the removal range at the first comment that precedes the def, if
352
360
  # any exist. Without this, comments between the modifier and the def are
353
361
  # dropped because they fall inside the removed range.
@@ -60,7 +60,7 @@ module RuboCop
60
60
  add_offense(node.loc.keyword, message: MSG_ALIAS) do |corrector|
61
61
  autocorrect(corrector, node)
62
62
  end
63
- elsif node.children.none? { |arg| bareword?(arg) }
63
+ elsif node.children.all? { |arg| !bareword?(arg) && bareword_symbol?(arg) }
64
64
  add_offense_for_args(node) { |corrector| autocorrect(corrector, node) }
65
65
  end
66
66
  end
@@ -97,7 +97,7 @@ module RuboCop
97
97
 
98
98
  def add_offense_for_args(node, &block)
99
99
  existing_args = node.children.map(&:source).join(' ')
100
- preferred_args = node.children.map { |a| a.source[1..] }.join(' ')
100
+ preferred_args = node.children.map { |node| bareword_for(node) }.join(' ')
101
101
  arg_ranges = node.children.map(&:source_range)
102
102
  msg = format(MSG_SYMBOL_ARGS, prefer: preferred_args, current: existing_args)
103
103
  add_offense(arg_ranges.reduce(&:join), message: msg, &block)
@@ -138,6 +138,15 @@ module RuboCop
138
138
  !sym_node.source.start_with?(':') || sym_node.dsym_type?
139
139
  end
140
140
 
141
+ def bareword_symbol?(sym_node)
142
+ return false unless sym_node.sym_type?
143
+
144
+ value = sym_node.value.to_s
145
+ return true if value.match?(/\A[A-Za-z_]\w*[?!=]?\z/)
146
+
147
+ !sym_node.source.start_with?(':"', ":'") && !value.start_with?('@', '$')
148
+ end
149
+
141
150
  def correct_alias_method_to_alias(corrector, send_node)
142
151
  new, old = *send_node.arguments
143
152
  replacement = "alias #{identifier(new)} #{identifier(old)}"
@@ -153,17 +162,21 @@ module RuboCop
153
162
  end
154
163
 
155
164
  def correct_alias_with_symbol_args(corrector, node)
156
- corrector.replace(node.new_identifier, node.new_identifier.source[1..])
157
- corrector.replace(node.old_identifier, node.old_identifier.source[1..])
165
+ corrector.replace(node.new_identifier, bareword_for(node.new_identifier))
166
+ corrector.replace(node.old_identifier, bareword_for(node.old_identifier))
158
167
  end
159
168
 
160
169
  def identifier(node)
161
- if node.sym_type?
170
+ if bareword_symbol?(node)
162
171
  ":#{node.children.first}"
163
172
  else
164
173
  node.source
165
174
  end
166
175
  end
176
+
177
+ def bareword_for(sym_node)
178
+ sym_node.value.to_s
179
+ end
167
180
  end
168
181
  end
169
182
  end
@@ -39,9 +39,9 @@ module RuboCop
39
39
  # @!method ambiguous_endless_method_body(node)
40
40
  def_node_matcher :ambiguous_endless_method_body, <<~PATTERN
41
41
  ^${
42
- (if _ <def _>)
43
- ({and or} def _)
44
- ({while until} _ def)
42
+ (if _ <any_def _>)
43
+ ({and or} any_def _)
44
+ ({while until} _ any_def)
45
45
  }
46
46
  PATTERN
47
47
 
@@ -57,6 +57,7 @@ module RuboCop
57
57
  correct_to_multiline(corrector, node)
58
58
  end
59
59
  end
60
+ alias on_defs on_def
60
61
 
61
62
  private
62
63
 
@@ -48,6 +48,10 @@ module RuboCop
48
48
 
49
49
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
50
50
 
51
+ def self.autocorrect_incompatible_with
52
+ [Style::MethodCallWithArgsParentheses, Style::ReturnNilInPredicateMethodDefinition]
53
+ end
54
+
51
55
  def on_and(node)
52
56
  process_logical_operator(node) if style == :always
53
57
  end
@@ -153,7 +153,7 @@ module RuboCop
153
153
  BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
154
154
 
155
155
  def self.autocorrect_incompatible_with
156
- [Naming::BlockForwarding, Style::MethodDefParentheses]
156
+ [Naming::BlockForwarding, Style::EndlessMethod, Style::MethodDefParentheses]
157
157
  end
158
158
 
159
159
  def on_def(node)
@@ -202,7 +202,7 @@ module RuboCop
202
202
  rest_arg, kwrest_arg, block_arg = *forwardable_args
203
203
  registered_block_arg_offense = false
204
204
 
205
- send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
205
+ send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength -- the block parameter list does not wrap
206
206
  if !forward_rest && !forward_kwrest && c != :all_anonymous
207
207
  if allow_anonymous_forwarding_in_block?(forward_block_arg)
208
208
  register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
@@ -232,7 +232,7 @@ module RuboCop
232
232
 
233
233
  rest_arg, kwrest_arg, block_arg = *forwardable_args
234
234
 
235
- send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
235
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength -- the block parameter list does not wrap
236
236
  if allow_anonymous_forwarding_in_block?(forward_rest)
237
237
  register_forward_args_offense(def_node.arguments, rest_arg)
238
238
  register_forward_args_offense(send_node, forward_rest)
@@ -377,6 +377,7 @@ module RuboCop
377
377
  def add_parens_if_missing(node, corrector)
378
378
  return if parentheses?(node)
379
379
  return if node.send_type? && node.method?(:[])
380
+ return unless (@parenthesized_nodes ||= Set.new.compare_by_identity).add?(node)
380
381
 
381
382
  add_parentheses(node, corrector)
382
383
  end
@@ -499,6 +500,8 @@ module RuboCop
499
500
  end
500
501
 
501
502
  def offensive_block_forwarding?
503
+ return false if @send_node.block_literal?
504
+
502
505
  @block_arg ? forwarded_block_arg : allow_offense_for_no_block?
503
506
  end
504
507
 
@@ -50,10 +50,9 @@ module RuboCop
50
50
  def autocorrect(corrector, node)
51
51
  attr_name, setter = *node.arguments
52
52
 
53
- node_expr = node.source_range
54
- attr_expr = attr_name.source_range
55
-
56
- remove = range_between(attr_expr.end_pos, node_expr.end_pos) if setter&.boolean_type?
53
+ if setter&.boolean_type?
54
+ remove = range_between(attr_name.source_range.end_pos, setter.source_range.end_pos)
55
+ end
57
56
 
58
57
  corrector.replace(node.loc.selector, replacement_method(node))
59
58
  corrector.remove(remove) if remove
@@ -66,16 +66,18 @@ module RuboCop
66
66
 
67
67
  # @!method bit_operation?(node)
68
68
  def_node_matcher :bit_operation?, <<~PATTERN
69
- (begin
70
- (send _ :& _))
69
+ {
70
+ (begin (send _ :& _))
71
+ (send _ :& _)
72
+ }
71
73
  PATTERN
72
74
 
73
75
  # rubocop:disable-next Metrics/AbcSize
74
76
  def on_send(node)
75
- return unless node.receiver&.begin_type?
77
+ return unless bit_operation?(node.receiver)
76
78
  return unless (preferred_method = preferred_method(node))
77
79
 
78
- bit_operation = node.receiver.children.first
80
+ bit_operation = node.receiver.begin_type? ? node.receiver.children.first : node.receiver
79
81
  lhs, _operator, rhs = *bit_operation
80
82
 
81
83
  preferred = if preferred_method == 'allbits?' && lhs.source == node.first_argument.source
@@ -177,7 +177,7 @@ module RuboCop
177
177
  BRACES_REQUIRED_MESSAGE = "Brace delimiters `{...}` required for '%<method_name>s' method."
178
178
 
179
179
  def self.autocorrect_incompatible_with
180
- [Style::RedundantBegin]
180
+ [Layout::SpaceBeforeBlockBraces, Style::MethodCallWithArgsParentheses, Style::RedundantBegin]
181
181
  end
182
182
 
183
183
  def on_send(node)
@@ -196,6 +196,8 @@ module RuboCop
196
196
  end
197
197
  end
198
198
  alias on_csend on_send
199
+ alias on_super on_send
200
+ alias on_yield on_send
199
201
 
200
202
  def on_block(node)
201
203
  return if part_of_ignored_node?(node)
@@ -292,7 +294,7 @@ module RuboCop
292
294
  corrector.replace(b, '{')
293
295
  corrector.replace(e, '}')
294
296
 
295
- corrector.wrap(node.body, "begin\n", "\nend") if begin_required?(node)
297
+ wrap_body_with_begin(corrector, node.body) if begin_required?(node)
296
298
  end
297
299
 
298
300
  def whitespace_before?(range)
@@ -372,6 +374,7 @@ module RuboCop
372
374
  # rubocop:disable-next Metrics/CyclomaticComplexity -- inlined special_method checks to avoid double evaluation
373
375
  def proper_block_style?(node)
374
376
  return true if require_do_end?(node)
377
+ return true if collection_of_for_loop?(node)
375
378
 
376
379
  method_name = node.method_name
377
380
  return true if allowed_method?(method_name) || matches_allowed_pattern?(method_name)
@@ -398,6 +401,10 @@ module RuboCop
398
401
  !modifier_rescue?(body)
399
402
  end
400
403
 
404
+ def collection_of_for_loop?(node)
405
+ node.parent&.for_type? && node.parent.collection == node
406
+ end
407
+
401
408
  def modifier_rescue?(rescue_node)
402
409
  return false if rescue_node.body.nil? || rescue_node.else_branch
403
410
  return false unless rescue_node.resbody_branches.one?
@@ -438,11 +445,20 @@ module RuboCop
438
445
  end
439
446
 
440
447
  def correction_would_break_code?(node)
441
- return false unless node.keywords?
448
+ return loop_condition?(node) if node.braces?
442
449
 
443
450
  node.send_node.arguments? && !node.send_node.parenthesized?
444
451
  end
445
452
 
453
+ # A `do` in the condition of `while` or `until` is taken as the start of
454
+ # the loop body. Inside the body of another block it is unambiguous again.
455
+ def loop_condition?(node)
456
+ ancestors = node.each_ancestor.take_while { |ancestor| !ancestor.any_block_type? }
457
+ [node, *ancestors].each_cons(2).any? do |child, parent|
458
+ parent.type?(:while, :until) && parent.condition.equal?(child)
459
+ end
460
+ end
461
+
446
462
  def functional_method?(method_name)
447
463
  functional_methods.include?(method_name)
448
464
  end
@@ -490,6 +506,16 @@ module RuboCop
490
506
  node.type?(:array, :range)
491
507
  end
492
508
 
509
+ def wrap_body_with_begin(corrector, body)
510
+ heredoc_ends = body.each_node(:any_str).select(&:heredoc?).map do |str|
511
+ str.loc.heredoc_end
512
+ end
513
+ body_end = [body.source_range, *heredoc_ends].max_by(&:end_pos)
514
+
515
+ corrector.insert_before(body, "begin\n")
516
+ corrector.insert_after(body_end, "\nend")
517
+ end
518
+
493
519
  def begin_required?(block_node)
494
520
  # If the block contains `rescue` or `ensure`, it needs to be wrapped in
495
521
  # `begin`...`end` when changing `do-end` to `{}`.