rubocop 1.91.0 → 1.92.2

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 (278) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +4 -1
  4. data/lib/rubocop/cached_data.rb +47 -7
  5. data/lib/rubocop/changed_files.rb +35 -13
  6. data/lib/rubocop/cli/command/cop_names.rb +57 -0
  7. data/lib/rubocop/cli/command/execute_runner.rb +2 -2
  8. data/lib/rubocop/cli/command/explain.rb +34 -0
  9. data/lib/rubocop/cli/command/show_cops.rb +6 -0
  10. data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
  11. data/lib/rubocop/cli.rb +3 -2
  12. data/lib/rubocop/comment_config.rb +17 -8
  13. data/lib/rubocop/config.rb +0 -4
  14. data/lib/rubocop/config_loader.rb +6 -3
  15. data/lib/rubocop/config_loader_resolver.rb +37 -12
  16. data/lib/rubocop/config_obsoletion/removed_cop.rb +1 -1
  17. data/lib/rubocop/config_obsoletion.rb +9 -0
  18. data/lib/rubocop/config_validator.rb +11 -0
  19. data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
  20. data/lib/rubocop/cop/badge.rb +1 -1
  21. data/lib/rubocop/cop/base.rb +42 -21
  22. data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
  23. data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
  24. data/lib/rubocop/cop/cop_documentation.rb +81 -0
  25. data/lib/rubocop/cop/cop_explanation.rb +140 -0
  26. data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
  27. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +37 -7
  28. data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
  29. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +25 -4
  30. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
  31. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
  32. data/lib/rubocop/cop/documentation.rb +1 -1
  33. data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
  34. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
  35. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
  36. data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
  37. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
  38. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
  39. data/lib/rubocop/cop/layout/argument_alignment.rb +5 -1
  40. data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
  41. data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
  42. data/lib/rubocop/cop/layout/class_structure.rb +29 -7
  43. data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
  44. data/lib/rubocop/cop/layout/dot_position.rb +25 -15
  45. data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
  46. data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
  47. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  48. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
  49. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
  50. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
  51. data/lib/rubocop/cop/layout/end_alignment.rb +21 -25
  52. data/lib/rubocop/cop/layout/extra_spacing.rb +21 -6
  53. data/lib/rubocop/cop/layout/first_argument_indentation.rb +27 -1
  54. data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
  55. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +16 -8
  56. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
  57. data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
  58. data/lib/rubocop/cop/layout/hash_alignment.rb +16 -12
  59. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +7 -3
  60. data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
  61. data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
  62. data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
  63. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  64. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
  65. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
  66. data/lib/rubocop/cop/layout/line_length.rb +176 -26
  67. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
  68. data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
  69. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +9 -0
  70. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
  71. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +30 -5
  72. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
  73. data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
  74. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
  75. data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
  76. data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
  77. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +6 -11
  78. data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
  79. data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
  80. data/lib/rubocop/cop/layout/space_before_block_braces.rb +16 -1
  81. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
  82. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +32 -9
  83. data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
  84. data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
  85. data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
  86. data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
  87. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
  88. data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
  89. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
  90. data/lib/rubocop/cop/lint/interpolation_check.rb +20 -17
  91. data/lib/rubocop/cop/lint/literal_as_condition.rb +15 -0
  92. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
  93. data/lib/rubocop/cop/lint/loop.rb +24 -2
  94. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +71 -11
  95. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
  96. data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
  97. data/lib/rubocop/cop/lint/number_conversion.rb +3 -1
  98. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
  99. data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
  100. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +39 -9
  101. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
  102. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
  103. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
  104. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
  105. data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
  106. data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
  107. data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
  108. data/lib/rubocop/cop/lint/void.rb +8 -1
  109. data/lib/rubocop/cop/metrics/class_length.rb +4 -2
  110. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
  111. data/lib/rubocop/cop/metrics/module_length.rb +4 -2
  112. data/lib/rubocop/cop/mixin/alignment.rb +4 -0
  113. data/lib/rubocop/cop/mixin/check_line_breakable.rb +23 -19
  114. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +8 -2
  115. data/lib/rubocop/cop/mixin/code_length.rb +10 -2
  116. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  117. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
  118. data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
  119. data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
  120. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +41 -6
  121. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +26 -2
  122. data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
  123. data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
  124. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
  125. data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
  126. data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
  127. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +17 -2
  128. data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
  129. data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
  130. data/lib/rubocop/cop/mixin/statement_modifier.rb +39 -5
  131. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  132. data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
  133. data/lib/rubocop/cop/mixin.rb +2 -0
  134. data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
  135. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  136. data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
  137. data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
  138. data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
  139. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
  140. data/lib/rubocop/cop/offense.rb +59 -3
  141. data/lib/rubocop/cop/registry.rb +1 -1
  142. data/lib/rubocop/cop/security/json_load.rb +16 -4
  143. data/lib/rubocop/cop/style/access_modifier_declarations.rb +37 -2
  144. data/lib/rubocop/cop/style/alias.rb +18 -5
  145. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
  146. data/lib/rubocop/cop/style/and_or.rb +37 -10
  147. data/lib/rubocop/cop/style/arguments_forwarding.rb +32 -3
  148. data/lib/rubocop/cop/style/attr.rb +3 -4
  149. data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
  150. data/lib/rubocop/cop/style/block_delimiters.rb +35 -3
  151. data/lib/rubocop/cop/style/case_equality.rb +14 -3
  152. data/lib/rubocop/cop/style/case_like_if.rb +6 -3
  153. data/lib/rubocop/cop/style/class_and_module_children.rb +57 -16
  154. data/lib/rubocop/cop/style/class_methods_definitions.rb +15 -0
  155. data/lib/rubocop/cop/style/collection_querying.rb +79 -46
  156. data/lib/rubocop/cop/style/combinable_loops.rb +89 -11
  157. data/lib/rubocop/cop/style/concat_array_literals.rb +58 -7
  158. data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
  159. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +65 -9
  160. data/lib/rubocop/cop/style/double_negation.rb +11 -0
  161. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  162. data/lib/rubocop/cop/style/empty_method.rb +3 -1
  163. data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
  164. data/lib/rubocop/cop/style/endless_method.rb +104 -11
  165. data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
  166. data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
  167. data/lib/rubocop/cop/style/float_division.rb +37 -2
  168. data/lib/rubocop/cop/style/for.rb +53 -2
  169. data/lib/rubocop/cop/style/format_string.rb +28 -6
  170. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
  171. data/lib/rubocop/cop/style/guard_clause.rb +31 -22
  172. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
  173. data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
  174. data/lib/rubocop/cop/style/hash_lookup_method.rb +42 -9
  175. data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
  176. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  177. data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
  178. data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -26
  179. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
  180. data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
  181. data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
  182. data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
  183. data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
  184. data/lib/rubocop/cop/style/lambda.rb +34 -1
  185. data/lib/rubocop/cop/style/lambda_call.rb +7 -2
  186. data/lib/rubocop/cop/style/map_into_array.rb +1 -2
  187. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +80 -13
  188. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +26 -2
  189. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
  190. data/lib/rubocop/cop/style/method_def_parentheses.rb +38 -4
  191. data/lib/rubocop/cop/style/missing_else.rb +7 -1
  192. data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
  193. data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
  194. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
  195. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
  196. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
  197. data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
  198. data/lib/rubocop/cop/style/mutable_constant.rb +52 -7
  199. data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
  200. data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
  201. data/lib/rubocop/cop/style/nested_modifier.rb +27 -8
  202. data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
  203. data/lib/rubocop/cop/style/next.rb +24 -10
  204. data/lib/rubocop/cop/style/nil_comparison.rb +16 -4
  205. data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
  206. data/lib/rubocop/cop/style/not.rb +10 -5
  207. data/lib/rubocop/cop/style/numeric_predicate.rb +28 -5
  208. data/lib/rubocop/cop/style/one_line_conditional.rb +13 -2
  209. data/lib/rubocop/cop/style/parentheses_around_condition.rb +19 -1
  210. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
  211. data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
  212. data/lib/rubocop/cop/style/raise_args.rb +80 -11
  213. data/lib/rubocop/cop/style/reduce_to_hash.rb +47 -33
  214. data/lib/rubocop/cop/style/redundant_begin.rb +45 -5
  215. data/lib/rubocop/cop/style/redundant_condition.rb +30 -13
  216. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -0
  217. data/lib/rubocop/cop/style/redundant_exception.rb +27 -11
  218. data/lib/rubocop/cop/style/redundant_fetch_block.rb +9 -1
  219. data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
  220. data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
  221. data/lib/rubocop/cop/style/redundant_parentheses.rb +12 -1
  222. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
  223. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +20 -0
  224. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
  225. data/lib/rubocop/cop/style/redundant_self.rb +9 -1
  226. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
  227. data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
  228. data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
  229. data/lib/rubocop/cop/style/require_order.rb +25 -8
  230. data/lib/rubocop/cop/style/rescue_modifier.rb +11 -9
  231. data/lib/rubocop/cop/style/return_nil.rb +17 -2
  232. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
  233. data/lib/rubocop/cop/style/sample.rb +9 -8
  234. data/lib/rubocop/cop/style/self_assignment.rb +12 -15
  235. data/lib/rubocop/cop/style/semicolon.rb +16 -5
  236. data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
  237. data/lib/rubocop/cop/style/single_line_methods.rb +42 -4
  238. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
  239. data/lib/rubocop/cop/style/string_concatenation.rb +21 -4
  240. data/lib/rubocop/cop/style/struct_inheritance.rb +6 -0
  241. data/lib/rubocop/cop/style/super_arguments.rb +3 -0
  242. data/lib/rubocop/cop/style/symbol_proc.rb +24 -6
  243. data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
  244. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
  245. data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
  246. data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
  247. data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
  248. data/lib/rubocop/cop/team.rb +10 -5
  249. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  250. data/lib/rubocop/cop/variable_force/variable.rb +14 -1
  251. data/lib/rubocop/formatter/base_formatter.rb +22 -0
  252. data/lib/rubocop/formatter/formatter_set.rb +4 -0
  253. data/lib/rubocop/formatter/json_formatter.rb +71 -1
  254. data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
  255. data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
  256. data/lib/rubocop/formatter/sarif_formatter.rb +12 -7
  257. data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
  258. data/lib/rubocop/lsp/routes.rb +23 -23
  259. data/lib/rubocop/lsp/runtime.rb +47 -11
  260. data/lib/rubocop/lsp/stdin_runner.rb +11 -5
  261. data/lib/rubocop/lsp.rb +5 -2
  262. data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
  263. data/lib/rubocop/mcp/explain_tool.rb +68 -0
  264. data/lib/rubocop/mcp/scope.rb +65 -0
  265. data/lib/rubocop/mcp/server.rb +184 -76
  266. data/lib/rubocop/mcp/source_files.rb +35 -0
  267. data/lib/rubocop/offense_limit.rb +30 -0
  268. data/lib/rubocop/options.rb +45 -10
  269. data/lib/rubocop/plugin/configuration_integrator.rb +36 -8
  270. data/lib/rubocop/remote_config.rb +4 -1
  271. data/lib/rubocop/result_cache.rb +20 -13
  272. data/lib/rubocop/runner.rb +110 -42
  273. data/lib/rubocop/server/cache.rb +6 -6
  274. data/lib/rubocop/target_ruby.rb +21 -9
  275. data/lib/rubocop/util.rb +69 -0
  276. data/lib/rubocop/version.rb +1 -1
  277. data/lib/rubocop.rb +5 -0
  278. metadata +16 -5
@@ -152,6 +152,10 @@ module RuboCop
152
152
 
153
153
  MSG = 'Indent the first argument one step more than %<base>s.'
154
154
 
155
+ def self.autocorrect_incompatible_with
156
+ [Layout::ArgumentAlignment, Layout::HashAlignment]
157
+ end
158
+
155
159
  def on_send(node)
156
160
  return unless should_check?(node)
157
161
  return if same_line?(node, node.first_argument)
@@ -180,7 +184,13 @@ module RuboCop
180
184
 
181
185
  top_level_send = find_top_level_send(send_node)
182
186
  node_to_correct =
183
- should_correct_entire_chain?(send_node, top_level_send) ? top_level_send : node
187
+ if should_correct_entire_chain?(send_node, top_level_send)
188
+ top_level_send
189
+ elsif hash_elements_aligned_by_argument_alignment?(node)
190
+ node.children.first
191
+ else
192
+ node
193
+ end
184
194
 
185
195
  AlignmentCorrector.correct(corrector, processed_source, node_to_correct, column_delta)
186
196
  end
@@ -189,6 +199,7 @@ module RuboCop
189
199
  return false unless style == :special_for_inner_method_call_in_parentheses
190
200
  return false unless inner_call?(top_level_send)
191
201
  return false unless display_column(send_node.source_range) < column_delta.abs
202
+ return false if column_delta.positive?
192
203
 
193
204
  top_level_send != send_node || begins_its_line?(top_level_send.loc.end)
194
205
  end
@@ -209,6 +220,21 @@ module RuboCop
209
220
  top_level_send
210
221
  end
211
222
 
223
+ # `Layout/ArgumentAlignment` with `with_fixed_indentation` indents the pairs of an
224
+ # unbraced hash to a fixed column, so they must not move along with the first element.
225
+ def hash_elements_aligned_by_argument_alignment?(node)
226
+ return false if !node.hash_type? || node.braces?
227
+ return false unless enforce_first_argument_with_fixed_indentation?
228
+
229
+ argument_alignment_applies?(node.parent) && !enforce_hash_argument_with_separator?
230
+ end
231
+
232
+ def enforce_hash_argument_with_separator?
233
+ HashAlignment::SEPARATOR_ALIGNMENT_STYLES.any? do |style|
234
+ config.for_enabled_cop('Layout/HashAlignment')[style]&.include?('separator')
235
+ end
236
+ end
237
+
212
238
  def bare_operator?(node)
213
239
  node.operator_method? && !node.dot?
214
240
  end
@@ -6,6 +6,10 @@ module RuboCop
6
6
  # Checks for a line break before the first element in a
7
7
  # multi-line array.
8
8
  #
9
+ # NOTE: An array whose first element is an array literal is not checked when
10
+ # `Layout/SpaceInsideArrayLiteralBrackets` is enabled with `EnforcedStyle: compact`,
11
+ # since that style joins the two opening brackets.
12
+ #
9
13
  # @example
10
14
  #
11
15
  # # bad
@@ -70,6 +74,7 @@ module RuboCop
70
74
  def on_array(node)
71
75
  return if !node.loc.begin && !assignment_on_same_line?(node)
72
76
  return if allow_implicit_array_brackets? && !node.bracketed?
77
+ return if compact_nested_array?(node)
73
78
 
74
79
  check_children_line_break(node, node.children, ignore_last: ignore_last_element?)
75
80
  end
@@ -85,6 +90,16 @@ module RuboCop
85
90
  !!cop_config['AllowImplicitArrayLiterals']
86
91
  end
87
92
 
93
+ def compact_nested_array?(node)
94
+ node.square_brackets? && node.children.first&.source&.start_with?('[') &&
95
+ compact_array_brackets_enforced?
96
+ end
97
+
98
+ def compact_array_brackets_enforced?
99
+ config.cop_enabled?('Layout/SpaceInsideArrayLiteralBrackets') &&
100
+ config.for_cop('Layout/SpaceInsideArrayLiteralBrackets')['EnforcedStyle'] == 'compact'
101
+ end
102
+
88
103
  def ignore_last_element?
89
104
  !!cop_config['AllowMultilineFinalElement']
90
105
  end
@@ -156,16 +156,22 @@ module RuboCop
156
156
  if first_pair
157
157
  return if same_line?(first_pair, left_brace)
158
158
 
159
- if separator_style?(first_pair)
160
- check_based_on_longest_key(hash_node, left_brace, left_parenthesis)
161
- else
162
- check_first(first_pair, left_brace, left_parenthesis, 0)
163
- end
159
+ check_first_pair(hash_node, first_pair, left_brace, left_parenthesis)
164
160
  end
165
161
 
166
162
  check_right_brace(hash_node.loc.end, first_pair, left_brace, left_parenthesis)
167
163
  end
168
164
 
165
+ def check_first_pair(hash_node, first_pair, left_brace, left_parenthesis)
166
+ return unless begins_its_line?(first_pair.source_range)
167
+
168
+ if separator_style?(first_pair)
169
+ check_based_on_longest_key(hash_node, left_brace, left_parenthesis)
170
+ else
171
+ check_first(first_pair, left_brace, left_parenthesis, 0)
172
+ end
173
+ end
174
+
169
175
  def check_right_brace(right_brace, first_pair, left_brace, left_parenthesis)
170
176
  # if the right brace is on the same line as the last value, accept
171
177
  return if /\S/.match?(right_brace.source_line[0...right_brace.column])
@@ -187,9 +193,11 @@ module RuboCop
187
193
  end
188
194
 
189
195
  def check_based_on_longest_key(hash_node, left_brace, left_parenthesis)
190
- key_lengths = hash_node.keys.map { |key| key.source_range.length }
191
- check_first(hash_node.pairs.first, left_brace, left_parenthesis,
192
- key_lengths.max - key_lengths.first)
196
+ first_key = hash_node.keys.first
197
+ key_lengths = hash_node.keys.select(&:single_line?).map { |key| key.source_range.length }
198
+ offset = first_key.single_line? ? key_lengths.max - first_key.source_range.length : 0
199
+
200
+ check_first(hash_node.pairs.first, left_brace, left_parenthesis, offset)
193
201
  end
194
202
 
195
203
  # Returns the description of what the correct indentation is based on.
@@ -75,6 +75,12 @@ module RuboCop
75
75
 
76
76
  MSG = 'Add a line break before the first argument of a multi-line method argument list.'
77
77
 
78
+ # A line break inserted after `(` while `Style/MethodCallWithArgsParentheses` removes
79
+ # the parentheses in the same pass leaves the method name alone on its line.
80
+ def self.autocorrect_incompatible_with
81
+ [Style::MethodCallWithArgsParentheses]
82
+ end
83
+
78
84
  def on_send(node)
79
85
  return if allowed_method?(node.method_name)
80
86
 
@@ -59,6 +59,10 @@ module RuboCop
59
59
 
60
60
  MSG = 'Add a line break before the first parameter of a multi-line method parameter list.'
61
61
 
62
+ def self.autocorrect_incompatible_with
63
+ [Style::MethodDefParentheses]
64
+ end
65
+
62
66
  def on_def(node)
63
67
  check_method_line_break(node, node.arguments, ignore_last: ignore_last_element?)
64
68
  end
@@ -215,7 +215,7 @@ module RuboCop
215
215
  check_pairs(node)
216
216
  end
217
217
 
218
- attr_accessor :offenses_by, :column_deltas
218
+ attr_accessor :offenses_by, :column_deltas, :unalignable_styles
219
219
 
220
220
  private
221
221
 
@@ -240,6 +240,7 @@ module RuboCop
240
240
  def reset!
241
241
  self.offenses_by = {}
242
242
  self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
243
+ self.unalignable_styles = []
243
244
  end
244
245
 
245
246
  def check_pairs(node)
@@ -265,7 +266,9 @@ module RuboCop
265
266
  kwsplat_offenses = offenses_by.delete(KeywordSplatAlignment)
266
267
  register_offenses_with_format(kwsplat_offenses, KeywordSplatAlignment)
267
268
 
268
- format, offenses = offenses_by.min_by { |_, v| v.length }
269
+ candidates = offenses_by.reject { |style, _| unalignable_styles.include?(style) }
270
+ candidates = offenses_by if candidates.empty?
271
+ format, offenses = candidates.min_by { |_, v| v.length }
269
272
  register_offenses_with_format(offenses, format)
270
273
  end
271
274
 
@@ -283,10 +286,19 @@ module RuboCop
283
286
  offenses_by[alignment.class] ||= []
284
287
  return if good_alignment? delta
285
288
 
289
+ if key_out_of_line?(delta, node)
290
+ unalignable_styles << alignment.class
291
+ return
292
+ end
293
+
286
294
  column_deltas[alignment.class][node] = delta
287
295
  offenses_by[alignment.class].push(node)
288
296
  end
289
297
 
298
+ def key_out_of_line?(delta, node)
299
+ (delta[:key] || 0) < -node.source_range.column
300
+ end
301
+
290
302
  def ignore_hash_argument?(node)
291
303
  case cop_config['EnforcedLastArgumentHashStyle']
292
304
  when 'always_inspect' then false
@@ -325,18 +337,10 @@ module RuboCop
325
337
  node.loc.operator)
326
338
  else
327
339
  delta_value = delta[:key] || 0
328
- correct_no_value(corrector, delta_value, node.source_range)
340
+ adjust(corrector, delta_value, node.source_range)
329
341
  end
330
342
  end
331
343
 
332
- def correct_no_value(corrector, key_delta, key)
333
- adjust(corrector, clamped_key_delta(key_delta, key), key)
334
- end
335
-
336
- def clamped_key_delta(key_delta, key)
337
- [key_delta, -key.column].max
338
- end
339
-
340
344
  def correct_key_value(corrector, delta, key, value, separator)
341
345
  # We can't use the instance variable inside the lambda. That would
342
346
  # just give each lambda the same reference and they would all get the
@@ -345,7 +349,7 @@ module RuboCop
345
349
  value_delta = delta[:value] || 0
346
350
  key_delta = delta[:key] || 0
347
351
 
348
- adjust(corrector, clamped_key_delta(key_delta, key), key)
352
+ adjust(corrector, key_delta, key)
349
353
  adjust(corrector, separator_delta, separator)
350
354
  adjust(corrector, value_delta, value)
351
355
  end
@@ -57,8 +57,10 @@ module RuboCop
57
57
  MSG = 'Put the closing parenthesis for a method call with a ' \
58
58
  'HEREDOC parameter on the same line as the HEREDOC opening.'
59
59
 
60
+ # `Layout/MultilineMethodCallBraceLayout` can move the same closing parenthesis after
61
+ # the last argument in the same pass, and both insertions are kept.
60
62
  def self.autocorrect_incompatible_with
61
- [Style::TrailingCommaInArguments]
63
+ [Layout::MultilineMethodCallBraceLayout, Style::TrailingCommaInArguments]
62
64
  end
63
65
 
64
66
  def on_send(node)
@@ -117,6 +119,8 @@ module RuboCop
117
119
  previous = heredoc
118
120
  current = previous.parent
119
121
  until send_missing_closing_parens?(current, previous, heredoc)
122
+ return if current&.any_block_type? && !current.send_node.equal?(previous)
123
+
120
124
  previous = current
121
125
  current = current.parent
122
126
  return unless previous && current
@@ -229,8 +233,8 @@ module RuboCop
229
233
  end
230
234
 
231
235
  def find_most_bottom_of_heredoc_end(arguments)
232
- arguments.filter_map do |argument|
233
- argument.loc.heredoc_end.end_pos if argument.loc?(:heredoc_end)
236
+ arguments.flat_map { |argument| argument.each_node(:any_str).to_a }.filter_map do |node|
237
+ node.loc.heredoc_end.end_pos if node.loc?(:heredoc_end)
234
238
  end.max
235
239
  end
236
240
 
@@ -55,6 +55,10 @@ module RuboCop
55
55
  (send _ {:squish :squish!})
56
56
  PATTERN
57
57
 
58
+ def on_new_investigation
59
+ @offending_heredoc_bodies = nil
60
+ end
61
+
58
62
  def on_heredoc(node)
59
63
  body = heredoc_body(node)
60
64
  return if body.strip.empty?
@@ -77,6 +81,9 @@ module RuboCop
77
81
  private
78
82
 
79
83
  def register_offense(node, heredoc_indent_type)
84
+ return if within_offending_heredoc?(node)
85
+
86
+ offending_heredoc_bodies << node.loc.heredoc_body
80
87
  message = message(heredoc_indent_type)
81
88
 
82
89
  add_offense(node.loc.heredoc_body, message: message) do |corrector|
@@ -90,6 +97,14 @@ module RuboCop
90
97
  end
91
98
  end
92
99
 
100
+ def within_offending_heredoc?(node)
101
+ offending_heredoc_bodies.any? { |body| body.contains?(node.source_range) }
102
+ end
103
+
104
+ def offending_heredoc_bodies
105
+ @offending_heredoc_bodies ||= []
106
+ end
107
+
93
108
  def message(heredoc_indent_type)
94
109
  current_indent_type = "<<#{heredoc_indent_type}"
95
110
 
@@ -178,10 +178,24 @@ module RuboCop
178
178
  end
179
179
 
180
180
  def check_normal_style(node)
181
- check_alignment(
182
- node.children.reject { |child| bare_access_modifier?(child) },
183
- base_column_for_normal_style(node)
184
- )
181
+ items = node.children.reject { |child| bare_access_modifier?(child) }
182
+
183
+ check_alignment(items, base_column_for_normal_style(node) || governed_base_column(items))
184
+ end
185
+
186
+ def governed_base_column(items)
187
+ return unless config.cop_enabled?('Layout/IndentationWidth')
188
+ return if items.empty? || indentation_width_enabled_at?(items.first)
189
+
190
+ governed_item = items.find { |item| indentation_width_enabled_at?(item) }
191
+
192
+ display_column(governed_item.source_range) if governed_item
193
+ end
194
+
195
+ def indentation_width_enabled_at?(node)
196
+ comment_config = processed_source.comment_config
197
+
198
+ comment_config.cop_enabled_at_line?('Layout/IndentationWidth', node.first_line)
185
199
  end
186
200
 
187
201
  def check_indented_internal_methods_style(node)
@@ -197,7 +211,10 @@ module RuboCop
197
211
  children_to_check.last << child
198
212
  end
199
213
  end
200
- children_to_check.each { |group| check_alignment(group) }
214
+
215
+ children_to_check.each do |group|
216
+ check_alignment(group, governed_base_column(group))
217
+ end
201
218
  end
202
219
  end
203
220
  end
@@ -6,6 +6,9 @@ module RuboCop
6
6
  # Checks that the indentation method is consistent.
7
7
  # Either tabs only or spaces only are used for indentation.
8
8
  #
9
+ # With `EnforcedStyle: tabs`, spaces that follow the indenting tabs are
10
+ # taken to be alignment rather than indentation, and are left alone.
11
+ #
9
12
  # @example EnforcedStyle: spaces (default)
10
13
  # # bad
11
14
  # # This example uses a tab to indent bar.
@@ -67,7 +70,7 @@ module RuboCop
67
70
  match = if style == :spaces
68
71
  line.match(/\A\s*\t+/)
69
72
  else
70
- line.match(/\A\s* +/)
73
+ line.match(/\A +/)
71
74
  end
72
75
  return unless match
73
76
 
@@ -82,7 +82,7 @@ module RuboCop
82
82
 
83
83
  # @!method access_modifier?(node)
84
84
  def_node_matcher :access_modifier?, <<~PATTERN
85
- [(send ...) access_modifier?]
85
+ [(send ...) bare_access_modifier?]
86
86
  PATTERN
87
87
 
88
88
  def on_rescue(node)
@@ -250,7 +250,7 @@ module RuboCop
250
250
 
251
251
  def check_members_for_normal_style(base, members)
252
252
  members.first.children.each do |member|
253
- next if member.send_type? && member.access_modifier?
253
+ next if member.send_type? && member.bare_access_modifier?
254
254
 
255
255
  check_indentation(base, member)
256
256
  end
@@ -111,6 +111,12 @@ module RuboCop
111
111
  comments.map(&:source_range)
112
112
  end
113
113
 
114
+ def output_record_separator_ranges(ast)
115
+ return [] if ast.nil?
116
+
117
+ ast.each_node(:gvar).select { |gvar| gvar.source == '$\\' }.map(&:source_range)
118
+ end
119
+
114
120
  def last_line(processed_source)
115
121
  last_token = processed_source.tokens.last
116
122
 
@@ -123,7 +129,8 @@ module RuboCop
123
129
 
124
130
  def ignored_ranges
125
131
  @ignored_ranges ||= ignored_literal_ranges(processed_source.ast) +
126
- comment_ranges(processed_source.comments)
132
+ comment_ranges(processed_source.comments) +
133
+ output_record_separator_ranges(processed_source.ast)
127
134
  end
128
135
 
129
136
  def ignored_parent?(node)
@@ -87,10 +87,10 @@ module RuboCop
87
87
  return if children.empty?
88
88
 
89
89
  if style == :aligned && !always_indented?(node)
90
- check_aligned(children, 1)
90
+ check_aligned(children, 1, children[0].loc.column)
91
91
  else
92
92
  check_indented(children)
93
- check_aligned(children, 2)
93
+ check_aligned(children, 2, indented_column(children))
94
94
  end
95
95
  end
96
96
 
@@ -110,21 +110,37 @@ module RuboCop
110
110
  PARENT_TYPES_FOR_INDENTED.include?(dstr_node.parent&.type)
111
111
  end
112
112
 
113
- def check_aligned(children, start_index)
113
+ def check_aligned(children, start_index, target_column)
114
114
  base_column = children[start_index - 1].loc.column
115
- children[start_index..].each do |child|
116
- @column_delta = base_column - child.loc.column
117
- add_offense_and_correction(child, MSG_ALIGN) if @column_delta != 0
118
- base_column = child.loc.column
115
+ same_column_runs(children[start_index..]).each do |run|
116
+ column = run.first.loc.column
117
+ if column != base_column && column != target_column
118
+ register_misaligned_run(run, target_column - column)
119
+ end
120
+ base_column = column
121
+ end
122
+ end
123
+
124
+ def same_column_runs(parts)
125
+ parts.chunk_while { |a, b| a.loc.column == b.loc.column }
126
+ end
127
+
128
+ def register_misaligned_run(run, column_delta)
129
+ @column_delta = column_delta
130
+ add_offense(run.first, message: MSG_ALIGN) do |corrector|
131
+ run.each { |child| autocorrect(corrector, child) }
119
132
  end
120
133
  end
121
134
 
122
135
  def check_indented(children)
123
- @column_delta = base_column(children[0]) + configured_indentation_width -
124
- children[1].loc.column
136
+ @column_delta = indented_column(children) - children[1].loc.column
125
137
  add_offense_and_correction(children[1], MSG_INDENT) if @column_delta != 0
126
138
  end
127
139
 
140
+ def indented_column(children)
141
+ base_column(children[0]) + configured_indentation_width
142
+ end
143
+
128
144
  def base_column(child)
129
145
  grandparent = child.parent.parent
130
146
  if grandparent&.pair_type?