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
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Lint/RedundantCopDisableDirective needs to be disabled so as
4
4
  # to be able to provide examples of rubocop:disable comments.
5
- # rubocop:disable-next Lint/RedundantCopDisableDirective
5
+ # rubocop:disable-next Lint/RedundantCopDisableDirective -- the examples below read as real directives
6
6
  module RuboCop
7
7
  module Cop
8
8
  module Migration
@@ -15,6 +15,10 @@ module RuboCop
15
15
  cop_config['IndentationWidth'] || config.for_cop('Layout/IndentationWidth')['Width'] || 2
16
16
  end
17
17
 
18
+ def using_tabs?
19
+ config.for_cop('Layout/IndentationStyle')['EnforcedStyle'] == 'tabs'
20
+ end
21
+
18
22
  def indentation(node)
19
23
  offset(node) + (SPACE * configured_indentation_width)
20
24
  end
@@ -66,7 +70,7 @@ module RuboCop
66
70
  end
67
71
 
68
72
  # @deprecated Use processed_source.line_with_comment?(line)
69
- def end_of_line_comment(line) # rubocop:disable Naming/PredicateMethod
73
+ def end_of_line_comment(line) # rubocop:disable Naming/PredicateMethod -- a deprecated shim kept under its original name
70
74
  warn Rainbow(<<~WARNING).yellow, uplevel: 1
71
75
  `end_of_line_comment` is deprecated. Use `processed_source.line_with_comment?` instead.
72
76
  WARNING
@@ -45,7 +45,7 @@ module RuboCop
45
45
  match.captures
46
46
  end
47
47
 
48
- KEYWORDS_REGEX_CACHE = {} # rubocop:disable Style/MutableConstant
48
+ KEYWORDS_REGEX_CACHE = {} # rubocop:disable Style/MutableConstant -- a cache, written to at runtime
49
49
  private_constant :KEYWORDS_REGEX_CACHE
50
50
 
51
51
  def regex
@@ -94,22 +94,29 @@ module RuboCop
94
94
 
95
95
  # @api private
96
96
  def first_argument_is_heredoc?(node)
97
- first_argument = node.first_argument
98
-
99
- first_argument.respond_to?(:heredoc?) && first_argument.heredoc?
97
+ node.first_argument.respond_to?(:heredoc?) && node.first_argument.heredoc?
100
98
  end
101
99
 
102
100
  # @api private
103
101
  # If a `send` or `csend` node contains a heredoc argument, splitting cannot happen
104
102
  # after the heredoc or else it will cause a syntax error.
105
103
  def shift_elements_for_heredoc_arg(node, elements, index)
106
- return index unless node.type?(:call, :array)
104
+ return index unless node.type?(:call, :array, :hash)
105
+ return index unless (heredoc_pos = heredoc_begin_position(node))
106
+
107
+ last_safe = elements.rindex { |element| element.source_range.begin_pos <= heredoc_pos }
108
+ return nil if last_safe.nil? ||
109
+ (last_safe.zero? && elements.first.source_range.end_pos > heredoc_pos)
107
110
 
108
- heredoc_index = elements.index { |arg| arg.respond_to?(:heredoc?) && arg.heredoc? }
109
- return index unless heredoc_index
110
- return nil if heredoc_index.zero?
111
+ [index, last_safe + 1].min
112
+ end
111
113
 
112
- heredoc_index >= index ? index : heredoc_index + 1
114
+ # @api private
115
+ def heredoc_begin_position(node)
116
+ children = node.call_type? ? node.arguments : node.children
117
+ children.flat_map { |child| [child, *child.each_descendant(:any_str)] }
118
+ .find { |descendant| descendant.type?(:any_str) && descendant.heredoc? }
119
+ &.source_range&.begin_pos
113
120
  end
114
121
 
115
122
  # @api private
@@ -128,9 +135,7 @@ module RuboCop
128
135
  # or redundant edits, we only mark one offense at a time.
129
136
  return true if contained_by_breakable_collection_on_same_line?(node)
130
137
 
131
- return true if contained_by_multiline_collection_that_could_be_broken_up?(node)
132
-
133
- false
138
+ contained_by_multiline_collection_that_could_be_broken_up?(node)
134
139
  end
135
140
 
136
141
  # @api private
@@ -145,9 +150,7 @@ module RuboCop
145
150
  # break before the second argument and the rest of the
146
151
  # argument will get auto-formatted onto separate lines
147
152
  # by other cops.
148
- has_second_element = elements.length >= 2
149
-
150
- starts_with_bracket && has_second_element
153
+ starts_with_bracket && elements.length >= 2
151
154
  end
152
155
 
153
156
  # @api private
@@ -14,9 +14,13 @@ module RuboCop
14
14
  private
15
15
 
16
16
  def too_long?(node)
17
+ too_long_as_single_line?(node.first_line..node.last_line)
18
+ end
19
+
20
+ def too_long_as_single_line?(line_range)
17
21
  return false unless max_line_length
18
22
 
19
- lines = processed_source.lines[(node.first_line - 1)...node.last_line]
23
+ lines = processed_source.lines[(line_range.begin - 1)...line_range.end]
20
24
  to_single_line(lines.join("\n")).length > max_line_length
21
25
  end
22
26
 
@@ -59,12 +59,20 @@ module RuboCop
59
59
  return node.loc.name if node.casgn_type?
60
60
 
61
61
  if LSP.enabled?
62
- end_range = node.loc?(:name) ? node.loc.name : node.loc.begin
63
- node.source_range.begin.join(end_range)
62
+ node.source_range.begin.join(header_end(node))
64
63
  else
65
64
  node.source_range
66
65
  end
67
66
  end
67
+
68
+ # Where the header of a definition ends: the name of a class, module or
69
+ # method, the `self` of `class << self`, or the opening of a block.
70
+ def header_end(node)
71
+ return node.loc.name if node.loc?(:name)
72
+ return node.identifier.source_range if node.sclass_type?
73
+
74
+ node.loc.begin
75
+ end
68
76
  end
69
77
  end
70
78
  end
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Layout
6
6
  # Common functionality for checking if presence/absence of empty lines
7
7
  # around some kind of body matches the configuration.
8
- module EmptyLinesAroundBody
8
+ module EmptyLinesAroundBody # rubocop:disable Metrics/ModuleLength
9
9
  extend NodePattern::Macros
10
10
  include ConfigurableEnforcedStyle
11
11
  include RangeHelp
@@ -14,6 +14,8 @@ module RuboCop
14
14
  MSG_MISSING = 'Empty line missing at %<kind>s body %<location>s.'
15
15
  MSG_DEFERRED = 'Empty line missing before first %<type>s definition'
16
16
 
17
+ LEADING_DOT_TYPES = %i[tDOT tANDDOT].to_set.freeze
18
+
17
19
  private
18
20
 
19
21
  # @!method constant_definition?(node)
@@ -29,6 +31,7 @@ module RuboCop
29
31
 
30
32
  first_line = adjusted_first_line || node.source_range.first_line
31
33
  last_line = node.source_range.last_line
34
+ return if first_line >= last_line
32
35
 
33
36
  case style
34
37
  when :empty_lines_except_namespace
@@ -99,12 +102,20 @@ module RuboCop
99
102
  return unless yield(processed_source.lines[line])
100
103
 
101
104
  offset = style == :empty_lines && msg.include?('end.') ? 2 : 1
105
+ return if style == :empty_lines && leading_dot_line?(line + offset)
106
+
102
107
  range = source_range(processed_source.buffer, line + offset, 0)
103
108
  add_offense(range, message: msg) do |corrector|
104
109
  EmptyLineCorrector.correct(corrector, [style, range])
105
110
  end
106
111
  end
107
112
 
113
+ def leading_dot_line?(line)
114
+ first_token = processed_source.sorted_tokens.find { |token| token.line == line }
115
+
116
+ LEADING_DOT_TYPES.include?(first_token&.type)
117
+ end
118
+
108
119
  def check_deferred_empty_line(body)
109
120
  node = first_empty_line_required_child(body)
110
121
  return unless node
@@ -0,0 +1,69 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for checking whether a method body can become the
6
+ # body of an endless method definition without changing its meaning.
7
+ module EndlessMethodBodyHelp
8
+ private
9
+
10
+ def endless_method_body?(body)
11
+ return false if body.type?(:begin, :kwbegin, :rescue, :ensure, :masgn)
12
+ return false if low_precedence_body?(body)
13
+ return false if ends_with_omitted_hash_value?(body) || ends_with_anonymous_argument?(body)
14
+ return false if body.assignment? && multiple_values?(assigned_value(body))
15
+
16
+ !command_disallowed_in_endless_body?(body)
17
+ end
18
+
19
+ # `def foo = bar and baz` parses as `(def foo = bar) and baz`.
20
+ def low_precedence_body?(body)
21
+ body.type?(:any_match_pattern, :while_post, :until_post) ||
22
+ (body.type?(:and, :or) && body.semantic_operator?) ||
23
+ (body.type?(:if, :while, :until) && body.modifier_form?)
24
+ end
25
+
26
+ # `foo = 1, 2` and `foo = *bar` assign an array without brackets.
27
+ def multiple_values?(node)
28
+ node.array_type? && !node.bracketed?
29
+ end
30
+
31
+ def ends_with_omitted_hash_value?(body)
32
+ body.each_descendant(:pair).any? do |pair|
33
+ pair.value_omission? && pair.source_range.end_pos == body.source_range.end_pos
34
+ end
35
+ end
36
+
37
+ def ends_with_anonymous_argument?(body)
38
+ forwarding = %i[forwarded_restarg forwarded_kwrestarg block_pass]
39
+
40
+ body.each_descendant(*forwarding).any? do |argument|
41
+ argument.source_range.end_pos == body.source_range.end_pos &&
42
+ (!argument.block_pass_type? || argument.children.first.nil?)
43
+ end
44
+ end
45
+
46
+ def command_disallowed_in_endless_body?(body)
47
+ return true if body.assignment? && command_call?(assigned_value(body))
48
+
49
+ body.each_node(:any_block).any? do |block|
50
+ block.keywords? && command_call?(block.send_node)
51
+ end
52
+ end
53
+
54
+ def assigned_value(node)
55
+ while node.assignment? || node.rescue_type?
56
+ node = node.rescue_type? ? node.body : node.children.last
57
+ end
58
+ node
59
+ end
60
+
61
+ def command_call?(node)
62
+ node = node.send_node if node.any_block_type?
63
+ return false unless node.type?(:call, :super, :yield)
64
+
65
+ node.arguments? && !node.parenthesized? && !node.operator_method? && !node.setter_method?
66
+ end
67
+ end
68
+ end
69
+ end
@@ -7,9 +7,9 @@ module RuboCop
7
7
  SIGILS = '@$' # if a variable starts with a sigil it will be removed
8
8
 
9
9
  def forbidden_identifier?(name)
10
- name = name.to_s.delete(SIGILS)
10
+ return false if forbidden_identifiers.empty?
11
11
 
12
- forbidden_identifiers.any? && forbidden_identifiers.include?(name)
12
+ forbidden_identifiers.include?(name.to_s.delete(SIGILS))
13
13
  end
14
14
 
15
15
  def forbidden_identifiers
@@ -55,7 +55,7 @@ module RuboCop
55
55
  # Common functionality for checking alignment of hash values.
56
56
  module ValueAlignment
57
57
  def checkable_layout?(node)
58
- !node.pairs_on_same_line? && !node.mixed_delimiters?
58
+ !node.pairs_on_same_line? && !node.mixed_delimiters? && alignable_values?(node)
59
59
  end
60
60
 
61
61
  def deltas(first_pair, current_pair)
@@ -68,6 +68,16 @@ module RuboCop
68
68
 
69
69
  private
70
70
 
71
+ def alignable_values?(node)
72
+ return false if node.pairs.first.value_omission?
73
+
74
+ node.pairs.none? { |pair| value_on_later_line?(pair) }
75
+ end
76
+
77
+ def value_on_later_line?(pair)
78
+ pair.value && pair.key.last_line != pair.value.first_line
79
+ end
80
+
71
81
  def separator_delta(first_pair, current_pair, key_delta)
72
82
  if current_pair.hash_rocket?
73
83
  hash_rocket_delta(first_pair, current_pair) - key_delta
@@ -142,6 +152,17 @@ module RuboCop
142
152
  {}
143
153
  end
144
154
 
155
+ # Keys are right-aligned by the column their last line ends on.
156
+ # A key spanning several lines ends on a line other than the one it starts on,
157
+ # so moving its first line would never change that column and the correction
158
+ # would be repeated on every pass. Such pairs are left alone, and so is every pair
159
+ # when the first key spans several lines, since there is then no column to right-align to.
160
+ def deltas(first_pair, current_pair)
161
+ return {} if first_pair.key.multiline? || current_pair.key.multiline?
162
+
163
+ super
164
+ end
165
+
145
166
  private
146
167
 
147
168
  def key_delta(first_pair, current_pair)
@@ -153,7 +174,10 @@ module RuboCop
153
174
  end
154
175
 
155
176
  def value_delta(first_pair, current_pair)
156
- current_pair.value_omission? ? 0 : first_pair.value_delta(current_pair)
177
+ return 0 if first_pair.equal?(current_pair) || current_pair.value_omission?
178
+
179
+ expected_value_column = first_pair.loc.operator.end.column + 1
180
+ expected_value_column - current_pair.value.loc.column
157
181
  end
158
182
  end
159
183
 
@@ -11,6 +11,15 @@ module RuboCop
11
11
  DO_NOT_MIX_OMIT_VALUE_MSG = "#{DO_NOT_MIX_MSG_PREFIX} #{OMIT_HASH_VALUE_MSG}"
12
12
  DO_NOT_MIX_EXPLICIT_VALUE_MSG = "#{DO_NOT_MIX_MSG_PREFIX} #{EXPLICIT_HASH_VALUE_MSG}"
13
13
 
14
+ # A keyword parameter can be named after a keyword, as in `def foo(if:)`,
15
+ # but the parameter can only be referenced by an omitted hash value,
16
+ # so `{ if: }` has no explicit form: `{ if: if }` is invalid Ruby.
17
+ KEYWORDS = %i[
18
+ __ENCODING__ __FILE__ __LINE__ BEGIN END alias and begin break case class def do
19
+ else elsif end ensure false for if in module next nil not or redo rescue retry
20
+ return self super then true undef unless until when while yield
21
+ ].to_set.freeze
22
+
14
23
  DefNode = Struct.new(:node) do
15
24
  def selector
16
25
  if node.loc?(:selector)
@@ -53,7 +62,7 @@ module RuboCop
53
62
  replacement = "#{hash_key_source}:"
54
63
  self.config_to_allow_offenses = { 'Enabled' => false }
55
64
  else
56
- return unless node.value_omission?
65
+ return if !node.value_omission? || keyword_value?(node)
57
66
 
58
67
  message = EXPLICIT_HASH_VALUE_MSG
59
68
  replacement = "#{hash_key_source}: #{hash_key_source}"
@@ -87,13 +96,26 @@ module RuboCop
87
96
  def ignore_mixed_hash_shorthand_syntax?(hash_node)
88
97
  target_ruby_version <= 3.0 ||
89
98
  !%w[consistent either_consistent].include?(enforced_shorthand_syntax) ||
90
- !hash_node.hash_type?
99
+ !hash_node.hash_type? || hash_rockets_enforced?(hash_node)
91
100
  end
92
101
 
93
102
  def ignore_hash_shorthand_syntax?(pair_node)
94
103
  target_ruby_version <= 3.0 || enforced_shorthand_syntax == 'either' ||
95
104
  %w[consistent either_consistent].include?(enforced_shorthand_syntax) ||
96
- !pair_node.parent.hash_type?
105
+ !pair_node.parent.hash_type? || hash_rockets_enforced?(pair_node.parent)
106
+ end
107
+
108
+ def hash_rockets_enforced?(hash_node)
109
+ style == :hash_rockets || force_hash_rockets?(hash_node.pairs) ||
110
+ no_mixed_keys_enforces_hash_rockets?(hash_node.pairs)
111
+ end
112
+
113
+ def no_mixed_keys_enforces_hash_rockets?(pairs)
114
+ case style
115
+ when :no_mixed_keys then !sym_indices?(pairs) || pairs.first.delimiter == '=>'
116
+ when :ruby19_no_mixed_keys then !sym_indices?(pairs)
117
+ else false
118
+ end
97
119
  end
98
120
 
99
121
  def enforced_shorthand_syntax
@@ -206,6 +228,8 @@ module RuboCop
206
228
  def mixed_shorthand_syntax_check(hash_value_type_breakdown)
207
229
  if hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
208
230
  each_omitted_value_pair(hash_value_type_breakdown) do |pair_node|
231
+ next if keyword_value?(pair_node)
232
+
209
233
  hash_key_source = pair_node.key.source
210
234
  replacement = "#{hash_key_source}: #{hash_key_source}"
211
235
  register_offense(pair_node, DO_NOT_MIX_EXPLICIT_VALUE_MSG, replacement)
@@ -229,6 +253,10 @@ module RuboCop
229
253
  register_offense(pair_node, OMIT_HASH_VALUE_MSG, replacement)
230
254
  end
231
255
  end
256
+
257
+ def keyword_value?(pair_node)
258
+ KEYWORDS.include?(pair_node.key.value)
259
+ end
232
260
  end
233
261
  end
234
262
  # rubocop:enable Metrics/ModuleLength
@@ -38,7 +38,7 @@ module RuboCop
38
38
  (block (send _ :each_with_object (hash)) ...)}
39
39
  PATTERN
40
40
 
41
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
41
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- the patterns matched here all name their block parameters
42
42
  on_bad_each_with_object(node) do |*match|
43
43
  handle_possible_offense(node, match, 'each_with_object')
44
44
  end
@@ -32,7 +32,9 @@ module RuboCop
32
32
  branches << node.if_branch
33
33
 
34
34
  else_branch = node.else_branch
35
- if_conditional_branches(else_branch, branches) if else_branch&.if_type?
35
+ if else_branch&.if_type? && else_branch.elsif?
36
+ if_conditional_branches(else_branch, branches)
37
+ end
36
38
  branches
37
39
  end
38
40
  end
@@ -11,8 +11,10 @@ module RuboCop
11
11
  return if all_on_same_line?(children, ignore_last: ignore_last)
12
12
 
13
13
  last_seen_line = -1
14
- children.each do |child|
14
+ children.each_with_index do |child, index|
15
15
  if last_seen_line >= child.first_line
16
+ next if heredoc_opened_before?(children.first(index), child)
17
+
16
18
  add_offense(child) { |corrector| EmptyLineCorrector.insert_before(corrector, child) }
17
19
  else
18
20
  last_seen_line = child.last_line
@@ -27,6 +29,14 @@ module RuboCop
27
29
 
28
30
  nodes.first.first_line == nodes.last.last_line
29
31
  end
32
+
33
+ def heredoc_opened_before?(previous_children, child)
34
+ previous_children.any? do |previous|
35
+ previous.each_node(:any_str).any? do |str|
36
+ str.heredoc? && same_line?(str, child)
37
+ end
38
+ end
39
+ end
30
40
  end
31
41
  end
32
42
  end
@@ -15,6 +15,7 @@ module RuboCop
15
15
  # If the last node is or contains a conflicting HEREDOC, we don't want
16
16
  # to adjust the brace layout because this will result in invalid code.
17
17
  return if last_line_heredoc?(node.children.last)
18
+ return if heredoc_opened_on_closing_brace_line?(node)
18
19
 
19
20
  check(node)
20
21
  end
@@ -136,6 +137,14 @@ module RuboCop
136
137
 
137
138
  node.children.any? { |child| last_line_heredoc?(child, parent) }
138
139
  end
140
+
141
+ def heredoc_opened_on_closing_brace_line?(node)
142
+ closing_brace_line = node.loc.end.line
143
+
144
+ node.each_descendant(:any_str).any? do |str|
145
+ str.heredoc? && str.first_line == closing_brace_line
146
+ end
147
+ end
139
148
  end
140
149
  end
141
150
  end
@@ -40,7 +40,7 @@ module RuboCop
40
40
  OrderedGemCorrector.correct(
41
41
  processed_source,
42
42
  current,
43
- previous_declaration(current),
43
+ previous,
44
44
  treat_comments_as_separators
45
45
  ).call(corrector)
46
46
  end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for checking whether a node is used in a pattern of
6
+ # pattern matching, where only some expressions are allowed.
7
+ module PatternMatchingHelp
8
+ PATTERN_TYPES = %i[
9
+ array_pattern array_pattern_with_tail begin const_pattern find_pattern hash_pattern
10
+ match_alt match_as pair
11
+ ].freeze
12
+
13
+ private
14
+
15
+ def in_pattern?(node)
16
+ child = node
17
+
18
+ node.each_ancestor do |ancestor|
19
+ case ancestor.type
20
+ when :in_pattern
21
+ return ancestor.pattern.equal?(child)
22
+ when :match_pattern, :match_pattern_p
23
+ return ancestor.children[1].equal?(child)
24
+ when *PATTERN_TYPES
25
+ child = ancestor
26
+ else
27
+ return false
28
+ end
29
+ end
30
+
31
+ false
32
+ end
33
+ end
34
+ end
35
+ end
@@ -174,15 +174,31 @@ module RuboCop
174
174
  # ^
175
175
  tokens = remove_equals_in_def(tokens, processed_source)
176
176
 
177
- # Only attempt to align the first = on each line
178
- Set.new(tokens.uniq(&:line))
177
+ # Only attempt to align the first = on each line. An `=` that comes after a comparison
178
+ # on its line is left out as well: whether a line is aligned is judged by its first
179
+ # assignment or comparison operator, so such an `=` could never be found aligned
180
+ # and `Layout/SpaceAroundOperators` would keep undoing the padding added for it.
181
+ Set.new(tokens.uniq(&:line).select do |token|
182
+ first_operator_on_line(token.line).equal?(token)
183
+ end)
179
184
  end
180
185
  end
181
186
 
182
187
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
183
188
  # rubocop:disable Metrics/PerceivedComplexity, Metrics/MethodLength
184
189
  def relevant_assignment_lines(line_range)
185
- relevant_lines(line_range) { |line_number| assignment_lines.include?(line_number) }
190
+ relevant_lines(line_range, interrupting_operator_lines) do |line_number|
191
+ assignment_lines.include?(line_number)
192
+ end
193
+ end
194
+
195
+ def interrupting_operator_lines
196
+ @interrupting_operator_lines ||=
197
+ processed_source.tokens.each_with_object(Set.new) do |token, lines|
198
+ next unless ASSIGNMENT_OR_COMPARISON_TOKENS.include?(token.type)
199
+
200
+ lines << token.line unless assignment_lines.include?(token.line)
201
+ end
186
202
  end
187
203
 
188
204
  def alignment_lines(line_number)
@@ -259,6 +275,16 @@ module RuboCop
259
275
 
260
276
  asgn_tokens.reject { |t| eqls_to_ignore.include?(t.begin_pos) }
261
277
  end
278
+
279
+ def first_operator_on_line(line)
280
+ @first_operator_by_line ||= processed_source.tokens.each_with_object({}) do |token, by_line|
281
+ next unless ASSIGNMENT_OR_COMPARISON_TOKENS.include?(token.type)
282
+
283
+ by_line[token.line] ||= token
284
+ end
285
+
286
+ @first_operator_by_line[line]
287
+ end
262
288
  end
263
289
  end
264
290
  end
@@ -119,6 +119,21 @@ module RuboCop
119
119
  end
120
120
  end
121
121
 
122
+ # Whether the `def`/`defs` node overrides a method defined by an ancestor
123
+ # of its enclosing class or module elsewhere in the project.
124
+ def overrides_inherited_method?(def_node)
125
+ return false unless project_index
126
+ return false unless (namespace_node = def_node.each_ancestor(:class, :module).first)
127
+
128
+ declaration = resolve_constant_in_index(namespace_node.identifier)
129
+ return false unless declaration.is_a?(Rubydex::Namespace)
130
+
131
+ scope = def_node.defs_type? ? indexed_singleton_of(declaration) : declaration
132
+ !scope.nil? && inherited_index_member?(scope, "#{def_node.method_name}()")
133
+ rescue StandardError
134
+ false
135
+ end
136
+
122
137
  # Whether every link of the declaration's ancestry is resolved in the
123
138
  # index: no definition of any ancestor has an unresolved superclass or
124
139
  # mixin reference. Unresolved links silently vanish from `ancestors`,
@@ -51,15 +51,25 @@ module RuboCop
51
51
  # regardless of size (for cops where verification is the offense logic).
52
52
  def verified_by_reparse(items, oversized: :report)
53
53
  scope_groups(items).flat_map do |scope, group|
54
- if (oversized == :report && verification_too_large?(scope)) ||
55
- (group.size > 1 && corrections_verify?(scope, group))
54
+ if oversized == :report && verification_too_large?(scope)
56
55
  group
57
56
  else
58
- group.select { |item| corrections_verify?(scope, [item]) }
57
+ verified_subset(scope, group)
59
58
  end
60
59
  end
61
60
  end
62
61
 
62
+ # Verifies a group with a single reparse and bisects it when that fails,
63
+ # so a few significant items among many cost a logarithmic number of
64
+ # reparses rather than one each.
65
+ def verified_subset(scope, group)
66
+ return group if corrections_verify?(scope, group)
67
+ return [] if group.one?
68
+
69
+ half = group.size / 2
70
+ verified_subset(scope, group.take(half)) + verified_subset(scope, group.drop(half))
71
+ end
72
+
63
73
  # Whether the exact correction for `item` produces source that still
64
74
  # parses, without requiring an equivalent AST. For corrections that
65
75
  # intentionally change the tree.
@@ -96,9 +96,15 @@ module RuboCop
96
96
  [parenthesized, first_line_comment(node)].compact.join(' ')
97
97
  end
98
98
 
99
+ # rubocop:disable-next Metrics/AbcSize
99
100
  def if_body_source(if_body)
100
101
  if if_body.call_type? && !if_body.method?(:[]=) && omitted_value_in_last_hash_arg?(if_body)
101
102
  "#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
103
+ elsif (value = wrapped_value(if_body))
104
+ prefix = if_body.source_range.begin.join(value.source_range.begin).source
105
+ suffix = value.source_range.end.join(if_body.source_range.end).source
106
+
107
+ "#{prefix}#{if_body_source(value)}#{suffix}"
102
108
  else
103
109
  if_body.source
104
110
  end
@@ -116,6 +122,14 @@ module RuboCop
116
122
  if_body.source_range.begin.join(end_range).source
117
123
  end
118
124
 
125
+ def wrapped_value(if_body)
126
+ if if_body.type?(:return, :next, :break)
127
+ if_body.first_argument if if_body.arguments.one?
128
+ elsif if_body.type?(:lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn)
129
+ if_body.expression
130
+ end
131
+ end
132
+
119
133
  def first_line_comment(node)
120
134
  comment = processed_source.comment_at_line(node.first_line)
121
135
  return unless comment
@@ -137,9 +151,15 @@ module RuboCop
137
151
  parent = node.parent
138
152
  return false if parent.nil?
139
153
  return true if parent.assignment? || parent.operator_keyword?
140
- return true if %i[array pair].include?(parent.type)
154
+ return true if parent.type?(:array, :pair, :call, :yield, :super)
155
+
156
+ ternary_branch_or_endless_method_body?(parent)
157
+ end
158
+
159
+ def ternary_branch_or_endless_method_body?(parent)
160
+ return parent.ternary? if parent.if_type?
141
161
 
142
- node.parent.send_type?
162
+ parent.any_def_type? && parent.endless?
143
163
  end
144
164
 
145
165
  def comment_disables_cop?(comment)