rubocop 1.25.0 → 1.26.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +25 -15
  4. data/lib/rubocop/cli.rb +1 -1
  5. data/lib/rubocop/cop/badge.rb +7 -1
  6. data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -3
  7. data/lib/rubocop/cop/generator.rb +2 -7
  8. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +46 -0
  9. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  10. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  11. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +5 -1
  12. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -1
  13. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +7 -8
  14. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  15. data/lib/rubocop/cop/lint/inherit_exception.rb +19 -28
  16. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -2
  17. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +5 -0
  18. data/lib/rubocop/cop/lint/symbol_conversion.rb +3 -2
  19. data/lib/rubocop/cop/lint/useless_times.rb +13 -9
  20. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +27 -13
  21. data/lib/rubocop/cop/mixin/line_length_help.rb +17 -6
  22. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
  23. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  24. data/lib/rubocop/cop/security/yaml_load.rb +9 -3
  25. data/lib/rubocop/cop/style/def_with_parentheses.rb +16 -11
  26. data/lib/rubocop/cop/style/for.rb +4 -0
  27. data/lib/rubocop/cop/style/lambda_call.rb +12 -20
  28. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -5
  29. data/lib/rubocop/cop/style/nested_file_dirname.rb +66 -0
  30. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +3 -2
  31. data/lib/rubocop/cop/style/redundant_begin.rb +2 -6
  32. data/lib/rubocop/cop/style/select_by_regexp.rb +6 -1
  33. data/lib/rubocop/cop/style/sole_nested_conditional.rb +50 -12
  34. data/lib/rubocop/cop/style/string_concatenation.rb +7 -1
  35. data/lib/rubocop/cop/style/swap_values.rb +2 -0
  36. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
  37. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
  38. data/lib/rubocop/cop/style/unless_else.rb +4 -0
  39. data/lib/rubocop/cop/variable_force.rb +1 -5
  40. data/lib/rubocop/cops_documentation_generator.rb +2 -2
  41. data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -2
  42. data/lib/rubocop/options.rb +8 -2
  43. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  44. data/lib/rubocop/runner.rb +1 -1
  45. data/lib/rubocop/target_ruby.rb +1 -1
  46. data/lib/rubocop/version.rb +1 -1
  47. data/lib/rubocop.rb +1 -0
  48. metadata +7 -5
@@ -7,17 +7,21 @@ module RuboCop
7
7
  # potential security issues leading to remote code execution when
8
8
  # loading from an untrusted source.
9
9
  #
10
+ # NOTE: Ruby 3.1+ (Psych 4) uses `Psych.load` as `Psych.safe_load` by default.
11
+ #
10
12
  # @safety
11
13
  # The behaviour of the code might change depending on what was
12
14
  # in the YAML payload, since `YAML.safe_load` is more restrictive.
13
15
  #
14
16
  # @example
15
17
  # # bad
16
- # YAML.load("--- foo")
18
+ # YAML.load("--- !ruby/object:Foo {}") # Psych 3 is unsafe by default
17
19
  #
18
20
  # # good
19
- # YAML.safe_load("--- foo")
20
- # YAML.dump("foo")
21
+ # YAML.safe_load("--- !ruby/object:Foo {}", [Foo]) # Ruby 2.5 (Psych 3)
22
+ # YAML.safe_load("--- !ruby/object:Foo {}", permitted_classes: [Foo]) # Ruby 3.0- (Psych 3)
23
+ # YAML.load("--- !ruby/object:Foo {}", permitted_classes: [Foo]) # Ruby 3.1+ (Psych 4)
24
+ # YAML.dump(foo)
21
25
  #
22
26
  class YAMLLoad < Base
23
27
  extend AutoCorrector
@@ -31,6 +35,8 @@ module RuboCop
31
35
  PATTERN
32
36
 
33
37
  def on_send(node)
38
+ return if target_ruby_version >= 3.1
39
+
34
40
  yaml_load(node) do
35
41
  add_offense(node.loc.selector) do |corrector|
36
42
  corrector.replace(node.loc.selector, 'safe_load')
@@ -11,27 +11,33 @@ module RuboCop
11
11
  #
12
12
  # # bad
13
13
  # def foo()
14
- # # does a thing
14
+ # do_something
15
15
  # end
16
16
  #
17
17
  # # good
18
18
  # def foo
19
- # # does a thing
19
+ # do_something
20
20
  # end
21
21
  #
22
- # # also good
23
- # def foo() does_a_thing end
22
+ # # bad
23
+ # def foo() = do_something
24
+ #
25
+ # # good
26
+ # def foo = do_something
27
+ #
28
+ # # good (without parentheses it's a syntax error)
29
+ # def foo() do_something end
24
30
  #
25
31
  # @example
26
32
  #
27
33
  # # bad
28
34
  # def Baz.foo()
29
- # # does a thing
35
+ # do_something
30
36
  # end
31
37
  #
32
38
  # # good
33
39
  # def Baz.foo
34
- # # does a thing
40
+ # do_something
35
41
  # end
36
42
  class DefWithParentheses < Base
37
43
  extend AutoCorrector
@@ -39,12 +45,11 @@ module RuboCop
39
45
  MSG = "Omit the parentheses in defs when the method doesn't accept any arguments."
40
46
 
41
47
  def on_def(node)
42
- return if node.single_line?
43
- return unless !node.arguments? && (node_arguments_loc_begin = node.arguments.loc.begin)
48
+ return if node.single_line? && !node.endless?
49
+ return unless !node.arguments? && (node_arguments = node.arguments.source_range)
44
50
 
45
- add_offense(node_arguments_loc_begin) do |corrector|
46
- corrector.remove(node_arguments_loc_begin)
47
- corrector.remove(node.arguments.loc.end)
51
+ add_offense(node_arguments) do |corrector|
52
+ corrector.remove(node_arguments)
48
53
  end
49
54
  end
50
55
  alias on_defs on_def
@@ -38,6 +38,10 @@ module RuboCop
38
38
  # end
39
39
  # end
40
40
  #
41
+ # @safety
42
+ # This cop's autocorrection is unsafe because the scope of
43
+ # variables is different between `each` and `for`.
44
+ #
41
45
  class For < Base
42
46
  include ConfigurableEnforcedStyle
43
47
  include RangeHelp
@@ -22,45 +22,37 @@ module RuboCop
22
22
  include ConfigurableEnforcedStyle
23
23
  extend AutoCorrector
24
24
 
25
+ MSG = 'Prefer the use of `%<prefer>s` over `%<current>s`.'
25
26
  RESTRICT_ON_SEND = %i[call].freeze
26
27
 
27
28
  def on_send(node)
28
29
  return unless node.receiver
29
30
 
30
31
  if offense?(node)
31
- add_offense(node) do |corrector|
32
+ prefer = prefer(node)
33
+ current = node.source
34
+
35
+ add_offense(node, message: format(MSG, prefer: prefer, current: current)) do |corrector|
32
36
  opposite_style_detected
33
- autocorrect(corrector, node)
37
+ corrector.replace(node, prefer)
34
38
  end
35
39
  else
36
40
  correct_style_detected
37
41
  end
38
42
  end
39
43
 
40
- def autocorrect(corrector, node)
41
- if explicit_style?
42
- receiver = node.receiver.source
43
- replacement = node.source.sub("#{receiver}.", "#{receiver}.call")
44
-
45
- corrector.replace(node, replacement)
46
- else
47
- add_parentheses(node, corrector) unless node.parenthesized?
48
- corrector.remove(node.loc.selector)
49
- end
50
- end
51
-
52
44
  private
53
45
 
54
46
  def offense?(node)
55
47
  (explicit_style? && node.implicit_call?) || (implicit_style? && !node.implicit_call?)
56
48
  end
57
49
 
58
- def message(_node)
59
- if explicit_style?
60
- 'Prefer the use of `lambda.call(...)` over `lambda.(...)`.'
61
- else
62
- 'Prefer the use of `lambda.(...)` over `lambda.call(...)`.'
63
- end
50
+ def prefer(node)
51
+ receiver = node.receiver.source
52
+ arguments = node.arguments.map(&:source).join(', ')
53
+ method = explicit_style? ? "call(#{arguments})" : "(#{arguments})"
54
+
55
+ "#{receiver}.#{method}"
64
56
  end
65
57
 
66
58
  def implicit_style?
@@ -48,15 +48,21 @@ module RuboCop
48
48
  node.each_ancestor(:def, :defs).any?(&:endless?) && node.arguments.any?
49
49
  end
50
50
 
51
- # Require hash value omission be enclosed in parentheses to prevent the following issue:
52
- # https://bugs.ruby-lang.org/issues/18396.
53
51
  def require_parentheses_for_hash_value_omission?(node)
54
52
  return false unless (last_argument = node.last_argument)
53
+ return false if !last_argument.hash_type? || !last_argument.pairs.last&.value_omission?
55
54
 
56
- next_line = node.parent&.assignment? ? node.parent.right_sibling : node.right_sibling
57
- return false unless next_line
55
+ modifier_form?(node) || exist_next_line_expression?(node)
56
+ end
58
57
 
59
- last_argument.hash_type? && last_argument.pairs.last&.value_omission? && next_line
58
+ def modifier_form?(node)
59
+ node.parent.respond_to?(:modifier_form?) && node.parent.modifier_form?
60
+ end
61
+
62
+ # Require hash value omission be enclosed in parentheses to prevent the following issue:
63
+ # https://bugs.ruby-lang.org/issues/18396.
64
+ def exist_next_line_expression?(node)
65
+ node.parent&.assignment? ? node.parent.right_sibling : node.right_sibling
60
66
  end
61
67
 
62
68
  def syntax_like_method_call?(node)
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for nested `File.dirname`.
7
+ # It replaces nested `File.dirname` with the level argument introduced in Ruby 3.1.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # File.dirname(File.dirname(path))
13
+ #
14
+ # # good
15
+ # File.dirname(path, 2)
16
+ #
17
+ class NestedFileDirname < Base
18
+ include RangeHelp
19
+ extend AutoCorrector
20
+ extend TargetRubyVersion
21
+
22
+ MSG = 'Use `dirname(%<path>s, %<level>s)` instead.'
23
+ RESTRICT_ON_SEND = %i[dirname].freeze
24
+
25
+ minimum_target_ruby_version 3.1
26
+
27
+ # @!method file_dirname?(node)
28
+ def_node_matcher :file_dirname?, <<~PATTERN
29
+ (send
30
+ (const {cbase nil?} :File) :dirname ...)
31
+ PATTERN
32
+
33
+ def on_send(node)
34
+ return if file_dirname?(node.parent) || !file_dirname?(node.first_argument)
35
+
36
+ path, level = path_with_dir_level(node, 1)
37
+ return if level < 2
38
+
39
+ message = format(MSG, path: path, level: level)
40
+ range = offense_range(node)
41
+
42
+ add_offense(range, message: message) do |corrector|
43
+ corrector.replace(range, "dirname(#{path}, #{level})")
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def path_with_dir_level(node, level)
50
+ first_argument = node.first_argument
51
+
52
+ if file_dirname?(first_argument)
53
+ level += 1
54
+ path_with_dir_level(first_argument, level)
55
+ else
56
+ [first_argument.source, level]
57
+ end
58
+ end
59
+
60
+ def offense_range(node)
61
+ range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -54,8 +54,9 @@ module RuboCop
54
54
  private
55
55
 
56
56
  def format_message(argument)
57
- source = argument.source
58
- format(MSG, original: source, replacement: source.sub(/\s+=/, ':'))
57
+ replacement = "#{argument.name}: #{argument.default_value.source}"
58
+
59
+ format(MSG, original: argument.source, replacement: replacement)
59
60
  end
60
61
  end
61
62
  end
@@ -97,7 +97,7 @@ module RuboCop
97
97
  offense_range = node.loc.begin
98
98
 
99
99
  add_offense(offense_range) do |corrector|
100
- if any_ancestor_assignment_node?(node)
100
+ if node.parent&.assignment?
101
101
  replace_begin_with_statement(corrector, offense_range, node)
102
102
  else
103
103
  corrector.remove(offense_range)
@@ -170,11 +170,7 @@ module RuboCop
170
170
  end
171
171
 
172
172
  def valid_begin_assignment?(node)
173
- any_ancestor_assignment_node?(node) && !node.children.one?
174
- end
175
-
176
- def any_ancestor_assignment_node?(node)
177
- node.each_ancestor.any?(&:assignment?)
173
+ node.parent&.assignment? && !node.children.one?
178
174
  end
179
175
  end
180
176
  end
@@ -69,6 +69,11 @@ module RuboCop
69
69
  }
70
70
  PATTERN
71
71
 
72
+ # @!method env_const?(node)
73
+ def_node_matcher :env_const?, <<~PATTERN
74
+ (const {nil? cbase} :ENV)
75
+ PATTERN
76
+
72
77
  # @!method calls_lvar?(node, name)
73
78
  def_node_matcher :calls_lvar?, <<~PATTERN
74
79
  {
@@ -94,7 +99,7 @@ module RuboCop
94
99
  def receiver_allowed?(node)
95
100
  return false unless node
96
101
 
97
- node.hash_type? || creates_hash?(node)
102
+ node.hash_type? || creates_hash?(node) || env_const?(node)
98
103
  end
99
104
 
100
105
  def register_offense(node, block_node, regexp)
@@ -15,6 +15,11 @@ module RuboCop
15
15
  # end
16
16
  # end
17
17
  #
18
+ # # bad
19
+ # if condition_b
20
+ # do_something
21
+ # end if condition_a
22
+ #
18
23
  # # good
19
24
  # if condition_a && condition_b
20
25
  # do_something
@@ -26,12 +31,21 @@ module RuboCop
26
31
  # do_something if condition_b
27
32
  # end
28
33
  #
34
+ # # bad
35
+ # if condition_b
36
+ # do_something
37
+ # end if condition_a
38
+ #
29
39
  # @example AllowModifier: true
30
40
  # # good
31
41
  # if condition_a
32
42
  # do_something if condition_b
33
43
  # end
34
44
  #
45
+ # # good
46
+ # if condition_b
47
+ # do_something
48
+ # end if condition_a
35
49
  class SoleNestedConditional < Base
36
50
  include RangeHelp
37
51
  extend AutoCorrector
@@ -47,7 +61,7 @@ module RuboCop
47
61
 
48
62
  if_branch = node.if_branch
49
63
  return if use_variable_assignment_in_condition?(node.condition, if_branch)
50
- return unless offending_branch?(if_branch)
64
+ return unless offending_branch?(node, if_branch)
51
65
 
52
66
  message = format(MSG, conditional_type: node.keyword)
53
67
  add_offense(if_branch.loc.keyword, message: message) do |corrector|
@@ -72,13 +86,13 @@ module RuboCop
72
86
  end
73
87
  end
74
88
 
75
- def offending_branch?(branch)
89
+ def offending_branch?(node, branch)
76
90
  return false unless branch
77
91
 
78
92
  branch.if_type? &&
79
93
  !branch.else? &&
80
94
  !branch.ternary? &&
81
- !(branch.modifier_form? && allow_modifier?)
95
+ !((node.modifier_form? || branch.modifier_form?) && allow_modifier?)
82
96
  end
83
97
 
84
98
  def autocorrect(corrector, node, if_branch)
@@ -86,6 +100,14 @@ module RuboCop
86
100
  corrector.wrap(node.condition, '(', ')')
87
101
  end
88
102
 
103
+ if outer_condition_modify_form?(node, if_branch)
104
+ autocorrect_outer_condition_modify_form(corrector, node, if_branch)
105
+ else
106
+ autocorrect_outer_condition_basic(corrector, node, if_branch)
107
+ end
108
+ end
109
+
110
+ def autocorrect_outer_condition_basic(corrector, node, if_branch)
89
111
  correct_from_unless_to_if(corrector, node) if node.unless?
90
112
 
91
113
  and_operator = if_branch.unless? ? ' && !' : ' && '
@@ -97,11 +119,17 @@ module RuboCop
97
119
  end
98
120
  end
99
121
 
100
- def correct_from_unless_to_if(corrector, node)
122
+ def autocorrect_outer_condition_modify_form(corrector, node, if_branch)
123
+ correct_from_unless_to_if(corrector, if_branch, is_modify_form: true) if if_branch.unless?
124
+ correct_for_outer_condition_modify_form_style(corrector, node, if_branch)
125
+ end
126
+
127
+ def correct_from_unless_to_if(corrector, node, is_modify_form: false)
101
128
  corrector.replace(node.loc.keyword, 'if')
102
129
 
103
130
  condition = node.condition
104
- if condition.send_type? && condition.comparison_method? && !condition.parenthesized?
131
+ if (condition.send_type? && condition.comparison_method? && !condition.parenthesized?) ||
132
+ (is_modify_form && wrap_condition?(condition))
105
133
  corrector.wrap(node.condition, '!(', ')')
106
134
  else
107
135
  corrector.insert_before(node.condition, '!')
@@ -113,7 +141,7 @@ module RuboCop
113
141
  correct_outer_condition(corrector, outer_condition)
114
142
 
115
143
  condition = if_branch.condition
116
- corrector.insert_after(outer_condition, replacement_condition(and_operator, condition))
144
+ corrector.insert_after(outer_condition, "#{and_operator}#{replace_condition(condition)}")
117
145
 
118
146
  range = range_between(if_branch.loc.keyword.begin_pos, condition.source_range.end_pos)
119
147
  corrector.remove(range_with_surrounding_space(range: range, newlines: false))
@@ -129,6 +157,16 @@ module RuboCop
129
157
  corrector.wrap(if_branch.condition, '(', ')') if wrap_condition?(if_branch.condition)
130
158
  end
131
159
 
160
+ def correct_for_outer_condition_modify_form_style(corrector, node, if_branch)
161
+ condition = if_branch.condition
162
+ corrector.insert_before(condition,
163
+ "#{'!' if node.unless?}#{replace_condition(node.condition)} && ")
164
+
165
+ corrector.remove(node.condition.loc.expression)
166
+ corrector.remove(range_with_surrounding_space(range: node.loc.keyword, newlines: false))
167
+ corrector.replace(if_branch.loc.keyword, 'if')
168
+ end
169
+
132
170
  def correct_for_comment(corrector, node, if_branch)
133
171
  return if config.for_cop('Style/IfUnlessModifier')['Enabled']
134
172
 
@@ -165,17 +203,17 @@ module RuboCop
165
203
  (node.send_type? && node.arguments.any? && !node.parenthesized?)
166
204
  end
167
205
 
168
- def replacement_condition(and_operator, condition)
169
- if wrap_condition?(condition)
170
- "#{and_operator}(#{condition.source})"
171
- else
172
- "#{and_operator}#{condition.source}"
173
- end
206
+ def replace_condition(condition)
207
+ wrap_condition?(condition) ? "(#{condition.source})" : condition.source
174
208
  end
175
209
 
176
210
  def allow_modifier?
177
211
  cop_config['AllowModifier']
178
212
  end
213
+
214
+ def outer_condition_modify_form?(node, if_branch)
215
+ node.condition.loc.expression.begin_pos > if_branch.condition.loc.expression.begin_pos
216
+ end
179
217
  end
180
218
  end
181
219
  end
@@ -134,7 +134,13 @@ module RuboCop
134
134
  end
135
135
 
136
136
  def uncorrectable?(part)
137
- part.multiline? || (part.str_type? && part.heredoc?) || part.each_descendant(:block).any?
137
+ part.multiline? || heredoc?(part) || part.each_descendant(:block).any?
138
+ end
139
+
140
+ def heredoc?(node)
141
+ return false unless node.str_type? || node.dstr_type?
142
+
143
+ node.heredoc?
138
144
  end
139
145
 
140
146
  def corrected_ancestor?(node)
@@ -58,6 +58,8 @@ module RuboCop
58
58
  end
59
59
 
60
60
  def simple_assignment?(node)
61
+ return false unless node.respond_to?(:type)
62
+
61
63
  SIMPLE_ASSIGNMENT_TYPES.include?(node.type)
62
64
  end
63
65
 
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # last item of all non-empty, multiline array literals.
11
11
  # * `comma`: Requires a comma after last item in an array,
12
12
  # but only when each item is on its own line.
13
- # * `no_comma`: Does not requires a comma after the
13
+ # * `no_comma`: Does not require a comma after the
14
14
  # last item in an array
15
15
  #
16
16
  # @example EnforcedStyleForMultiline: consistent_comma
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # last item of all non-empty, multiline hash literals.
11
11
  # * `comma`: Requires a comma after the last item in a hash,
12
12
  # but only when each item is on its own line.
13
- # * `no_comma`: Does not requires a comma after the
13
+ # * `no_comma`: Does not require a comma after the
14
14
  # last item in a hash
15
15
  #
16
16
  # @example EnforcedStyleForMultiline: consistent_comma
@@ -32,10 +32,14 @@ module RuboCop
32
32
  body_range = range_between_condition_and_else(node, node.condition)
33
33
  else_range = range_between_else_and_end(node)
34
34
 
35
+ next if part_of_ignored_node?(node)
36
+
35
37
  corrector.replace(node.loc.keyword, 'if')
36
38
  corrector.replace(body_range, else_range.source)
37
39
  corrector.replace(else_range, body_range.source)
38
40
  end
41
+
42
+ ignore_node(node)
39
43
  end
40
44
 
41
45
  def range_between_condition_and_else(node, condition)
@@ -186,11 +186,7 @@ module RuboCop
186
186
  end
187
187
 
188
188
  def regexp_captured_names(node)
189
- regexp_string = node.children.select(&:str_type?).map do |child|
190
- child.children.first
191
- end.join || ''
192
-
193
- regexp = Regexp.new(regexp_string)
189
+ regexp = node.to_regexp
194
190
 
195
191
  regexp.named_captures.keys
196
192
  end
@@ -191,8 +191,8 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
191
191
 
192
192
  def wrap_backtick(value)
193
193
  if value.is_a?(String)
194
- # Use `+` to prevent text like `**/*.gemspec` from being bold.
195
- value.start_with?('*') ? "`+#{value}+`" : "`#{value}`"
194
+ # Use `+` to prevent text like `**/*.gemspec`, `spec/**/*` from being bold.
195
+ value.include?('*') ? "`+#{value}+`" : "`#{value}`"
196
196
  else
197
197
  "`#{value}`"
198
198
  end
@@ -121,9 +121,14 @@ module RuboCop
121
121
  output_buffer.puts "# Offense count: #{offense_count}" if show_offense_counts?
122
122
 
123
123
  cop_class = Cop::Registry.global.find_by_cop_name(cop_name)
124
- output_buffer.puts '# Cop supports --auto-correct.' if cop_class&.support_autocorrect?
125
-
126
124
  default_cfg = default_config(cop_name)
125
+
126
+ if supports_safe_auto_correct?(cop_class, default_cfg)
127
+ output_buffer.puts '# This cop supports safe auto-correction (--auto-correct).'
128
+ elsif supports_unsafe_autocorrect?(cop_class, default_cfg)
129
+ output_buffer.puts '# This cop supports unsafe auto-correction (--auto-correct-all).'
130
+ end
131
+
127
132
  return unless default_cfg
128
133
 
129
134
  params = cop_config_params(default_cfg, cfg)
@@ -132,6 +137,15 @@ module RuboCop
132
137
  output_cop_param_comments(output_buffer, params, default_cfg)
133
138
  end
134
139
 
140
+ def supports_safe_auto_correct?(cop_class, default_cfg)
141
+ cop_class&.support_autocorrect? &&
142
+ (default_cfg.nil? || default_cfg['Safe'] || default_cfg['Safe'].nil?)
143
+ end
144
+
145
+ def supports_unsafe_autocorrect?(cop_class, default_cfg)
146
+ cop_class&.support_autocorrect? && !default_cfg.nil? && default_cfg['Safe'] == false
147
+ end
148
+
135
149
  def cop_config_params(default_cfg, cfg)
136
150
  default_cfg.keys -
137
151
  %w[Description StyleGuide Reference Enabled Exclude Safe
@@ -467,8 +467,14 @@ module RuboCop
467
467
  'This option applies to the previously',
468
468
  'specified --format, or the default format',
469
469
  'if no format is specified.'],
470
- fail_level: ['Minimum severity (A/I/R/C/W/E/F) for exit',
471
- 'with error code.'],
470
+ fail_level: ['Minimum severity for exit with error code.',
471
+ ' [A] autocorrect',
472
+ ' [I] info',
473
+ ' [R] refactor',
474
+ ' [C] convention',
475
+ ' [W] warning',
476
+ ' [E] error',
477
+ ' [F] fatal'],
472
478
  display_time: 'Display elapsed time in seconds.',
473
479
  display_only_failed: ['Only output offense messages. Omit passing',
474
480
  'cops. Only valid for --format junit.'],
@@ -135,3 +135,7 @@ end
135
135
  RSpec.shared_context 'ruby 3.1', :ruby31 do
136
136
  let(:ruby_version) { 3.1 }
137
137
  end
138
+
139
+ RSpec.shared_context 'ruby 3.2', :ruby32 do
140
+ let(:ruby_version) { 3.2 }
141
+ end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  class Runner # rubocop:disable Metrics/ClassLength
9
9
  # An exception indicating that the inspection loop got stuck correcting
10
10
  # offenses back and forth.
11
- class InfiniteCorrectionLoop < RuntimeError
11
+ class InfiniteCorrectionLoop < StandardError
12
12
  attr_reader :offenses
13
13
 
14
14
  def initialize(path, offenses_by_iteration, loop_start: -1)
@@ -4,7 +4,7 @@ module RuboCop
4
4
  # The kind of Ruby that code inspected by RuboCop is written in.
5
5
  # @api private
6
6
  class TargetRuby
7
- KNOWN_RUBIES = [2.5, 2.6, 2.7, 3.0, 3.1].freeze
7
+ KNOWN_RUBIES = [2.5, 2.6, 2.7, 3.0, 3.1, 3.2].freeze
8
8
  DEFAULT_VERSION = KNOWN_RUBIES.first
9
9
 
10
10
  OBSOLETE_RUBIES = {
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.25.0'
6
+ STRING = '1.26.1'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, '\
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
data/lib/rubocop.rb CHANGED
@@ -552,6 +552,7 @@ require_relative 'rubocop/cop/style/negated_if'
552
552
  require_relative 'rubocop/cop/style/negated_if_else_condition'
553
553
  require_relative 'rubocop/cop/style/negated_unless'
554
554
  require_relative 'rubocop/cop/style/negated_while'
555
+ require_relative 'rubocop/cop/style/nested_file_dirname'
555
556
  require_relative 'rubocop/cop/style/nested_modifier'
556
557
  require_relative 'rubocop/cop/style/nested_parenthesized_calls'
557
558
  require_relative 'rubocop/cop/style/nested_ternary_operator'