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
|
@@ -85,7 +85,7 @@ module RuboCop
|
|
|
85
85
|
/xi.freeze
|
|
86
86
|
|
|
87
87
|
def self.autocorrect_incompatible_with
|
|
88
|
-
[Style::MethodCallWithArgsParentheses]
|
|
88
|
+
[Style::MethodCallWithArgsParentheses, Style::MethodDefParentheses]
|
|
89
89
|
end
|
|
90
90
|
|
|
91
91
|
def on_block(node)
|
|
@@ -122,6 +122,7 @@ module RuboCop
|
|
|
122
122
|
def on_new_investigation
|
|
123
123
|
@breakable_range_by_line_index = {}
|
|
124
124
|
@breakable_string_delimiters = {}
|
|
125
|
+
@breakable_strings = {}
|
|
125
126
|
@endless_methods_by_line = {}
|
|
126
127
|
@heredocs = nil
|
|
127
128
|
|
|
@@ -207,6 +208,7 @@ module RuboCop
|
|
|
207
208
|
def check_for_breakable_node(node)
|
|
208
209
|
breakable_node = extract_breakable_node(node, max)
|
|
209
210
|
return if breakable_node.nil?
|
|
211
|
+
return if compact_nested_array_break?(node, breakable_node)
|
|
210
212
|
|
|
211
213
|
line_index = breakable_node.first_line - 1
|
|
212
214
|
range = breakable_node.source_range
|
|
@@ -217,6 +219,20 @@ module RuboCop
|
|
|
217
219
|
breakable_range_by_line_index[line_index] = range
|
|
218
220
|
end
|
|
219
221
|
|
|
222
|
+
def compact_nested_array_break?(node, breakable_node)
|
|
223
|
+
return false if !node.array_type? || !node.square_brackets?
|
|
224
|
+
return false unless breakable_node.equal?(node.children.first)
|
|
225
|
+
return false unless breakable_node.source.start_with?('[')
|
|
226
|
+
|
|
227
|
+
compact_array_brackets_enforced?
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def compact_array_brackets_enforced?
|
|
231
|
+
return false unless config.cop_enabled?('Layout/SpaceInsideArrayLiteralBrackets')
|
|
232
|
+
|
|
233
|
+
config.for_cop('Layout/SpaceInsideArrayLiteralBrackets')['EnforcedStyle'] == 'compact'
|
|
234
|
+
end
|
|
235
|
+
|
|
220
236
|
def check_for_breakable_semicolons(processed_source)
|
|
221
237
|
tokens = processed_source.tokens.select { |t| t.type == :tSEMI }
|
|
222
238
|
tokens.reverse_each do |token|
|
|
@@ -238,6 +254,7 @@ module RuboCop
|
|
|
238
254
|
breakable_range_by_line_index[line_index] = range_between(pos, pos + 1)
|
|
239
255
|
end
|
|
240
256
|
|
|
257
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
241
258
|
def check_for_breakable_str(node)
|
|
242
259
|
line_index = node.loc.line - 1
|
|
243
260
|
return if breakable_range_by_line_index[line_index]
|
|
@@ -248,6 +265,7 @@ module RuboCop
|
|
|
248
265
|
|
|
249
266
|
breakable_range_by_line_index[line_index] = range_between(pos, pos + 1)
|
|
250
267
|
breakable_string_delimiters[line_index] = delimiter
|
|
268
|
+
breakable_strings[line_index] = node
|
|
251
269
|
end
|
|
252
270
|
|
|
253
271
|
def check_for_breakable_dstr(node) # rubocop:disable Metrics/AbcSize
|
|
@@ -301,7 +319,32 @@ module RuboCop
|
|
|
301
319
|
return unless (pos = breakable_string_range(node))
|
|
302
320
|
|
|
303
321
|
content_begin_pos = node.loc?(:begin) ? node.loc.begin.end_pos : source_range.begin_pos
|
|
304
|
-
|
|
322
|
+
if blank_left_part?(node, content_begin_pos, pos)
|
|
323
|
+
pos = breakable_string_range_at_limit(source_range)
|
|
324
|
+
end
|
|
325
|
+
pos.end_pos if pos && leaves_two_parts?(node, content_begin_pos, pos)
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def leaves_two_parts?(node, content_begin_pos, pos)
|
|
329
|
+
pos.end_pos > content_begin_pos && !blank_rest?(node, pos.end_pos)
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
def blank_left_part?(node, content_begin_pos, pos)
|
|
333
|
+
return false unless pos.end_pos > content_begin_pos
|
|
334
|
+
return false unless starts_after_quote?(node)
|
|
335
|
+
|
|
336
|
+
blank_between?(content_begin_pos, pos.end_pos)
|
|
337
|
+
end
|
|
338
|
+
|
|
339
|
+
def starts_after_quote?(node)
|
|
340
|
+
return true if node.loc?(:begin)
|
|
341
|
+
|
|
342
|
+
quote = node.parent&.loc&.begin if node.parent&.dstr_type?
|
|
343
|
+
quote ? quote.end_pos == node.source_range.begin_pos : false
|
|
344
|
+
end
|
|
345
|
+
|
|
346
|
+
def blank_between?(begin_pos, end_pos)
|
|
347
|
+
range_between(begin_pos, end_pos).source.strip.empty?
|
|
305
348
|
end
|
|
306
349
|
|
|
307
350
|
# Locate where to break a string that is too long, ensuring that escape characters
|
|
@@ -325,11 +368,17 @@ module RuboCop
|
|
|
325
368
|
|
|
326
369
|
def breakable_space_position(node, substr)
|
|
327
370
|
limit = string_content_length(node) - 1
|
|
328
|
-
space_pos = substr.
|
|
329
|
-
space_pos =
|
|
371
|
+
space_pos = space_before_word(node, substr.length - 1)
|
|
372
|
+
space_pos = space_before_word(node, limit - 1) if space_pos && space_pos + 1 > limit
|
|
330
373
|
space_pos
|
|
331
374
|
end
|
|
332
375
|
|
|
376
|
+
def space_before_word(node, max_pos)
|
|
377
|
+
return if max_pos.negative?
|
|
378
|
+
|
|
379
|
+
node.source.rindex(/\s(?=\S)/, max_pos)
|
|
380
|
+
end
|
|
381
|
+
|
|
333
382
|
def escape_sequence_start(text)
|
|
334
383
|
text.match(ESCAPE_SEQUENCE_TAIL)&.begin(1)
|
|
335
384
|
end
|
|
@@ -339,10 +388,25 @@ module RuboCop
|
|
|
339
388
|
return if adjustment.abs > source_range.size
|
|
340
389
|
|
|
341
390
|
cut = source_range.adjust(end_pos: adjustment)
|
|
391
|
+
cut = cut.resize(size_before_whitespace_run(source_range.source, cut.size))
|
|
342
392
|
escape_pos = escape_sequence_start(cut.source)
|
|
393
|
+
|
|
343
394
|
escape_pos ? source_range.resize(escape_pos) : cut
|
|
344
395
|
end
|
|
345
396
|
|
|
397
|
+
def size_before_whitespace_run(text, size)
|
|
398
|
+
return size if size.zero?
|
|
399
|
+
return size unless text[size]&.match?(/\s/)
|
|
400
|
+
|
|
401
|
+
text.rindex(/\S/, size - 1) || size
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def blank_rest?(node, break_pos)
|
|
405
|
+
offset = break_pos - node.source_range.begin_pos
|
|
406
|
+
|
|
407
|
+
node.source[offset...string_content_length(node)].strip.empty?
|
|
408
|
+
end
|
|
409
|
+
|
|
346
410
|
def string_content_length(node)
|
|
347
411
|
content_end = node.loc?(:end) ? node.loc.end.begin_pos : node.source_range.end_pos
|
|
348
412
|
|
|
@@ -360,7 +424,9 @@ module RuboCop
|
|
|
360
424
|
def opens_string?(begin_node)
|
|
361
425
|
quote = begin_node.parent.loc.begin
|
|
362
426
|
|
|
363
|
-
|
|
427
|
+
return false unless quote
|
|
428
|
+
|
|
429
|
+
blank_between?(quote.end_pos, begin_node.source_range.begin_pos)
|
|
364
430
|
end
|
|
365
431
|
|
|
366
432
|
def breakable_range_by_line_index
|
|
@@ -375,6 +441,10 @@ module RuboCop
|
|
|
375
441
|
@breakable_string_delimiters ||= {}
|
|
376
442
|
end
|
|
377
443
|
|
|
444
|
+
def breakable_strings
|
|
445
|
+
@breakable_strings ||= {}
|
|
446
|
+
end
|
|
447
|
+
|
|
378
448
|
def heredocs
|
|
379
449
|
@heredocs ||= extract_heredocs(processed_source.ast)
|
|
380
450
|
end
|
|
@@ -431,10 +501,38 @@ module RuboCop
|
|
|
431
501
|
"\n"
|
|
432
502
|
end
|
|
433
503
|
|
|
434
|
-
|
|
504
|
+
break_ranges(line_index).each do |range|
|
|
505
|
+
corrector.insert_before(range, insertion)
|
|
506
|
+
end
|
|
435
507
|
end
|
|
436
508
|
end
|
|
437
509
|
|
|
510
|
+
def break_ranges(line_index)
|
|
511
|
+
return [] if breakable_range.nil?
|
|
512
|
+
return [breakable_range] unless (node = breakable_strings[line_index])&.loc?(:end)
|
|
513
|
+
|
|
514
|
+
string_break_ranges(node, breakable_string_delimiters[line_index])
|
|
515
|
+
end
|
|
516
|
+
|
|
517
|
+
def string_break_ranges(node, delimiter)
|
|
518
|
+
ranges = [breakable_range]
|
|
519
|
+
pos = breakable_range.begin_pos
|
|
520
|
+
|
|
521
|
+
while (pos = next_string_break_position(node, pos, delimiter))
|
|
522
|
+
ranges << range_between(pos, pos + 1)
|
|
523
|
+
end
|
|
524
|
+
|
|
525
|
+
ranges
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
def next_string_break_position(node, pos, delimiter)
|
|
529
|
+
rest = parse("#{delimiter}#{node.source_range.with(begin_pos: pos).source}").ast
|
|
530
|
+
return unless rest&.str_type?
|
|
531
|
+
return unless (rest_pos = breakable_string_position(rest))
|
|
532
|
+
|
|
533
|
+
pos + rest_pos - delimiter.length
|
|
534
|
+
end
|
|
535
|
+
|
|
438
536
|
def excess_range(uri_range, line, line_index)
|
|
439
537
|
excessive_position = if uri_range && uri_range.begin < max
|
|
440
538
|
uri_range.end
|
|
@@ -106,11 +106,13 @@ module RuboCop
|
|
|
106
106
|
ALWAYS_SAME_LINE_MESSAGE = 'Closing hash brace must be on the same ' \
|
|
107
107
|
'line as the last hash element.'
|
|
108
108
|
|
|
109
|
-
# Moving the closing brace
|
|
110
|
-
# `
|
|
111
|
-
# the brace
|
|
109
|
+
# Moving the closing brace after a method call value while
|
|
110
|
+
# `Layout/MultilineMethodCallBraceLayout` moves that call's closing parenthesis
|
|
111
|
+
# before a comment in the same pass places the brace after the comment.
|
|
112
|
+
# Moving it while `Style/HashAsLastArrayItem` or `Style/RedundantDoubleSplatHashBraces`
|
|
113
|
+
# removes the braces in the same pass leaves the brace behind.
|
|
112
114
|
def self.autocorrect_incompatible_with
|
|
113
|
-
[Style::HashAsLastArrayItem, Style::RedundantDoubleSplatHashBraces]
|
|
115
|
+
[Layout::MultilineMethodCallBraceLayout, Style::HashAsLastArrayItem, Style::RedundantDoubleSplatHashBraces]
|
|
114
116
|
end
|
|
115
117
|
|
|
116
118
|
def on_hash(node)
|
|
@@ -102,7 +102,7 @@ module RuboCop
|
|
|
102
102
|
def autocorrect(corrector, node)
|
|
103
103
|
if @send_node.block_node
|
|
104
104
|
correct_selector_only(corrector, node)
|
|
105
|
-
correct_block(corrector, @send_node.block_node)
|
|
105
|
+
correct_block(corrector, @send_node.block_node, node.first_line)
|
|
106
106
|
else
|
|
107
107
|
AlignmentCorrector.correct(corrector, processed_source, node, @column_delta)
|
|
108
108
|
end
|
|
@@ -114,10 +114,21 @@ module RuboCop
|
|
|
114
114
|
AlignmentCorrector.correct(corrector, processed_source, selector_range, @column_delta)
|
|
115
115
|
end
|
|
116
116
|
|
|
117
|
-
def correct_block(corrector, block_node)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
def correct_block(corrector, block_node, selector_line)
|
|
118
|
+
lines_to_shift = block_lines(block_node) - [selector_line]
|
|
119
|
+
|
|
120
|
+
lines_to_shift.each do |line|
|
|
121
|
+
line_range = processed_source.buffer.line_range(line)
|
|
122
|
+
|
|
123
|
+
AlignmentCorrector.correct(corrector, processed_source, line_range, @column_delta)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def block_lines(block_node)
|
|
128
|
+
body = block_node.body
|
|
129
|
+
lines = body ? (body.first_line..body.last_line).to_a : []
|
|
130
|
+
|
|
131
|
+
(lines << block_node.loc.end.line).uniq
|
|
121
132
|
end
|
|
122
133
|
|
|
123
134
|
def relevant_node?(send_node)
|
|
@@ -25,10 +25,10 @@ module RuboCop
|
|
|
25
25
|
|
|
26
26
|
MSG = 'Put method call on a separate line if chained to a single line block.'
|
|
27
27
|
|
|
28
|
-
#
|
|
29
|
-
#
|
|
28
|
+
# These cops rewrite a method chained to the block in the same pass,
|
|
29
|
+
# which must not start a line of its own.
|
|
30
30
|
def self.autocorrect_incompatible_with
|
|
31
|
-
[Style::FloatDivision, Style::MapToHash, Style::NilComparison]
|
|
31
|
+
[Style::FloatDivision, Style::MapToHash, Style::NilComparison, Style::RedundantSort]
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
def on_send(node)
|
|
@@ -108,14 +108,9 @@ module RuboCop
|
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
def left_ref_bracket(node, tokens)
|
|
111
|
-
|
|
112
|
-
previous_token = previous_token(current_token)
|
|
111
|
+
bracket_pos = node.loc.selector.begin_pos
|
|
113
112
|
|
|
114
|
-
|
|
115
|
-
tokens.find(&:left_ref_bracket?)
|
|
116
|
-
else
|
|
117
|
-
current_token
|
|
118
|
-
end
|
|
113
|
+
tokens.find { |token| token.left_ref_bracket? && token.begin_pos == bracket_pos }
|
|
119
114
|
end
|
|
120
115
|
|
|
121
116
|
def closing_bracket(tokens, opening_bracket)
|
|
@@ -129,11 +124,6 @@ module RuboCop
|
|
|
129
124
|
end
|
|
130
125
|
end
|
|
131
126
|
|
|
132
|
-
def previous_token(current_token)
|
|
133
|
-
index = processed_source.tokens.index(current_token)
|
|
134
|
-
index.nil? || index.zero? ? nil : processed_source.tokens[index - 1]
|
|
135
|
-
end
|
|
136
|
-
|
|
137
127
|
def empty_config
|
|
138
128
|
cop_config['EnforcedStyleForEmptyBrackets']
|
|
139
129
|
end
|
|
@@ -55,7 +55,8 @@ module RuboCop
|
|
|
55
55
|
return node if first_argument_is_regexp?(node) || !node.parent
|
|
56
56
|
|
|
57
57
|
if (node.parent.send_type? && node.receiver) ||
|
|
58
|
-
method_chain_to_regexp_receiver?(node, regexp_receiver)
|
|
58
|
+
method_chain_to_regexp_receiver?(node, regexp_receiver) ||
|
|
59
|
+
part_of_hash_argument?(node)
|
|
59
60
|
node = find_offense_node(node.parent, regexp_receiver)
|
|
60
61
|
end
|
|
61
62
|
|
|
@@ -72,6 +73,10 @@ module RuboCop
|
|
|
72
73
|
|
|
73
74
|
parent.parent && parent_receiver.receiver == regexp_receiver
|
|
74
75
|
end
|
|
76
|
+
|
|
77
|
+
def part_of_hash_argument?(node)
|
|
78
|
+
node.pair_type? || node.parent.pair_type? || (node.hash_type? && !node.braces?)
|
|
79
|
+
end
|
|
75
80
|
end
|
|
76
81
|
end
|
|
77
82
|
end
|
|
@@ -34,6 +34,10 @@ module RuboCop
|
|
|
34
34
|
|
|
35
35
|
MSG = 'Put a method call with a HEREDOC receiver on the same line as the HEREDOC opening.'
|
|
36
36
|
|
|
37
|
+
def self.autocorrect_incompatible_with
|
|
38
|
+
[Style::MethodCallWithArgsParentheses]
|
|
39
|
+
end
|
|
40
|
+
|
|
37
41
|
def on_send(node)
|
|
38
42
|
heredoc = heredoc_node_descendent_receiver(node)
|
|
39
43
|
return unless heredoc
|
|
@@ -140,6 +140,8 @@ module RuboCop
|
|
|
140
140
|
corrected_method: correct_sym_method(to_method)
|
|
141
141
|
)
|
|
142
142
|
add_offense(node, message: message) do |corrector|
|
|
143
|
+
next if part_of_ignored_node?(node)
|
|
144
|
+
|
|
143
145
|
remove_parentheses(corrector, node) if node.parenthesized?
|
|
144
146
|
|
|
145
147
|
corrector.replace(sym_node, correct_sym_method(to_method))
|
|
@@ -60,7 +60,7 @@ module RuboCop
|
|
|
60
60
|
|
|
61
61
|
rest_operands = grouped_operands[begin_of_rest_operands..]
|
|
62
62
|
rest_operands.each do |operand|
|
|
63
|
-
next
|
|
63
|
+
next unless correction_needed?(operand, dot_op, grouped_operands)
|
|
64
64
|
|
|
65
65
|
register_offense(operand, dot_op)
|
|
66
66
|
end
|
|
@@ -100,12 +100,58 @@ module RuboCop
|
|
|
100
100
|
end
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
+
def correction_needed?(operand, dot_op, grouped_operands)
|
|
104
|
+
return false if already_appropriate_call?(operand, dot_op)
|
|
105
|
+
|
|
106
|
+
dot_op == '&.' || receiver_guaranteed?(operand, grouped_operands)
|
|
107
|
+
end
|
|
108
|
+
|
|
103
109
|
def already_appropriate_call?(operand, dot_op)
|
|
104
110
|
return true if operand.safe_navigation? && dot_op == '&.'
|
|
105
111
|
|
|
106
112
|
(operand.dot? || operand.operator_method?) && dot_op == '.'
|
|
107
113
|
end
|
|
108
114
|
|
|
115
|
+
def receiver_guaranteed?(operand, grouped_operands)
|
|
116
|
+
grouped_operands.take_while { |guard| !guard.equal?(operand) }.any? do |guard|
|
|
117
|
+
guaranteed_by?(guard, operand)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def guaranteed_by?(guard, operand)
|
|
122
|
+
return false unless (path = logical_path(guard, operand))
|
|
123
|
+
|
|
124
|
+
truthiness = path.last.first.and_type? ? :truthy : :falsey
|
|
125
|
+
path[0...-1].reverse_each do |node, child|
|
|
126
|
+
return false unless (truthiness = child_truthiness(node, child, truthiness))
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
!guard.csend_type? || truthiness == :truthy
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def logical_path(guard, operand)
|
|
133
|
+
path = []
|
|
134
|
+
child = guard
|
|
135
|
+
|
|
136
|
+
guard.each_ancestor do |node|
|
|
137
|
+
unless node.begin_type?
|
|
138
|
+
return nil unless node.operator_keyword?
|
|
139
|
+
|
|
140
|
+
path << [node, child]
|
|
141
|
+
end
|
|
142
|
+
return path if operand.each_ancestor.any? { |ancestor| ancestor.equal?(node) }
|
|
143
|
+
|
|
144
|
+
child = node
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def child_truthiness(node, child, truthiness)
|
|
149
|
+
deciding = node.and_type? ? :truthy : :falsey
|
|
150
|
+
return truthiness == deciding ? deciding : :unknown if node.lhs.equal?(child)
|
|
151
|
+
|
|
152
|
+
deciding if truthiness == deciding
|
|
153
|
+
end
|
|
154
|
+
|
|
109
155
|
def register_offense(operand, dot_operator)
|
|
110
156
|
offense_range = operand.operator_method? ? operand : operand.loc.dot
|
|
111
157
|
message = dot_operator == '.' ? USE_DOT_MSG : USE_SAFE_NAVIGATION_MSG
|
|
@@ -35,15 +35,13 @@ module RuboCop
|
|
|
35
35
|
ASSIGNMENT_TYPES = %i[lvasgn ivasgn cvasgn gvasgn].freeze
|
|
36
36
|
|
|
37
37
|
def on_def(node)
|
|
38
|
-
return
|
|
38
|
+
return if !node.body || node.void_context?
|
|
39
39
|
|
|
40
40
|
last_expr = last_expression(node.body)
|
|
41
41
|
return unless setter_call_to_local_variable?(last_expr)
|
|
42
42
|
|
|
43
|
-
tracker = MethodVariableTracker.new(node.body)
|
|
44
43
|
receiver, = *last_expr
|
|
45
|
-
|
|
46
|
-
return unless tracker.contain_local_object?(variable_name)
|
|
44
|
+
return unless contain_local_object?(node.body, receiver)
|
|
47
45
|
|
|
48
46
|
loc_name = receiver.loc.name
|
|
49
47
|
|
|
@@ -66,6 +64,11 @@ module RuboCop
|
|
|
66
64
|
expression.is_a?(Array) ? expression.last : expression
|
|
67
65
|
end
|
|
68
66
|
|
|
67
|
+
def contain_local_object?(body, receiver)
|
|
68
|
+
variable_name, = *receiver
|
|
69
|
+
MethodVariableTracker.new(body).contain_local_object?(variable_name)
|
|
70
|
+
end
|
|
71
|
+
|
|
69
72
|
# This class tracks variable assignments in a method body
|
|
70
73
|
# and if a variable contains object passed as argument at the end of
|
|
71
74
|
# the method.
|
|
@@ -76,11 +76,7 @@ module RuboCop
|
|
|
76
76
|
def extract_first_element_over_column_limit(node, elements, max)
|
|
77
77
|
line = node.first_line
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
# can result in changed behavior or a syntax error.
|
|
81
|
-
if node.call_type? && !node.parenthesized? && !first_argument_is_heredoc?(node)
|
|
82
|
-
elements = elements.drop(1)
|
|
83
|
-
end
|
|
79
|
+
elements = elements.drop(1) unless first_element_movable?(node)
|
|
84
80
|
|
|
85
81
|
i = 0
|
|
86
82
|
i += 1 while within_column_limit?(elements[i], max, line)
|
|
@@ -93,7 +89,12 @@ module RuboCop
|
|
|
93
89
|
end
|
|
94
90
|
|
|
95
91
|
# @api private
|
|
96
|
-
|
|
92
|
+
# If a method call or definition is not parenthesized, the first element cannot be moved,
|
|
93
|
+
# because it can result in changed behavior or a syntax error.
|
|
94
|
+
def first_element_movable?(node)
|
|
95
|
+
return !node.arguments.loc.begin.nil? if node.any_def_type?
|
|
96
|
+
return true if !node.call_type? || node.parenthesized?
|
|
97
|
+
|
|
97
98
|
node.first_argument.respond_to?(:heredoc?) && node.first_argument.heredoc?
|
|
98
99
|
end
|
|
99
100
|
|
|
@@ -5,6 +5,8 @@ module RuboCop
|
|
|
5
5
|
# Checks for code on multiple lines that could be rewritten on a single line
|
|
6
6
|
# without changing semantics or exceeding the `Max` parameter of `Layout/LineLength`.
|
|
7
7
|
module CheckSingleLineSuitability
|
|
8
|
+
include LineLengthHelp
|
|
9
|
+
|
|
8
10
|
def suitable_as_single_line?(node)
|
|
9
11
|
!too_long?(node) &&
|
|
10
12
|
!comment_within?(node) &&
|
|
@@ -21,7 +23,7 @@ module RuboCop
|
|
|
21
23
|
return false unless max_line_length
|
|
22
24
|
|
|
23
25
|
lines = processed_source.lines[(line_range.begin - 1)...line_range.end]
|
|
24
|
-
to_single_line(lines.join("\n"))
|
|
26
|
+
line_length(to_single_line(lines.join("\n"))) > max_line_length
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
def to_single_line(source)
|
|
@@ -45,12 +45,44 @@ module RuboCop
|
|
|
45
45
|
|
|
46
46
|
def command_disallowed_in_endless_body?(body)
|
|
47
47
|
return true if body.assignment? && command_call?(assigned_value(body))
|
|
48
|
+
return true if body_disallowed_in_argument?(body)
|
|
49
|
+
return true if negated_command_call?(body)
|
|
48
50
|
|
|
49
51
|
body.each_node(:any_block).any? do |block|
|
|
50
52
|
block.keywords? && command_call?(block.send_node)
|
|
51
53
|
end
|
|
52
54
|
end
|
|
53
55
|
|
|
56
|
+
def body_disallowed_in_argument?(body)
|
|
57
|
+
command_body_in_argument?(body) || do_end_block_body_in_command_argument?(body)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# `private def foo = bar baz` parses only on Ruby 4.0+, and only as the sole argument.
|
|
61
|
+
def command_body_in_argument?(body)
|
|
62
|
+
return false unless command_call?(body)
|
|
63
|
+
|
|
64
|
+
call = argument_receiving_call(body.parent)
|
|
65
|
+
return false if call.nil?
|
|
66
|
+
|
|
67
|
+
target_ruby_version < 4.0 || !call.arguments.one?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def argument_receiving_call(def_node)
|
|
71
|
+
call = def_node.parent
|
|
72
|
+
return unless call&.call_type?
|
|
73
|
+
|
|
74
|
+
call if call.arguments.any? { |argument| argument.equal?(def_node) }
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def do_end_block_body_in_command_argument?(body)
|
|
78
|
+
call = argument_receiving_call(body.parent)
|
|
79
|
+
return false if call.nil? || call.parenthesized?
|
|
80
|
+
|
|
81
|
+
body.each_node(:any_block).any? do |block|
|
|
82
|
+
block.keywords? && !block.send_node.lambda_literal?
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
54
86
|
def assigned_value(node)
|
|
55
87
|
while node.assignment? || node.rescue_type?
|
|
56
88
|
node = node.rescue_type? ? node.body : node.children.last
|
|
@@ -64,6 +96,10 @@ module RuboCop
|
|
|
64
96
|
|
|
65
97
|
node.arguments? && !node.parenthesized? && !node.operator_method? && !node.setter_method?
|
|
66
98
|
end
|
|
99
|
+
|
|
100
|
+
def negated_command_call?(node)
|
|
101
|
+
node.send_type? && node.prefix_bang? && command_call?(node.receiver)
|
|
102
|
+
end
|
|
67
103
|
end
|
|
68
104
|
end
|
|
69
105
|
end
|
|
@@ -60,8 +60,9 @@ module RuboCop
|
|
|
60
60
|
|
|
61
61
|
def deltas(first_pair, current_pair)
|
|
62
62
|
key_delta = key_delta(first_pair, current_pair)
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
shift = separator_shift(current_pair, key_delta)
|
|
64
|
+
separator_delta = separator_delta(first_pair, current_pair, shift)
|
|
65
|
+
value_delta = value_delta(first_pair, current_pair) - shift - separator_delta
|
|
65
66
|
|
|
66
67
|
{ key: key_delta, separator: separator_delta, value: value_delta }
|
|
67
68
|
end
|
|
@@ -78,9 +79,13 @@ module RuboCop
|
|
|
78
79
|
pair.value && pair.key.last_line != pair.value.first_line
|
|
79
80
|
end
|
|
80
81
|
|
|
81
|
-
def
|
|
82
|
+
def separator_shift(current_pair, key_delta)
|
|
83
|
+
current_pair.key.multiline? ? 0 : key_delta
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def separator_delta(first_pair, current_pair, shift)
|
|
82
87
|
if current_pair.hash_rocket?
|
|
83
|
-
hash_rocket_delta(first_pair, current_pair) -
|
|
88
|
+
hash_rocket_delta(first_pair, current_pair) - shift
|
|
84
89
|
else
|
|
85
90
|
0
|
|
86
91
|
end
|
|
@@ -98,7 +98,7 @@ module RuboCop
|
|
|
98
98
|
|
|
99
99
|
# rubocop:disable-next Metrics/AbcSize
|
|
100
100
|
def if_body_source(if_body)
|
|
101
|
-
if
|
|
101
|
+
if unparenthesized_call_with_omitted_value?(if_body)
|
|
102
102
|
"#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
|
|
103
103
|
elsif (value = wrapped_value(if_body))
|
|
104
104
|
prefix = if_body.source_range.begin.join(value.source_range.begin).source
|
|
@@ -110,7 +110,8 @@ module RuboCop
|
|
|
110
110
|
end
|
|
111
111
|
end
|
|
112
112
|
|
|
113
|
-
def
|
|
113
|
+
def unparenthesized_call_with_omitted_value?(if_body)
|
|
114
|
+
return false if !if_body.call_type? || if_body.method?(:[]=) || if_body.parenthesized?
|
|
114
115
|
return false unless (last_argument = if_body.last_argument)
|
|
115
116
|
|
|
116
117
|
last_argument.hash_type? && last_argument.pairs.last&.value_omission?
|
|
@@ -63,9 +63,10 @@ module RuboCop
|
|
|
63
63
|
(send nil? VISIBILITY_SCOPES def)
|
|
64
64
|
PATTERN
|
|
65
65
|
|
|
66
|
+
# A modifier applies to every symbol it is given, not only to a sole argument.
|
|
66
67
|
# @!method visibility_inline_on_method_name?(node, method_name:)
|
|
67
68
|
def_node_matcher :visibility_inline_on_method_name?, <<~PATTERN
|
|
68
|
-
(send nil? VISIBILITY_SCOPES (sym %method_name))
|
|
69
|
+
(send nil? VISIBILITY_SCOPES <(sym %method_name) ...>)
|
|
69
70
|
PATTERN
|
|
70
71
|
end
|
|
71
72
|
end
|
|
@@ -128,7 +128,7 @@ module RuboCop
|
|
|
128
128
|
if child_node.lvar_type?
|
|
129
129
|
parent_node = child_node.parent
|
|
130
130
|
if parent_node.respond_to?(:value_omission?) && parent_node.value_omission?
|
|
131
|
-
corrector.
|
|
131
|
+
corrector.replace(parent_node.loc.operator, ": #{preferred_name}")
|
|
132
132
|
else
|
|
133
133
|
corrector.replace(child_node, preferred_name)
|
|
134
134
|
end
|