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
@@ -46,13 +46,6 @@ module RuboCop
46
46
 
47
47
  private
48
48
 
49
- def arguments_range(node)
50
- range_between(
51
- node.first_argument.source_range.begin_pos,
52
- node.last_argument.source_range.end_pos
53
- )
54
- end
55
-
56
49
  def group_satisfied?(group_types, symbol_args)
57
50
  group_types.all? { |type| symbol_args.any? { |arg| arg.value == type } }
58
51
  end
@@ -31,15 +31,9 @@ module RuboCop
31
31
  dup_arguments = arguments.dup
32
32
  dup_arguments.delete(config_node)
33
33
 
34
- corrector.replace(offense_range(arguments), dup_arguments.map(&:source).join(', '))
34
+ corrector.replace(arguments_range(node), dup_arguments.map(&:source).join(', '))
35
35
  end
36
36
  end
37
-
38
- private
39
-
40
- def offense_range(arguments)
41
- range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
42
- end
43
37
  end
44
38
  end
45
39
  end
@@ -109,7 +109,7 @@ module RuboCop
109
109
  end
110
110
 
111
111
  def on_if(node)
112
- traverse_condition(node.condition) do |cond|
112
+ node.condition.each_node(:send) do |cond|
113
113
  add_offense(cond, message: MSG_FOR_CONDITIONAL_USE) if style_detected_api_used?(cond)
114
114
  end
115
115
  end
@@ -134,12 +134,6 @@ module RuboCop
134
134
  no_acceptable_style_check(node) ||
135
135
  style_detected_check(node)
136
136
  end
137
-
138
- def traverse_condition(condition, &block)
139
- yield condition if condition.send_type?
140
-
141
- condition.each_child_node { |child| traverse_condition(child, &block) }
142
- end
143
137
  end
144
138
  end
145
139
  end
@@ -53,7 +53,7 @@ module RuboCop
53
53
 
54
54
  def on_send(node)
55
55
  return if !multiple_arguments?(node) || (node.call_type? && node.method?(:[]=)) ||
56
- autocorrect_incompatible_with_other_cops?
56
+ binary_operator_call?(node) || autocorrect_incompatible_with_other_cops?
57
57
 
58
58
  items = flattened_arguments(node)
59
59
 
@@ -64,6 +64,10 @@ module RuboCop
64
64
 
65
65
  private
66
66
 
67
+ def binary_operator_call?(node)
68
+ node.binary_operation? && !node.method?(:[]) && !node.loc.dot
69
+ end
70
+
67
71
  def autocorrect_incompatible_with_other_cops?
68
72
  with_first_argument_style? && enforce_hash_argument_with_separator?
69
73
  end
@@ -68,6 +68,7 @@ module RuboCop
68
68
  # end
69
69
  #
70
70
  class BlockAlignment < Base
71
+ include Alignment
71
72
  include ConfigurableEnforcedStyle
72
73
  include RangeHelp
73
74
  extend AutoCorrector
@@ -154,6 +155,32 @@ module RuboCop
154
155
  else
155
156
  start_for_line_node(node)
156
157
  end
158
+
159
+ if using_tabs? && (indentation = anchor_indentation(ancestor_node, node))
160
+ replace_end_indentation(corrector, node, indentation)
161
+ else
162
+ shift_end_to_start_col(corrector, ancestor_node, node)
163
+ end
164
+ end
165
+
166
+ def anchor_indentation(ancestor_node, node)
167
+ if style == :start_of_block
168
+ do_line_anchor_loc(node, node.loc.begin).source_line[/\A\s*/]
169
+ else
170
+ anchor_loc = (ancestor_node || node).source_range
171
+ anchor_loc.source_line[/\A\s*/] if begins_its_line?(anchor_loc)
172
+ end
173
+ end
174
+
175
+ def replace_end_indentation(corrector, node, indentation)
176
+ loc_end = node.loc.end
177
+ whitespace = range_between(loc_end.begin_pos - loc_end.column, loc_end.begin_pos)
178
+ return if whitespace.source == indentation
179
+
180
+ corrector.replace(whitespace, indentation)
181
+ end
182
+
183
+ def shift_end_to_start_col(corrector, ancestor_node, node)
157
184
  start_col = compute_start_col(ancestor_node, node)
158
185
  loc_end = node.loc.end
159
186
  delta = start_col - loc_end.column
@@ -164,8 +164,12 @@ module RuboCop
164
164
  cop_config['IndentOneStep']
165
165
  end
166
166
 
167
+ # Under tabs one step is a single tab character, which counts as one column
168
+ # regardless of the configured indentation width.
167
169
  def indentation_width
168
- indent_one_step? ? configured_indentation_width : 0
170
+ return 0 unless indent_one_step?
171
+
172
+ using_tabs? ? 1 : configured_indentation_width
169
173
  end
170
174
 
171
175
  def incorrect_style(when_node, branch_type)
@@ -176,8 +180,10 @@ module RuboCop
176
180
  detect_incorrect_style(when_node)
177
181
 
178
182
  whitespace = whitespace_range(when_node)
183
+ next unless whitespace.source.strip.empty?
179
184
 
180
- corrector.replace(whitespace, replacement(when_node)) if whitespace.source.strip.empty?
185
+ indentation = replacement(when_node)
186
+ corrector.replace(whitespace, indentation) if indentation
181
187
  end
182
188
  end
183
189
 
@@ -193,10 +199,7 @@ module RuboCop
193
199
  end
194
200
 
195
201
  def base_column(case_node, base)
196
- case base
197
- when :case then case_node.location.keyword.column
198
- when :end then case_node.location.end.column
199
- end
202
+ base_location(case_node, base)&.column
200
203
  end
201
204
 
202
205
  def whitespace_range(node)
@@ -207,13 +210,26 @@ module RuboCop
207
210
  end
208
211
 
209
212
  def replacement(node)
213
+ base_loc = configured_base_location(node)
214
+
215
+ return ' ' * (base_loc.column + indentation_width) unless using_tabs?
216
+ return unless begins_its_line?(base_loc)
217
+
218
+ base_loc.source_line[/\A\s*/] + ("\t" * indentation_width)
219
+ end
220
+
221
+ def configured_base_location(node)
210
222
  case_node = node.each_ancestor(:case, :case_match).first
211
223
  base_type = cop_config[style_parameter_name] == 'end' ? :end : :case
212
224
 
213
- column = base_column(case_node, base_type)
214
- column += indentation_width
225
+ base_location(case_node, base_type)
226
+ end
215
227
 
216
- ' ' * column
228
+ def base_location(case_node, base)
229
+ case base
230
+ when :case then case_node.location.keyword
231
+ when :end then case_node.location.end
232
+ end
217
233
  end
218
234
  end
219
235
  end
@@ -188,6 +188,14 @@ module RuboCop
188
188
 
189
189
  MSG = '`%<category>s` is supposed to appear before `%<previous>s`.'
190
190
 
191
+ # A moved element is inserted before the line break that precedes its anchor.
192
+ # When the anchor follows a blank line, `Layout/EmptyLines`,
193
+ # `Layout/EmptyLinesAroundAccessModifier` or `Layout/EmptyLinesAroundClassBody`
194
+ # may remove that line break in the same pass.
195
+ def self.autocorrect_incompatible_with
196
+ [Layout::EmptyLines, Layout::EmptyLinesAroundAccessModifier, Layout::EmptyLinesAroundClassBody]
197
+ end
198
+
191
199
  # Validates code style on class declaration.
192
200
  # Add offense when find a node out of expected order.
193
201
  # A node is out of order when its category is expected earlier than
@@ -333,9 +341,26 @@ module RuboCop
333
341
 
334
342
  return "#{node_visibility(node)}_methods"
335
343
  end
344
+ return class_method_category(node) if node.defs_type?
345
+
336
346
  HUMANIZED_NODE_TYPE[node.type] || node.type
337
347
  end
338
348
 
349
+ # Only `private_class_method` reaches a singleton method; a bare `private` does not.
350
+ # Such a call follows the definition it names, so only right siblings are searched.
351
+ def class_method_category(node)
352
+ modifier = node.right_siblings.reverse.find do |sibling|
353
+ class_method_visibility_modifier?(sibling, method_name: node.method_name)
354
+ end
355
+
356
+ modifier ? :"#{modifier.method_name}s" : HUMANIZED_NODE_TYPE[node.type]
357
+ end
358
+
359
+ # @!method class_method_visibility_modifier?(node, method_name:)
360
+ def_node_matcher :class_method_visibility_modifier?, <<~PATTERN
361
+ (send nil? {:private_class_method :public_class_method} <(sym %method_name) ...>)
362
+ PATTERN
363
+
339
364
  def dynamic_constant?(node)
340
365
  return false unless node.casgn_type? && node.namespace.nil?
341
366
 
@@ -421,12 +446,9 @@ module RuboCop
421
446
  end
422
447
 
423
448
  def end_position_for(node)
424
- if node.casgn_type?
425
- heredoc = find_heredoc(node)
426
- return heredoc.location.heredoc_end.end_pos + 1 if heredoc
427
- end
449
+ heredoc_end_lines = heredocs(node).map { |heredoc| heredoc.loc.heredoc_end.line }
450
+ end_line = [node.last_line, *heredoc_end_lines].max
428
451
 
429
- end_line = buffer.line_for_position(node.source_range.end_pos)
430
452
  buffer.line_range(end_line).end_pos
431
453
  end
432
454
 
@@ -449,8 +471,8 @@ module RuboCop
449
471
  buffer.line_range(node.loc.line).begin_pos - 1
450
472
  end
451
473
 
452
- def find_heredoc(node)
453
- node.each_node(:any_str).find(&:heredoc?)
474
+ def heredocs(node)
475
+ node.each_node(:any_str).select(&:heredoc?)
454
476
  end
455
477
 
456
478
  def buffer
@@ -49,6 +49,10 @@ module RuboCop
49
49
  return unless node.def_modifier?
50
50
 
51
51
  method_def = node.each_descendant(:any_def).first
52
+ # A single-line `def` has nothing to align, even when a line
53
+ # continuation puts it on a later line than the modifier.
54
+ return if method_def.single_line?
55
+
52
56
  expr = node.source_range
53
57
 
54
58
  line_start = range_between(expr.begin_pos, method_def.loc.keyword.end_pos)
@@ -27,10 +27,6 @@ module RuboCop
27
27
  include RangeHelp
28
28
  extend AutoCorrector
29
29
 
30
- def self.autocorrect_incompatible_with
31
- [Style::RedundantSelf]
32
- end
33
-
34
30
  def on_send(node)
35
31
  return unless node.dot? || node.safe_navigation?
36
32
 
@@ -46,21 +42,35 @@ module RuboCop
46
42
 
47
43
  private
48
44
 
45
+ # The dot and the gap it moves across are replaced in one action, so that another
46
+ # correction that rewrites a range spanning the dot clashes with this one instead of
47
+ # leaving the moved dot behind.
49
48
  def autocorrect(corrector, dot, node)
50
- dot_range = if processed_source[dot.line - 1].strip == '.'
51
- range_by_whole_lines(dot, include_final_newline: true)
52
- else
53
- dot
54
- end
55
- corrector.remove(dot_range)
56
- case style
57
- when :leading
58
- corrector.insert_before(selector_range(node), dot.source)
59
- when :trailing
60
- corrector.insert_after(node.receiver, dot.source)
49
+ dot_range = removed_dot_range(dot)
50
+
51
+ if style == :leading
52
+ move_dot_before_selector(corrector, dot, dot_range, selector_range(node))
53
+ else
54
+ move_dot_after_receiver(corrector, dot, dot_range, node.receiver)
61
55
  end
62
56
  end
63
57
 
58
+ def removed_dot_range(dot)
59
+ return dot unless processed_source[dot.line - 1].strip == '.'
60
+
61
+ range_by_whole_lines(dot, include_final_newline: true)
62
+ end
63
+
64
+ def move_dot_before_selector(corrector, dot, dot_range, selector)
65
+ gap = range_between(dot_range.end_pos, selector.begin_pos)
66
+ corrector.replace(dot_range.join(gap), "#{gap.source}#{dot.source}")
67
+ end
68
+
69
+ def move_dot_after_receiver(corrector, dot, dot_range, receiver)
70
+ gap = range_between(receiver.source_range.end_pos, dot_range.begin_pos)
71
+ corrector.replace(gap.join(dot_range), "#{dot.source}#{gap.source}")
72
+ end
73
+
64
74
  def message(dot)
65
75
  "Place the #{dot.source} on the " +
66
76
  case style
@@ -61,21 +61,23 @@ module RuboCop
61
61
  return if node.ternary?
62
62
 
63
63
  if node.modifier_form?
64
- check_condition(node.condition) if node.right_sibling
64
+ check_condition(node.condition, node.right_sibling) if followed_by_statement?(node)
65
65
  else
66
- check_condition(node.condition)
66
+ check_condition(node.condition, node.if_branch)
67
67
  end
68
68
  end
69
69
 
70
70
  def on_while(node)
71
- check_condition(node.condition)
71
+ return if node.modifier_form? && !followed_by_statement?(node)
72
+
73
+ check_condition(node.condition, node.modifier_form? ? node.right_sibling : node.body)
72
74
  end
73
75
  alias on_until on_while
74
76
 
75
77
  def on_while_post(node)
76
- return unless node.right_sibling
78
+ return unless followed_by_statement?(node)
77
79
 
78
- check_condition(node.condition)
80
+ check_condition(node.condition, node.right_sibling)
79
81
  end
80
82
  alias on_until_post on_while_post
81
83
 
@@ -84,7 +86,8 @@ module RuboCop
84
86
  last_condition = when_node.conditions.last
85
87
 
86
88
  next if !multiline_when_condition?(when_node) ||
87
- next_line_empty?(last_condition.last_line)
89
+ next_line_empty?(last_condition.last_line) ||
90
+ body_on_line?(when_node.body, last_condition.last_line)
88
91
 
89
92
  add_offense(when_node, &autocorrect(last_condition))
90
93
  end
@@ -94,7 +97,8 @@ module RuboCop
94
97
  node.resbody_branches.each do |resbody|
95
98
  rescued_exceptions = resbody.exceptions
96
99
  next if !multiline_rescue_exceptions?(rescued_exceptions) ||
97
- next_line_empty?(rescued_exceptions.last.last_line)
100
+ next_line_empty?(rescued_exceptions.last.last_line) ||
101
+ body_on_line?(resbody.body, rescued_exceptions.last.last_line)
98
102
 
99
103
  add_offense(resbody, &autocorrect(rescued_exceptions.last))
100
104
  end
@@ -102,9 +106,14 @@ module RuboCop
102
106
 
103
107
  private
104
108
 
105
- def check_condition(condition)
109
+ def followed_by_statement?(node)
110
+ node.parent&.type?(:begin, :kwbegin) && node.right_sibling
111
+ end
112
+
113
+ def check_condition(condition, following_node)
106
114
  return unless condition.multiline?
107
115
  return if next_line_empty?(condition.last_line)
116
+ return if body_on_line?(following_node, condition.last_line)
108
117
 
109
118
  add_offense(condition, &autocorrect(condition))
110
119
  end
@@ -113,6 +122,10 @@ module RuboCop
113
122
  processed_source[line].blank?
114
123
  end
115
124
 
125
+ def body_on_line?(body, line)
126
+ body&.first_line == line
127
+ end
128
+
116
129
  def multiline_when_condition?(when_node)
117
130
  when_node.conditions.first.first_line != when_node.conditions.last.last_line
118
131
  end
@@ -27,8 +27,7 @@ module RuboCop
27
27
 
28
28
  def on_new_investigation
29
29
  return if processed_source.tokens.empty?
30
- # Quick check if we possibly have consecutive blank lines.
31
- return unless processed_source.raw_source.include?("\n\n\n")
30
+ return unless consecutive_blank_lines_possible?
32
31
 
33
32
  lines = Set.new
34
33
  processed_source.tokens.each { |token| lines << token.line }
@@ -42,6 +41,10 @@ module RuboCop
42
41
 
43
42
  private
44
43
 
44
+ def consecutive_blank_lines_possible?
45
+ processed_source.buffer.source.include?("\n\n\n")
46
+ end
47
+
45
48
  def each_extra_empty_line(lines)
46
49
  prev_line = 1
47
50
 
@@ -91,7 +91,7 @@ module RuboCop
91
91
  end
92
92
 
93
93
  def next_line_node(node)
94
- return if node.parent.type?(:if, :rescue, :ensure)
94
+ return if node.parent.type?(:if, :rescue, :ensure, :and, :or)
95
95
 
96
96
  node.right_sibling
97
97
  end
@@ -111,6 +111,7 @@ module RuboCop
111
111
 
112
112
  def require_empty_line?(node)
113
113
  return false unless node.respond_to?(:type)
114
+ return false if node.left_sibling.last_line == node.first_line
114
115
 
115
116
  !allow_alias?(node) && !attribute_or_allowed_method?(node)
116
117
  end
@@ -38,13 +38,19 @@ module RuboCop
38
38
  KIND = 'block'
39
39
 
40
40
  def on_block(node)
41
- first_line = node.send_node.last_line
42
-
43
- check(node, node.body, adjusted_first_line: first_line)
41
+ check(node, node.body, adjusted_first_line: body_start_line(node))
44
42
  end
45
43
 
46
44
  alias on_numblock on_block
47
45
  alias on_itblock on_block
46
+
47
+ private
48
+
49
+ def body_start_line(node)
50
+ return node.loc.begin.line unless node.arguments?
51
+
52
+ [node.loc.begin.line, node.arguments.last_line].max
53
+ end
48
54
  end
49
55
  end
50
56
  end
@@ -85,8 +85,12 @@ module RuboCop
85
85
  next if line == line_of_def_or_kwbegin || last_body_and_end_on_same_line?(body)
86
86
 
87
87
  keyword = loc.source
88
+
88
89
  # below the keyword
89
- check_line(style, line, message('after', keyword), &:empty?)
90
+ unless left_to_block_body_cop?(body, line)
91
+ check_line(style, line, message('after', keyword), &:empty?)
92
+ end
93
+
90
94
  # above the keyword
91
95
  check_line(style, line - 2, message('before', keyword), &:empty?)
92
96
  end
@@ -122,6 +126,15 @@ module RuboCop
122
126
  end
123
127
  end
124
128
 
129
+ def left_to_block_body_cop?(body, keyword_line)
130
+ return false unless body.parent.any_block_type?
131
+
132
+ cop_config = config.for_enabled_cop('Layout/EmptyLinesAroundBlockBody')
133
+ return false if cop_config['EnforcedStyle'] != 'empty_lines'
134
+
135
+ only_empty_lines_until_end?(body, keyword_line)
136
+ end
137
+
125
138
  def keyword_locations_in_rescue(node)
126
139
  [node.loc.else, *node.resbody_branches.map { |body| body.loc.keyword }].compact
127
140
  end
@@ -133,6 +146,15 @@ module RuboCop
133
146
  *keyword_locations(rescue_body_without_ensure)
134
147
  ]
135
148
  end
149
+
150
+ def only_empty_lines_until_end?(body, keyword_line)
151
+ end_line = body.parent.loc.end.line
152
+ next_line = (keyword_line + 1).upto(end_line).find do |line_number|
153
+ !processed_source.lines[line_number - 1].strip.empty?
154
+ end
155
+
156
+ next_line == end_line
157
+ end
136
158
  end
137
159
  end
138
160
  end
@@ -80,10 +80,6 @@ module RuboCop
80
80
  include RangeHelp
81
81
  extend AutoCorrector
82
82
 
83
- def on_class(node)
84
- check_other_alignment(node)
85
- end
86
-
87
83
  def on_sclass(node)
88
84
  if node.parent&.assignment?
89
85
  check_asgn_alignment(node.parent, node)
@@ -91,10 +87,8 @@ module RuboCop
91
87
  check_other_alignment(node)
92
88
  end
93
89
  end
94
-
95
- def on_module(node)
96
- check_other_alignment(node)
97
- end
90
+ alias on_class on_sclass
91
+ alias on_module on_sclass
98
92
 
99
93
  def on_if(node)
100
94
  check_other_alignment(node) unless node.ternary?
@@ -123,16 +117,8 @@ module RuboCop
123
117
  AlignmentCorrector.align_end(corrector, processed_source, node, alignment_node(node))
124
118
  end
125
119
 
126
- # rubocop:disable-next Metrics/CyclomaticComplexity
127
120
  def check_assignment(node, rhs)
128
- # If there are method calls chained to the right hand side of the
129
- # assignment, we let rhs be the receiver of those method calls before
130
- # we check if it's an if/unless/while/until.
131
- return unless (rhs = first_part_of_call_chain(rhs))
132
-
133
- # If `rhs` is a `begin` node or a logical operator,
134
- # unwrap to find the leading conditional.
135
- rhs = rhs.child_nodes.first while rhs&.type?(:begin, :or, :and)
121
+ rhs = leading_node(rhs)
136
122
 
137
123
  return unless rhs&.conditional?
138
124
  return if rhs.if_type? && rhs.ternary?
@@ -151,6 +137,16 @@ module RuboCop
151
137
  ignore_node(inner_node)
152
138
  end
153
139
 
140
+ def leading_node(rhs)
141
+ # If there are method calls chained to the right hand side of the assignment,
142
+ # we let rhs be the receiver of those method calls.
143
+ rhs = first_part_of_call_chain(rhs)
144
+
145
+ # If `rhs` is a `begin` node or a logical operator, unwrap to find the leading node.
146
+ rhs = rhs.child_nodes.first while rhs&.type?(:begin, :or, :and)
147
+ rhs
148
+ end
149
+
154
150
  def asgn_variable_align_with(outer_node, inner_node)
155
151
  expr = outer_node.source_range
156
152
 
@@ -175,13 +171,7 @@ module RuboCop
175
171
  when :keyword
176
172
  node
177
173
  when :variable
178
- align_to = alignment_node_for_variable_style(node)
179
-
180
- while (parent = align_to.parent) && parent.send_type? && same_line?(align_to, parent)
181
- align_to = parent
182
- end
183
-
184
- align_to
174
+ alignment_node_for_variable_style(node)
185
175
  else
186
176
  start_line_range(node)
187
177
  end
@@ -207,7 +197,13 @@ module RuboCop
207
197
 
208
198
  def assignment_or_operator_method(node)
209
199
  node.ancestors.find do |ancestor|
210
- ancestor.assignment_or_similar? || (ancestor.send_type? && ancestor.operator_method?)
200
+ if ancestor.assignment_or_similar?
201
+ leading_node(extract_rhs(ancestor)).equal?(node)
202
+ elsif ancestor.send_type? && ancestor.operator_method?
203
+ !leading_node(ancestor).equal?(node)
204
+ elsif ancestor.send_type?
205
+ leading_node(ancestor.last_argument).equal?(node)
206
+ end
211
207
  end
212
208
  end
213
209
  end
@@ -30,12 +30,17 @@ module RuboCop
30
30
  # some_object.method(arg) # this is some comment
31
31
  class ExtraSpacing < Base
32
32
  extend AutoCorrector
33
+ include LineLengthHelp
33
34
  include PrecedingFollowingAlignment
34
35
  include RangeHelp
35
36
 
36
37
  MSG_UNNECESSARY = 'Unnecessary spacing detected.'
37
38
  MSG_UNALIGNED_ASGN = '`=` is not aligned with the %<location>s assignment.'
38
39
 
40
+ def self.autocorrect_incompatible_with
41
+ [Layout::RedundantLineBreak, Style::SelfAssignment]
42
+ end
43
+
39
44
  def on_new_investigation
40
45
  return if processed_source.blank?
41
46
 
@@ -73,9 +78,14 @@ module RuboCop
73
78
  def check_assignment(token)
74
79
  return unless aligned_with_preceding_equals_operator(token) == :no
75
80
 
81
+ tokens, align_to = equal_sign_alignment(token.line)
82
+ return if exceeds_max_line_length?(tokens, align_to)
83
+
76
84
  message = format(MSG_UNALIGNED_ASGN, location: 'preceding')
77
85
  add_offense(token.pos, message: message) do |corrector|
78
- align_equal_signs(token.pos, corrector)
86
+ tokens.each do |asgn_token|
87
+ align_equal_sign(corrector, asgn_token, align_to)
88
+ end
79
89
  end
80
90
  end
81
91
 
@@ -236,14 +246,19 @@ module RuboCop
236
246
  cop_config['ForceEqualSignAlignment']
237
247
  end
238
248
 
239
- def align_equal_signs(range, corrector)
240
- lines = all_relevant_assignment_lines(range.line)
249
+ def equal_sign_alignment(line_number)
250
+ lines = all_relevant_assignment_lines(line_number)
241
251
  tokens = assignment_tokens.select { |t| lines.include?(t.line) }
242
252
 
243
- columns = tokens.map { |t| align_column(t) }
244
- align_to = columns.max
253
+ [tokens, tokens.map { |t| align_column(t) }.max]
254
+ end
255
+
256
+ def exceeds_max_line_length?(tokens, align_to)
257
+ max_line_length && tokens.any? do |token|
258
+ padding = align_to - token.pos.last_column
245
259
 
246
- tokens.each { |token| align_equal_sign(corrector, token, align_to) }
260
+ padding.positive? && line_length(token.pos.source_line) + padding > max_line_length
261
+ end
247
262
  end
248
263
 
249
264
  def align_equal_sign(corrector, token, align_to)