rubocop 1.92.0 → 1.92.1
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.
- checksums.yaml +4 -4
- data/config/default.yml +1 -0
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +16 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +5 -1
- data/lib/rubocop/cop/layout/class_structure.rb +21 -7
- data/lib/rubocop/cop/layout/dot_position.rb +25 -15
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +11 -7
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -7
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +26 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +11 -5
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +5 -3
- data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
- data/lib/rubocop/cop/layout/line_length.rb +104 -6
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +6 -4
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +16 -5
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +3 -3
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +2 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
- data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +7 -6
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +3 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +36 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +9 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
- data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +30 -2
- data/lib/rubocop/cop/style/and_or.rb +3 -3
- data/lib/rubocop/cop/style/arguments_forwarding.rb +28 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +6 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +2 -0
- data/lib/rubocop/cop/style/class_methods_definitions.rb +7 -0
- data/lib/rubocop/cop/style/collection_querying.rb +79 -46
- data/lib/rubocop/cop/style/combinable_loops.rb +4 -0
- data/lib/rubocop/cop/style/concat_array_literals.rb +13 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
- data/lib/rubocop/cop/style/endless_method.rb +5 -1
- data/lib/rubocop/cop/style/for.rb +14 -1
- data/lib/rubocop/cop/style/guard_clause.rb +22 -21
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +63 -2
- data/lib/rubocop/cop/style/lambda.rb +16 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +36 -4
- data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
- data/lib/rubocop/cop/style/mutable_constant.rb +25 -7
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +19 -9
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -2
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
- data/lib/rubocop/cop/style/require_order.rb +16 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +6 -0
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +5 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +6 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +23 -23
- data/lib/rubocop/server/cache.rb +4 -4
- data/lib/rubocop/target_ruby.rb +21 -9
- data/lib/rubocop/version.rb +1 -1
- metadata +2 -2
|
@@ -100,6 +100,7 @@ module RuboCop
|
|
|
100
100
|
pattern_matching_nodes(condition).any?
|
|
101
101
|
|
|
102
102
|
return unless (msg = message(node))
|
|
103
|
+
return if modifier_sharing_line_in_logical_operator?(node)
|
|
103
104
|
|
|
104
105
|
add_offense(node.loc.keyword, message: format(msg, keyword: node.keyword)) do |corrector|
|
|
105
106
|
next if part_of_ignored_node?(node)
|
|
@@ -167,11 +168,11 @@ module RuboCop
|
|
|
167
168
|
return to_modifier_form_with_move_comment(node, indent(node), comment)
|
|
168
169
|
end
|
|
169
170
|
|
|
170
|
-
heredoc_ranges = heredoc_ranges_in(node
|
|
171
|
+
heredoc_ranges = heredoc_ranges_in(node)
|
|
171
172
|
unless heredoc_ranges.empty?
|
|
172
173
|
remove_heredoc(corrector, heredoc_ranges)
|
|
173
174
|
|
|
174
|
-
return to_normal_form_with_heredoc(node, indent(node)
|
|
175
|
+
return to_normal_form_with_heredoc(node, indent(node))
|
|
175
176
|
end
|
|
176
177
|
|
|
177
178
|
to_normal_form(node, indent(node))
|
|
@@ -233,11 +234,18 @@ module RuboCop
|
|
|
233
234
|
end
|
|
234
235
|
|
|
235
236
|
def collection_from_ancestor(node)
|
|
236
|
-
return node if node&.type?(:array, :call)
|
|
237
|
+
return node if node&.type?(:array, :call, :and, :or)
|
|
237
238
|
|
|
238
239
|
node.parent if node&.type?(:pair)
|
|
239
240
|
end
|
|
240
241
|
|
|
242
|
+
def modifier_sharing_line_in_logical_operator?(node)
|
|
243
|
+
collection = find_containing_collection(node)
|
|
244
|
+
return false if !node.modifier_form? || !collection&.operator_keyword?
|
|
245
|
+
|
|
246
|
+
another_modifier_if_on_same_line?(node)
|
|
247
|
+
end
|
|
248
|
+
|
|
241
249
|
def another_modifier_if_on_same_line?(node)
|
|
242
250
|
collection = find_containing_collection(node)
|
|
243
251
|
return false unless collection
|
|
@@ -280,15 +288,14 @@ module RuboCop
|
|
|
280
288
|
end
|
|
281
289
|
end
|
|
282
290
|
|
|
283
|
-
def to_normal_form_with_heredoc(node, indentation
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
#{
|
|
288
|
-
|
|
289
|
-
#{
|
|
290
|
-
|
|
291
|
-
RUBY
|
|
291
|
+
def to_normal_form_with_heredoc(node, indentation)
|
|
292
|
+
[
|
|
293
|
+
"#{node.keyword} #{node.condition.source}",
|
|
294
|
+
*heredoc_ranges_in(node.condition).map(&:source),
|
|
295
|
+
"#{indentation} #{node.body.source}",
|
|
296
|
+
*heredoc_ranges_in(node.if_branch).map(&:source),
|
|
297
|
+
"#{indentation}end"
|
|
298
|
+
].join("\n")
|
|
292
299
|
end
|
|
293
300
|
|
|
294
301
|
def to_modifier_form_with_move_comment(node, indentation, comment)
|
|
@@ -59,6 +59,8 @@ module RuboCop
|
|
|
59
59
|
MSG_AVOID_IT_PARAMETER = 'Avoid using `it` block parameter.'
|
|
60
60
|
MSG_AVOID_IT_PARAMETER_MULTILINE = 'Avoid using `it` block parameter for multi-line blocks.'
|
|
61
61
|
|
|
62
|
+
SCOPE_TYPES = %i[any_def class module sclass].freeze
|
|
63
|
+
|
|
62
64
|
minimum_target_ruby_version 3.4
|
|
63
65
|
|
|
64
66
|
# `Style/StabbyLambdaParentheses` wraps the parameter this cop removes in the same pass,
|
|
@@ -67,6 +69,10 @@ module RuboCop
|
|
|
67
69
|
[Style::Lambda, Style::StabbyLambdaParentheses]
|
|
68
70
|
end
|
|
69
71
|
|
|
72
|
+
def on_new_investigation
|
|
73
|
+
@it_variable_definitions = nil
|
|
74
|
+
end
|
|
75
|
+
|
|
70
76
|
def on_block(node)
|
|
71
77
|
return unless style == :always
|
|
72
78
|
return unless node.arguments.one?
|
|
@@ -75,7 +81,7 @@ module RuboCop
|
|
|
75
81
|
return unless node.first_argument.arg_type?
|
|
76
82
|
|
|
77
83
|
block_argument_name = node.first_argument.source
|
|
78
|
-
return if
|
|
84
|
+
return if keep_parameter_name?(node.body, block_argument_name)
|
|
79
85
|
|
|
80
86
|
find_block_variables(node, block_argument_name).each do |variable|
|
|
81
87
|
add_offense(variable, message: MSG_USE_IT_PARAMETER) do |corrector|
|
|
@@ -116,7 +122,7 @@ module RuboCop
|
|
|
116
122
|
private
|
|
117
123
|
|
|
118
124
|
def find_block_variables(node, block_argument_name)
|
|
119
|
-
return []
|
|
125
|
+
return [] if !node.body || it_variable_in_scope?(node)
|
|
120
126
|
|
|
121
127
|
ranges = inner_block_ranges(node.body)
|
|
122
128
|
|
|
@@ -125,10 +131,47 @@ module RuboCop
|
|
|
125
131
|
end
|
|
126
132
|
end
|
|
127
133
|
|
|
134
|
+
def it_variable_in_scope?(node)
|
|
135
|
+
scope = nearest_scope(node)
|
|
136
|
+
return true if it_argument_in_scope?(node, scope)
|
|
137
|
+
|
|
138
|
+
it_variable_definitions.any? do |definition|
|
|
139
|
+
nearest_scope(definition).equal?(scope) && visible_in_block?(definition, node)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def it_variable_definitions
|
|
144
|
+
@it_variable_definitions ||=
|
|
145
|
+
variable_definitions(processed_source.ast).filter_map do |name, definition|
|
|
146
|
+
definition if name == 'it'
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def nearest_scope(node)
|
|
151
|
+
node.each_ancestor(*SCOPE_TYPES).first
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def it_argument_in_scope?(node, scope)
|
|
155
|
+
owners = node.each_ancestor(:block).select { |block| nearest_scope(block).equal?(scope) }
|
|
156
|
+
owners << scope if scope&.any_def_type?
|
|
157
|
+
|
|
158
|
+
owners.any? { |owner| owner.arguments.argument_list.any? { |arg| arg.name == :it } }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def visible_in_block?(definition, node)
|
|
162
|
+
return true if definition.source_range.begin_pos < node.source_range.begin_pos
|
|
163
|
+
|
|
164
|
+
node.source_range.contains?(definition.source_range)
|
|
165
|
+
end
|
|
166
|
+
|
|
128
167
|
def inner_block_ranges(body)
|
|
129
168
|
body.each_node(:any_block).map { |block| block.loc.begin.join(block.loc.end) }
|
|
130
169
|
end
|
|
131
170
|
|
|
171
|
+
def keep_parameter_name?(body, block_arg_name)
|
|
172
|
+
used_within_inner_block?(body, block_arg_name) || reassigned?(body, block_arg_name)
|
|
173
|
+
end
|
|
174
|
+
|
|
132
175
|
def used_within_inner_block?(body, block_argument_name)
|
|
133
176
|
return false unless body
|
|
134
177
|
|
|
@@ -139,11 +182,29 @@ module RuboCop
|
|
|
139
182
|
end
|
|
140
183
|
end
|
|
141
184
|
|
|
185
|
+
def reassigned?(body, block_argument_name)
|
|
186
|
+
return false unless body
|
|
187
|
+
|
|
188
|
+
variable_definitions(body).any? { |name, _definition| name == block_argument_name }
|
|
189
|
+
end
|
|
190
|
+
|
|
142
191
|
def block_variables(body, block_argument_name)
|
|
143
192
|
body.each_descendant(:lvar).select do |descendant|
|
|
144
193
|
descendant.source == block_argument_name
|
|
145
194
|
end
|
|
146
195
|
end
|
|
196
|
+
|
|
197
|
+
def variable_definitions(node)
|
|
198
|
+
node.each_node(:lvasgn, :match_var, :match_with_lvasgn).flat_map do |definition|
|
|
199
|
+
names = if definition.match_with_lvasgn_type?
|
|
200
|
+
definition.children.first.each_capture(named: true).map(&:name)
|
|
201
|
+
else
|
|
202
|
+
[definition.children.first.to_s]
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
names.map { |name| [name, definition] }
|
|
206
|
+
end
|
|
207
|
+
end
|
|
147
208
|
end
|
|
148
209
|
end
|
|
149
210
|
end
|
|
@@ -129,12 +129,27 @@ module RuboCop
|
|
|
129
129
|
|
|
130
130
|
return unless node.arguments?
|
|
131
131
|
|
|
132
|
-
arg_str =
|
|
132
|
+
arg_str = lambda_arg_string(node.arguments)
|
|
133
|
+
arg_str = " #{arg_str} " if space_inside_parens?
|
|
134
|
+
arg_str = "(#{arg_str})"
|
|
135
|
+
arg_str = " #{arg_str}" if space_in_lambda_literal_required?
|
|
133
136
|
|
|
134
137
|
corrector.insert_after(node.send_node, arg_str)
|
|
135
138
|
corrector.remove(arguments_with_whitespace(node))
|
|
136
139
|
end
|
|
137
140
|
|
|
141
|
+
def space_inside_parens?
|
|
142
|
+
return false unless config.cop_enabled?('Layout/SpaceInsideParens')
|
|
143
|
+
|
|
144
|
+
%w[space compact].include?(config.for_cop('Layout/SpaceInsideParens')['EnforcedStyle'])
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def space_in_lambda_literal_required?
|
|
148
|
+
return false unless config.cop_enabled?('Layout/SpaceInLambdaLiteral')
|
|
149
|
+
|
|
150
|
+
config.for_cop('Layout/SpaceInLambdaLiteral')['EnforcedStyle'] == 'require_space'
|
|
151
|
+
end
|
|
152
|
+
|
|
138
153
|
def arguments_with_whitespace(node)
|
|
139
154
|
node.loc.begin.end.join(node.arguments.loc.end)
|
|
140
155
|
end
|
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
|
30
30
|
|
|
31
31
|
private
|
|
32
32
|
|
|
33
|
-
def omit_parentheses(node) # rubocop:disable Metrics/PerceivedComplexity
|
|
33
|
+
def omit_parentheses(node) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
|
34
34
|
return unless node.parenthesized?
|
|
35
35
|
return if inside_endless_method_def?(node)
|
|
36
36
|
return if require_parentheses_for_hash_value_omission?(node)
|
|
@@ -42,6 +42,7 @@ module RuboCop
|
|
|
42
42
|
return if allowed_string_interpolation_method_call?(node)
|
|
43
43
|
return if code_after_closing_parenthesis_on_its_own_line?(node)
|
|
44
44
|
return if comment_before_first_argument?(node)
|
|
45
|
+
return if args_parenthesized?(node)
|
|
45
46
|
|
|
46
47
|
(@pending_omit_offenses ||= []) << node
|
|
47
48
|
end
|
|
@@ -132,7 +133,7 @@ module RuboCop
|
|
|
132
133
|
opening.source_line[(opening.column + 1)..].gsub(TRAILING_WHITESPACE_REGEX, '').empty?
|
|
133
134
|
end
|
|
134
135
|
|
|
135
|
-
def legitimate_call_with_parentheses?(node) # rubocop:disable Metrics/PerceivedComplexity
|
|
136
|
+
def legitimate_call_with_parentheses?(node) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
|
136
137
|
call_in_literals?(node) ||
|
|
137
138
|
node.parent&.when_type? ||
|
|
138
139
|
call_with_ambiguous_arguments?(node) ||
|
|
@@ -142,7 +143,9 @@ module RuboCop
|
|
|
142
143
|
allowed_multiline_call_with_parentheses?(node) ||
|
|
143
144
|
allowed_chained_call_with_parentheses?(node) ||
|
|
144
145
|
assignment_in_condition?(node) ||
|
|
145
|
-
|
|
146
|
+
command_assignment_in_expression?(node) ||
|
|
147
|
+
forwards_anonymous_rest_arguments?(node) ||
|
|
148
|
+
trailing_comma?(node)
|
|
146
149
|
end
|
|
147
150
|
|
|
148
151
|
def call_in_literals?(node)
|
|
@@ -278,7 +281,7 @@ module RuboCop
|
|
|
278
281
|
end
|
|
279
282
|
|
|
280
283
|
def assigned_before?(node, target)
|
|
281
|
-
node.assignment? && node.loc.operator.begin < target.
|
|
284
|
+
node.assignment? && node.loc.operator.begin < target.source_range.begin
|
|
282
285
|
end
|
|
283
286
|
|
|
284
287
|
def inside_string_interpolation?(node)
|
|
@@ -295,6 +298,27 @@ module RuboCop
|
|
|
295
298
|
parent.assignment? && (grandparent.conditional? || grandparent.when_type?)
|
|
296
299
|
end
|
|
297
300
|
|
|
301
|
+
# rubocop:disable-next Metrics/PerceivedComplexity
|
|
302
|
+
def command_assignment_in_expression?(node)
|
|
303
|
+
value = node.parent&.type?(:any_block, :rescue) ? node.parent : node
|
|
304
|
+
assignment = outermost_assignment(value)
|
|
305
|
+
return false if assignment.equal?(value)
|
|
306
|
+
|
|
307
|
+
call_in_literals?(assignment) ||
|
|
308
|
+
call_in_logical_operators?(assignment) ||
|
|
309
|
+
call_in_optional_arguments?(assignment) ||
|
|
310
|
+
call_as_argument_or_chain?(assignment) ||
|
|
311
|
+
assignment.parent&.type?(:masgn, :return, :next, :break, :defined?)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def outermost_assignment(value)
|
|
315
|
+
parent = value.parent
|
|
316
|
+
return value if !parent&.assignment? || parent.masgn_type?
|
|
317
|
+
return value unless assigned_before?(parent, value)
|
|
318
|
+
|
|
319
|
+
outermost_assignment(parent)
|
|
320
|
+
end
|
|
321
|
+
|
|
298
322
|
def forwards_anonymous_rest_arguments?(node)
|
|
299
323
|
node.arguments.any? do |argument|
|
|
300
324
|
next true if argument.forwarded_restarg_type?
|
|
@@ -302,6 +326,14 @@ module RuboCop
|
|
|
302
326
|
argument.hash_type? && argument.children.any?(&:forwarded_kwrestarg_type?)
|
|
303
327
|
end
|
|
304
328
|
end
|
|
329
|
+
|
|
330
|
+
def trailing_comma?(node)
|
|
331
|
+
return false unless (last_argument = node.last_argument)
|
|
332
|
+
|
|
333
|
+
range = last_argument.source_range.end.join(node.loc.end.begin)
|
|
334
|
+
|
|
335
|
+
processed_source.tokens_within(range).any?(&:comma?)
|
|
336
|
+
end
|
|
305
337
|
end
|
|
306
338
|
end
|
|
307
339
|
end
|
|
@@ -117,17 +117,26 @@ module RuboCop
|
|
|
117
117
|
|
|
118
118
|
def separate_mixins(node)
|
|
119
119
|
arguments = node.arguments.reverse
|
|
120
|
-
mixins = [
|
|
120
|
+
mixins = [mixin_call(node.method_name, arguments.first.source, node.parenthesized?)]
|
|
121
121
|
|
|
122
122
|
arguments[1..].inject(mixins) do |replacement, arg|
|
|
123
|
-
|
|
123
|
+
call = mixin_call(node.method_name, arg.source, node.parenthesized?)
|
|
124
|
+
replacement << "#{indent(node)}#{call}"
|
|
124
125
|
end.join("\n")
|
|
125
126
|
end
|
|
126
127
|
|
|
127
128
|
def group_mixins(node, mixins)
|
|
128
129
|
mixin_names = mixins.reverse.flat_map { |mixin| mixin.arguments.map(&:source) }
|
|
129
130
|
|
|
130
|
-
|
|
131
|
+
mixin_call(node.method_name, mixin_names.join(', '), mixins.any?(&:parenthesized?))
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def mixin_call(method_name, arguments_source, parenthesized)
|
|
135
|
+
if parenthesized
|
|
136
|
+
"#{method_name}(#{arguments_source})"
|
|
137
|
+
else
|
|
138
|
+
"#{method_name} #{arguments_source}"
|
|
139
|
+
end
|
|
131
140
|
end
|
|
132
141
|
end
|
|
133
142
|
end
|
|
@@ -150,7 +150,7 @@ module RuboCop
|
|
|
150
150
|
# is the last element and spans multiple lines, the trailing comma lands between the literal
|
|
151
151
|
# and the `.freeze` appended in the same pass.
|
|
152
152
|
def self.autocorrect_incompatible_with
|
|
153
|
-
[Style::TrailingCommaInArrayLiteral, Style::TrailingCommaInHashLiteral]
|
|
153
|
+
[Style::HashAsLastArrayItem, Style::TrailingCommaInArrayLiteral, Style::TrailingCommaInHashLiteral]
|
|
154
154
|
end
|
|
155
155
|
|
|
156
156
|
def on_casgn(node)
|
|
@@ -228,15 +228,32 @@ module RuboCop
|
|
|
228
228
|
return
|
|
229
229
|
end
|
|
230
230
|
|
|
231
|
+
return expand_omitted_hash_value(corrector, node.parent) if omitted_hash_value?(node)
|
|
232
|
+
|
|
233
|
+
wrap_for_freeze(corrector, node, expr)
|
|
234
|
+
corrector.insert_after(expr, '.freeze')
|
|
235
|
+
|
|
236
|
+
freeze_nested_literals(corrector, node) if recursive?
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def omitted_hash_value?(node)
|
|
240
|
+
node.parent&.pair_type? && node.parent.value_omission?
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def expand_omitted_hash_value(corrector, pair)
|
|
244
|
+
key = pair.key.value
|
|
245
|
+
|
|
246
|
+
corrector.replace(pair, "#{key}: #{key}.freeze")
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def wrap_for_freeze(corrector, node, expr)
|
|
231
250
|
if node.array_type? && !node.bracketed?
|
|
232
251
|
corrector.wrap(expr, '[', ']')
|
|
252
|
+
elsif node.hash_type? && !node.braces?
|
|
253
|
+
corrector.wrap(expr, '{ ', ' }')
|
|
233
254
|
elsif requires_parentheses?(node)
|
|
234
255
|
corrector.wrap(expr, '(', ')')
|
|
235
256
|
end
|
|
236
|
-
|
|
237
|
-
corrector.insert_after(expr, '.freeze')
|
|
238
|
-
|
|
239
|
-
freeze_nested_literals(corrector, node) if recursive?
|
|
240
257
|
end
|
|
241
258
|
|
|
242
259
|
# Recursively freezes every nested mutable literal inside an array or
|
|
@@ -262,13 +279,14 @@ module RuboCop
|
|
|
262
279
|
# Returns the child literals of an array or hash node that may
|
|
263
280
|
# themselves need freezing. For hashes, both keys and values are
|
|
264
281
|
# included. Percent-literal arrays (e.g. `%w(a b)`) are skipped because
|
|
265
|
-
# `.freeze` cannot be appended to their contents.
|
|
282
|
+
# `.freeze` cannot be appended to their contents. Splat elements are
|
|
283
|
+
# skipped because the splatted object is not stored in the array.
|
|
266
284
|
def literal_children(node)
|
|
267
285
|
case node.type
|
|
268
286
|
when :array
|
|
269
287
|
return [] if node.percent_literal?
|
|
270
288
|
|
|
271
|
-
node.children
|
|
289
|
+
node.children.reject(&:splat_type?)
|
|
272
290
|
when :hash
|
|
273
291
|
node.children.flat_map { |child| child.pair_type? ? child.children : [] }
|
|
274
292
|
else
|
|
@@ -83,7 +83,7 @@ module RuboCop
|
|
|
83
83
|
control_op_condition(cond) do |first_child, rest_children|
|
|
84
84
|
return if require_parentheses?(node, first_child)
|
|
85
85
|
return if semicolon_separated_expressions?(first_child, rest_children)
|
|
86
|
-
return if modifier_op?(first_child)
|
|
86
|
+
return if modifier_op?(first_child) || first_child.masgn_type?
|
|
87
87
|
return if parens_allowed?(cond)
|
|
88
88
|
|
|
89
89
|
message = message(cond)
|
|
@@ -101,10 +101,7 @@ module RuboCop
|
|
|
101
101
|
return if exception.send_type? && exception.first_argument&.hash_type?
|
|
102
102
|
|
|
103
103
|
add_offense(node, message: format(COMPACT_MSG, method: node.method_name)) do |corrector|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
corrector.replace(node, replacement)
|
|
107
|
-
opposite_style_detected
|
|
104
|
+
replace_raise(corrector, node, correction_exploded_to_compact(node))
|
|
108
105
|
end
|
|
109
106
|
else
|
|
110
107
|
correct_style_detected
|
|
@@ -121,13 +118,22 @@ module RuboCop
|
|
|
121
118
|
return if allowed_non_exploded_type?(first_arg)
|
|
122
119
|
|
|
123
120
|
add_offense(node, message: format(EXPLODED_MSG, method: node.method_name)) do |corrector|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
corrector.replace(node, replacement)
|
|
127
|
-
opposite_style_detected
|
|
121
|
+
replace_raise(corrector, node, correction_compact_to_exploded(node))
|
|
128
122
|
end
|
|
129
123
|
end
|
|
130
124
|
|
|
125
|
+
def replace_raise(corrector, node, replacement)
|
|
126
|
+
opposite_style_detected
|
|
127
|
+
return if inside_corrected_raise?(node)
|
|
128
|
+
|
|
129
|
+
corrector.replace(node, replacement)
|
|
130
|
+
ignore_node(node)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def inside_corrected_raise?(node)
|
|
134
|
+
node.each_ancestor(:send).any? { |ancestor| ignored_node?(ancestor) }
|
|
135
|
+
end
|
|
136
|
+
|
|
131
137
|
def use_new_method?(first_arg)
|
|
132
138
|
first_arg.send_type? && first_arg.receiver && first_arg.method?(:new)
|
|
133
139
|
end
|
|
@@ -152,7 +158,11 @@ module RuboCop
|
|
|
152
158
|
end
|
|
153
159
|
|
|
154
160
|
def requires_parens?(parent)
|
|
155
|
-
|
|
161
|
+
return true if parent.operator_keyword?
|
|
162
|
+
return true if parent.type?(:call, :super, :yield, :array, :pair)
|
|
163
|
+
return true if parent.any_def_type? && parent.endless?
|
|
164
|
+
|
|
165
|
+
parent.if_type? && parent.ternary?
|
|
156
166
|
end
|
|
157
167
|
end
|
|
158
168
|
end
|
|
@@ -191,7 +191,8 @@ module RuboCop
|
|
|
191
191
|
def use_modifier_form_after_multiline_begin_block?(node)
|
|
192
192
|
return false unless (parent = node.parent)
|
|
193
193
|
|
|
194
|
-
node.multiline? && parent.if_type? && parent.modifier_form?
|
|
194
|
+
node.multiline? && parent.if_type? && parent.modifier_form? &&
|
|
195
|
+
!parent.condition.equal?(node)
|
|
195
196
|
end
|
|
196
197
|
|
|
197
198
|
def correct_modifier_form_after_multiline_begin_block(corrector, node)
|
|
@@ -30,6 +30,10 @@ module RuboCop
|
|
|
30
30
|
|
|
31
31
|
minimum_target_ruby_version 3.0
|
|
32
32
|
|
|
33
|
+
def self.autocorrect_incompatible_with
|
|
34
|
+
[Layout::MultilineMethodCallBraceLayout]
|
|
35
|
+
end
|
|
36
|
+
|
|
33
37
|
# @!method redundant_unfreeze?(node)
|
|
34
38
|
def_node_matcher :redundant_unfreeze?, <<~PATTERN
|
|
35
39
|
{
|
|
@@ -41,9 +45,10 @@ module RuboCop
|
|
|
41
45
|
def on_dstr(node)
|
|
42
46
|
return if uninterpolated_string?(node) || uninterpolated_heredoc?(node)
|
|
43
47
|
return unless redundant_unfreeze?(node.parent)
|
|
48
|
+
return if comment_outside_string?(node)
|
|
44
49
|
|
|
45
50
|
add_offense(offense_range(node.parent)) do |corrector|
|
|
46
|
-
corrector
|
|
51
|
+
remove_unfreeze(corrector, node.parent, node)
|
|
47
52
|
end
|
|
48
53
|
end
|
|
49
54
|
|
|
@@ -56,6 +61,24 @@ module RuboCop
|
|
|
56
61
|
node.loc.selector
|
|
57
62
|
end
|
|
58
63
|
end
|
|
64
|
+
|
|
65
|
+
# Only the parts around the string are removed, so that an unfrozen string
|
|
66
|
+
# interpolated into it can be corrected in the same pass.
|
|
67
|
+
def remove_unfreeze(corrector, node, string)
|
|
68
|
+
corrector.remove(node.source_range.begin.join(string.source_range.begin))
|
|
69
|
+
corrector.remove(string.source_range.end.join(node.source_range.end))
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def comment_outside_string?(node)
|
|
73
|
+
call_range = node.parent.source_range
|
|
74
|
+
string_range = node.source_range
|
|
75
|
+
|
|
76
|
+
processed_source.comments.any? do |comment|
|
|
77
|
+
range = comment.source_range
|
|
78
|
+
|
|
79
|
+
call_range.contains?(range) && !string_range.contains?(range)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
59
82
|
end
|
|
60
83
|
end
|
|
61
84
|
end
|
|
@@ -23,14 +23,20 @@ module RuboCop
|
|
|
23
23
|
# foo = bar unless condition
|
|
24
24
|
#
|
|
25
25
|
class RedundantSelfAssignmentBranch < Base
|
|
26
|
+
include RescueNode
|
|
26
27
|
extend AutoCorrector
|
|
27
28
|
|
|
28
29
|
MSG = 'Remove the self-assignment branch.'
|
|
29
30
|
|
|
31
|
+
STATEMENT_BODY_TYPES = %i[
|
|
32
|
+
kwbegin def defs block numblock itblock class module sclass rescue ensure
|
|
33
|
+
].freeze
|
|
34
|
+
|
|
30
35
|
def on_lvasgn(node)
|
|
31
36
|
expression = node.expression
|
|
32
37
|
|
|
33
38
|
return unless use_if_and_else_branch?(expression)
|
|
39
|
+
return unless statement?(node)
|
|
34
40
|
|
|
35
41
|
if_branch = expression.if_branch
|
|
36
42
|
else_branch = expression.else_branch
|
|
@@ -51,6 +57,28 @@ module RuboCop
|
|
|
51
57
|
!expression.ternary? || !expression.else?
|
|
52
58
|
end
|
|
53
59
|
|
|
60
|
+
def statement?(node)
|
|
61
|
+
parent = node.parent
|
|
62
|
+
return true if parent.nil? || parent.type?(*STATEMENT_BODY_TYPES)
|
|
63
|
+
return parent.loc.begin.nil? if parent.begin_type?
|
|
64
|
+
return !rescue_modifier?(parent) if parent.resbody_type?
|
|
65
|
+
|
|
66
|
+
statement_branch?(node, parent)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def statement_branch?(node, parent)
|
|
70
|
+
case parent.type
|
|
71
|
+
when :if
|
|
72
|
+
!parent.ternary? && !node.equal?(parent.condition)
|
|
73
|
+
when :when, :in_pattern, :while, :until, :for
|
|
74
|
+
node.equal?(parent.body)
|
|
75
|
+
when :case, :case_match
|
|
76
|
+
node.equal?(parent.else_branch)
|
|
77
|
+
else
|
|
78
|
+
false
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
54
82
|
def inconvertible_to_modifier?(if_branch, else_branch)
|
|
55
83
|
multiple_statements?(if_branch) || multiple_statements?(else_branch) ||
|
|
56
84
|
(else_branch.respond_to?(:elsif?) && else_branch.elsif?)
|
|
@@ -123,12 +123,29 @@ module RuboCop
|
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
def register_offense(node, sort_node, sorter, accessor)
|
|
126
|
+
return if code_after_accessor_kept_apart?(node)
|
|
127
|
+
|
|
126
128
|
message = message(node, sorter, accessor)
|
|
127
129
|
add_offense(offense_range(sort_node, node), message: message) do |corrector|
|
|
128
130
|
autocorrect(corrector, node, sort_node, sorter, accessor)
|
|
129
131
|
end
|
|
130
132
|
end
|
|
131
133
|
|
|
134
|
+
def code_after_accessor_kept_apart?(node)
|
|
135
|
+
return false if with_logical_operator?(node)
|
|
136
|
+
|
|
137
|
+
source = before_accessor_source(node)
|
|
138
|
+
return false if !source.include?("\n") || source.strip.empty?
|
|
139
|
+
|
|
140
|
+
rest = code_after_accessor(node)
|
|
141
|
+
|
|
142
|
+
!rest.empty? && !rest.match?(/\A(#|&?\.|[)\]},])/)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def code_after_accessor(node)
|
|
146
|
+
processed_source.lines[node.last_line - 1][node.source_range.last_column..].strip
|
|
147
|
+
end
|
|
148
|
+
|
|
132
149
|
def offense_range(sort_node, node)
|
|
133
150
|
range_between(sort_node.loc.selector.begin_pos, node.source_range.end_pos)
|
|
134
151
|
end
|
|
@@ -146,12 +163,29 @@ module RuboCop
|
|
|
146
163
|
end
|
|
147
164
|
|
|
148
165
|
def autocorrect(corrector, node, sort_node, sorter, accessor)
|
|
149
|
-
# Remove accessor, e.g. `first` or `[-1]`.
|
|
150
|
-
corrector.remove(range_between(accessor_start(node), node.source_range.end_pos))
|
|
151
166
|
# Replace "sort" or "sort_by" with the appropriate min/max method.
|
|
152
167
|
corrector.replace(sort_node.loc.selector, suggestion(sorter, accessor, arg_value(node)))
|
|
153
|
-
|
|
154
|
-
|
|
168
|
+
remove_accessor(corrector, node)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def remove_accessor(corrector, node)
|
|
172
|
+
if removable_line_break_before_accessor?(node)
|
|
173
|
+
corrector.remove(node.receiver.source_range.end.join(node.source_range.end))
|
|
174
|
+
else
|
|
175
|
+
corrector.remove(range_between(accessor_start(node), node.source_range.end_pos))
|
|
176
|
+
|
|
177
|
+
replace_with_logical_operator(corrector, node) if with_logical_operator?(node)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def removable_line_break_before_accessor?(node)
|
|
182
|
+
source = before_accessor_source(node)
|
|
183
|
+
|
|
184
|
+
source.include?("\n") && source.strip.empty?
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def before_accessor_source(node)
|
|
188
|
+
node.receiver.source_range.end.join((node.loc.dot || node.loc.selector).begin).source
|
|
155
189
|
end
|
|
156
190
|
|
|
157
191
|
def replace_with_logical_operator(corrector, node)
|