rubocop 1.66.0 → 1.67.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +15 -6
- data/config/internal_affairs.yml +11 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/comment_config.rb +4 -8
- data/lib/rubocop/config.rb +4 -16
- data/lib/rubocop/config_loader.rb +14 -8
- data/lib/rubocop/config_loader_resolver.rb +3 -3
- data/lib/rubocop/config_validator.rb +7 -10
- data/lib/rubocop/cop/base.rb +6 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
- data/lib/rubocop/cop/cop.rb +8 -0
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
- data/lib/rubocop/cop/internal_affairs.rb +16 -0
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -5
- data/lib/rubocop/cop/layout/leading_comment_space.rb +28 -1
- data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
- data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
- data/lib/rubocop/cop/lint/ensure_return.rb +0 -3
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +10 -4
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +5 -14
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +25 -2
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +105 -41
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
- data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
- data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
- data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +12 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +46 -6
- data/lib/rubocop/cop/style/block_delimiters.rb +14 -1
- data/lib/rubocop/cop/style/collection_compact.rb +10 -10
- data/lib/rubocop/cop/style/combinable_loops.rb +7 -0
- data/lib/rubocop/cop/style/commented_keyword.rb +7 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/empty_else.rb +1 -0
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +1 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +6 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +16 -5
- data/lib/rubocop/cop/style/lambda.rb +1 -1
- data/lib/rubocop/cop/style/magic_comment_format.rb +3 -8
- data/lib/rubocop/cop/style/map_into_array.rb +54 -10
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -7
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +25 -6
- data/lib/rubocop/cop/style/redundant_begin.rb +4 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +3 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/require_order.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +13 -1
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
- data/lib/rubocop/cop/style/safe_navigation.rb +92 -50
- data/lib/rubocop/cop/style/select_by_regexp.rb +9 -6
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/team.rb +8 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +73 -34
- data/lib/rubocop/file_finder.rb +9 -4
- data/lib/rubocop/lsp/runtime.rb +2 -0
- data/lib/rubocop/lsp/server.rb +0 -1
- data/lib/rubocop/rspec/expect_offense.rb +1 -0
- data/lib/rubocop/runner.rb +3 -0
- data/lib/rubocop/server/cache.rb +6 -1
- data/lib/rubocop/server/core.rb +1 -0
- data/lib/rubocop/target_ruby.rb +12 -12
- data/lib/rubocop/version.rb +3 -1
- data/lib/rubocop/yaml_duplication_checker.rb +20 -26
- data/lib/rubocop.rb +2 -0
- metadata +12 -10
@@ -68,6 +68,8 @@ module RuboCop
|
|
68
68
|
# class Foo
|
69
69
|
#
|
70
70
|
# private :bar, :baz
|
71
|
+
# private *%i[qux quux]
|
72
|
+
# private *METHOD_NAMES
|
71
73
|
#
|
72
74
|
# end
|
73
75
|
#
|
@@ -76,6 +78,8 @@ module RuboCop
|
|
76
78
|
# class Foo
|
77
79
|
#
|
78
80
|
# private :bar, :baz
|
81
|
+
# private *%i[qux quux]
|
82
|
+
# private *METHOD_NAMES
|
79
83
|
#
|
80
84
|
# end
|
81
85
|
#
|
@@ -128,7 +132,9 @@ module RuboCop
|
|
128
132
|
|
129
133
|
# @!method access_modifier_with_symbol?(node)
|
130
134
|
def_node_matcher :access_modifier_with_symbol?, <<~PATTERN
|
131
|
-
(send nil? {:private :protected :public :module_function}
|
135
|
+
(send nil? {:private :protected :public :module_function}
|
136
|
+
{(sym _) (splat {#percent_symbol_array? const})}
|
137
|
+
)
|
132
138
|
PATTERN
|
133
139
|
|
134
140
|
# @!method access_modifier_with_attr?(node)
|
@@ -170,6 +176,10 @@ module RuboCop
|
|
170
176
|
end
|
171
177
|
end
|
172
178
|
|
179
|
+
def percent_symbol_array?(node)
|
180
|
+
node.array_type? && node.percent_literal?(:symbol)
|
181
|
+
end
|
182
|
+
|
173
183
|
def allow_modifiers_on_symbols?(node)
|
174
184
|
cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
|
175
185
|
end
|
@@ -218,7 +228,7 @@ module RuboCop
|
|
218
228
|
|
219
229
|
def find_corresponding_def_node(node)
|
220
230
|
if access_modifier_with_symbol?(node)
|
221
|
-
method_name = node.first_argument.value
|
231
|
+
method_name = node.first_argument.respond_to?(:value) && node.first_argument.value
|
222
232
|
node.parent.each_child_node(:def).find do |child|
|
223
233
|
child.method?(method_name)
|
224
234
|
end
|
@@ -10,6 +10,9 @@ module RuboCop
|
|
10
10
|
# NOTE: If there is a method call before the accessor method it is always allowed
|
11
11
|
# as it might be intended like Sorbet.
|
12
12
|
#
|
13
|
+
# NOTE: If there is a RBS::Inline annotation comment just after the accessor method
|
14
|
+
# it is always allowed.
|
15
|
+
#
|
13
16
|
# @example EnforcedStyle: grouped (default)
|
14
17
|
# # bad
|
15
18
|
# class Foo
|
@@ -92,7 +95,7 @@ module RuboCop
|
|
92
95
|
comment_line?(processed_source[node.first_line - 2])
|
93
96
|
end
|
94
97
|
|
95
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
98
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
96
99
|
def groupable_accessor?(node)
|
97
100
|
return true unless (previous_expression = node.left_siblings.last)
|
98
101
|
|
@@ -105,11 +108,16 @@ module RuboCop
|
|
105
108
|
|
106
109
|
return true unless previous_expression.send_type?
|
107
110
|
|
111
|
+
# Accessors with RBS::Inline annotations shouldn't be groupable.
|
112
|
+
return false if processed_source.comments.any? do |c|
|
113
|
+
same_line?(c, previous_expression) && c.text.start_with?('#:')
|
114
|
+
end
|
115
|
+
|
108
116
|
previous_expression.attribute_accessor? ||
|
109
117
|
previous_expression.access_modifier? ||
|
110
118
|
node.first_line - previous_expression.last_line > 1 # there is a space between nodes
|
111
119
|
end
|
112
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
120
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
113
121
|
|
114
122
|
def class_send_elements(class_node)
|
115
123
|
class_def = class_node.body
|
@@ -180,7 +180,8 @@ module RuboCop
|
|
180
180
|
end
|
181
181
|
|
182
182
|
def only_forwards_all?(send_classifications)
|
183
|
-
|
183
|
+
all_classifications = %i[all all_anonymous].freeze
|
184
|
+
send_classifications.all? { |_, c, _, _| all_classifications.include?(c) }
|
184
185
|
end
|
185
186
|
|
186
187
|
# rubocop:disable Metrics/MethodLength
|
@@ -188,8 +189,8 @@ module RuboCop
|
|
188
189
|
_rest_arg, _kwrest_arg, block_arg = *forwardable_args
|
189
190
|
registered_block_arg_offense = false
|
190
191
|
|
191
|
-
send_classifications.each do |send_node,
|
192
|
-
if !forward_rest && !forward_kwrest
|
192
|
+
send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
193
|
+
if !forward_rest && !forward_kwrest && c != :all_anonymous
|
193
194
|
# Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
|
194
195
|
# in Ruby 3.3.0.
|
195
196
|
if outside_block?(forward_block_arg)
|
@@ -213,6 +214,7 @@ module RuboCop
|
|
213
214
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
214
215
|
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
215
216
|
return unless use_anonymous_forwarding?
|
217
|
+
return if send_inside_block?(send_classifications)
|
216
218
|
|
217
219
|
rest_arg, kwrest_arg, block_arg = *forwardable_args
|
218
220
|
|
@@ -355,8 +357,15 @@ module RuboCop
|
|
355
357
|
cop_config.fetch('UseAnonymousForwarding', false)
|
356
358
|
end
|
357
359
|
|
360
|
+
def send_inside_block?(send_classifications)
|
361
|
+
send_classifications.any? do |send_node, *|
|
362
|
+
send_node.each_ancestor(:block, :numblock).any?
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
358
366
|
def add_parens_if_missing(node, corrector)
|
359
367
|
return if parentheses?(node)
|
368
|
+
return if node.send_type? && node.method?(:[])
|
360
369
|
|
361
370
|
add_parentheses(node, corrector)
|
362
371
|
end
|
@@ -374,6 +383,23 @@ module RuboCop
|
|
374
383
|
# @!method forwarded_block_arg?(node, block_name)
|
375
384
|
def_node_matcher :forwarded_block_arg?, '(block_pass {(lvar %1) nil?})'
|
376
385
|
|
386
|
+
# @!method def_all_anonymous_args?(node)
|
387
|
+
def_node_matcher :def_all_anonymous_args?, <<~PATTERN
|
388
|
+
(
|
389
|
+
def _
|
390
|
+
(args ... (restarg) (kwrestarg) (blockarg nil?))
|
391
|
+
_
|
392
|
+
)
|
393
|
+
PATTERN
|
394
|
+
|
395
|
+
# @!method send_all_anonymous_args?(node)
|
396
|
+
def_node_matcher :send_all_anonymous_args?, <<~PATTERN
|
397
|
+
(
|
398
|
+
send _ _
|
399
|
+
... (forwarded_restarg) (hash (forwarded_kwrestarg)) (block_pass nil?)
|
400
|
+
)
|
401
|
+
PATTERN
|
402
|
+
|
377
403
|
def initialize(def_node, send_node, referenced_lvars, forwardable_args, **config)
|
378
404
|
@def_node = def_node
|
379
405
|
@send_node = send_node
|
@@ -405,7 +431,9 @@ module RuboCop
|
|
405
431
|
def classification
|
406
432
|
return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
|
407
433
|
|
408
|
-
if
|
434
|
+
if ruby_32_only_anonymous_forwarding?
|
435
|
+
:all_anonymous
|
436
|
+
elsif can_forward_all?
|
409
437
|
:all
|
410
438
|
else
|
411
439
|
:rest_or_kwrest
|
@@ -414,16 +442,28 @@ module RuboCop
|
|
414
442
|
|
415
443
|
private
|
416
444
|
|
445
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
417
446
|
def can_forward_all?
|
418
447
|
return false if any_arg_referenced?
|
419
|
-
return false if
|
448
|
+
return false if ruby_30_or_lower_optarg?
|
449
|
+
return false if ruby_32_or_higher_missing_rest_or_kwest?
|
420
450
|
return false unless offensive_block_forwarding?
|
421
451
|
return false if additional_kwargs_or_forwarded_kwargs?
|
422
452
|
|
423
453
|
no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
|
424
454
|
end
|
455
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
456
|
+
|
457
|
+
# def foo(a = 41, ...) is a syntax error in 3.0.
|
458
|
+
def ruby_30_or_lower_optarg?
|
459
|
+
target_ruby_version <= 3.0 && @def_node.arguments.any?(&:optarg_type?)
|
460
|
+
end
|
461
|
+
|
462
|
+
def ruby_32_only_anonymous_forwarding?
|
463
|
+
def_all_anonymous_args?(@def_node) && send_all_anonymous_args?(@send_node)
|
464
|
+
end
|
425
465
|
|
426
|
-
def
|
466
|
+
def ruby_32_or_higher_missing_rest_or_kwest?
|
427
467
|
target_ruby_version >= 3.2 && !forwarded_rest_and_kwrest_args
|
428
468
|
end
|
429
469
|
|
@@ -176,6 +176,10 @@ module RuboCop
|
|
176
176
|
|
177
177
|
BRACES_REQUIRED_MESSAGE = "Brace delimiters `{...}` required for '%<method_name>s' method."
|
178
178
|
|
179
|
+
def self.autocorrect_incompatible_with
|
180
|
+
[Style::RedundantBegin]
|
181
|
+
end
|
182
|
+
|
179
183
|
def on_send(node)
|
180
184
|
return unless node.arguments?
|
181
185
|
return if node.parenthesized?
|
@@ -341,8 +345,9 @@ module RuboCop
|
|
341
345
|
end
|
342
346
|
end
|
343
347
|
|
348
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
344
349
|
def proper_block_style?(node)
|
345
|
-
return true if require_braces?(node)
|
350
|
+
return true if require_braces?(node) || require_do_end?(node)
|
346
351
|
return special_method_proper_block_style?(node) if special_method?(node.method_name)
|
347
352
|
|
348
353
|
case style
|
@@ -352,6 +357,7 @@ module RuboCop
|
|
352
357
|
when :always_braces then braces_style?(node)
|
353
358
|
end
|
354
359
|
end
|
360
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
355
361
|
|
356
362
|
def require_braces?(node)
|
357
363
|
return false unless node.braces?
|
@@ -361,6 +367,13 @@ module RuboCop
|
|
361
367
|
end
|
362
368
|
end
|
363
369
|
|
370
|
+
def require_do_end?(node)
|
371
|
+
return false if node.braces? || node.multiline?
|
372
|
+
return false unless (resbody = node.each_descendant(:resbody).first)
|
373
|
+
|
374
|
+
resbody.children.first&.array_type?
|
375
|
+
end
|
376
|
+
|
364
377
|
def special_method?(method_name)
|
365
378
|
allowed_method?(method_name) ||
|
366
379
|
matches_allowed_pattern?(method_name) ||
|
@@ -21,6 +21,7 @@ module RuboCop
|
|
21
21
|
# array.reject(&:nil?)
|
22
22
|
# array.reject { |e| e.nil? }
|
23
23
|
# array.select { |e| !e.nil? }
|
24
|
+
# array.filter { |e| !e.nil? }
|
24
25
|
# array.grep_v(nil)
|
25
26
|
# array.grep_v(NilClass)
|
26
27
|
#
|
@@ -29,10 +30,9 @@ module RuboCop
|
|
29
30
|
#
|
30
31
|
# # bad
|
31
32
|
# hash.reject!(&:nil?)
|
32
|
-
# array.delete_if(&:nil?)
|
33
33
|
# hash.reject! { |k, v| v.nil? }
|
34
|
-
# array.delete_if { |e| e.nil? }
|
35
34
|
# hash.select! { |k, v| !v.nil? }
|
35
|
+
# hash.filter! { |k, v| !v.nil? }
|
36
36
|
#
|
37
37
|
# # good
|
38
38
|
# hash.compact!
|
@@ -48,14 +48,15 @@ module RuboCop
|
|
48
48
|
extend TargetRubyVersion
|
49
49
|
|
50
50
|
MSG = 'Use `%<good>s` instead of `%<bad>s`.'
|
51
|
-
RESTRICT_ON_SEND = %i[reject
|
51
|
+
RESTRICT_ON_SEND = %i[reject reject! select select! filter filter! grep_v].freeze
|
52
52
|
TO_ENUM_METHODS = %i[to_enum lazy].freeze
|
53
|
+
FILTER_METHODS = %i[filter filter!].freeze
|
53
54
|
|
54
55
|
minimum_target_ruby_version 2.4
|
55
56
|
|
56
57
|
# @!method reject_method_with_block_pass?(node)
|
57
58
|
def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
|
58
|
-
(call !nil? {:reject :
|
59
|
+
(call !nil? {:reject :reject!}
|
59
60
|
(block_pass
|
60
61
|
(sym :nil?)))
|
61
62
|
PATTERN
|
@@ -64,7 +65,7 @@ module RuboCop
|
|
64
65
|
def_node_matcher :reject_method?, <<~PATTERN
|
65
66
|
(block
|
66
67
|
(call
|
67
|
-
!nil? {:reject :
|
68
|
+
!nil? {:reject :reject!})
|
68
69
|
$(args ...)
|
69
70
|
(call
|
70
71
|
$(lvar _) :nil?))
|
@@ -74,7 +75,7 @@ module RuboCop
|
|
74
75
|
def_node_matcher :select_method?, <<~PATTERN
|
75
76
|
(block
|
76
77
|
(call
|
77
|
-
!nil? {:select :select!})
|
78
|
+
!nil? {:select :select! :filter :filter!})
|
78
79
|
$(args ...)
|
79
80
|
(call
|
80
81
|
(call
|
@@ -87,11 +88,10 @@ module RuboCop
|
|
87
88
|
PATTERN
|
88
89
|
|
89
90
|
def on_send(node)
|
91
|
+
return if target_ruby_version < 2.6 && FILTER_METHODS.include?(node.method_name)
|
90
92
|
return unless (range = offense_range(node))
|
91
93
|
return if allowed_receiver?(node.receiver)
|
92
|
-
if
|
93
|
-
return
|
94
|
-
end
|
94
|
+
return if target_ruby_version <= 3.0 && to_enum_method?(node)
|
95
95
|
|
96
96
|
good = good_method_name(node)
|
97
97
|
message = format(MSG, good: good, bad: range.source)
|
@@ -127,7 +127,7 @@ module RuboCop
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def good_method_name(node)
|
130
|
-
if node.bang_method?
|
130
|
+
if node.bang_method?
|
131
131
|
'compact!'
|
132
132
|
else
|
133
133
|
'compact'
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
# can be combined into a single loop. It is very likely that combining them
|
8
8
|
# will make the code more efficient and more concise.
|
9
9
|
#
|
10
|
+
# NOTE: Autocorrection is not applied when the block variable names differ in separate loops,
|
11
|
+
# as it is impossible to determine which variable name should be prioritized.
|
12
|
+
#
|
10
13
|
# @safety
|
11
14
|
# The cop is unsafe, because the first loop might modify state that the
|
12
15
|
# second loop depends on; these two aren't combinable.
|
@@ -61,6 +64,7 @@ module RuboCop
|
|
61
64
|
|
62
65
|
MSG = 'Combine this loop with the previous loop.'
|
63
66
|
|
67
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
64
68
|
def on_block(node)
|
65
69
|
return unless node.parent&.begin_type?
|
66
70
|
return unless collection_looping_method?(node)
|
@@ -68,9 +72,12 @@ module RuboCop
|
|
68
72
|
return unless node.body && node.left_sibling.body
|
69
73
|
|
70
74
|
add_offense(node) do |corrector|
|
75
|
+
next unless node.arguments == node.left_sibling.arguments
|
76
|
+
|
71
77
|
combine_with_left_sibling(corrector, node)
|
72
78
|
end
|
73
79
|
end
|
80
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
74
81
|
|
75
82
|
alias on_numblock on_block
|
76
83
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# Note that some comments
|
12
12
|
# (`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`)
|
13
|
-
# are allowed.
|
13
|
+
# and RBS::Inline annotation comments are allowed.
|
14
14
|
#
|
15
15
|
# Autocorrection removes comments from `end` keyword and keeps comments
|
16
16
|
# for `class`, `module`, `def` and `begin` above the keyword.
|
@@ -82,6 +82,8 @@ module RuboCop
|
|
82
82
|
|
83
83
|
def offensive?(comment)
|
84
84
|
line = source_line(comment)
|
85
|
+
return false if rbs_inline_annotation?(line, comment)
|
86
|
+
|
85
87
|
KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
|
86
88
|
ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
|
87
89
|
end
|
@@ -89,6 +91,10 @@ module RuboCop
|
|
89
91
|
def source_line(comment)
|
90
92
|
comment.source_range.source_line
|
91
93
|
end
|
94
|
+
|
95
|
+
def rbs_inline_annotation?(line, comment)
|
96
|
+
comment.text.start_with?('#:') && line.start_with?(/\A\s*def\s/)
|
97
|
+
end
|
92
98
|
end
|
93
99
|
end
|
94
100
|
end
|
@@ -73,7 +73,7 @@ module RuboCop
|
|
73
73
|
elsif_branches << node.if_branch
|
74
74
|
|
75
75
|
else_branch = node.else_branch
|
76
|
-
if else_branch&.if_type? && else_branch
|
76
|
+
if else_branch&.if_type? && else_branch.elsif?
|
77
77
|
expand_elsif(else_branch, elsif_branches)
|
78
78
|
else
|
79
79
|
elsif_branches << else_branch
|
@@ -36,7 +36,7 @@ module RuboCop
|
|
36
36
|
def on_class(node)
|
37
37
|
return unless data_define?(node.parent_class)
|
38
38
|
|
39
|
-
add_offense(node.parent_class
|
39
|
+
add_offense(node.parent_class) do |corrector|
|
40
40
|
corrector.remove(range_with_surrounding_space(node.loc.keyword, newlines: false))
|
41
41
|
corrector.replace(node.loc.operator, '=')
|
42
42
|
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
def_node_matcher :array_node, '(send (const {nil? cbase} :Array) :new (array)?)'
|
35
35
|
|
36
36
|
# @!method hash_node(node)
|
37
|
-
def_node_matcher :hash_node, '(send (const {nil? cbase} :Hash) :new
|
37
|
+
def_node_matcher :hash_node, '(send (const {nil? cbase} :Hash) :new)'
|
38
38
|
|
39
39
|
# @!method str_node(node)
|
40
40
|
def_node_matcher :str_node, '(send (const {nil? cbase} :String) :new)'
|
@@ -136,7 +136,7 @@ module RuboCop
|
|
136
136
|
actual: line_node.source,
|
137
137
|
expected: expected)
|
138
138
|
|
139
|
-
add_offense(line_node
|
139
|
+
add_offense(line_node, message: message) do |corrector|
|
140
140
|
corrector.replace(line_node, expected)
|
141
141
|
end
|
142
142
|
end
|
@@ -234,11 +234,11 @@ module RuboCop
|
|
234
234
|
end
|
235
235
|
|
236
236
|
def autocorrect_heredoc_argument(corrector, node, heredoc_branch, leave_branch, guard)
|
237
|
+
remove_whole_lines(corrector, node.loc.end)
|
237
238
|
return unless node.else?
|
238
239
|
|
239
240
|
remove_whole_lines(corrector, leave_branch.source_range)
|
240
241
|
remove_whole_lines(corrector, node.loc.else)
|
241
|
-
remove_whole_lines(corrector, node.loc.end)
|
242
242
|
remove_whole_lines(corrector, range_of_branch_to_remove(node, guard))
|
243
243
|
corrector.insert_after(
|
244
244
|
heredoc_branch.last_argument.loc.heredoc_end, "\n#{leave_branch.source}"
|
@@ -57,6 +57,11 @@ module RuboCop
|
|
57
57
|
(call $(call _ ${:keys :values}) :each (block_pass (sym _)))
|
58
58
|
PATTERN
|
59
59
|
|
60
|
+
# @!method hash_mutated?(node, receiver)
|
61
|
+
def_node_matcher :hash_mutated?, <<~PATTERN
|
62
|
+
`(send %1 :[]= ...)
|
63
|
+
PATTERN
|
64
|
+
|
60
65
|
def on_block(node)
|
61
66
|
return unless handleable?(node)
|
62
67
|
|
@@ -103,6 +108,7 @@ module RuboCop
|
|
103
108
|
def handleable?(node)
|
104
109
|
return false if use_array_converter_method_as_preceding?(node)
|
105
110
|
return false unless (root_receiver = root_receiver(node))
|
111
|
+
return false if hash_mutated?(node, root_receiver)
|
106
112
|
|
107
113
|
!root_receiver.literal? || root_receiver.hash_type?
|
108
114
|
end
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
# {a: 1, b: 2}
|
69
69
|
# {:c => 3, 'd' => 4}
|
70
70
|
#
|
71
|
-
# @example EnforcedShorthandSyntax: always
|
71
|
+
# @example EnforcedShorthandSyntax: always
|
72
72
|
#
|
73
73
|
# # bad
|
74
74
|
# {foo: foo, bar: bar}
|
@@ -84,7 +84,7 @@ module RuboCop
|
|
84
84
|
# # good
|
85
85
|
# {foo: foo, bar: bar}
|
86
86
|
#
|
87
|
-
# @example EnforcedShorthandSyntax: either
|
87
|
+
# @example EnforcedShorthandSyntax: either (default)
|
88
88
|
#
|
89
89
|
# # good
|
90
90
|
# {foo: foo, bar: bar}
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
71
71
|
|
72
72
|
else_branch = node.else_branch
|
73
73
|
|
74
|
-
return unless else_branch&.if_type? && else_branch
|
74
|
+
return unless else_branch&.if_type? && else_branch.if?
|
75
75
|
return if allow_if_modifier_in_else_branch?(else_branch)
|
76
76
|
|
77
77
|
add_offense(else_branch.loc.keyword) do |corrector|
|
@@ -36,10 +36,12 @@ module RuboCop
|
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
39
40
|
def message(node)
|
40
41
|
template = if node.if_branch&.begin_type?
|
41
42
|
MSG_NEWLINE
|
42
|
-
elsif node.else_branch&.if_type? || node.else_branch&.begin_type?
|
43
|
+
elsif node.else_branch&.if_type? || node.else_branch&.begin_type? ||
|
44
|
+
use_block_in_branches?(node)
|
43
45
|
MSG_IF_ELSE
|
44
46
|
else
|
45
47
|
MSG_TERNARY
|
@@ -47,15 +49,20 @@ module RuboCop
|
|
47
49
|
|
48
50
|
format(template, expr: node.condition.source)
|
49
51
|
end
|
52
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
50
53
|
|
51
54
|
def autocorrect(corrector, node)
|
52
|
-
if node.
|
55
|
+
if node.branches.compact.any?(&:begin_type?) || use_block_in_branches?(node)
|
53
56
|
corrector.replace(node.loc.begin, "\n")
|
54
57
|
else
|
55
58
|
corrector.replace(node, replacement(node))
|
56
59
|
end
|
57
60
|
end
|
58
61
|
|
62
|
+
def use_block_in_branches?(node)
|
63
|
+
node.branches.compact.any? { |branch| branch.block_type? || branch.numblock_type? }
|
64
|
+
end
|
65
|
+
|
59
66
|
def replacement(node)
|
60
67
|
return correct_elsif(node) if node.else_branch&.if_type?
|
61
68
|
|
@@ -74,16 +81,14 @@ module RuboCop
|
|
74
81
|
RUBY
|
75
82
|
end
|
76
83
|
|
77
|
-
# rubocop:disable Metrics/AbcSize
|
78
84
|
def build_expression(expr)
|
79
|
-
return expr.source
|
85
|
+
return expr.source unless require_argument_parentheses?(expr)
|
80
86
|
|
81
87
|
method = expr.source_range.begin.join(expr.loc.selector.end)
|
82
88
|
arguments = expr.first_argument.source_range.begin.join(expr.source_range.end)
|
83
89
|
|
84
90
|
"#{method.source}(#{arguments.source})"
|
85
91
|
end
|
86
|
-
# rubocop:enable Metrics/AbcSize
|
87
92
|
|
88
93
|
def build_else_branch(second_condition)
|
89
94
|
result = <<~RUBY
|
@@ -104,6 +109,12 @@ module RuboCop
|
|
104
109
|
|
105
110
|
result
|
106
111
|
end
|
112
|
+
|
113
|
+
def require_argument_parentheses?(node)
|
114
|
+
return false unless node.call_type?
|
115
|
+
|
116
|
+
!node.parenthesized? && node.arguments.any? && !node.method?(:[]) && !node.method?(:[]=)
|
117
|
+
end
|
107
118
|
end
|
108
119
|
end
|
109
120
|
end
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
|
69
69
|
return unless offending_selector?(node, selector)
|
70
70
|
|
71
|
-
add_offense(node.send_node
|
71
|
+
add_offense(node.send_node, message: message(node, selector)) do |corrector|
|
72
72
|
if node.send_node.lambda_literal?
|
73
73
|
LambdaLiteralToMethodCorrector.new(node).call(corrector)
|
74
74
|
else
|
@@ -105,26 +105,21 @@ module RuboCop
|
|
105
105
|
|
106
106
|
# Value object to extract source ranges for the different parts of a magic comment
|
107
107
|
class CommentRange
|
108
|
+
extend SimpleForwardable
|
109
|
+
|
108
110
|
DIRECTIVE_REGEXP = Regexp.union(MagicComment::KEYWORDS.map do |_, v|
|
109
111
|
Regexp.new(v, Regexp::IGNORECASE)
|
110
112
|
end).freeze
|
111
113
|
|
112
114
|
VALUE_REGEXP = Regexp.new("(?:#{DIRECTIVE_REGEXP}:\s*)(.*?)(?=;|$)")
|
113
115
|
|
116
|
+
def_delegators :@comment, :text, :loc
|
114
117
|
attr_reader :comment
|
115
118
|
|
116
119
|
def initialize(comment)
|
117
120
|
@comment = comment
|
118
121
|
end
|
119
122
|
|
120
|
-
def text
|
121
|
-
@comment.text
|
122
|
-
end
|
123
|
-
|
124
|
-
def loc
|
125
|
-
@comment.loc
|
126
|
-
end
|
127
|
-
|
128
123
|
# A magic comment can contain one directive (normal style) or
|
129
124
|
# multiple directives (emacs style)
|
130
125
|
def directives
|