rubocop 1.92.0 → 1.92.2
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/config.rb +0 -4
- data/lib/rubocop/config_obsoletion.rb +9 -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/empty_line_corrector.rb +1 -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_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
- data/lib/rubocop/cop/layout/end_alignment.rb +5 -15
- data/lib/rubocop/cop/layout/extra_spacing.rb +18 -7
- 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 +127 -11
- 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/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +3 -3
- data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +12 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
- 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/interpolation_check.rb +20 -17
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +2 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
- data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -8
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
- 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/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +36 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +26 -5
- data/lib/rubocop/cop/mixin/statement_modifier.rb +17 -3
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- 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 +34 -11
- 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/case_equality.rb +14 -3
- data/lib/rubocop/cop/style/class_and_module_children.rb +6 -3
- 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 +38 -6
- data/lib/rubocop/cop/style/float_division.rb +16 -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/hash_lookup_method.rb +10 -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/method_call_with_args_parentheses.rb +1 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +9 -1
- 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/numeric_predicate.rb +7 -0
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +19 -1
- data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
- data/lib/rubocop/cop/style/raise_args.rb +80 -11
- data/lib/rubocop/cop/style/reduce_to_hash.rb +32 -34
- data/lib/rubocop/cop/style/redundant_begin.rb +26 -3
- data/lib/rubocop/cop/style/redundant_exception.rb +13 -9
- 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.rb +9 -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 +26 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +12 -1
- 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/plugin/configuration_integrator.rb +24 -3
- data/lib/rubocop/runner.rb +1 -1
- 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
|
@@ -146,11 +146,26 @@ module RuboCop
|
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
def comment_before_to_f?(node)
|
|
149
|
+
return true if comment_around_fdiv_operator?(node)
|
|
150
|
+
|
|
149
151
|
operands_losing_to_f(node).any? do |operand|
|
|
150
152
|
next false unless to_f_method?(operand)
|
|
151
153
|
|
|
152
154
|
range = operand.receiver.source_range.end.join(operand.loc.selector.begin)
|
|
153
|
-
|
|
155
|
+
comment_in_range?(range)
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def comment_around_fdiv_operator?(node)
|
|
160
|
+
return false unless style == :fdiv
|
|
161
|
+
|
|
162
|
+
range = node.receiver.source_range.end.join(node.first_argument.source_range.begin)
|
|
163
|
+
comment_in_range?(range)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def comment_in_range?(range)
|
|
167
|
+
processed_source.each_comment_in_lines(range.line..range.last_line).any? do |comment|
|
|
168
|
+
range.contains?(comment.source_range)
|
|
154
169
|
end
|
|
155
170
|
end
|
|
156
171
|
|
|
@@ -56,8 +56,10 @@ module RuboCop
|
|
|
56
56
|
|
|
57
57
|
# `Style/RedundantBegin` removes the `begin` of a block body in the same pass,
|
|
58
58
|
# leaving a `rescue` or `ensure` clause directly in the `for` body.
|
|
59
|
+
# `Style/ItBlockParameter` replaces block parameter references in the body
|
|
60
|
+
# with `it` in the same pass, while they become `for` loop variables.
|
|
59
61
|
def self.autocorrect_incompatible_with
|
|
60
|
-
[Style::RedundantBegin]
|
|
62
|
+
[Style::RedundantBegin, Style::ItBlockParameter]
|
|
61
63
|
end
|
|
62
64
|
|
|
63
65
|
def on_for(node)
|
|
@@ -78,6 +80,7 @@ module RuboCop
|
|
|
78
80
|
|
|
79
81
|
if style == :for
|
|
80
82
|
return unless node.receiver
|
|
83
|
+
return unless convertible_to_for?(node)
|
|
81
84
|
return if rescue_or_ensure_body?(node) || do_end_block_in_collection?(node)
|
|
82
85
|
|
|
83
86
|
add_offense(node, message: PREFER_FOR) do |corrector|
|
|
@@ -123,6 +126,16 @@ module RuboCop
|
|
|
123
126
|
node.multiline? && node.method?(:each) && !node.send_node.arguments?
|
|
124
127
|
end
|
|
125
128
|
|
|
129
|
+
def convertible_to_for?(node)
|
|
130
|
+
return false if node.type?(:numblock, :itblock)
|
|
131
|
+
return true unless node.arguments?
|
|
132
|
+
|
|
133
|
+
arguments = node.arguments
|
|
134
|
+
return false if arguments.children.one? && arguments.children.first.restarg_type?
|
|
135
|
+
|
|
136
|
+
arguments.each_descendant.all? { |arg| arg.type?(:arg, :restarg, :mlhs) }
|
|
137
|
+
end
|
|
138
|
+
|
|
126
139
|
def rescue_or_ensure_body?(node)
|
|
127
140
|
node.body&.type?(:rescue, :ensure)
|
|
128
141
|
end
|
|
@@ -186,40 +186,37 @@ module RuboCop
|
|
|
186
186
|
return if trivial?(node)
|
|
187
187
|
|
|
188
188
|
example = "#{conditional_keyword} #{condition.source}; #{scope_exiting_keyword}; end"
|
|
189
|
-
replacement =
|
|
190
|
-
#{conditional_keyword} #{condition.source}
|
|
191
|
-
#{scope_exiting_keyword}
|
|
192
|
-
end
|
|
193
|
-
RUBY
|
|
189
|
+
replacement = "#{conditional_keyword} #{condition.source}\n #{scope_exiting_keyword}"
|
|
194
190
|
end
|
|
195
191
|
|
|
196
192
|
add_offense(node.loc.keyword, message: format(MSG, example: example)) do |corrector|
|
|
197
193
|
next if node.else? && guard.nil?
|
|
198
194
|
|
|
199
|
-
autocorrect(corrector, node,
|
|
195
|
+
autocorrect(corrector, node, example, replacement, guard)
|
|
200
196
|
end
|
|
201
197
|
end
|
|
202
198
|
|
|
203
199
|
# rubocop:disable-next Metrics/AbcSize
|
|
204
|
-
def autocorrect(corrector, node,
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if_branch = node.if_branch
|
|
208
|
-
else_branch = node.else_branch
|
|
209
|
-
|
|
200
|
+
def autocorrect(corrector, node, example, multiline_replacement, guard)
|
|
201
|
+
range = node.loc.keyword.join(node.condition.source_range)
|
|
202
|
+
corrector.replace(range, multiline_replacement || example)
|
|
210
203
|
corrector.replace(node.loc.begin, "\n") if node.then?
|
|
211
204
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
elsif (else_heredoc = find_heredoc_argument(else_branch))
|
|
215
|
-
autocorrect_heredoc_argument(corrector, node, else_heredoc, if_branch, guard)
|
|
216
|
-
else
|
|
217
|
-
corrector.remove(node.loc.end)
|
|
218
|
-
return unless node.else?
|
|
205
|
+
branches = [node.if_branch, node.else_branch]
|
|
206
|
+
guard_branch, leave_branch = guard == :else ? branches.reverse : branches
|
|
219
207
|
|
|
220
|
-
|
|
221
|
-
|
|
208
|
+
heredoc = find_heredoc_argument(guard_branch)
|
|
209
|
+
close_multiline_guard_clause(corrector, range, heredoc, guard) if multiline_replacement
|
|
210
|
+
|
|
211
|
+
if heredoc
|
|
212
|
+
return autocorrect_heredoc_argument(corrector, node, heredoc, leave_branch, guard)
|
|
222
213
|
end
|
|
214
|
+
|
|
215
|
+
corrector.remove(node.loc.end)
|
|
216
|
+
return unless node.else?
|
|
217
|
+
|
|
218
|
+
corrector.remove(node.loc.else)
|
|
219
|
+
corrector.remove(range_of_branch_to_remove(node, guard))
|
|
223
220
|
end
|
|
224
221
|
|
|
225
222
|
def heredoc?(argument)
|
|
@@ -241,6 +238,10 @@ module RuboCop
|
|
|
241
238
|
find_heredoc_argument(node.receiver)
|
|
242
239
|
end
|
|
243
240
|
|
|
241
|
+
def close_multiline_guard_clause(corrector, range, heredoc, guard)
|
|
242
|
+
corrector.insert_after(guard && heredoc ? heredoc.loc.heredoc_end : range, "\nend")
|
|
243
|
+
end
|
|
244
|
+
|
|
244
245
|
def autocorrect_heredoc_argument(corrector, node, heredoc_node, leave_branch, guard)
|
|
245
246
|
remove_whole_lines(corrector, node.loc.end)
|
|
246
247
|
return unless node.else?
|
|
@@ -44,6 +44,10 @@ module RuboCop
|
|
|
44
44
|
include ConfigurableEnforcedStyle
|
|
45
45
|
extend AutoCorrector
|
|
46
46
|
|
|
47
|
+
def self.autocorrect_incompatible_with
|
|
48
|
+
[Layout::MultilineArrayBraceLayout, Style::TrailingCommaInArrayLiteral]
|
|
49
|
+
end
|
|
50
|
+
|
|
47
51
|
def on_hash(node)
|
|
48
52
|
return if node.children.first&.kwsplat_type?
|
|
49
53
|
return unless (array = containing_array(node))
|
|
@@ -90,9 +90,19 @@ module RuboCop
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
def exempt_from_brackets?(node)
|
|
93
|
+
return true if forwarded_or_splatted?(node.first_argument)
|
|
94
|
+
|
|
93
95
|
comment_before_dot?(node) || env_fetch_preferred?(node.receiver)
|
|
94
96
|
end
|
|
95
97
|
|
|
98
|
+
def forwarded_or_splatted?(argument)
|
|
99
|
+
if argument.hash_type? && !argument.braces?
|
|
100
|
+
argument.children.any? { |child| child.type?(:kwsplat, :forwarded_kwrestarg) }
|
|
101
|
+
else
|
|
102
|
+
argument.type?(:forwarded_args, :forwarded_restarg, :splat, :block_pass)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
96
106
|
def comment_before_dot?(node)
|
|
97
107
|
processed_source.contains_comment?(node.receiver.source_range.end.join(node.loc.dot))
|
|
98
108
|
end
|
|
@@ -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
|
|
@@ -169,12 +169,20 @@ module RuboCop
|
|
|
169
169
|
location = node.arguments.source_range
|
|
170
170
|
|
|
171
171
|
add_offense(location, message: MSG_MISSING) do |corrector|
|
|
172
|
-
|
|
172
|
+
corrector.replace(range_before_arguments(node), '(')
|
|
173
|
+
corrector.insert_after(location, ')')
|
|
173
174
|
|
|
174
175
|
unexpected_style_detected 'require_no_parentheses'
|
|
175
176
|
end
|
|
176
177
|
end
|
|
177
178
|
|
|
179
|
+
def range_before_arguments(node)
|
|
180
|
+
range = node.loc.name.end.join(node.arguments.source_range.begin)
|
|
181
|
+
last_line_break = range.source.rindex("\n")
|
|
182
|
+
|
|
183
|
+
last_line_break ? range.resize(last_line_break) : range
|
|
184
|
+
end
|
|
185
|
+
|
|
178
186
|
def unwanted_parentheses(args)
|
|
179
187
|
add_offense(args, message: MSG_PRESENT) do |corrector|
|
|
180
188
|
# offense is registered on args node when parentheses are unwanted
|
|
@@ -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
|
|
@@ -99,7 +99,10 @@ module RuboCop
|
|
|
99
99
|
|
|
100
100
|
message = format(MSG, prefer: replacement, current: node.source)
|
|
101
101
|
add_offense(node, message: message) do |corrector|
|
|
102
|
+
next if inside_corrected_predicate?(node)
|
|
103
|
+
|
|
102
104
|
corrector.replace(node, replacement)
|
|
105
|
+
ignore_node(node)
|
|
103
106
|
end
|
|
104
107
|
end
|
|
105
108
|
|
|
@@ -115,6 +118,10 @@ module RuboCop
|
|
|
115
118
|
BitwisePredicate.support_target_ruby_version?(target_ruby_version)
|
|
116
119
|
end
|
|
117
120
|
|
|
121
|
+
def inside_corrected_predicate?(node)
|
|
122
|
+
node.each_ancestor(:send).any? { |ancestor| ignored_node?(ancestor) }
|
|
123
|
+
end
|
|
124
|
+
|
|
118
125
|
def check(node)
|
|
119
126
|
numeric, operator =
|
|
120
127
|
if style == :predicate
|
|
@@ -83,7 +83,8 @@ 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
|
+
return if command_call_assignment?(first_child)
|
|
87
88
|
return if parens_allowed?(cond)
|
|
88
89
|
|
|
89
90
|
message = message(cond)
|
|
@@ -115,6 +116,23 @@ module RuboCop
|
|
|
115
116
|
node.basic_conditional? && node.modifier_form?
|
|
116
117
|
end
|
|
117
118
|
|
|
119
|
+
def command_call_assignment?(node)
|
|
120
|
+
return false if !node.assignment? && !setter_method?(node)
|
|
121
|
+
|
|
122
|
+
value = node.children.last
|
|
123
|
+
value = value.body if value.rescue_type?
|
|
124
|
+
|
|
125
|
+
command_call_assignment?(value) || command_call?(value)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
def command_call?(node)
|
|
129
|
+
node = node.send_node if node.any_block_type?
|
|
130
|
+
return false if !node.type?(:call, :super, :yield) || !node.arguments?
|
|
131
|
+
return false if node.parenthesized? || node.operator_method? || node.setter_method?
|
|
132
|
+
|
|
133
|
+
!node.method?(:[])
|
|
134
|
+
end
|
|
135
|
+
|
|
118
136
|
def message(node)
|
|
119
137
|
kw = node.parent.keyword
|
|
120
138
|
article = kw == 'while' ? 'a' : 'an'
|
|
@@ -86,14 +86,12 @@ module RuboCop
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def correct_quotes(str)
|
|
89
|
-
correction = if style == :single_quotes
|
|
90
|
-
to_string_literal(str)
|
|
91
|
-
else
|
|
92
|
-
str.gsub("\\'", "'").inspect
|
|
93
|
-
end
|
|
94
|
-
|
|
95
89
|
# The conversion process doubles escaped slashes, so they have to be reverted
|
|
96
|
-
|
|
90
|
+
if style == :single_quotes
|
|
91
|
+
to_string_literal(str).gsub('\\\\', '\\').gsub('\"', '"')
|
|
92
|
+
else
|
|
93
|
+
str.gsub("\\'", "'").inspect.gsub('\\\\', '\\')
|
|
94
|
+
end
|
|
97
95
|
end
|
|
98
96
|
|
|
99
97
|
def style
|