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
@@ -4,10 +4,10 @@ module RuboCop
4
4
  module Cop
5
5
  module Style
6
6
  # Checks for directive scopes that can be expressed with the tighter
7
- # `disable-next` form: a `disable`/`enable` pair wrapping exactly one
8
- # statement, or a `push`/`pop` that only disables cops around exactly
9
- # one statement. A statement-scoped directive cannot drift as the
10
- # surrounding code changes and needs no closing boundary.
7
+ # next-statement forms: a `disable`/`enable` pair, an
8
+ # `enable`/`disable` pair, or a `push`/`pop` with signed arguments
9
+ # wrapping exactly one statement. A statement-scoped directive cannot
10
+ # drift as the surrounding code changes and needs no closing boundary.
11
11
  #
12
12
  # @safety
13
13
  # The autocorrection is unsafe because the suppression scope shrinks
@@ -37,6 +37,21 @@ module RuboCop
37
37
  # def foo
38
38
  # end
39
39
  #
40
+ # # bad
41
+ # # rubocop:disable Metrics/AbcSize
42
+ # # rubocop:push +Metrics/AbcSize
43
+ # def foo
44
+ # end
45
+ # # rubocop:pop
46
+ # # rubocop:enable Metrics/AbcSize
47
+ #
48
+ # # good
49
+ # # rubocop:disable Metrics/AbcSize
50
+ # # rubocop:enable-next Metrics/AbcSize
51
+ # def foo
52
+ # end
53
+ # # rubocop:enable Metrics/AbcSize
54
+ #
40
55
  # # good - the region spans more than one statement
41
56
  # # rubocop:disable Metrics/AbcSize
42
57
  # def foo
@@ -52,7 +67,9 @@ module RuboCop
52
67
 
53
68
  MSG_PAIR = 'Use `%<mode>s-next` instead of a `%<mode>s`/`enable` pair ' \
54
69
  'around a single statement.'
55
- MSG_PUSH_POP = 'Use `disable-next` instead of `push`/`pop` around a single statement.'
70
+ MSG_ENABLE_PAIR = 'Use `enable-next` instead of an `enable`/`disable` pair ' \
71
+ 'around a single statement.'
72
+ MSG_PUSH_POP = 'Use `%<replacement>s` instead of `push`/`pop` around a single statement.'
56
73
 
57
74
  def on_new_investigation
58
75
  processed_source.comments.each do |comment|
@@ -61,8 +78,10 @@ module RuboCop
61
78
 
62
79
  if plain_disable?(directive)
63
80
  check_pair(directive)
64
- elsif disable_only_push?(directive)
81
+ elsif signed_push?(directive)
65
82
  check_push_pop(directive)
83
+ elsif plain_enable?(directive)
84
+ check_enable_pair(directive)
66
85
  end
67
86
  end
68
87
  end
@@ -77,8 +96,12 @@ module RuboCop
77
96
  directive.disabled? && !directive.disable_next?
78
97
  end
79
98
 
80
- def disable_only_push?(directive)
81
- directive.push? && !directive.push_args.empty? && directive.push_args.keys == ['-']
99
+ def plain_enable?(directive)
100
+ directive.enabled? && !directive.enable_next? && !directive.all_cops?
101
+ end
102
+
103
+ def signed_push?(directive)
104
+ directive.push? && !directive.signed_args.empty?
82
105
  end
83
106
 
84
107
  def check_pair(directive)
@@ -100,15 +123,132 @@ module RuboCop
100
123
  end
101
124
 
102
125
  def check_push_pop(directive)
103
- pop = single_statement_closing_directive(directive)
104
- return unless pop&.pop?
126
+ pop_line = balancing_pop_line(directive)
127
+ return unless pop_line && comment_config.comment_only_line?(pop_line)
128
+ return unless wraps_single_statement?(directive, pop_line)
105
129
 
106
- add_offense(directive.comment, message: MSG_PUSH_POP) do |corrector|
107
- corrector.replace(directive.comment, disable_next_replacement(directive))
108
- remove_line(corrector, pop.comment)
130
+ pop_comment = processed_source.comment_at_line(pop_line)
131
+ replacement = push_replacement(directive)
132
+ message = format(MSG_PUSH_POP, replacement: replacement_mode(directive))
133
+ add_offense(directive.comment, message: message) do |corrector|
134
+ corrector.replace(directive.comment, replacement)
135
+ remove_line(corrector, pop_comment)
109
136
  end
110
137
  end
111
138
 
139
+ # The line of the `pop` balancing this `push`, taking nesting into
140
+ # account, or `nil` when the push is never popped.
141
+ def balancing_pop_line(push_directive)
142
+ depth = 0
143
+ each_directive_after(push_directive) do |directive|
144
+ if directive.push?
145
+ depth += 1
146
+ elsif directive.pop?
147
+ return directive.line_number if depth.zero?
148
+
149
+ depth -= 1
150
+ end
151
+ end
152
+ nil
153
+ end
154
+
155
+ def each_directive_after(reference)
156
+ processed_source.comments.each do |comment|
157
+ directive = DirectiveComment.new(comment)
158
+ next unless directive.cop_names || directive.push? || directive.pop?
159
+
160
+ yield directive if directive.line_number > reference.line_number
161
+ end
162
+ end
163
+
164
+ def replacement_mode(directive)
165
+ ops = directive.signed_args.keys.sort
166
+ if ops == ['-']
167
+ 'disable-next'
168
+ elsif ops == ['+']
169
+ 'enable-next'
170
+ else
171
+ 'next'
172
+ end
173
+ end
174
+
175
+ def push_replacement(directive)
176
+ text = case replacement_mode(directive)
177
+ when 'disable-next'
178
+ "# rubocop:disable-next #{directive.signed_args['-'].join(', ')}"
179
+ when 'enable-next'
180
+ "# rubocop:enable-next #{directive.signed_args['+'].join(', ')}"
181
+ else
182
+ "# rubocop:next #{directive.cops}"
183
+ end
184
+ reason = directive.reason
185
+ reason ? "#{text} -- #{reason}" : text
186
+ end
187
+
188
+ # An `enable`/`disable` pair around one statement inside a disabled
189
+ # region re-enables the cops for just that statement - `enable-next`
190
+ # says the same without the closing boundary. The pair only counts
191
+ # when the `enable` really closed open disables (otherwise the
192
+ # trailing `disable` opens a new region and the conversion would
193
+ # change what is covered).
194
+ def check_enable_pair(directive)
195
+ closing = enable_pair_closing(directive)
196
+ return unless closing
197
+
198
+ add_offense(directive.comment, message: MSG_ENABLE_PAIR) do |corrector|
199
+ corrector.replace(directive.comment,
200
+ directive.comment.text.sub(/\benable\b/, 'enable-next'))
201
+ remove_line(corrector, closing.comment)
202
+ end
203
+ end
204
+
205
+ def enable_pair_closing(directive)
206
+ scope = comment_config.statement_scope_after(directive.line_number)
207
+ return nil unless scope && scope.begin == directive.line_number + 1
208
+
209
+ closing = re_disable_below(directive, scope.end + 1)
210
+ closing if closing && closed_open_disables?(directive, closing)
211
+ end
212
+
213
+ def re_disable_below(directive, line)
214
+ return nil unless comment_config.comment_only_line?(line)
215
+
216
+ comment = processed_source.comment_at_line(line)
217
+ return nil unless comment
218
+
219
+ closing = DirectiveComment.new(comment)
220
+ return nil unless closing.disabled? && !closing.disable_next?
221
+ return nil unless closing.raw_cop_names.sort == directive.raw_cop_names.sort
222
+
223
+ closing
224
+ end
225
+
226
+ # Every cop of the pair must have a range the `enable` closed and a
227
+ # range the trailing `disable` reopened - otherwise the `enable` was
228
+ # not inside a disabled region and the conversion would change what
229
+ # is covered.
230
+ def closed_open_disables?(directive, closing)
231
+ directive.cop_names.all? do |cop|
232
+ ranges = comment_config.cop_disabled_line_ranges[qualified_name(cop)]
233
+ ranges && closed_at?(ranges, directive.line_number) && reopened_by?(ranges, closing)
234
+ end
235
+ end
236
+
237
+ def closed_at?(ranges, line)
238
+ ranges.any? { |range| range.end == line }
239
+ end
240
+
241
+ def reopened_by?(ranges, closing)
242
+ ranges.any? do |range|
243
+ range.respond_to?(:directive) && range.directive.comment.equal?(closing.comment)
244
+ end
245
+ end
246
+
247
+ def qualified_name(cop_name)
248
+ Registry.qualified_cop_name(cop_name.strip, processed_source.file_path,
249
+ correct_namespace: false)
250
+ end
251
+
112
252
  # The directive closing this one's scope, when that scope wraps
113
253
  # exactly one statement - `nil` otherwise.
114
254
  def single_statement_closing_directive(directive)
@@ -133,7 +273,7 @@ module RuboCop
133
273
  ends = ranges.map(&:end).uniq
134
274
  return nil unless ends.size == 1 && ends.first.to_f.finite?
135
275
 
136
- directive.push? ? ends.first + 1 : ends.first
276
+ ends.first
137
277
  end
138
278
 
139
279
  def ranges_opened_by(directive)
@@ -155,13 +295,6 @@ module RuboCop
155
295
  !scope.nil? && scope.begin == directive.line_number + 1 && scope.end + 1 == closing_line
156
296
  end
157
297
 
158
- def disable_next_replacement(directive)
159
- cops = directive.push_args['-'].join(', ')
160
- reason = directive.reason
161
- text = "# rubocop:disable-next #{cops}"
162
- reason ? "#{text} -- #{reason}" : text
163
- end
164
-
165
298
  def remove_line(corrector, comment)
166
299
  corrector.remove(range_by_whole_lines(comment.source_range, include_final_newline: true))
167
300
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable Lint/RedundantCopDisableDirective
3
+ # rubocop:disable Lint/RedundantCopDisableDirective -- the examples below read as real directives
4
4
 
5
5
  module RuboCop
6
6
  module Cop
@@ -12,6 +12,10 @@ module RuboCop
12
12
  # Specific cops can be allowed with the `AllowedCops` configuration. Note that
13
13
  # if this configuration is set, `rubocop:disable all` is still disallowed.
14
14
  #
15
+ # `AllowedCops` and `DisallowedCops` accept cop names and department names
16
+ # alike. Listing a cop does not cover its whole department: a directive
17
+ # disabling `Metrics` is broader than one disabling `Metrics/AbcSize`.
18
+ #
15
19
  # Alternatively, specific cops can be disallowed with the `DisallowedCops`
16
20
  # configuration. When `DisallowedCops` is set, only directives for the listed
17
21
  # cops (and `all`) will be flagged. This is useful when you want
@@ -19,11 +23,18 @@ module RuboCop
19
23
  # allowlisting all other cops. `AllowedCops` and `DisallowedCops` should not
20
24
  # both be set at the same time; if `DisallowedCops` is set, it takes precedence.
21
25
  #
22
- # With `AllowTrailingComment` set to `true`, a disable directive carrying
26
+ # `AllowedDirectives` names directive forms - `disable`, `todo`,
27
+ # `disable-next`, `todo-next`, `push`, `next` - and exempts them from the
28
+ # cop entirely. `rubocop:todo` is the usual candidate, since
29
+ # `--disable-uncorrectable` generates those and they record debt rather
30
+ # than a decision someone should be asked to justify.
31
+ #
32
+ # With `AllowWithReason` set to `true`, a disable directive carrying
23
33
  # a `--` trailing justification comment is allowed, so a team can require
24
34
  # every disable to be documented instead of banning them outright. Enable
25
35
  # directives are not checked in this mode, since they end a suppression
26
- # rather than start one.
36
+ # rather than start one. Offenses in this mode are not autocorrected,
37
+ # since only a human can supply the missing justification.
27
38
  #
28
39
  # This cop cannot be disabled via directive comments when it is explicitly
29
40
  # enabled with `Enabled: true`. This prevents users from bypassing the cop
@@ -58,7 +69,21 @@ module RuboCop
58
69
  # foo
59
70
  # # rubocop:enable Metrics/AbcSize
60
71
  #
61
- # @example AllowTrailingComment: true
72
+ # @example AllowedDirectives: [todo]
73
+ # # good - the cop does not look at `todo` directives at all
74
+ # x = 0 # rubocop:todo Layout/SpaceAroundOperators
75
+ #
76
+ # # bad
77
+ # x = 0 # rubocop:disable Layout/SpaceAroundOperators
78
+ #
79
+ # @example AllowedCops: [Metrics]
80
+ # # good - every cop the directive disables is in an exempt department
81
+ # # rubocop:disable Metrics/AbcSize
82
+ # def foo
83
+ # end
84
+ # # rubocop:enable Metrics/AbcSize
85
+ #
86
+ # @example AllowWithReason: true
62
87
  # # bad
63
88
  # x = 0 # rubocop:disable Layout/SpaceAroundOperators
64
89
  #
@@ -75,16 +100,18 @@ module RuboCop
75
100
  'comment are not permitted.'
76
101
 
77
102
  def on_new_investigation
103
+ @matching_pops = nil
104
+
78
105
  processed_source.comments.each do |comment|
79
106
  directive = DirectiveComment.new(comment)
80
- next if allow_trailing_comment? && (directive.reason || directive.enabled?)
107
+ next if ignored?(directive)
81
108
 
82
109
  directive_cops = directive_cops(directive)
83
110
  disallowed_cops = compute_disallowed_cops(directive_cops)
84
111
 
85
112
  next unless disallowed_cops.any?
86
113
 
87
- register_offense(comment, directive_cops, disallowed_cops)
114
+ register_offense(directive, directive_cops, disallowed_cops)
88
115
  end
89
116
  end
90
117
 
@@ -95,28 +122,70 @@ module RuboCop
95
122
  if directive_cops.include?('all')
96
123
  directive_cops
97
124
  else
98
- directive_cops.uniq.select { |cop| disallowed_cops_config.include?(cop) }
125
+ directive_cops.uniq.select { |cop| listed?(disallowed_cops_config, cop) }
99
126
  end
100
127
  else
101
- directive_cops.reject { |cop| allowed_cops.include?(cop) }
128
+ directive_cops.reject { |cop| cop != 'all' && listed?(allowed_cops, cop) }
102
129
  end
103
130
  end
104
131
 
105
- def register_offense(comment, directive_cops, disallowed_cops)
106
- add_offense(comment, message: offense_message(disallowed_cops)) do |corrector|
107
- replacement = ''
132
+ def register_offense(directive, directive_cops, disallowed_cops)
133
+ comment = directive.comment
108
134
 
109
- if directive_cops.length != disallowed_cops.length
110
- replacement = comment.text.sub(/#{Regexp.union(disallowed_cops)},?\s*/, '')
111
- .sub(/,\s*$/, '')
135
+ add_offense(comment, message: offense_message(disallowed_cops)) do |corrector|
136
+ # The remedy in `AllowWithReason` mode is to write the missing `--` justification,
137
+ # which cannot be autocorrected. Removing the directive would also unsuppress
138
+ # the disabled cops and let their autocorrections rewrite the annotated code.
139
+ next if allow_with_reason?
140
+
141
+ if directive_cops.length == disallowed_cops.length
142
+ remove_directive(corrector, directive)
143
+ elsif signed_args?(directive)
144
+ remove_signed_args(corrector, directive, disallowed_cops)
145
+ else
146
+ remove_cops(corrector, comment, disallowed_cops)
112
147
  end
148
+ end
149
+ end
150
+
151
+ # A `push` without its `pop` leaves an orphan `pop` behind, so the pair goes together.
152
+ def remove_directive(corrector, directive)
153
+ corrector.replace(directive.comment, '')
154
+ return unless directive.push? && (pop = matching_pop(directive.comment))
113
155
 
114
- corrector.replace(comment, replacement)
156
+ corrector.replace(pop, '')
157
+ end
158
+
159
+ def matching_pop(push_comment)
160
+ @matching_pops ||= pair_pushes_with_pops
161
+ @matching_pops[push_comment]
162
+ end
163
+
164
+ def pair_pushes_with_pops
165
+ pushes = []
166
+ processed_source.comments.each_with_object({}) do |comment, pairs|
167
+ directive = DirectiveComment.new(comment)
168
+ if directive.push?
169
+ pushes.push(comment)
170
+ elsif directive.pop? && (push = pushes.pop)
171
+ pairs[push] = comment
172
+ end
115
173
  end
116
174
  end
117
175
 
176
+ def remove_signed_args(corrector, directive, disallowed_cops)
177
+ range = directive.range
178
+ names = Regexp.union(disallowed_cops)
179
+ corrector.replace(range, range.source.gsub(/\s+[+-]#{names}(?!\S)/, ''))
180
+ end
181
+
182
+ def remove_cops(corrector, comment, disallowed_cops)
183
+ corrector.replace(comment, comment.text.sub(/#{Regexp.union(disallowed_cops)},?\s*/, '')
184
+ .sub(/,\s*$/, ''))
185
+ end
186
+
118
187
  def offense_message(disallowed_cops)
119
- if allow_trailing_comment?
188
+ if allow_with_reason?
120
189
  MSG_MISSING_REASON
121
190
  elsif any_cops_allowed? || disallowed_cops_config.any?
122
191
  format(MSG_FOR_COPS, cops: "`#{disallowed_cops.join('`, `')}`")
@@ -126,18 +195,49 @@ module RuboCop
126
195
  end
127
196
 
128
197
  def directive_cops(directive)
198
+ return directive.signed_args.values.flatten if signed_args?(directive)
199
+
129
200
  match_captures = directive.match_captures
130
201
  match_captures && match_captures[1] ? match_captures[1].split(',').map(&:strip) : []
131
202
  end
132
203
 
133
- def allow_trailing_comment?
134
- cop_config['AllowTrailingComment']
204
+ def signed_args?(directive)
205
+ directive.push? || directive.next?
206
+ end
207
+
208
+ def ignored?(directive)
209
+ return true if exempt_mode?(directive)
210
+
211
+ allow_with_reason? && (directive.reason || directive.enabled?)
212
+ end
213
+
214
+ def exempt_mode?(directive)
215
+ allowed_directives.include?(directive.mode)
216
+ end
217
+
218
+ def allowed_directives
219
+ @allowed_directives ||= Array(cop_config['AllowedDirectives'])
220
+ end
221
+
222
+ def allow_with_reason?
223
+ # TODO: The obsolete `AllowTrailingComment` is honored for backward compatibility
224
+ # and will be removed in RuboCop 2.0.
225
+ allow_trailing_comment = cop_config['AllowTrailingComment'] # rubocop:disable InternalAffairs/UndefinedConfig -- obsolete key, gone from default.yml on purpose
226
+ return allow_trailing_comment unless allow_trailing_comment.nil?
227
+
228
+ cop_config['AllowWithReason']
135
229
  end
136
230
 
137
231
  def allowed_cops
138
232
  @allowed_cops ||= Array(cop_config['AllowedCops']).to_set
139
233
  end
140
234
 
235
+ # A name matches either outright or through its department, so
236
+ # `Metrics` covers `Metrics/AbcSize` but not the other way round.
237
+ def listed?(names, cop)
238
+ names.include?(cop) || names.include?(cop.split('/').first)
239
+ end
240
+
141
241
  def any_cops_allowed?
142
242
  allowed_cops.any?
143
243
  end
@@ -119,6 +119,7 @@ module RuboCop
119
119
 
120
120
  def on_def(node)
121
121
  return if node.method?(:initialize)
122
+ return if allowed_methods.include?(node.method_name)
122
123
 
123
124
  parent = node.parent
124
125
  modifier_node?(parent) ? check(parent) : check(node)
@@ -130,7 +131,6 @@ module RuboCop
130
131
  def check(node)
131
132
  return if non_public?(node) && !require_for_non_public_methods?
132
133
  return if documentation_comment?(node)
133
- return if method_allowed?(node)
134
134
 
135
135
  add_offense(node)
136
136
  end
@@ -139,14 +139,6 @@ module RuboCop
139
139
  cop_config['RequireForNonPublicMethods']
140
140
  end
141
141
 
142
- def method_allowed?(node)
143
- # For a modifier form like `module_function def foo; end`, `node` is the
144
- # `module_function`/`ruby2_keywords` send; the real method name is on its
145
- # `def`/`defs` argument, not the modifier itself.
146
- method_name = node.send_type? ? node.first_argument.method_name : node.method_name
147
- allowed_methods.include?(method_name)
148
- end
149
-
150
142
  def allowed_methods
151
143
  @allowed_methods ||= cop_config.fetch('AllowedMethods', []).map(&:to_sym)
152
144
  end
@@ -70,6 +70,7 @@ module RuboCop
70
70
 
71
71
  def on_send(node)
72
72
  return unless double_negative?(node) && node.prefix_bang?
73
+ return if part_of_longer_negation?(node)
73
74
  return if style == :allowed_in_returns && allowed_in_returns?(node)
74
75
 
75
76
  location = node.loc.selector
@@ -81,10 +82,20 @@ module RuboCop
81
82
 
82
83
  private
83
84
 
85
+ def part_of_longer_negation?(node)
86
+ return true if negation?(node.parent) && node.parent.receiver.equal?(node)
87
+
88
+ negation?(node.receiver.receiver)
89
+ end
90
+
84
91
  def allowed_in_returns?(node)
85
92
  node.parent&.return_type? || end_of_method_definition?(node)
86
93
  end
87
94
 
95
+ def negation?(node)
96
+ node&.send_type? && node.method?(:!)
97
+ end
98
+
88
99
  def end_of_method_definition?(node)
89
100
  return false unless (def_node = find_def_node_from_ascendant(node))
90
101
 
@@ -26,7 +26,7 @@ module RuboCop
26
26
 
27
27
  MSG = 'Use `Integer#times` for a simple loop which iterates a fixed number of times.'
28
28
 
29
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
29
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- only matches blocks that take no parameters
30
30
  return unless offending?(node)
31
31
 
32
32
  send_node = node.send_node
@@ -28,7 +28,7 @@ module RuboCop
28
28
 
29
29
  MSG = 'Omit pipes for the empty block parameters.'
30
30
 
31
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
31
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- the offense is an empty `||`
32
32
  send_node = node.send_node
33
33
  check(node) unless send_node.send_type? && send_node.lambda_literal?
34
34
  end
@@ -23,7 +23,7 @@ module RuboCop
23
23
 
24
24
  MSG = 'Omit parentheses for the empty lambda parameters.'
25
25
 
26
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
26
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- the offense is an empty `()`
27
27
  send_node = node.send_node
28
28
  return unless send_node.send_type?
29
29
 
@@ -103,7 +103,7 @@ module RuboCop
103
103
  end
104
104
 
105
105
  def replacement_range(node)
106
- if hash_node(node) && first_argument_unparenthesized?(node)
106
+ if offense_hash_node?(node) && first_argument_unparenthesized?(node)
107
107
  # `some_method {}` is not same as `some_method Hash.new`
108
108
  # because the braces are interpreted as a block. We will have
109
109
  # to rewrite the arguments to wrap them in parenthesis.
@@ -53,11 +53,11 @@ module RuboCop
53
53
 
54
54
  def on_def(node)
55
55
  return if node.body || processed_source.contains_comment?(node.source_range)
56
- return if correct_style?(node)
56
+ return if correct_style?(node) || compact_style_disallowed?
57
57
 
58
58
  add_offense(node) do |corrector|
59
59
  correction = corrected(node)
60
- next if compact_style? && max_line_length && correction.size > max_line_length
60
+ next if correction_exceeds_line_length?(correction)
61
61
 
62
62
  corrector.replace(node, correction)
63
63
  end
@@ -74,6 +74,12 @@ module RuboCop
74
74
  (compact_style? && compact?(node)) || (expanded_style? && expanded?(node))
75
75
  end
76
76
 
77
+ def compact_style_disallowed?
78
+ return false unless compact_style?
79
+
80
+ config.for_enabled_cop('Style/SingleLineMethods')['AllowIfMethodIsEmpty'] == false
81
+ end
82
+
77
83
  def corrected(node)
78
84
  scope = node.receiver ? "#{node.receiver.source}." : ''
79
85
  arguments = if node.arguments?
@@ -86,14 +92,20 @@ module RuboCop
86
92
  ["def #{signature}", 'end'].join(joint(node))
87
93
  end
88
94
 
95
+ def correction_exceeds_line_length?(correction)
96
+ compact_style? && max_line_length && correction.size > max_line_length
97
+ end
98
+
89
99
  def joint(node)
90
100
  indent = ' ' * node.loc.column
91
101
 
92
102
  compact_style? ? '; ' : "\n#{indent}"
93
103
  end
94
104
 
105
+ # A method with an argument spanning multiple lines (e.g. a hash default
106
+ # value) can't be put on a single line, so it's as compact as it gets.
95
107
  def compact?(node)
96
- node.single_line?
108
+ node.single_line? || node.arguments.any?(&:multiline?)
97
109
  end
98
110
 
99
111
  def expanded?(node)