rubocop 0.38.0 → 0.39.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/README.md +11 -3
- data/config/default.yml +13 -0
- data/config/enabled.yml +15 -3
- data/lib/rubocop.rb +2 -0
- data/lib/rubocop/ast_node/builder.rb +6 -0
- data/lib/rubocop/cli.rb +2 -2
- data/lib/rubocop/config.rb +13 -13
- data/lib/rubocop/config_loader.rb +5 -28
- data/lib/rubocop/config_loader_resolver.rb +42 -0
- data/lib/rubocop/cop/cop.rb +4 -5
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +9 -2
- data/lib/rubocop/cop/mixin/statement_modifier.rb +5 -4
- data/lib/rubocop/cop/performance/case_when_splat.rb +1 -1
- data/lib/rubocop/cop/performance/count.rb +20 -0
- data/lib/rubocop/cop/performance/detect.rb +12 -0
- data/lib/rubocop/cop/performance/redundant_merge.rb +10 -1
- data/lib/rubocop/cop/performance/times_map.rb +14 -0
- data/lib/rubocop/cop/style/case_indentation.rb +14 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +221 -20
- data/lib/rubocop/cop/style/file_name.rb +31 -17
- data/lib/rubocop/cop/style/if_unless_modifier.rb +8 -0
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +45 -0
- data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +3 -2
- data/lib/rubocop/cop/style/next.rb +6 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +37 -8
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -0
- data/lib/rubocop/cop/style/redundant_self.rb +1 -1
- data/lib/rubocop/cop/style/space_around_keyword.rb +10 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +23 -14
- data/lib/rubocop/cop/style/zero_length_predicate.rb +25 -0
- data/lib/rubocop/formatter/html_formatter.rb +3 -3
- data/lib/rubocop/result_cache.rb +2 -2
- data/lib/rubocop/runner.rb +3 -3
- data/lib/rubocop/target_finder.rb +2 -6
- data/lib/rubocop/version.rb +1 -1
- metadata +6 -4
@@ -18,6 +18,11 @@ module RuboCop
|
|
18
18
|
# # good
|
19
19
|
# [].detect { |item| true }
|
20
20
|
# [].reverse.detect { |item| true }
|
21
|
+
#
|
22
|
+
# `ActiveRecord` compatibility:
|
23
|
+
# `ActiveRecord` does not implement a `detect` method and `find` has its
|
24
|
+
# own meaning. Correcting ActiveRecord methods with this cop should be
|
25
|
+
# considered unsafe.
|
21
26
|
class Detect < Cop
|
22
27
|
MSG = 'Use `%s` instead of `%s.%s`.'.freeze
|
23
28
|
REVERSE_MSG = 'Use `reverse.%s` instead of `%s.%s`.'.freeze
|
@@ -26,6 +31,7 @@ module RuboCop
|
|
26
31
|
DANGEROUS_METHODS = [:first, :last].freeze
|
27
32
|
|
28
33
|
def on_send(node)
|
34
|
+
return unless should_run?
|
29
35
|
receiver, second_method, *args = *node
|
30
36
|
return unless check_second_call(receiver, second_method, args)
|
31
37
|
|
@@ -67,6 +73,12 @@ module RuboCop
|
|
67
73
|
|
68
74
|
private
|
69
75
|
|
76
|
+
def should_run?
|
77
|
+
!(cop_config['SafeMode'.freeze] ||
|
78
|
+
config['Rails'.freeze] &&
|
79
|
+
config['Rails'.freeze]['Enabled'.freeze])
|
80
|
+
end
|
81
|
+
|
70
82
|
def check_second_call(receiver, method, args)
|
71
83
|
receiver &&
|
72
84
|
DANGEROUS_METHODS.include?(method) &&
|
@@ -17,10 +17,19 @@ module RuboCop
|
|
17
17
|
|
18
18
|
def_node_matcher :redundant_merge, '(send $_ :merge! (hash $...))'
|
19
19
|
def_node_matcher :modifier_flow_control, '[{if while until} #modifier?]'
|
20
|
+
def_node_matcher :each_with_object_node, <<-END
|
21
|
+
(block (send _ :each_with_object _) (args _ $_) ...)
|
22
|
+
END
|
20
23
|
|
21
24
|
def on_send(node)
|
22
25
|
redundant_merge(node) do |receiver, pairs|
|
23
|
-
|
26
|
+
if node.value_used?
|
27
|
+
parent = node.parent
|
28
|
+
grandparent = parent.parent if parent.begin_type?
|
29
|
+
second_arg = each_with_object_node(grandparent || parent)
|
30
|
+
next if second_arg.nil?
|
31
|
+
next unless receiver.loc.name.source == second_arg.loc.name.source
|
32
|
+
end
|
24
33
|
next if pairs.size > 1 && !receiver.pure?
|
25
34
|
next if pairs.size > max_key_value_pairs
|
26
35
|
|
@@ -42,6 +42,20 @@ module RuboCop
|
|
42
42
|
{(block (send (send !nil :times) ${:map :collect}) ...)
|
43
43
|
(send (send !nil :times) ${:map :collect} (block_pass ...))}
|
44
44
|
END
|
45
|
+
|
46
|
+
def autocorrect(node)
|
47
|
+
send_node = node.send_type? ? node : node.each_descendant(:send).first
|
48
|
+
|
49
|
+
receiver, _method_name, *args = *send_node
|
50
|
+
count, = *receiver
|
51
|
+
|
52
|
+
replacement = "Array.new(#{count.source}" \
|
53
|
+
"#{args.map { |arg| ", #{arg.source}" }.join})"
|
54
|
+
|
55
|
+
lambda do |corrector|
|
56
|
+
corrector.replace(send_node.loc.expression, replacement)
|
57
|
+
end
|
58
|
+
end
|
45
59
|
end
|
46
60
|
end
|
47
61
|
end
|
@@ -64,20 +64,27 @@ module RuboCop
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def autocorrect(node)
|
67
|
+
whitespace = whitespace_range(node)
|
68
|
+
return false unless whitespace.source.strip.empty?
|
69
|
+
|
70
|
+
->(corrector) { corrector.replace(whitespace, replacement(node)) }
|
71
|
+
end
|
72
|
+
|
73
|
+
def whitespace_range(node)
|
67
74
|
when_column = node.location.keyword.column
|
68
|
-
source_buffer = node.source_range.source_buffer
|
69
75
|
begin_pos = node.loc.keyword.begin_pos
|
70
|
-
whitespace = Parser::Source::Range.new(source_buffer,
|
71
|
-
begin_pos - when_column,
|
72
|
-
begin_pos)
|
73
|
-
return false unless whitespace.source.strip.empty?
|
74
76
|
|
77
|
+
Parser::Source::Range.new(node.source_range.source_buffer,
|
78
|
+
begin_pos - when_column,
|
79
|
+
begin_pos)
|
80
|
+
end
|
81
|
+
|
82
|
+
def replacement(node)
|
75
83
|
case_node = node.each_ancestor(:case).first
|
76
84
|
base_type = cop_config[parameter_name] == 'end' ? :end : :case
|
77
85
|
column = base_column(case_node, base_type)
|
78
86
|
column += configured_indentation_width if cop_config['IndentOneStep']
|
79
|
-
|
80
|
-
->(corrector) { corrector.replace(whitespace, ' ' * column) }
|
87
|
+
' ' * column
|
81
88
|
end
|
82
89
|
end
|
83
90
|
end
|
@@ -28,13 +28,6 @@ module RuboCop
|
|
28
28
|
when_branches.map { |branch| branch.children[1] }
|
29
29
|
end
|
30
30
|
|
31
|
-
def correct_branches(corrector, branches)
|
32
|
-
branches.each do |branch|
|
33
|
-
*_, assignment = *branch
|
34
|
-
corrector.replace(branch.source_range, assignment.source)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
31
|
def tail(branch)
|
39
32
|
branch.begin_type? ? [*branch].last : branch
|
40
33
|
end
|
@@ -89,7 +82,7 @@ module RuboCop
|
|
89
82
|
indices = node.children[2...-1].map(&:source).join(', ')
|
90
83
|
"#{receiver}[#{indices}] = "
|
91
84
|
elsif node.method_name.to_s.end_with?(EQUAL) &&
|
92
|
-
![:!=,
|
85
|
+
![:!=, :==, :===, :>=, :<=].include?(node.method_name)
|
93
86
|
"#{receiver}.#{node.method_name[0...-1]} = "
|
94
87
|
else
|
95
88
|
"#{receiver} #{node.method_name} "
|
@@ -102,6 +95,8 @@ module RuboCop
|
|
102
95
|
# condition can be used instead.
|
103
96
|
#
|
104
97
|
# @example
|
98
|
+
# EnforcedStyle: assign_to_condition
|
99
|
+
#
|
105
100
|
# # bad
|
106
101
|
# if foo
|
107
102
|
# bar = 1
|
@@ -145,12 +140,61 @@ module RuboCop
|
|
145
140
|
# some_other_method
|
146
141
|
# 2
|
147
142
|
# end
|
143
|
+
#
|
144
|
+
# EnforcedStyle: assign_inside_condition
|
145
|
+
# # bad
|
146
|
+
# bar = if foo
|
147
|
+
# 1
|
148
|
+
# else
|
149
|
+
# 2
|
150
|
+
# end
|
151
|
+
#
|
152
|
+
# bar += case foo
|
153
|
+
# when 'a'
|
154
|
+
# 1
|
155
|
+
# else
|
156
|
+
# 2
|
157
|
+
# end
|
158
|
+
#
|
159
|
+
# bar << if foo
|
160
|
+
# some_method
|
161
|
+
# 1
|
162
|
+
# else
|
163
|
+
# some_other_method
|
164
|
+
# 2
|
165
|
+
# end
|
166
|
+
#
|
167
|
+
# # good
|
168
|
+
# if foo
|
169
|
+
# bar = 1
|
170
|
+
# else
|
171
|
+
# bar = 2
|
172
|
+
# end
|
173
|
+
#
|
174
|
+
# case foo
|
175
|
+
# when 'a'
|
176
|
+
# bar += 1
|
177
|
+
# else
|
178
|
+
# bar += 2
|
179
|
+
# end
|
180
|
+
#
|
181
|
+
# if foo
|
182
|
+
# some_method
|
183
|
+
# bar = 1
|
184
|
+
# else
|
185
|
+
# some_other_method
|
186
|
+
# bar = 2
|
187
|
+
# end
|
148
188
|
class ConditionalAssignment < Cop
|
149
189
|
include IfNode
|
150
190
|
include ConditionalAssignmentHelper
|
191
|
+
include ConfigurableEnforcedStyle
|
192
|
+
include IgnoredNode
|
151
193
|
|
152
194
|
MSG = 'Use the return of the conditional for variable assignment ' \
|
153
195
|
'and comparison.'.freeze
|
196
|
+
ASSIGN_TO_CONDITION_MSG =
|
197
|
+
'Assign variables inside of conditionals'.freeze
|
154
198
|
VARIABLE_ASSIGNMENT_TYPES =
|
155
199
|
[:casgn, :cvasgn, :gvasgn, :ivasgn, :lvasgn].freeze
|
156
200
|
ASSIGNMENT_TYPES =
|
@@ -164,13 +208,40 @@ module RuboCop
|
|
164
208
|
SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'.freeze
|
165
209
|
WIDTH = 'Width'.freeze
|
166
210
|
METHODS = [:[]=, :<<, :=~, :!~, :<=>].freeze
|
211
|
+
CONDITION_TYPES = [:if, :case].freeze
|
167
212
|
|
168
|
-
|
169
|
-
|
170
|
-
|
213
|
+
ASSIGNMENT_TYPES.each do |type|
|
214
|
+
define_method "on_#{type}" do |node|
|
215
|
+
return if part_of_ignored_node?(node)
|
216
|
+
check_assignment_to_condition(node)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
def on_send(node)
|
221
|
+
return unless assignment_type?(node)
|
222
|
+
check_assignment_to_condition(node)
|
223
|
+
end
|
224
|
+
|
225
|
+
def check_assignment_to_condition(node)
|
226
|
+
return unless style == :assign_inside_condition
|
227
|
+
ignore_node(node)
|
228
|
+
*_variable, assignment = *node
|
229
|
+
if assignment.respond_to?(:type)
|
230
|
+
if assignment.begin_type? && assignment.children.size == 1
|
231
|
+
assignment, = *assignment
|
232
|
+
end
|
233
|
+
|
234
|
+
return unless CONDITION_TYPES.include?(assignment.type)
|
235
|
+
end
|
236
|
+
_condition, *branches, else_branch = *assignment
|
237
|
+
return unless else_branch # empty else
|
238
|
+
return if single_line_conditions_only? &&
|
239
|
+
[*branches, else_branch].any?(&:begin_type?)
|
240
|
+
add_offense(node, :expression, ASSIGN_TO_CONDITION_MSG)
|
171
241
|
end
|
172
242
|
|
173
243
|
def on_if(node)
|
244
|
+
return unless style == :assign_to_condition
|
174
245
|
return if elsif?(node)
|
175
246
|
|
176
247
|
_condition, if_branch, else_branch = *node
|
@@ -183,6 +254,7 @@ module RuboCop
|
|
183
254
|
end
|
184
255
|
|
185
256
|
def on_case(node)
|
257
|
+
return unless style == :assign_to_condition
|
186
258
|
_condition, *when_branches, else_branch = *node
|
187
259
|
return unless else_branch # empty else
|
188
260
|
|
@@ -193,21 +265,42 @@ module RuboCop
|
|
193
265
|
end
|
194
266
|
|
195
267
|
def autocorrect(node)
|
268
|
+
if assignment_type?(node)
|
269
|
+
move_assignment_inside_condition(node)
|
270
|
+
else
|
271
|
+
move_assignment_outside_condition(node)
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
private
|
276
|
+
|
277
|
+
def move_assignment_outside_condition(node)
|
196
278
|
if ternary_op?(node)
|
197
279
|
TernaryCorrector.correct(node)
|
280
|
+
elsif node.loc.keyword.is?(IF)
|
281
|
+
IfCorrector.correct(self, node)
|
282
|
+
elsif node.loc.keyword.is?(UNLESS)
|
283
|
+
UnlessCorrector.correct(self, node)
|
198
284
|
else
|
199
|
-
|
200
|
-
when IF
|
201
|
-
IfCorrector.correct(self, node)
|
202
|
-
when UNLESS
|
203
|
-
UnlessCorrector.correct(self, node)
|
204
|
-
else
|
205
|
-
CaseCorrector.correct(self, node)
|
206
|
-
end
|
285
|
+
CaseCorrector.correct(self, node)
|
207
286
|
end
|
208
287
|
end
|
209
288
|
|
210
|
-
|
289
|
+
def move_assignment_inside_condition(node)
|
290
|
+
*_assignment, condition = *node
|
291
|
+
if ternary_op?(condition) || ternary_op?(condition.children[0])
|
292
|
+
TernaryCorrector.move_assignment_inside_condition(node)
|
293
|
+
elsif condition.case_type?
|
294
|
+
CaseCorrector.move_assignment_inside_condition(node)
|
295
|
+
elsif condition.if_type?
|
296
|
+
IfCorrector.move_assignment_inside_condition(node)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
def lhs_all_match?(branches)
|
301
|
+
first_lhs = lhs(branches.first)
|
302
|
+
branches.all? { |branch| lhs(branch) == first_lhs }
|
303
|
+
end
|
211
304
|
|
212
305
|
def assignment_types_match?(*nodes)
|
213
306
|
return unless assignment_type?(nodes.first)
|
@@ -283,10 +376,47 @@ module RuboCop
|
|
283
376
|
end
|
284
377
|
end
|
285
378
|
|
379
|
+
# Helper module to provide common methods to ConditionalAssignment
|
380
|
+
# correctors
|
381
|
+
module ConditionalCorrectorHelper
|
382
|
+
def remove_whitespace_in_branches(corrector, branch, condition, column)
|
383
|
+
branch.each_node do |child|
|
384
|
+
child_expression = child.loc.expression
|
385
|
+
white_space =
|
386
|
+
Parser::Source::Range.new(child_expression.source_buffer,
|
387
|
+
child_expression.begin_pos -
|
388
|
+
(child.loc.expression.column -
|
389
|
+
column - 2),
|
390
|
+
child_expression.begin_pos)
|
391
|
+
|
392
|
+
corrector.remove(white_space) if white_space.source.strip.empty?
|
393
|
+
end
|
394
|
+
|
395
|
+
[condition.loc.else, condition.loc.end].each do |loc|
|
396
|
+
corrector.remove_preceding(loc, loc.column - column)
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def assignment(node)
|
401
|
+
*_, condition = *node
|
402
|
+
Parser::Source::Range.new(node.loc.expression.source_buffer,
|
403
|
+
node.loc.expression.begin_pos,
|
404
|
+
condition.loc.expression.begin_pos)
|
405
|
+
end
|
406
|
+
|
407
|
+
def correct_branches(corrector, branches)
|
408
|
+
branches.each do |branch|
|
409
|
+
*_, assignment = *branch
|
410
|
+
corrector.replace(branch.source_range, assignment.source)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
286
415
|
# Corrector to correct conditional assignment in ternary conditions.
|
287
416
|
class TernaryCorrector
|
288
417
|
class << self
|
289
418
|
include ConditionalAssignmentHelper
|
419
|
+
include ConditionalCorrectorHelper
|
290
420
|
|
291
421
|
def correct(node)
|
292
422
|
condition, if_branch, else_branch = *node
|
@@ -306,6 +436,25 @@ module RuboCop
|
|
306
436
|
corrector.replace(node.source_range, correction)
|
307
437
|
end
|
308
438
|
end
|
439
|
+
|
440
|
+
def move_assignment_inside_condition(node)
|
441
|
+
*_var, rhs = *node
|
442
|
+
condition, = *rhs if rhs.begin_type? && rhs.children.size == 1
|
443
|
+
assignment = assignment(node)
|
444
|
+
_condition, if_branch, else_branch = *(condition || rhs)
|
445
|
+
|
446
|
+
lambda do |corrector|
|
447
|
+
corrector.remove(assignment)
|
448
|
+
if rhs.begin_type?
|
449
|
+
corrector.remove(rhs.loc.begin)
|
450
|
+
corrector.remove(rhs.loc.end)
|
451
|
+
end
|
452
|
+
corrector.insert_before(if_branch.loc.expression,
|
453
|
+
assignment.source)
|
454
|
+
corrector.insert_before(else_branch.loc.expression,
|
455
|
+
assignment.source)
|
456
|
+
end
|
457
|
+
end
|
309
458
|
end
|
310
459
|
end
|
311
460
|
|
@@ -313,6 +462,7 @@ module RuboCop
|
|
313
462
|
class IfCorrector
|
314
463
|
class << self
|
315
464
|
include ConditionalAssignmentHelper
|
465
|
+
include ConditionalCorrectorHelper
|
316
466
|
|
317
467
|
def correct(cop, node)
|
318
468
|
_condition, if_branch, else_branch = *node
|
@@ -332,6 +482,31 @@ module RuboCop
|
|
332
482
|
corrector.insert_before(node.loc.end, indent(cop, lhs(if_branch)))
|
333
483
|
end
|
334
484
|
end
|
485
|
+
|
486
|
+
def move_assignment_inside_condition(node)
|
487
|
+
column = node.loc.expression.column
|
488
|
+
*_var, condition = *node
|
489
|
+
_condition, if_branch, else_branch = *condition
|
490
|
+
elsif_branches, else_branch = expand_elses(else_branch)
|
491
|
+
assignment = assignment(node)
|
492
|
+
|
493
|
+
lambda do |corrector|
|
494
|
+
corrector.remove(assignment)
|
495
|
+
|
496
|
+
[if_branch, *elsif_branches, else_branch].each do |branch|
|
497
|
+
branch_assignment = tail(branch)
|
498
|
+
corrector.insert_before(branch_assignment.loc.expression,
|
499
|
+
assignment.source)
|
500
|
+
|
501
|
+
remove_whitespace_in_branches(corrector, branch,
|
502
|
+
condition, column)
|
503
|
+
|
504
|
+
corrector
|
505
|
+
.remove_preceding(branch.parent.loc.else,
|
506
|
+
branch.parent.loc.else.column - column)
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|
335
510
|
end
|
336
511
|
end
|
337
512
|
|
@@ -339,6 +514,7 @@ module RuboCop
|
|
339
514
|
class CaseCorrector
|
340
515
|
class << self
|
341
516
|
include ConditionalAssignmentHelper
|
517
|
+
include ConditionalCorrectorHelper
|
342
518
|
|
343
519
|
def correct(cop, node)
|
344
520
|
_condition, *when_branches, else_branch = *node
|
@@ -357,6 +533,31 @@ module RuboCop
|
|
357
533
|
indent(cop, lhs(else_branch)))
|
358
534
|
end
|
359
535
|
end
|
536
|
+
|
537
|
+
def move_assignment_inside_condition(node)
|
538
|
+
column = node.loc.expression.column
|
539
|
+
*_var, condition = *node
|
540
|
+
_condition, *when_branches, else_branch = *condition
|
541
|
+
when_branches = expand_when_branches(when_branches)
|
542
|
+
assignment = assignment(node)
|
543
|
+
|
544
|
+
lambda do |corrector|
|
545
|
+
corrector.remove(assignment)
|
546
|
+
|
547
|
+
[*when_branches, else_branch].each do |branch|
|
548
|
+
branch_assignment = tail(branch)
|
549
|
+
corrector.insert_before(branch_assignment.loc.expression,
|
550
|
+
assignment.source)
|
551
|
+
|
552
|
+
remove_whitespace_in_branches(corrector, branch,
|
553
|
+
condition, column)
|
554
|
+
|
555
|
+
corrector
|
556
|
+
.remove_preceding(branch.parent.loc.keyword,
|
557
|
+
branch.parent.loc.keyword.column - column)
|
558
|
+
end
|
559
|
+
end
|
560
|
+
end
|
360
561
|
end
|
361
562
|
end
|
362
563
|
|