rubocop 1.58.0 → 1.60.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +3 -3
- data/config/default.yml +9 -1
- data/lib/rubocop/config.rb +0 -2
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_validator.rb +0 -2
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/exclude_limit.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +5 -1
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +16 -1
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -1
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -0
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +23 -2
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/self_assignment.rb +1 -0
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
- data/lib/rubocop/cop/lint/syntax.rb +6 -3
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
- data/lib/rubocop/cop/naming/block_forwarding.rb +10 -2
- data/lib/rubocop/cop/naming/constant_name.rb +1 -2
- data/lib/rubocop/cop/registry.rb +4 -4
- data/lib/rubocop/cop/security/open.rb +2 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +16 -3
- data/lib/rubocop/cop/style/array_first_last.rb +1 -1
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/collection_compact.rb +7 -6
- data/lib/rubocop/cop/style/combinable_loops.rb +11 -0
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/eval_with_location.rb +0 -11
- data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +29 -4
- data/lib/rubocop/cop/style/hash_except.rb +2 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +39 -2
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +3 -2
- data/lib/rubocop/cop/style/map_to_hash.rb +9 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -3
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -3
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +1 -0
- data/lib/rubocop/cop/style/redundant_each.rb +7 -4
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +8 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +15 -7
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_sort.rb +8 -7
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/sample.rb +2 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +6 -5
- data/lib/rubocop/cop/style/single_argument_dig.rb +5 -2
- data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cops_documentation_generator.rb +11 -1
- data/lib/rubocop/ext/regexp_node.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/json_formatter.rb +0 -1
- data/lib/rubocop/formatter.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/options.rb +0 -8
- data/lib/rubocop/rspec/shared_contexts.rb +6 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/server/cache.rb +0 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +1 -0
- metadata +8 -7
- /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -186,12 +186,12 @@ module RuboCop
|
|
186
186
|
rest_arg, kwrest_arg, _block_arg = *forwardable_args
|
187
187
|
|
188
188
|
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
|
189
|
-
if forward_rest
|
189
|
+
if outside_block?(forward_rest)
|
190
190
|
register_forward_args_offense(def_node.arguments, rest_arg)
|
191
191
|
register_forward_args_offense(send_node, forward_rest)
|
192
192
|
end
|
193
193
|
|
194
|
-
if forward_kwrest
|
194
|
+
if outside_block?(forward_kwrest)
|
195
195
|
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
196
196
|
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
197
197
|
end
|
@@ -250,6 +250,12 @@ module RuboCop
|
|
250
250
|
redundant_arg_names.include?(arg.source) ? arg : nil
|
251
251
|
end
|
252
252
|
|
253
|
+
def outside_block?(node)
|
254
|
+
return false unless node
|
255
|
+
|
256
|
+
node.each_ancestor(:block, :numblock).none?
|
257
|
+
end
|
258
|
+
|
253
259
|
def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
|
254
260
|
add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
|
255
261
|
add_parens_if_missing(def_arguments_or_send, corrector)
|
@@ -340,7 +346,7 @@ module RuboCop
|
|
340
346
|
end
|
341
347
|
|
342
348
|
def classification
|
343
|
-
return nil unless forwarded_rest_arg || forwarded_kwrest_arg
|
349
|
+
return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
|
344
350
|
|
345
351
|
if can_forward_all?
|
346
352
|
:all
|
@@ -424,9 +430,16 @@ module RuboCop
|
|
424
430
|
def no_additional_args?
|
425
431
|
forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
|
426
432
|
|
433
|
+
return false if missing_rest_arg_or_kwrest_arg?
|
434
|
+
|
427
435
|
@def_node.arguments.size == forwardable_count &&
|
428
436
|
@send_node.arguments.size == forwardable_count
|
429
437
|
end
|
438
|
+
|
439
|
+
def missing_rest_arg_or_kwrest_arg?
|
440
|
+
(@rest_arg_name && !forwarded_rest_arg) ||
|
441
|
+
(@kwrest_arg_name && !forwarded_kwrest_arg)
|
442
|
+
end
|
430
443
|
end
|
431
444
|
end
|
432
445
|
end
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
|
7
|
-
# them to use `arr.first` and `arr.instead
|
7
|
+
# them to use `arr.first` and `arr.last` instead.
|
8
8
|
#
|
9
9
|
# The cop is disabled by default due to safety concerns.
|
10
10
|
#
|
@@ -53,7 +53,7 @@ module RuboCop
|
|
53
53
|
|
54
54
|
# @!method reject_method_with_block_pass?(node)
|
55
55
|
def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
|
56
|
-
(
|
56
|
+
(call !nil? {:reject :delete_if :reject!}
|
57
57
|
(block_pass
|
58
58
|
(sym :nil?)))
|
59
59
|
PATTERN
|
@@ -61,21 +61,21 @@ module RuboCop
|
|
61
61
|
# @!method reject_method?(node)
|
62
62
|
def_node_matcher :reject_method?, <<~PATTERN
|
63
63
|
(block
|
64
|
-
(
|
64
|
+
(call
|
65
65
|
!nil? {:reject :delete_if :reject!})
|
66
66
|
$(args ...)
|
67
|
-
(
|
67
|
+
(call
|
68
68
|
$(lvar _) :nil?))
|
69
69
|
PATTERN
|
70
70
|
|
71
71
|
# @!method select_method?(node)
|
72
72
|
def_node_matcher :select_method?, <<~PATTERN
|
73
73
|
(block
|
74
|
-
(
|
74
|
+
(call
|
75
75
|
!nil? {:select :select!})
|
76
76
|
$(args ...)
|
77
|
-
(
|
78
|
-
(
|
77
|
+
(call
|
78
|
+
(call
|
79
79
|
$(lvar _) :nil?) :!))
|
80
80
|
PATTERN
|
81
81
|
|
@@ -91,6 +91,7 @@ module RuboCop
|
|
91
91
|
|
92
92
|
add_offense(range, message: message) { |corrector| corrector.replace(range, good) }
|
93
93
|
end
|
94
|
+
alias on_csend on_send
|
94
95
|
|
95
96
|
private
|
96
97
|
|
@@ -105,6 +105,17 @@ module RuboCop
|
|
105
105
|
def combine_with_left_sibling(corrector, node)
|
106
106
|
corrector.remove(node.left_sibling.body.source_range.end.join(node.left_sibling.loc.end))
|
107
107
|
corrector.remove(node.source_range.begin.join(node.body.source_range.begin))
|
108
|
+
|
109
|
+
correct_end_of_block(corrector, node)
|
110
|
+
end
|
111
|
+
|
112
|
+
def correct_end_of_block(corrector, node)
|
113
|
+
return unless node.left_sibling.respond_to?(:braces?)
|
114
|
+
return if node.right_sibling&.block_type? || node.right_sibling&.numblock_type?
|
115
|
+
|
116
|
+
end_of_block = node.left_sibling.braces? ? '}' : ' end'
|
117
|
+
corrector.remove(node.loc.end)
|
118
|
+
corrector.insert_before(node.source_range.end, end_of_block)
|
108
119
|
end
|
109
120
|
end
|
110
121
|
end
|
@@ -49,12 +49,12 @@ module RuboCop
|
|
49
49
|
class DateTime < Base
|
50
50
|
extend AutoCorrector
|
51
51
|
|
52
|
-
CLASS_MSG = 'Prefer Time over DateTime
|
53
|
-
COERCION_MSG = 'Do not use
|
52
|
+
CLASS_MSG = 'Prefer `Time` over `DateTime`.'
|
53
|
+
COERCION_MSG = 'Do not use `#to_datetime`.'
|
54
54
|
|
55
55
|
# @!method date_time?(node)
|
56
56
|
def_node_matcher :date_time?, <<~PATTERN
|
57
|
-
(
|
57
|
+
(call (const {nil? (cbase)} :DateTime) ...)
|
58
58
|
PATTERN
|
59
59
|
|
60
60
|
# @!method historic_date?(node)
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
64
64
|
|
65
65
|
# @!method to_datetime?(node)
|
66
66
|
def_node_matcher :to_datetime?, <<~PATTERN
|
67
|
-
(
|
67
|
+
(call _ :to_datetime)
|
68
68
|
PATTERN
|
69
69
|
|
70
70
|
def on_send(node)
|
@@ -75,6 +75,7 @@ module RuboCop
|
|
75
75
|
|
76
76
|
add_offense(node, message: message) { |corrector| autocorrect(corrector, node) }
|
77
77
|
end
|
78
|
+
alias on_csend on_send
|
78
79
|
|
79
80
|
private
|
80
81
|
|
@@ -32,27 +32,27 @@ module RuboCop
|
|
32
32
|
|
33
33
|
send_node = node.send_node
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
add_offense(range) do |corrector|
|
35
|
+
add_offense(send_node) do |corrector|
|
38
36
|
range_type, min, max = each_range(node)
|
39
37
|
|
40
38
|
max += 1 if range_type == :irange
|
41
39
|
|
42
|
-
corrector.replace(
|
40
|
+
corrector.replace(send_node, "#{max - min}.times")
|
43
41
|
end
|
44
42
|
end
|
45
43
|
|
46
44
|
private
|
47
45
|
|
48
46
|
def offending?(node)
|
47
|
+
return false unless node.arguments.empty?
|
48
|
+
|
49
49
|
each_range_with_zero_origin?(node) || each_range_without_block_argument?(node)
|
50
50
|
end
|
51
51
|
|
52
52
|
# @!method each_range(node)
|
53
53
|
def_node_matcher :each_range, <<~PATTERN
|
54
54
|
(block
|
55
|
-
(
|
55
|
+
(call
|
56
56
|
(begin
|
57
57
|
(${irange erange}
|
58
58
|
(int $_) (int $_)))
|
@@ -64,7 +64,7 @@ module RuboCop
|
|
64
64
|
# @!method each_range_with_zero_origin?(node)
|
65
65
|
def_node_matcher :each_range_with_zero_origin?, <<~PATTERN
|
66
66
|
(block
|
67
|
-
(
|
67
|
+
(call
|
68
68
|
(begin
|
69
69
|
({irange erange}
|
70
70
|
(int 0) (int _)))
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
# @!method each_range_without_block_argument?(node)
|
77
77
|
def_node_matcher :each_range_without_block_argument?, <<~PATTERN
|
78
78
|
(block
|
79
|
-
(
|
79
|
+
(call
|
80
80
|
(begin
|
81
81
|
({irange erange}
|
82
82
|
(int _) (int _)))
|
@@ -58,12 +58,12 @@ module RuboCop
|
|
58
58
|
|
59
59
|
# @!method each_with_object_block_candidate?(node)
|
60
60
|
def_node_matcher :each_with_object_block_candidate?, <<~PATTERN
|
61
|
-
(block $(
|
61
|
+
(block $(call _ {:inject :reduce} _) $_ $_)
|
62
62
|
PATTERN
|
63
63
|
|
64
64
|
# @!method each_with_object_numblock_candidate?(node)
|
65
65
|
def_node_matcher :each_with_object_numblock_candidate?, <<~PATTERN
|
66
|
-
(numblock $(
|
66
|
+
(numblock $(call _ {:inject :reduce} _) 2 $_)
|
67
67
|
PATTERN
|
68
68
|
|
69
69
|
def autocorrect_block(corrector, node, return_value)
|
@@ -128,17 +128,6 @@ module RuboCop
|
|
128
128
|
node.method?(:eval) ? node.arguments.size >= 2 : true
|
129
129
|
end
|
130
130
|
|
131
|
-
# FIXME: It's a Style/ConditionalAssignment's false positive.
|
132
|
-
# rubocop:disable Style/ConditionalAssignment
|
133
|
-
def with_lineno?(node)
|
134
|
-
if node.method?(:eval)
|
135
|
-
node.arguments.size == 4
|
136
|
-
else
|
137
|
-
node.arguments.size == 3
|
138
|
-
end
|
139
|
-
end
|
140
|
-
# rubocop:enable Style/ConditionalAssignment
|
141
|
-
|
142
131
|
def add_offense_for_incorrect_line(method_name, line_node, sign, line_diff)
|
143
132
|
expected = expected_line(sign, line_diff)
|
144
133
|
message = format(MSG_INCORRECT_LINE,
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
30
30
|
|
31
31
|
# @!method exact_regexp_match(node)
|
32
32
|
def_node_matcher :exact_regexp_match, <<~PATTERN
|
33
|
-
(
|
33
|
+
(call
|
34
34
|
_ {:=~ :=== :!~ :match :match?}
|
35
35
|
(regexp
|
36
36
|
(str $_)
|
@@ -49,6 +49,7 @@ module RuboCop
|
|
49
49
|
corrector.replace(node, prefer)
|
50
50
|
end
|
51
51
|
end
|
52
|
+
alias on_csend on_send
|
52
53
|
|
53
54
|
private
|
54
55
|
|
@@ -58,18 +58,20 @@ module RuboCop
|
|
58
58
|
|
59
59
|
# rubocop:disable Metrics/AbcSize
|
60
60
|
def on_block(node)
|
61
|
+
return unless handleable?(node)
|
62
|
+
|
61
63
|
kv_each(node) do |target, method|
|
62
64
|
register_kv_offense(target, method) and return
|
63
65
|
end
|
64
66
|
|
65
67
|
return unless (key, value = each_arguments(node))
|
66
68
|
|
67
|
-
if unused_block_arg_exist?(node, value
|
69
|
+
if unused_block_arg_exist?(node, value)
|
68
70
|
message = message('each_key', node.method_name, value.source)
|
69
71
|
unused_range = key.source_range.end.join(value.source_range.end)
|
70
72
|
|
71
73
|
register_each_args_offense(node, message, 'each_key', unused_range)
|
72
|
-
elsif unused_block_arg_exist?(node, key
|
74
|
+
elsif unused_block_arg_exist?(node, key)
|
73
75
|
message = message('each_value', node.method_name, key.source)
|
74
76
|
unused_range = key.source_range.begin.join(value.source_range.begin)
|
75
77
|
|
@@ -88,6 +90,12 @@ module RuboCop
|
|
88
90
|
|
89
91
|
private
|
90
92
|
|
93
|
+
def handleable?(node)
|
94
|
+
return false unless (root_receiver = root_receiver(node))
|
95
|
+
|
96
|
+
!root_receiver.literal? || root_receiver.hash_type?
|
97
|
+
end
|
98
|
+
|
91
99
|
def register_kv_offense(target, method)
|
92
100
|
return unless (parent_receiver = target.receiver.receiver)
|
93
101
|
return if allowed_receiver?(parent_receiver)
|
@@ -99,8 +107,16 @@ module RuboCop
|
|
99
107
|
end
|
100
108
|
end
|
101
109
|
|
102
|
-
def unused_block_arg_exist?(node,
|
103
|
-
node.body.each_descendant(:lvar).map(&:source)
|
110
|
+
def unused_block_arg_exist?(node, block_arg)
|
111
|
+
lvar_sources = node.body.each_descendant(:lvar).map(&:source)
|
112
|
+
|
113
|
+
if block_arg.mlhs_type?
|
114
|
+
block_arg.each_descendant(:arg, :restarg).all? do |block_arg|
|
115
|
+
lvar_sources.none?(block_arg.source.delete_prefix('*'))
|
116
|
+
end
|
117
|
+
else
|
118
|
+
lvar_sources.none?(block_arg.source.delete_prefix('*'))
|
119
|
+
end
|
104
120
|
end
|
105
121
|
|
106
122
|
def message(prefer, method_name, unused_code)
|
@@ -127,6 +143,15 @@ module RuboCop
|
|
127
143
|
end
|
128
144
|
end
|
129
145
|
|
146
|
+
def root_receiver(node)
|
147
|
+
receiver = node.receiver
|
148
|
+
if receiver&.receiver
|
149
|
+
root_receiver(receiver)
|
150
|
+
else
|
151
|
+
receiver
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
130
155
|
def format_message(method_name, current)
|
131
156
|
format(MSG, prefer: "each_#{method_name[0..-2]}", current: current)
|
132
157
|
end
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
# @!method bad_method_with_poro?(node)
|
44
44
|
def_node_matcher :bad_method_with_poro?, <<~PATTERN
|
45
45
|
(block
|
46
|
-
(
|
46
|
+
(call _ _)
|
47
47
|
(args
|
48
48
|
$(arg _)
|
49
49
|
(arg _))
|
@@ -86,6 +86,7 @@ module RuboCop
|
|
86
86
|
corrector.replace(range, preferred_method)
|
87
87
|
end
|
88
88
|
end
|
89
|
+
alias on_csend on_send
|
89
90
|
|
90
91
|
private
|
91
92
|
|
@@ -158,7 +158,10 @@ module RuboCop
|
|
158
158
|
if head.assignment?
|
159
159
|
# The `send` node is used instead of the `indexasgn` node, so `name` cannot be used.
|
160
160
|
# https://github.com/rubocop/rubocop-ast/blob/v1.29.0/lib/rubocop/ast/node/indexasgn_node.rb
|
161
|
-
|
161
|
+
#
|
162
|
+
# FIXME: It would be better to update `RuboCop::AST::OpAsgnNode` or its subclasses to
|
163
|
+
# handle `self.foo ||= value` as a solution, instead of using `head.node_parts[0].to_s`.
|
164
|
+
assigned_value = head.send_type? ? head.receiver.source : head.node_parts[0].to_s
|
162
165
|
|
163
166
|
return if condition_variable == assigned_value
|
164
167
|
end
|
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
class InvertibleUnlessCondition < Base
|
52
52
|
extend AutoCorrector
|
53
53
|
|
54
|
-
MSG = '
|
54
|
+
MSG = 'Prefer `%<prefer>s` over `%<current>s`.'
|
55
55
|
|
56
56
|
def on_if(node)
|
57
57
|
return unless node.unless?
|
@@ -59,7 +59,10 @@ module RuboCop
|
|
59
59
|
condition = node.condition
|
60
60
|
return unless invertible?(condition)
|
61
61
|
|
62
|
-
|
62
|
+
message = format(MSG, prefer: "#{node.inverse_keyword} #{preferred_condition(condition)}",
|
63
|
+
current: "#{node.keyword} #{condition.source}")
|
64
|
+
|
65
|
+
add_offense(node, message: message) do |corrector|
|
63
66
|
corrector.replace(node.loc.keyword, node.inverse_keyword)
|
64
67
|
autocorrect(corrector, condition)
|
65
68
|
end
|
@@ -88,6 +91,40 @@ module RuboCop
|
|
88
91
|
(argument.const_type? && argument.short_name.to_s.upcase != argument.short_name.to_s)
|
89
92
|
end
|
90
93
|
|
94
|
+
def preferred_condition(node)
|
95
|
+
case node.type
|
96
|
+
when :begin then "(#{preferred_condition(node.children.first)})"
|
97
|
+
when :send then preferred_send_condition(node)
|
98
|
+
when :or, :and then preferred_logical_condition(node)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def preferred_send_condition(node)
|
103
|
+
receiver_source = node.receiver.source
|
104
|
+
return receiver_source if node.method?(:!)
|
105
|
+
|
106
|
+
inverse_method_name = inverse_methods[node.method_name]
|
107
|
+
return "#{receiver_source}.#{inverse_method_name}" unless node.arguments?
|
108
|
+
|
109
|
+
argument_list = node.arguments.map(&:source).join(', ')
|
110
|
+
if node.operator_method?
|
111
|
+
return "#{receiver_source} #{inverse_method_name} #{argument_list}"
|
112
|
+
end
|
113
|
+
|
114
|
+
if node.parenthesized?
|
115
|
+
return "#{receiver_source}.#{inverse_method_name}(#{argument_list})"
|
116
|
+
end
|
117
|
+
|
118
|
+
"#{receiver_source}.#{inverse_method_name} #{argument_list}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def preferred_logical_condition(node)
|
122
|
+
preferred_lhs = preferred_condition(node.lhs)
|
123
|
+
preferred_rhs = preferred_condition(node.rhs)
|
124
|
+
|
125
|
+
"#{preferred_lhs} #{node.inverse_operator} #{preferred_rhs}"
|
126
|
+
end
|
127
|
+
|
91
128
|
def autocorrect(corrector, node)
|
92
129
|
case node.type
|
93
130
|
when :begin
|
@@ -44,9 +44,9 @@ module RuboCop
|
|
44
44
|
|
45
45
|
# @!method map_and_compact?(node)
|
46
46
|
def_node_matcher :map_and_compact?, <<~RUBY
|
47
|
-
(
|
47
|
+
(call
|
48
48
|
(block
|
49
|
-
(
|
49
|
+
(call _ :map)
|
50
50
|
(args
|
51
51
|
$(arg _))
|
52
52
|
{
|
@@ -85,6 +85,7 @@ module RuboCop
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
end
|
88
|
+
alias on_csend on_send
|
88
89
|
|
89
90
|
private
|
90
91
|
|
@@ -37,8 +37,8 @@ module RuboCop
|
|
37
37
|
MSG = 'Pass a block to `to_h` instead of calling `%<method>s%<dot>sto_h`.'
|
38
38
|
RESTRICT_ON_SEND = %i[to_h].freeze
|
39
39
|
|
40
|
-
# @!method map_to_h
|
41
|
-
def_node_matcher :map_to_h
|
40
|
+
# @!method map_to_h(node)
|
41
|
+
def_node_matcher :map_to_h, <<~PATTERN
|
42
42
|
{
|
43
43
|
$(call ({block numblock} $(call _ {:map :collect}) ...) :to_h)
|
44
44
|
$(call $(call _ {:map :collect} (block_pass sym)) :to_h)
|
@@ -50,9 +50,9 @@ module RuboCop
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def on_send(node)
|
53
|
-
return unless (to_h_node, map_node = map_to_h
|
53
|
+
return unless (to_h_node, map_node = map_to_h(node))
|
54
54
|
|
55
|
-
message = format(MSG, method: map_node.loc.selector.source, dot:
|
55
|
+
message = format(MSG, method: map_node.loc.selector.source, dot: to_h_node.loc.dot.source)
|
56
56
|
add_offense(map_node.loc.selector, message: message) do |corrector|
|
57
57
|
# If the `to_h` call already has a block, do not autocorrect.
|
58
58
|
next if to_h_node.block_node
|
@@ -64,12 +64,17 @@ module RuboCop
|
|
64
64
|
|
65
65
|
private
|
66
66
|
|
67
|
+
# rubocop:disable Metrics/AbcSize
|
67
68
|
def autocorrect(corrector, to_h, map)
|
68
69
|
removal_range = range_between(to_h.loc.dot.begin_pos, to_h.loc.selector.end_pos)
|
69
70
|
|
70
71
|
corrector.remove(range_with_surrounding_space(removal_range, side: :left))
|
72
|
+
if (map_dot = map.loc.dot)
|
73
|
+
corrector.replace(map_dot, to_h.loc.dot.source)
|
74
|
+
end
|
71
75
|
corrector.replace(map.loc.selector, 'to_h')
|
72
76
|
end
|
77
|
+
# rubocop:enable Metrics/AbcSize
|
73
78
|
end
|
74
79
|
end
|
75
80
|
end
|
@@ -86,6 +86,7 @@ module RuboCop
|
|
86
86
|
|
87
87
|
def legitimate_call_with_parentheses?(node) # rubocop:disable Metrics/PerceivedComplexity
|
88
88
|
call_in_literals?(node) ||
|
89
|
+
node.parent&.when_type? ||
|
89
90
|
call_with_ambiguous_arguments?(node) ||
|
90
91
|
call_in_logical_operators?(node) ||
|
91
92
|
call_in_optional_arguments?(node) ||
|
@@ -126,23 +127,31 @@ module RuboCop
|
|
126
127
|
|
127
128
|
def call_with_ambiguous_arguments?(node) # rubocop:disable Metrics/PerceivedComplexity
|
128
129
|
call_with_braced_block?(node) ||
|
130
|
+
call_in_argument_with_block?(node) ||
|
129
131
|
call_as_argument_or_chain?(node) ||
|
130
132
|
call_in_match_pattern?(node) ||
|
131
133
|
hash_literal_in_arguments?(node) ||
|
132
134
|
node.descendants.any? do |n|
|
133
|
-
n.forwarded_args_type? ||
|
134
|
-
|
135
|
+
n.forwarded_args_type? || n.block_type? ||
|
136
|
+
ambiguous_literal?(n) || logical_operator?(n)
|
135
137
|
end
|
136
138
|
end
|
137
139
|
|
138
140
|
def call_with_braced_block?(node)
|
139
|
-
(node.
|
141
|
+
(node.call_type? || node.super_type?) && node.block_node&.braces?
|
142
|
+
end
|
143
|
+
|
144
|
+
def call_in_argument_with_block?(node)
|
145
|
+
parent = node.parent&.block_type? && node.parent&.parent
|
146
|
+
return false unless parent
|
147
|
+
|
148
|
+
parent.call_type? || parent.super_type? || parent.yield_type?
|
140
149
|
end
|
141
150
|
|
142
151
|
def call_as_argument_or_chain?(node)
|
143
152
|
node.parent &&
|
144
|
-
(
|
145
|
-
|
153
|
+
(node.parent.call_type? || node.parent.super_type? || node.parent.yield_type?) &&
|
154
|
+
!assigned_before?(node.parent, node)
|
146
155
|
end
|
147
156
|
|
148
157
|
def call_in_match_pattern?(node)
|
@@ -218,15 +218,13 @@ module RuboCop
|
|
218
218
|
send(style, node) # call require_parentheses or omit_parentheses
|
219
219
|
end
|
220
220
|
alias on_csend on_send
|
221
|
-
alias on_super on_send
|
222
221
|
alias on_yield on_send
|
223
222
|
|
224
223
|
private
|
225
224
|
|
226
225
|
def args_begin(node)
|
227
226
|
loc = node.loc
|
228
|
-
selector =
|
229
|
-
node.super_type? || node.yield_type? ? loc.keyword : loc.selector
|
227
|
+
selector = node.yield_type? ? loc.keyword : loc.selector
|
230
228
|
|
231
229
|
resize_by = args_parenthesized?(node) ? 2 : 1
|
232
230
|
selector.end.resize(resize_by)
|
@@ -8,6 +8,9 @@ module RuboCop
|
|
8
8
|
# This cop can be customized allowed methods with `AllowedMethods`.
|
9
9
|
# By default, there are no methods to allowed.
|
10
10
|
#
|
11
|
+
# NOTE: This cop allows the use of `it()` without arguments in blocks,
|
12
|
+
# as in `0.times { it() }`, following `Lint/ItWithoutArgumentsInBlock` cop.
|
13
|
+
#
|
11
14
|
# @example
|
12
15
|
# # bad
|
13
16
|
# object.some_method()
|
@@ -30,15 +33,18 @@ module RuboCop
|
|
30
33
|
|
31
34
|
MSG = 'Do not use parentheses for method calls with no arguments.'
|
32
35
|
|
36
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
33
37
|
def on_send(node)
|
34
38
|
return unless !node.arguments? && node.parenthesized?
|
35
39
|
return if ineligible_node?(node)
|
36
40
|
return if default_argument?(node)
|
37
41
|
return if allowed_method_name?(node.method_name)
|
38
42
|
return if same_name_assignment?(node)
|
43
|
+
return if parenthesized_it_method_in_block?(node)
|
39
44
|
|
40
45
|
register_offense(node)
|
41
46
|
end
|
47
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
42
48
|
|
43
49
|
private
|
44
50
|
|
@@ -71,6 +77,20 @@ module RuboCop
|
|
71
77
|
end
|
72
78
|
end
|
73
79
|
|
80
|
+
# Respects `Lint/ItWithoutArgumentsInBlock` cop and the following Ruby 3.3's warning:
|
81
|
+
#
|
82
|
+
# $ ruby -e '0.times { begin; it; end }'
|
83
|
+
# -e:1: warning: `it` calls without arguments will refer to the first block param in
|
84
|
+
# Ruby 3.4; use it() or self.it
|
85
|
+
#
|
86
|
+
def parenthesized_it_method_in_block?(node)
|
87
|
+
return false unless node.method?(:it)
|
88
|
+
return false unless (block_node = node.each_ancestor(:block).first)
|
89
|
+
return false unless block_node.arguments.empty_and_without_delimiters?
|
90
|
+
|
91
|
+
!node.receiver && node.arguments.empty? && !node.block_literal?
|
92
|
+
end
|
93
|
+
|
74
94
|
def any_assignment?(node)
|
75
95
|
node.each_ancestor(*AST::Node::ASSIGNMENTS).any? do |asgn_node|
|
76
96
|
# `obj.method = value` parses as (send ... :method= ...), and will
|
@@ -54,12 +54,10 @@ module RuboCop
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def offense?(node)
|
57
|
-
node.ternary? && node.multiline?
|
57
|
+
node.ternary? && node.multiline? && node.source != replacement(node)
|
58
58
|
end
|
59
59
|
|
60
60
|
def autocorrect(corrector, node)
|
61
|
-
return unless offense?(node)
|
62
|
-
|
63
61
|
corrector.replace(node, replacement(node))
|
64
62
|
return unless (parent = node.parent)
|
65
63
|
return unless (comments_in_condition = comments_in_condition(node))
|