rubocop 1.66.0 → 1.67.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/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
|