rubocop 1.89.0 → 1.91.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 (248) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +309 -14
  3. data/config/obsoletion.yml +9 -0
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop/cached_data.rb +7 -2
  6. data/lib/rubocop/changed_files.rb +112 -0
  7. data/lib/rubocop/cli/command/execute_runner.rb +52 -1
  8. data/lib/rubocop/cli.rb +11 -7
  9. data/lib/rubocop/comment_config/directive_range.rb +34 -0
  10. data/lib/rubocop/comment_config/disable_next.rb +143 -0
  11. data/lib/rubocop/comment_config/push_pop.rb +55 -0
  12. data/lib/rubocop/comment_config.rb +50 -64
  13. data/lib/rubocop/config.rb +33 -5
  14. data/lib/rubocop/config_loader.rb +13 -6
  15. data/lib/rubocop/config_loader_resolver.rb +50 -9
  16. data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
  17. data/lib/rubocop/config_obsoletion/removed_cop.rb +8 -0
  18. data/lib/rubocop/config_obsoletion.rb +1 -1
  19. data/lib/rubocop/config_validator.rb +19 -5
  20. data/lib/rubocop/cop/autocorrect_logic.rb +8 -0
  21. data/lib/rubocop/cop/badge.rb +1 -1
  22. data/lib/rubocop/cop/base.rb +49 -5
  23. data/lib/rubocop/cop/corrector.rb +3 -3
  24. data/lib/rubocop/cop/correctors.rb +2 -2
  25. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  26. data/lib/rubocop/cop/generator.rb +1 -1
  27. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -2
  28. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
  29. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
  30. data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
  31. data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
  32. data/lib/rubocop/cop/layout/class_structure.rb +102 -26
  33. data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
  34. data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
  35. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -2
  36. data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
  37. data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
  38. data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
  39. data/lib/rubocop/cop/layout/extra_spacing.rb +105 -3
  40. data/lib/rubocop/cop/layout/first_argument_indentation.rb +21 -1
  41. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
  42. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
  43. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -5
  44. data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
  45. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -2
  46. data/lib/rubocop/cop/layout/line_length.rb +20 -3
  47. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -2
  48. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -5
  49. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -2
  50. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +14 -3
  51. data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
  52. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +2 -4
  53. data/lib/rubocop/cop/lint/ambiguous_range.rb +1 -2
  54. data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
  55. data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
  56. data/lib/rubocop/cop/lint/constant_reassignment.rb +17 -11
  57. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +165 -15
  58. data/lib/rubocop/cop/lint/deprecated_reference.rb +11 -2
  59. data/lib/rubocop/cop/lint/duplicate_methods.rb +113 -15
  60. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  61. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
  62. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
  63. data/lib/rubocop/cop/lint/interpolation_check.rb +1 -2
  64. data/lib/rubocop/cop/lint/literal_as_condition.rb +11 -8
  65. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +3 -6
  66. data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +185 -0
  67. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +25 -12
  68. data/lib/rubocop/cop/lint/name_typo.rb +53 -6
  69. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  70. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
  71. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -0
  72. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
  73. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +122 -29
  74. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +47 -7
  75. data/lib/rubocop/cop/lint/redundant_require_statement.rb +1 -2
  76. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -2
  77. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +1 -2
  78. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +1 -2
  79. data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -2
  80. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -2
  81. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +2 -4
  82. data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
  83. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +1 -2
  84. data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -2
  85. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -2
  86. data/lib/rubocop/cop/lint/unused_private_method.rb +94 -17
  87. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -2
  88. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -2
  89. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +36 -0
  90. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  91. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -2
  92. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +61 -7
  93. data/lib/rubocop/cop/lint/void.rb +1 -2
  94. data/lib/rubocop/cop/lint.rb +3 -0
  95. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -2
  96. data/lib/rubocop/cop/migration/department_name.rb +1 -2
  97. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  98. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
  99. data/lib/rubocop/cop/mixin/comments_help.rb +1 -2
  100. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
  101. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +11 -1
  102. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +7 -4
  103. data/lib/rubocop/cop/mixin/hash_subset.rb +1 -2
  104. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  105. data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
  106. data/lib/rubocop/cop/mixin/line_length_help.rb +7 -1
  107. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +62 -6
  108. data/lib/rubocop/cop/mixin/range_help.rb +1 -2
  109. data/lib/rubocop/cop/mixin/statement_modifier.rb +13 -7
  110. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -4
  111. data/lib/rubocop/cop/mixin.rb +6 -2
  112. data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +16 -0
  113. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
  114. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  115. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -4
  116. data/lib/rubocop/cop/naming/method_name.rb +5 -2
  117. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -2
  118. data/lib/rubocop/cop/offense.rb +27 -4
  119. data/lib/rubocop/cop/registry.rb +43 -11
  120. data/lib/rubocop/cop/severity.rb +12 -0
  121. data/lib/rubocop/cop/style/access_modifier_declarations.rb +3 -2
  122. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -2
  123. data/lib/rubocop/cop/style/arguments_forwarding.rb +5 -8
  124. data/lib/rubocop/cop/style/array_first_last.rb +1 -2
  125. data/lib/rubocop/cop/style/bitwise_predicate.rb +1 -2
  126. data/lib/rubocop/cop/style/block_delimiters.rb +3 -6
  127. data/lib/rubocop/cop/style/case_like_if.rb +5 -7
  128. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -2
  129. data/lib/rubocop/cop/style/combinable_loops.rb +1 -2
  130. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -2
  131. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -2
  132. data/lib/rubocop/cop/style/constant_visibility.rb +6 -3
  133. data/lib/rubocop/cop/style/copyright.rb +1 -2
  134. data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
  135. data/lib/rubocop/cop/style/directive_scope.rb +304 -0
  136. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +83 -13
  137. data/lib/rubocop/cop/style/documentation_method.rb +1 -9
  138. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  139. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  140. data/lib/rubocop/cop/style/empty_case_condition.rb +1 -2
  141. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  142. data/lib/rubocop/cop/style/empty_method.rb +12 -2
  143. data/lib/rubocop/cop/style/endless_method.rb +31 -12
  144. data/lib/rubocop/cop/style/file_null.rb +2 -2
  145. data/lib/rubocop/cop/style/float_division.rb +10 -16
  146. data/lib/rubocop/cop/style/for.rb +5 -0
  147. data/lib/rubocop/cop/style/format_string_token.rb +1 -2
  148. data/lib/rubocop/cop/style/guard_clause.rb +5 -2
  149. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
  150. data/lib/rubocop/cop/style/hash_lookup_method.rb +3 -0
  151. data/lib/rubocop/cop/style/hash_syntax.rb +1 -2
  152. data/lib/rubocop/cop/style/identical_conditional_branches.rb +2 -4
  153. data/lib/rubocop/cop/style/if_inside_else.rb +1 -2
  154. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -2
  155. data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +1 -2
  156. data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
  157. data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
  158. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
  159. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  160. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +1 -2
  161. data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -2
  162. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -2
  163. data/lib/rubocop/cop/style/negative_array_index.rb +2 -4
  164. data/lib/rubocop/cop/style/nested_modifier.rb +9 -4
  165. data/lib/rubocop/cop/style/nil_comparison.rb +36 -9
  166. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  167. data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
  168. data/lib/rubocop/cop/style/not.rb +3 -1
  169. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
  170. data/lib/rubocop/cop/style/one_line_conditional.rb +1 -1
  171. data/lib/rubocop/cop/style/operator_method_call.rb +1 -2
  172. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -2
  173. data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
  174. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -2
  175. data/lib/rubocop/cop/style/redundant_condition.rb +6 -8
  176. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +11 -3
  177. data/lib/rubocop/cop/style/redundant_each.rb +1 -2
  178. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  179. data/lib/rubocop/cop/style/redundant_format.rb +2 -4
  180. data/lib/rubocop/cop/style/redundant_parentheses.rb +13 -5
  181. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -2
  182. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
  183. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +6 -6
  184. data/lib/rubocop/cop/style/redundant_return.rb +1 -2
  185. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -2
  186. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
  187. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -2
  188. data/lib/rubocop/cop/style/safe_navigation.rb +1 -2
  189. data/lib/rubocop/cop/style/sample.rb +11 -6
  190. data/lib/rubocop/cop/style/select_by_regexp.rb +1 -2
  191. data/lib/rubocop/cop/style/semicolon.rb +2 -4
  192. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  193. data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -2
  194. data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -2
  195. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  196. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +2 -0
  197. data/lib/rubocop/cop/style/string_concatenation.rb +18 -5
  198. data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
  199. data/lib/rubocop/cop/style/super_arguments.rb +1 -2
  200. data/lib/rubocop/cop/style/symbol_proc.rb +1 -2
  201. data/lib/rubocop/cop/style/time_now.rb +41 -0
  202. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  203. data/lib/rubocop/cop/style/yoda_condition.rb +1 -2
  204. data/lib/rubocop/cop/style.rb +2 -1
  205. data/lib/rubocop/cop/team.rb +11 -3
  206. data/lib/rubocop/cop/util.rb +3 -5
  207. data/lib/rubocop/cop/variable_force/variable.rb +1 -2
  208. data/lib/rubocop/cops_documentation_generator.rb +26 -8
  209. data/lib/rubocop/directive_comment.rb +73 -10
  210. data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
  211. data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
  212. data/lib/rubocop/formatter/formatter_set.rb +2 -1
  213. data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
  214. data/lib/rubocop/formatter/html_formatter.rb +2 -4
  215. data/lib/rubocop/formatter/json_formatter.rb +11 -6
  216. data/lib/rubocop/formatter/junit_formatter.rb +26 -9
  217. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -2
  218. data/lib/rubocop/formatter/sarif_formatter.rb +181 -0
  219. data/lib/rubocop/formatter/simple_text_formatter.rb +4 -3
  220. data/lib/rubocop/formatter/tap_formatter.rb +3 -1
  221. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -2
  222. data/lib/rubocop/formatter.rb +1 -0
  223. data/lib/rubocop/lockfile.rb +18 -0
  224. data/lib/rubocop/lsp/diagnostic.rb +4 -8
  225. data/lib/rubocop/lsp/routes.rb +48 -19
  226. data/lib/rubocop/magic_comment.rb +27 -0
  227. data/lib/rubocop/mcp/server.rb +1 -2
  228. data/lib/rubocop/options.rb +69 -7
  229. data/lib/rubocop/path_util.rb +2 -3
  230. data/lib/rubocop/plugin/configuration_integrator.rb +6 -3
  231. data/lib/rubocop/plugin/loader.rb +1 -1
  232. data/lib/rubocop/rake_task.rb +1 -2
  233. data/lib/rubocop/remote_config.rb +4 -4
  234. data/lib/rubocop/result_cache.rb +16 -5
  235. data/lib/rubocop/rspec/expect_offense.rb +2 -4
  236. data/lib/rubocop/rspec/shared_contexts.rb +4 -2
  237. data/lib/rubocop/runner.rb +90 -44
  238. data/lib/rubocop/server/cache.rb +1 -2
  239. data/lib/rubocop/server/cli.rb +2 -4
  240. data/lib/rubocop/server.rb +14 -0
  241. data/lib/rubocop/target_finder.rb +4 -1
  242. data/lib/rubocop/todo_audit.rb +111 -0
  243. data/lib/rubocop/unified_diff.rb +257 -0
  244. data/lib/rubocop/version.rb +3 -5
  245. data/lib/rubocop.rb +7 -1
  246. data/lib/ruby_lsp/rubocop/addon.rb +1 -2
  247. metadata +18 -6
  248. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
@@ -167,7 +167,7 @@ module RuboCop
167
167
  [Layout::SpaceBeforeBlockBraces]
168
168
  end
169
169
 
170
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
170
+ # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
171
171
  def on_block(node)
172
172
  symbol_proc?(node) do |dispatch_node, arguments_node, method_name|
173
173
  if active_support_extensions_enabled?
@@ -184,7 +184,6 @@ module RuboCop
184
184
  register_offense(node, method_name, dispatch_node.method_name)
185
185
  end
186
186
  end
187
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
188
187
  alias on_numblock on_block
189
188
  alias on_itblock on_block
190
189
 
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for `Time.new` without arguments, which is an implicit way
7
+ # to retrieve the current system time. Prefer the more explicit `Time.now`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # Time.new
12
+ #
13
+ # # good
14
+ # Time.now
15
+ #
16
+ # # good - `Time.new` with arguments constructs a specific time
17
+ # Time.new(2026, 8, 19)
18
+ #
19
+ class TimeNow < Base
20
+ extend AutoCorrector
21
+
22
+ MSG = 'Prefer `Time.now` over `Time.new` to retrieve the current time.'
23
+ RESTRICT_ON_SEND = %i[new].freeze
24
+
25
+ # @!method time_new?(node)
26
+ def_node_matcher :time_new?, <<~PATTERN
27
+ (call (const {nil? cbase} :Time) :new)
28
+ PATTERN
29
+
30
+ def on_send(node)
31
+ return unless time_new?(node)
32
+
33
+ add_offense(node) do |corrector|
34
+ corrector.replace(node.loc.selector.join(node.source_range.end), 'now')
35
+ end
36
+ end
37
+ alias on_csend on_send
38
+ end
39
+ end
40
+ end
41
+ end
@@ -64,7 +64,7 @@ module RuboCop
64
64
 
65
65
  MSG = 'Useless trailing comma present in block arguments.'
66
66
 
67
- def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler
67
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- a trailing comma needs an explicit parameter list
68
68
  # lambda literal (`->`) never has block arguments.
69
69
  return if node.send_node.lambda_literal?
70
70
  return unless useless_trailing_comma?(node)
@@ -122,7 +122,7 @@ module RuboCop
122
122
  node.comparison_method? && !noncommutative_operator?(node)
123
123
  end
124
124
 
125
- # rubocop:disable Metrics/CyclomaticComplexity
125
+ # rubocop:disable-next Metrics/CyclomaticComplexity
126
126
  def valid_yoda?(node)
127
127
  return true unless (rhs = node.first_argument)
128
128
 
@@ -133,7 +133,6 @@ module RuboCop
133
133
 
134
134
  enforce_yoda? ? constant_portion?(lhs) : constant_portion?(rhs)
135
135
  end
136
- # rubocop:enable Metrics/CyclomaticComplexity
137
136
 
138
137
  def message(node)
139
138
  format(MSG, source: node.source)
@@ -58,11 +58,11 @@ module RuboCop
58
58
  register_cop :DigChain, "#{__dir__}/style/dig_chain"
59
59
  register_cop :Dir, "#{__dir__}/style/dir"
60
60
  register_cop :DirEmpty, "#{__dir__}/style/dir_empty"
61
+ register_cop :DirectiveScope, "#{__dir__}/style/directive_scope"
61
62
  register_cop :DisableCopsWithinSourceCodeDirective, "#{__dir__}/style/disable_cops_within_source_code_directive"
62
63
  register_cop :DocumentationMethod, "#{__dir__}/style/documentation_method"
63
64
  register_cop :Documentation, "#{__dir__}/style/documentation"
64
65
  register_cop :DocumentDynamicEvalDefinition, "#{__dir__}/style/document_dynamic_eval_definition"
65
- register_cop :DoubleCopDisableDirective, "#{__dir__}/style/double_cop_disable_directive"
66
66
  register_cop :DoubleNegation, "#{__dir__}/style/double_negation"
67
67
  register_cop :EachForSimpleLoop, "#{__dir__}/style/each_for_simple_loop"
68
68
  register_cop :EachWithObject, "#{__dir__}/style/each_with_object"
@@ -282,6 +282,7 @@ module RuboCop
282
282
  register_cop :SymbolProc, "#{__dir__}/style/symbol_proc"
283
283
  register_cop :TallyMethod, "#{__dir__}/style/tally_method"
284
284
  register_cop :TernaryParentheses, "#{__dir__}/style/ternary_parentheses"
285
+ register_cop :TimeNow, "#{__dir__}/style/time_now"
285
286
  register_cop :TopLevelMethodDefinition, "#{__dir__}/style/top_level_method_definition"
286
287
  register_cop :TrailingBodyOnClass, "#{__dir__}/style/trailing_body_on_class"
287
288
  register_cop :TrailingBodyOnMethodDefinition, "#{__dir__}/style/trailing_body_on_method_definition"
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # For performance reasons, Team will first dispatch cops & forces in two groups,
10
10
  # first the ones needed for autocorrection (if any), then the rest
11
11
  # (unless autocorrections happened).
12
- # rubocop:disable Metrics/ClassLength
12
+ # rubocop:disable-next Metrics/ClassLength
13
13
  class Team
14
14
  InvestigationResult = Struct.new(:report, :corrector)
15
15
  private_constant :InvestigationResult
@@ -211,7 +211,7 @@ module RuboCop
211
211
  # run the other cops when no corrections are left
212
212
  on_duty = roundup_relevant_cops(processed_source)
213
213
 
214
- autocorrect_cops, other_cops = on_duty.partition(&:autocorrect?)
214
+ autocorrect_cops, other_cops = partition_by_correcting(on_duty)
215
215
  report = investigate_partial(autocorrect_cops, processed_source,
216
216
  offset: offset, original: original)
217
217
 
@@ -251,6 +251,15 @@ module RuboCop
251
251
  end
252
252
 
253
253
  # @return [Array<cop>]
254
+ # A cop whose unsafe correction is skipped still inserts todo comments
255
+ # under `--disable-uncorrectable`, so it must run with the correcting
256
+ # cops - correctors of the later `other_cops` round are never applied.
257
+ def partition_by_correcting(cops)
258
+ cops.partition do |cop|
259
+ cop.autocorrect? || cop.skipped_unsafe_correction_with_disable_uncorrectable?
260
+ end
261
+ end
262
+
254
263
  def roundup_relevant_cops(processed_source)
255
264
  (cops + opted_in_standby_cops(processed_source)).select do |cop|
256
265
  next false if cop.excluded_file?(processed_source.file_path)
@@ -395,6 +404,5 @@ module RuboCop
395
404
  end
396
405
  end
397
406
  end
398
- # rubocop:enable Metrics/ClassLength
399
407
  end
400
408
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  # This module contains a collection of useful utility methods.
6
- # rubocop:disable Metrics/ModuleLength
6
+ # rubocop:disable-next Metrics/ModuleLength
7
7
  module Util
8
8
  include PathUtil
9
9
 
@@ -35,7 +35,7 @@ module RuboCop
35
35
  node.loc_is?(:end, ')')
36
36
  end
37
37
 
38
- # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
38
+ # rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength
39
39
  def add_parentheses(node, corrector)
40
40
  if node.args_type?
41
41
  arguments_range = node.source_range
@@ -55,7 +55,6 @@ module RuboCop
55
55
  corrector.insert_after(args_end(node), ')')
56
56
  end
57
57
  end
58
- # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
59
58
 
60
59
  def any_descendant?(node, *types)
61
60
  if block_given?
@@ -64,7 +63,7 @@ module RuboCop
64
63
  end
65
64
  else
66
65
  # Use a block version to avoid allocating enumerators.
67
- node.each_descendant do # rubocop:disable Lint/UnreachableLoop
66
+ node.each_descendant do # rubocop:disable Lint/UnreachableLoop -- the block form avoids allocating an enumerator
68
67
  return true
69
68
  end
70
69
  end
@@ -210,6 +209,5 @@ module RuboCop
210
209
  source == target || (source.is_a?(Array) && source.include?(target))
211
210
  end
212
211
  end
213
- # rubocop:enable Metrics/ModuleLength
214
212
  end
215
213
  end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  !@references.empty?
48
48
  end
49
49
 
50
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
50
+ # rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
51
51
  def reference!(node)
52
52
  reference = Reference.new(node, @scope)
53
53
  @references << reference
@@ -72,7 +72,6 @@ module RuboCop
72
72
  end
73
73
  end
74
74
  end
75
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
76
75
 
77
76
  def in_modifier_conditional?(assignment, reference_node)
78
77
  conditional = modifier_conditional_of(assignment.node)
@@ -20,6 +20,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
20
20
  safety: ->(data) { safety_object(data.safety_objects, data.cop) },
21
21
  examples: ->(data) { examples(data.example_objects, data.cop) },
22
22
  configuration: ->(data) { configurations(data.cop.department, data.cop, data.config) },
23
+ preview: ->(data) { preview_defaults(data.cop) },
23
24
  references: ->(data) { references(data.cop, data.see_objects) }
24
25
  }.freeze
25
26
 
@@ -137,7 +138,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
137
138
  "NOTE: Requires Ruby version #{requirement}\n\n"
138
139
  end
139
140
 
140
- # rubocop:disable Metrics/MethodLength
141
+ # rubocop:disable-next Metrics/MethodLength
141
142
  def properties(cop)
142
143
  header = [
143
144
  'Enabled by default', 'Safe', 'Supports autocorrection', 'Version Added',
@@ -160,7 +161,6 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
160
161
  ]]
161
162
  "#{to_table(header, content)}\n"
162
163
  end
163
- # rubocop:enable Metrics/MethodLength
164
164
 
165
165
  def cop_header(cop)
166
166
  content = +"\n"
@@ -195,7 +195,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
195
195
  def configurations(department, cop, cop_config)
196
196
  header = ['Name', 'Default value', 'Configurable values']
197
197
  configs = cop_config.each_key.reject do |key|
198
- key == 'AllowMultipleStyles' ||
198
+ key == 'AllowMultipleStyles' || key == 'Preview' ||
199
199
  (key != 'SupportedTypes' && key.start_with?('Supported'))
200
200
  end
201
201
  return '' if configs.empty?
@@ -210,6 +210,22 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
210
210
  cop_subsection('Configurable attributes', cop) + to_table(header, content)
211
211
  end
212
212
 
213
+ def preview_defaults(cop)
214
+ cop_config = config.for_cop(cop)
215
+ preview = cop_config['Preview']
216
+ return '' unless preview.is_a?(Hash)
217
+
218
+ header = ['Name', 'Current default', 'Preview default']
219
+ content = preview.map do |name, value|
220
+ [name, format_table_value(cop_config[name]), format_table_value(value)]
221
+ end
222
+
223
+ cop_subsection('Preview defaults', cop) +
224
+ 'These defaults apply under xref:versioning.adoc#preview[Preview] and are ' \
225
+ "expected to become the regular defaults in the next major release.\n\n" +
226
+ to_table(header, content)
227
+ end
228
+
213
229
  def configuration_name(department, name)
214
230
  return name unless name == 'AllowMultilineFinalElement'
215
231
 
@@ -217,7 +233,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
217
233
  "xref:#{filename}#allowmultilinefinalelement[AllowMultilineFinalElement]"
218
234
  end
219
235
 
220
- # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
236
+ # rubocop:disable-next Metrics/CyclomaticComplexity,Metrics/MethodLength
221
237
  def configurable_values(cop_config, name)
222
238
  case name
223
239
  when /^Enforced/
@@ -244,7 +260,6 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
244
260
  end
245
261
  end
246
262
  end
247
- # rubocop:enable Metrics/CyclomaticComplexity,Metrics/MethodLength
248
263
 
249
264
  def to_table(header, content)
250
265
  table = ['|===', "| #{header.join(' | ')}\n\n"].join("\n")
@@ -303,7 +318,7 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
303
318
  "\ninclude::../partials/#{filename}[]\n"
304
319
  end
305
320
 
306
- # rubocop:disable Metrics/MethodLength
321
+ # rubocop:disable-next Metrics/MethodLength
307
322
  def print_cops_of_department(department)
308
323
  selected_cops = cops_of_department(department)
309
324
  content = +<<~HEADER
@@ -323,7 +338,6 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
323
338
  file.write("#{content.strip}\n")
324
339
  end
325
340
  end
326
- # rubocop:enable Metrics/MethodLength
327
341
 
328
342
  def print_cop_with_doc(cop) # rubocop:todo Metrics/AbcSize, Metrics/MethodLength
329
343
  cop_config = config.for_cop(cop)
@@ -392,7 +406,11 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
392
406
  def cop_status(status)
393
407
  return 'Disabled' unless status
394
408
 
395
- status == 'pending' ? 'Pending' : 'Enabled'
409
+ case status
410
+ when 'pending' then 'Pending'
411
+ when 'preview' then 'Preview'
412
+ else 'Enabled'
413
+ end
396
414
  end
397
415
 
398
416
  # HTML anchor are somewhat limited in what characters they can contain, just
@@ -26,19 +26,26 @@ module RuboCop
26
26
  # @api private
27
27
  PUSH_POP_ARGS_PATTERN = "([+\\-]#{COP_NAME_PATTERN_NC}(?:\\s+[+\\-]#{COP_NAME_PATTERN_NC})*)"
28
28
  # @api private
29
- AVAILABLE_MODES = %w[disable enable todo push pop].freeze
29
+ AVAILABLE_MODES = %w[disable enable todo push pop disable-next todo-next enable-next
30
+ next].freeze
31
+ # @api private
32
+ # Longest first, so a `-next` mode is not matched as its prefix
33
+ # (`-` is a word boundary).
34
+ MODES_PATTERN = AVAILABLE_MODES.sort_by { |mode| -mode.length }.join('|').freeze
30
35
  # @api private
31
36
  DIRECTIVE_MARKER_PATTERN = '# rubocop : '
32
37
  # @api private
33
38
  DIRECTIVE_MARKER_REGEXP = Regexp.new(DIRECTIVE_MARKER_PATTERN.gsub(' ', '\s*'))
34
39
  # @api private
35
- DIRECTIVE_HEADER_PATTERN = "#{DIRECTIVE_MARKER_PATTERN}((?:#{AVAILABLE_MODES.join('|')}))\\b"
40
+ DIRECTIVE_HEADER_PATTERN = "#{DIRECTIVE_MARKER_PATTERN}((?:#{MODES_PATTERN}))\\b"
36
41
  # @api private
37
42
  DIRECTIVE_COMMENT_REGEXP = Regexp.new(
38
43
  "#{DIRECTIVE_HEADER_PATTERN}(?:\\s+#{COPS_PATTERN}|\\s+#{PUSH_POP_ARGS_PATTERN})?"
39
44
  .gsub(' ', '\s*')
40
45
  )
41
46
  # @api private
47
+ SIGNED_OPERATIONS = %w[+ -].freeze
48
+ # @api private
42
49
  TRAILING_COMMENT_MARKER = '--'
43
50
  # @api private
44
51
  MALFORMED_DIRECTIVE_WITHOUT_COP_NAME_REGEXP = Regexp.new(
@@ -67,7 +74,7 @@ module RuboCop
67
74
  # Checks if the comment is malformed as a `# rubocop:` directive
68
75
  def malformed?
69
76
  return true if !start_with_marker? || @match_data.nil?
70
- return true if missing_cop_name?
77
+ return true if missing_cop_name? || invalid_signed_args?
71
78
 
72
79
  tail = @match_data.post_match.lstrip
73
80
  !(tail.empty? || tail.start_with?(TRAILING_COMMENT_MARKER))
@@ -80,6 +87,28 @@ module RuboCop
80
87
  MALFORMED_DIRECTIVE_WITHOUT_COP_NAME_REGEXP.match?(comment.text)
81
88
  end
82
89
 
90
+ # `push` and `next` arguments must be `+`/`-` prefixed cop names, and
91
+ # `pop` takes no arguments at all.
92
+ def invalid_signed_args?
93
+ return cops ? !cops.empty? : false if pop?
94
+ return false unless push? || next?
95
+ return false unless cops
96
+
97
+ cops.split.any? { |cop_spec| !cop_spec.start_with?('+', '-') }
98
+ end
99
+
100
+ # The text of the directive's optional `--` trailing comment, or `nil`
101
+ # when there is none.
102
+ def reason
103
+ return unless @match_data
104
+
105
+ tail = @match_data.post_match.lstrip
106
+ return unless tail.start_with?(TRAILING_COMMENT_MARKER)
107
+
108
+ reason = tail.delete_prefix(TRAILING_COMMENT_MARKER).strip
109
+ reason unless reason.empty?
110
+ end
111
+
83
112
  # Checks if this directive relates to single line
84
113
  def single_line?
85
114
  !comment.text.start_with?(DIRECTIVE_COMMENT_REGEXP)
@@ -98,6 +127,19 @@ module RuboCop
98
127
  )
99
128
  end
100
129
 
130
+ # `#range` stops at the cop list, so a `--` reason sits outside it. The reason documents the
131
+ # directive and means nothing once the directive is gone, so removal has to cover both. Any
132
+ # other trailing text is an ordinary comment and is left alone.
133
+ def range_with_reason
134
+ directive_range = range
135
+ trailing = Parser::Source::Range.new(
136
+ comment.source_range.source_buffer, directive_range.end_pos, comment.source_range.end_pos
137
+ )
138
+ return directive_range unless trailing.source.lstrip.start_with?(TRAILING_COMMENT_MARKER)
139
+
140
+ directive_range.with(end_pos: comment.source_range.end_pos)
141
+ end
142
+
101
143
  # Returns match captures to directive comment pattern
102
144
  def match_captures
103
145
  @match_captures ||= @match_data && begin
@@ -111,12 +153,22 @@ module RuboCop
111
153
 
112
154
  # Checks if this directive disables cops
113
155
  def disabled?
114
- %w[disable todo].include?(mode)
156
+ %w[disable todo].include?(mode) || disable_next?
157
+ end
158
+
159
+ # Checks if this directive disables cops for the next statement only
160
+ def disable_next?
161
+ %w[disable-next todo-next].include?(mode)
115
162
  end
116
163
 
117
164
  # Checks if this directive enables cops
118
165
  def enabled?
119
- mode == 'enable'
166
+ mode == 'enable' || enable_next?
167
+ end
168
+
169
+ # Checks if this directive enables cops for the next statement only
170
+ def enable_next?
171
+ mode == 'enable-next'
120
172
  end
121
173
 
122
174
  # Checks if this directive is a push
@@ -129,10 +181,17 @@ module RuboCop
129
181
  mode == 'pop'
130
182
  end
131
183
 
132
- # Returns the push arguments as a hash of cop names with their operations
133
- def push_args
134
- @push_args ||= parse_push_args
184
+ # Checks if this directive toggles cops for the next statement only
185
+ def next?
186
+ mode == 'next'
187
+ end
188
+
189
+ # Returns the `+`/`-` arguments of a `push` or `next` directive as a hash
190
+ # of operations to cop names
191
+ def signed_args
192
+ @signed_args ||= parse_signed_args
135
193
  end
194
+ alias push_args signed_args
136
195
 
137
196
  # Checks if this directive enables all cops
138
197
  def enabled_all?
@@ -176,6 +235,8 @@ module RuboCop
176
235
  end
177
236
 
178
237
  def directive_count
238
+ return signed_args.values.sum(&:count) if push? || next?
239
+
179
240
  raw_cop_names.count
180
241
  end
181
242
 
@@ -210,13 +271,15 @@ module RuboCop
210
271
  cops - [LINT_REDUNDANT_DIRECTIVE_COP, LINT_SYNTAX_COP]
211
272
  end
212
273
 
213
- def parse_push_args
214
- return {} unless push? && cops
274
+ def parse_signed_args
275
+ return {} unless (push? || next?) && cops
215
276
 
216
277
  args = {}
217
278
  cops.split.each do |cop_spec|
218
279
  op = cop_spec[0]
219
280
  cop_name = cop_spec[1..]
281
+ next unless SIGNED_OPERATIONS.include?(op)
282
+
220
283
  args[op] ||= []
221
284
  args[op] << cop_name
222
285
  end
@@ -23,6 +23,7 @@ module RuboCop
23
23
  Enabled
24
24
  Exclude
25
25
  Include
26
+ Preview
26
27
  Reference
27
28
  References
28
29
  Safe
@@ -93,6 +94,7 @@ module RuboCop
93
94
  command += ' --auto-gen-only-exclude' if @options[:auto_gen_only_exclude]
94
95
  command += ' --disable-pending-cops' if @options[:disable_pending_cops]
95
96
  command += ' --enable-pending-cops' if @options[:enable_pending_cops]
97
+ command += preview_option
96
98
  command += exclude_limit_option
97
99
  command += ' --no-offense-counts' unless show_offense_counts?
98
100
 
@@ -103,6 +105,14 @@ module RuboCop
103
105
  command
104
106
  end
105
107
 
108
+ def preview_option
109
+ case @options[:preview]
110
+ when true then ' --preview'
111
+ when false then ' --no-preview'
112
+ else ''
113
+ end
114
+ end
115
+
106
116
  def exclude_limit_option
107
117
  if no_exclude_limit?
108
118
  ' --no-exclude-limit'
@@ -259,7 +269,7 @@ module RuboCop
259
269
  config = ConfigStore.new.for(parent)
260
270
  cfg = config[cop_name] || {}
261
271
 
262
- if merge_mode_for_exclude?(config) || merge_mode_for_exclude?(cfg)
272
+ if exclude_merges?(config, cfg)
263
273
  offending_files
264
274
  else
265
275
  cop_exclude = cfg['Exclude']
@@ -272,6 +282,14 @@ module RuboCop
272
282
  end
273
283
  end
274
284
 
285
+ # `Preview` merges `Exclude` with the default configuration, so the excludes
286
+ # already in the configuration do not have to be copied into the todo file.
287
+ def exclude_merges?(config, cop_config)
288
+ merge_mode_for_exclude?(config) ||
289
+ merge_mode_for_exclude?(cop_config) ||
290
+ config.preview?(@options)
291
+ end
292
+
275
293
  def merge_mode_for_exclude?(cfg)
276
294
  Array(cfg.to_h.dig('inherit_mode', 'merge')).include?('Exclude')
277
295
  end
@@ -23,7 +23,9 @@ module RuboCop
23
23
 
24
24
  def message(offense)
25
25
  message =
26
- if offense.corrected_with_todo?
26
+ if offense.disabled?
27
+ "[Suppressed] #{offense.message}"
28
+ elsif offense.corrected_with_todo?
27
29
  "[Todo] #{offense.message}"
28
30
  elsif offense.corrected?
29
31
  "[Corrected] #{offense.message}"
@@ -23,6 +23,7 @@ module RuboCop
23
23
  '[pa]cman' => 'PacmanFormatter',
24
24
  '[p]rogress' => 'ProgressFormatter',
25
25
  '[q]uiet' => 'QuietFormatter',
26
+ '[sa]rif' => 'SARIFFormatter',
26
27
  '[s]imple' => 'SimpleTextFormatter',
27
28
  '[t]ap' => 'TapFormatter',
28
29
  '[w]orst' => 'WorstOffendersFormatter'
@@ -57,7 +58,7 @@ module RuboCop
57
58
  if output_path
58
59
  dir_path = File.dirname(output_path)
59
60
  FileUtils.mkdir_p(dir_path)
60
- output = File.open(output_path, 'w') # rubocop:disable Style/FileOpen
61
+ output = File.open(output_path, 'w') # rubocop:disable Style/FileOpen -- the file is closed by `close_output_files`, not by a block
61
62
  else
62
63
  output = $stdout
63
64
  end
@@ -15,6 +15,10 @@ module RuboCop
15
15
  @offenses_for_files[file] = offenses unless offenses.empty?
16
16
  end
17
17
 
18
+ def file_started(_file, options)
19
+ @config_store = options[:config_store]
20
+ end
21
+
18
22
  def finished(_inspected_files)
19
23
  @offenses_for_files.each do |file, offenses|
20
24
  offenses.each do |offense|
@@ -31,11 +35,8 @@ module RuboCop
31
35
  end
32
36
 
33
37
  def minimum_severity_to_fail
34
- @minimum_severity_to_fail ||= begin
35
- # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
36
- name = options.fetch(:fail_level, :refactor)
37
- RuboCop::Cop::Severity.new(name)
38
- end
38
+ @minimum_severity_to_fail ||=
39
+ RuboCop::Cop::Severity.minimum_to_fail(options, @config_store&.for_pwd)
39
40
  end
40
41
 
41
42
  def github_severity(offense)
@@ -74,11 +74,10 @@ module RuboCop
74
74
  end
75
75
 
76
76
  # Make Kernel#binding public.
77
- # rubocop:disable Lint/UselessMethodDefinition
77
+ # rubocop:disable-next Lint/UselessMethodDefinition -- redefined only to make `Kernel#binding` public
78
78
  def binding
79
79
  super
80
80
  end
81
- # rubocop:enable Lint/UselessMethodDefinition
82
81
 
83
82
  def decorated_message(offense)
84
83
  offense.message.gsub(/`(.+?)`/) { "<code>#{escape(Regexp.last_match(1))}</code>" }
@@ -144,11 +143,10 @@ module RuboCop
144
143
  }.freeze
145
144
 
146
145
  # Make Kernel#binding public.
147
- # rubocop:disable Lint/UselessMethodDefinition
146
+ # rubocop:disable-next Lint/UselessMethodDefinition -- redefined only to make `Kernel#binding` public
148
147
  def binding
149
148
  super
150
149
  end
151
- # rubocop:enable Lint/UselessMethodDefinition
152
150
  end
153
151
  end
154
152
  end
@@ -47,7 +47,7 @@ module RuboCop
47
47
  end
48
48
 
49
49
  def hash_for_offense(offense)
50
- {
50
+ hash = {
51
51
  severity: offense.severity.name,
52
52
  message: offense.message,
53
53
  cop_name: offense.cop_name,
@@ -55,18 +55,23 @@ module RuboCop
55
55
  correctable: offense.correctable?,
56
56
  location: hash_for_location(offense)
57
57
  }
58
+
59
+ # Suppressed offenses appear only under `--display-suppressed`, so
60
+ # these keys are additive for existing consumers.
61
+ if offense.disabled?
62
+ hash[:suppressed] = true
63
+ hash[:justification] = offense.justification
64
+ end
65
+
66
+ hash
58
67
  end
59
68
 
60
- # TODO: Consider better solution for Offense#real_column.
61
- # The minimum value of `start_column: real_column` is 1.
62
- # So, the minimum value of `last_column` should be 1.
63
- # And non-zero value of `last_column` should be used as is.
64
69
  def hash_for_location(offense)
65
70
  {
66
71
  start_line: offense.line,
67
72
  start_column: offense.real_column,
68
73
  last_line: offense.last_line,
69
- last_column: offense.last_column.zero? ? 1 : offense.last_column,
74
+ last_column: offense.real_last_column,
70
75
  length: offense.location.length,
71
76
  # `line` and `column` exist for compatibility.
72
77
  # Use `start_line` and `start_column` instead.