rubocop 1.56.0 → 1.57.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 +12 -6
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +3 -1
- data/lib/rubocop/cop/bundler/duplicated_group.rb +54 -8
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
- data/lib/rubocop/cop/internal_affairs/example_description.rb +42 -22
- data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
- data/lib/rubocop/cop/layout/dot_position.rb +1 -5
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +41 -8
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +3 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +13 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +5 -3
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +10 -1
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +16 -4
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +11 -4
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +5 -3
- data/lib/rubocop/cop/lint/useless_assignment.rb +38 -12
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +2 -2
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -2
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +5 -7
- data/lib/rubocop/cop/naming/file_name.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +22 -11
- data/lib/rubocop/cop/style/array_intersect.rb +13 -5
- data/lib/rubocop/cop/style/class_equality_comparison.rb +5 -0
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
- data/lib/rubocop/cop/style/for.rb +1 -1
- data/lib/rubocop/cop/style/format_string.rb +24 -3
- data/lib/rubocop/cop/style/guard_clause.rb +26 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +17 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +3 -1
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +6 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +9 -1
- data/lib/rubocop/cop/style/redundant_conditional.rb +1 -9
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +69 -6
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +18 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +24 -6
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +5 -0
- data/lib/rubocop/cop/style/return_nil.rb +6 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +65 -0
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
- data/lib/rubocop/cop/style/symbol_array.rb +12 -11
- data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
- data/lib/rubocop/cop/utils/regexp_ranges.rb +26 -13
- data/lib/rubocop/file_finder.rb +4 -7
- data/lib/rubocop/lsp/routes.rb +4 -1
- data/lib/rubocop/magic_comment.rb +12 -10
- data/lib/rubocop/rspec/shared_contexts.rb +2 -3
- data/lib/rubocop/server/cache.rb +1 -0
- data/lib/rubocop/target_ruby.rb +9 -5
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +1 -0
- metadata +13 -12
|
@@ -168,7 +168,7 @@ module RuboCop
|
|
|
168
168
|
# follows, and that the rules for space inside don't apply.
|
|
169
169
|
return true if token2.comment?
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
!same_line?(token1, token2) || token1.space_after?
|
|
172
172
|
end
|
|
173
173
|
end
|
|
174
174
|
end
|
|
@@ -95,8 +95,11 @@ module RuboCop
|
|
|
95
95
|
def assumed_usage_context?(node)
|
|
96
96
|
# Basically, debugger methods are not used as a method argument without arguments.
|
|
97
97
|
return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any?
|
|
98
|
+
return true if assumed_argument?(node)
|
|
98
99
|
|
|
99
|
-
node.each_ancestor.none?
|
|
100
|
+
node.each_ancestor.none? do |ancestor|
|
|
101
|
+
ancestor.block_type? || ancestor.numblock_type? || ancestor.lambda_or_proc?
|
|
102
|
+
end
|
|
100
103
|
end
|
|
101
104
|
|
|
102
105
|
def chained_method_name(send_node)
|
|
@@ -109,6 +112,12 @@ module RuboCop
|
|
|
109
112
|
end
|
|
110
113
|
chained_method_name
|
|
111
114
|
end
|
|
115
|
+
|
|
116
|
+
def assumed_argument?(node)
|
|
117
|
+
parent = node.parent
|
|
118
|
+
|
|
119
|
+
parent.call_type? || parent.literal? || parent.pair_type?
|
|
120
|
+
end
|
|
112
121
|
end
|
|
113
122
|
end
|
|
114
123
|
end
|
|
@@ -5,7 +5,7 @@ module RuboCop
|
|
|
5
5
|
module Lint
|
|
6
6
|
# Checks for blocks without a body.
|
|
7
7
|
# Such empty blocks are typically an oversight or we should provide a comment
|
|
8
|
-
#
|
|
8
|
+
# to clarify what we're aiming for.
|
|
9
9
|
#
|
|
10
10
|
# Empty lambdas and procs are ignored by default.
|
|
11
11
|
#
|
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
|
34
34
|
# interpolation should not be removed if the expanded value
|
|
35
35
|
# contains a space character.
|
|
36
36
|
expanded_value = autocorrected_value(final_node)
|
|
37
|
-
return if in_array_percent_literal?(begin_node) && /\s/.match?(expanded_value)
|
|
37
|
+
return if in_array_percent_literal?(begin_node) && /\s|\A\z/.match?(expanded_value)
|
|
38
38
|
|
|
39
39
|
add_offense(final_node) do |corrector|
|
|
40
40
|
return if final_node.dstr_type? # nested, fixed in next iteration
|
|
@@ -43,7 +43,6 @@ module RuboCop
|
|
|
43
43
|
#
|
|
44
44
|
class NonAtomicFileOperation < Base
|
|
45
45
|
extend AutoCorrector
|
|
46
|
-
include Alignment
|
|
47
46
|
|
|
48
47
|
MSG_REMOVE_FILE_EXIST_CHECK = 'Remove unnecessary existence check ' \
|
|
49
48
|
'`%<receiver>s.%<method_name>s`.'
|
|
@@ -51,18 +50,20 @@ module RuboCop
|
|
|
51
50
|
MAKE_FORCE_METHODS = %i[makedirs mkdir_p mkpath].freeze
|
|
52
51
|
MAKE_METHODS = %i[mkdir].freeze
|
|
53
52
|
REMOVE_FORCE_METHODS = %i[rm_f rm_rf].freeze
|
|
54
|
-
REMOVE_METHODS = %i[remove
|
|
55
|
-
|
|
56
|
-
RESTRICT_ON_SEND = (
|
|
57
|
-
|
|
53
|
+
REMOVE_METHODS = %i[remove delete unlink remove_file rm rmdir safe_unlink].freeze
|
|
54
|
+
RECURSIVE_REMOVE_METHODS = %i[remove_dir remove_entry remove_entry_secure].freeze
|
|
55
|
+
RESTRICT_ON_SEND = (
|
|
56
|
+
MAKE_METHODS + MAKE_FORCE_METHODS + REMOVE_METHODS + RECURSIVE_REMOVE_METHODS +
|
|
57
|
+
REMOVE_FORCE_METHODS
|
|
58
|
+
).freeze
|
|
58
59
|
|
|
59
60
|
# @!method send_exist_node(node)
|
|
60
|
-
def_node_search :send_exist_node,
|
|
61
|
+
def_node_search :send_exist_node, <<~PATTERN
|
|
61
62
|
$(send (const nil? {:FileTest :File :Dir :Shell}) {:exist? :exists?} ...)
|
|
62
63
|
PATTERN
|
|
63
64
|
|
|
64
65
|
# @!method receiver_and_method_name(node)
|
|
65
|
-
def_node_matcher :receiver_and_method_name,
|
|
66
|
+
def_node_matcher :receiver_and_method_name, <<~PATTERN
|
|
66
67
|
(send (const nil? $_) $_ ...)
|
|
67
68
|
PATTERN
|
|
68
69
|
|
|
@@ -140,6 +141,8 @@ module RuboCop
|
|
|
140
141
|
'mkdir_p'
|
|
141
142
|
elsif REMOVE_METHODS.include?(node.method_name)
|
|
142
143
|
'rm_f'
|
|
144
|
+
elsif RECURSIVE_REMOVE_METHODS.include?(node.method_name)
|
|
145
|
+
'rm_rf'
|
|
143
146
|
else
|
|
144
147
|
node.method_name
|
|
145
148
|
end
|
|
@@ -24,6 +24,10 @@ module RuboCop
|
|
|
24
24
|
#
|
|
25
25
|
# This cop target those features.
|
|
26
26
|
#
|
|
27
|
+
# @safety
|
|
28
|
+
# This cop's autocorrection is unsafe because if `require 'pp'` is removed from one file,
|
|
29
|
+
# `NameError` can be encountered when another file uses `PP.pp`.
|
|
30
|
+
#
|
|
27
31
|
# @example
|
|
28
32
|
# # bad
|
|
29
33
|
# require 'unloaded_feature'
|
|
@@ -4,8 +4,12 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Lint
|
|
6
6
|
# Checks for redundant safe navigation calls.
|
|
7
|
-
#
|
|
8
|
-
#
|
|
7
|
+
# Use cases where a constant is `nil` are rare and an offense is detected
|
|
8
|
+
# when the receiver is a constant.
|
|
9
|
+
#
|
|
10
|
+
# For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
|
|
11
|
+
# and `equal?` methods are checked by default.
|
|
12
|
+
# These are customizable with `AllowedMethods` option.
|
|
9
13
|
#
|
|
10
14
|
# The `AllowedMethods` option specifies nil-safe methods,
|
|
11
15
|
# in other words, it is a method that is allowed to skip safe navigation.
|
|
@@ -22,6 +26,9 @@ module RuboCop
|
|
|
22
26
|
#
|
|
23
27
|
# @example
|
|
24
28
|
# # bad
|
|
29
|
+
# Const&.do_something
|
|
30
|
+
#
|
|
31
|
+
# # bad
|
|
25
32
|
# do_something if attrs&.respond_to?(:[])
|
|
26
33
|
#
|
|
27
34
|
# # good
|
|
@@ -33,6 +40,9 @@ module RuboCop
|
|
|
33
40
|
# end
|
|
34
41
|
#
|
|
35
42
|
# # good
|
|
43
|
+
# Const.do_something
|
|
44
|
+
#
|
|
45
|
+
# # good
|
|
36
46
|
# while node.is_a?(BeginNode)
|
|
37
47
|
# node = node.parent
|
|
38
48
|
# end
|
|
@@ -63,8 +73,10 @@ module RuboCop
|
|
|
63
73
|
PATTERN
|
|
64
74
|
|
|
65
75
|
def on_csend(node)
|
|
66
|
-
|
|
67
|
-
|
|
76
|
+
unless node.receiver.const_type?
|
|
77
|
+
return unless check?(node) && allowed_method?(node.method_name)
|
|
78
|
+
return if respond_to_nil_specific_method?(node)
|
|
79
|
+
end
|
|
68
80
|
|
|
69
81
|
range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
|
|
70
82
|
add_offense(range) { |corrector| corrector.replace(node.loc.dot, '.') }
|
|
@@ -82,16 +82,23 @@ module RuboCop
|
|
|
82
82
|
def autocorrect(corrector, offense_range:, send_node:)
|
|
83
83
|
corrector.replace(
|
|
84
84
|
offense_range,
|
|
85
|
-
add_safe_navigation_operator(
|
|
86
|
-
offense_range: offense_range,
|
|
87
|
-
send_node: send_node
|
|
88
|
-
)
|
|
85
|
+
add_safe_navigation_operator(offense_range: offense_range, send_node: send_node)
|
|
89
86
|
)
|
|
87
|
+
|
|
88
|
+
corrector.wrap(send_node, '(', ')') if require_parentheses?(send_node)
|
|
90
89
|
end
|
|
91
90
|
|
|
92
91
|
def brackets?(send_node)
|
|
93
92
|
send_node.method?(:[]) || send_node.method?(:[]=)
|
|
94
93
|
end
|
|
94
|
+
|
|
95
|
+
def require_parentheses?(send_node)
|
|
96
|
+
return false unless send_node.comparison_method?
|
|
97
|
+
return false unless (node = send_node.parent)
|
|
98
|
+
|
|
99
|
+
(node.respond_to?(:logical_operator?) && node.logical_operator?) ||
|
|
100
|
+
(node.respond_to?(:comparison_method?) && node.comparison_method?)
|
|
101
|
+
end
|
|
95
102
|
end
|
|
96
103
|
end
|
|
97
104
|
end
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
|
74
74
|
end
|
|
75
75
|
end
|
|
76
76
|
|
|
77
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
77
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
78
78
|
def argument_match?(send_arg, def_arg)
|
|
79
79
|
def_arg_name = def_arg.children[0]
|
|
80
80
|
|
|
@@ -87,12 +87,14 @@ module RuboCop
|
|
|
87
87
|
send_arg.hash_type? &&
|
|
88
88
|
send_arg.pairs.any? { |pair| passing_keyword_arg?(pair, def_arg_name) }
|
|
89
89
|
when :kwrestarg
|
|
90
|
-
send_arg.each_child_node(:kwsplat).any?
|
|
90
|
+
send_arg.each_child_node(:kwsplat, :forwarded_kwrestarg).any? do |child|
|
|
91
|
+
child.source == def_arg.source
|
|
92
|
+
end
|
|
91
93
|
when :forward_arg
|
|
92
94
|
send_arg.forwarded_args_type?
|
|
93
95
|
end
|
|
94
96
|
end
|
|
95
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
97
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
|
96
98
|
end
|
|
97
99
|
end
|
|
98
100
|
end
|
|
@@ -7,12 +7,18 @@ module RuboCop
|
|
|
7
7
|
# scope.
|
|
8
8
|
# The basic idea for this cop was from the warning of `ruby -cw`:
|
|
9
9
|
#
|
|
10
|
-
#
|
|
10
|
+
# [source,console]
|
|
11
|
+
# ----
|
|
12
|
+
# assigned but unused variable - foo
|
|
13
|
+
# ----
|
|
11
14
|
#
|
|
12
15
|
# Currently this cop has advanced logic that detects unreferenced
|
|
13
16
|
# reassignments and properly handles varied cases such as branch, loop,
|
|
14
17
|
# rescue, ensure, etc.
|
|
15
18
|
#
|
|
19
|
+
# NOTE: Given the assignment `foo = 1, bar = 2`, removing unused variables
|
|
20
|
+
# can lead to a syntax error, so this case is not autocorrected.
|
|
21
|
+
#
|
|
16
22
|
# @safety
|
|
17
23
|
# This cop's autocorrection is unsafe because removing assignment from
|
|
18
24
|
# operator assignment can cause NameError if this assignment has been used to declare
|
|
@@ -51,25 +57,24 @@ module RuboCop
|
|
|
51
57
|
scope.variables.each_value { |variable| check_for_unused_assignments(variable) }
|
|
52
58
|
end
|
|
53
59
|
|
|
60
|
+
# rubocop:disable Metrics/AbcSize
|
|
54
61
|
def check_for_unused_assignments(variable)
|
|
55
62
|
return if variable.should_be_unused?
|
|
56
63
|
|
|
57
64
|
variable.assignments.each do |assignment|
|
|
58
|
-
next if assignment.used?
|
|
65
|
+
next if assignment.used? || part_of_ignored_node?(assignment.node)
|
|
59
66
|
|
|
60
67
|
message = message_for_useless_assignment(assignment)
|
|
68
|
+
range = offense_range(assignment)
|
|
61
69
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
else
|
|
65
|
-
assignment.node.loc.name
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
add_offense(location, message: message) do |corrector|
|
|
69
|
-
autocorrect(corrector, assignment)
|
|
70
|
+
add_offense(range, message: message) do |corrector|
|
|
71
|
+
autocorrect(corrector, assignment) unless sequential_assignment?(assignment.node)
|
|
70
72
|
end
|
|
73
|
+
|
|
74
|
+
ignore_node(assignment.node) if chained_assignment?(assignment.node)
|
|
71
75
|
end
|
|
72
76
|
end
|
|
77
|
+
# rubocop:enable Metrics/AbcSize
|
|
73
78
|
|
|
74
79
|
def message_for_useless_assignment(assignment)
|
|
75
80
|
variable = assignment.variable
|
|
@@ -77,6 +82,28 @@ module RuboCop
|
|
|
77
82
|
format(MSG, variable: variable.name) + message_specification(assignment, variable).to_s
|
|
78
83
|
end
|
|
79
84
|
|
|
85
|
+
def offense_range(assignment)
|
|
86
|
+
if assignment.regexp_named_capture?
|
|
87
|
+
assignment.node.children.first.source_range
|
|
88
|
+
else
|
|
89
|
+
assignment.node.loc.name
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def sequential_assignment?(node)
|
|
94
|
+
if node.lvasgn_type? && node.expression&.array_type? &&
|
|
95
|
+
node.each_descendant.any?(&:assignment?)
|
|
96
|
+
return true
|
|
97
|
+
end
|
|
98
|
+
return false unless node.parent
|
|
99
|
+
|
|
100
|
+
sequential_assignment?(node.parent)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def chained_assignment?(node)
|
|
104
|
+
node.respond_to?(:expression) && node.expression&.lvasgn_type?
|
|
105
|
+
end
|
|
106
|
+
|
|
80
107
|
def message_specification(assignment, variable)
|
|
81
108
|
if assignment.multiple_assignment?
|
|
82
109
|
multiple_assignment_message(variable.name)
|
|
@@ -96,8 +123,7 @@ module RuboCop
|
|
|
96
123
|
return_value_node = return_value_node_of_scope(scope)
|
|
97
124
|
return unless assignment.meta_assignment_node.equal?(return_value_node)
|
|
98
125
|
|
|
99
|
-
" Use `#{assignment.operator.
|
|
100
|
-
"instead of `#{assignment.operator}`."
|
|
126
|
+
" Use `#{assignment.operator.delete_suffix('=')}` instead of `#{assignment.operator}`."
|
|
101
127
|
end
|
|
102
128
|
|
|
103
129
|
def similar_name_message(variable)
|
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
|
12
12
|
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
|
13
13
|
# will be counted as one line regardless of its actual size.
|
|
14
14
|
#
|
|
15
|
+
# NOTE: This cop does not apply for `Struct` definitions.
|
|
15
16
|
#
|
|
16
17
|
# NOTE: The `ExcludedMethods` configuration is deprecated and only kept
|
|
17
18
|
# for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns`
|
|
@@ -40,7 +41,6 @@ module RuboCop
|
|
|
40
41
|
# )
|
|
41
42
|
# end # 6 points
|
|
42
43
|
#
|
|
43
|
-
# NOTE: This cop does not apply for `Struct` definitions.
|
|
44
44
|
class BlockLength < Base
|
|
45
45
|
include CodeLength
|
|
46
46
|
include AllowedMethods
|
|
@@ -11,6 +11,8 @@ module RuboCop
|
|
|
11
11
|
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
|
12
12
|
# will be counted as one line regardless of its actual size.
|
|
13
13
|
#
|
|
14
|
+
# NOTE: This cop also applies for `Struct` definitions.
|
|
15
|
+
#
|
|
14
16
|
# @example CountAsOne: ['array', 'heredoc', 'method_call']
|
|
15
17
|
#
|
|
16
18
|
# class Foo
|
|
@@ -34,8 +36,6 @@ module RuboCop
|
|
|
34
36
|
# )
|
|
35
37
|
# end # 6 points
|
|
36
38
|
#
|
|
37
|
-
#
|
|
38
|
-
# NOTE: This cop also applies for `Struct` definitions.
|
|
39
39
|
class ClassLength < Base
|
|
40
40
|
include CodeLength
|
|
41
41
|
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
|
10
10
|
include Util
|
|
11
11
|
|
|
12
12
|
FOLDABLE_TYPES = %i[array hash heredoc send csend].freeze
|
|
13
|
-
CLASSLIKE_TYPES = %i[class module
|
|
13
|
+
CLASSLIKE_TYPES = %i[class module].freeze
|
|
14
14
|
private_constant :FOLDABLE_TYPES, :CLASSLIKE_TYPES
|
|
15
15
|
|
|
16
16
|
def initialize(node, processed_source, count_comments: false, foldable_types: [])
|
|
@@ -145,7 +145,7 @@ module RuboCop
|
|
|
145
145
|
|
|
146
146
|
def extract_body(node)
|
|
147
147
|
case node.type
|
|
148
|
-
when :class, :module, :block, :numblock, :def, :defs
|
|
148
|
+
when :class, :module, :sclass, :block, :numblock, :def, :defs
|
|
149
149
|
node.body
|
|
150
150
|
when :casgn
|
|
151
151
|
_scope, _name, value = *node
|
|
@@ -20,16 +20,17 @@ module RuboCop
|
|
|
20
20
|
range = offending_range(node, lhs, rhs, style)
|
|
21
21
|
check(range, node, lhs, rhs)
|
|
22
22
|
end
|
|
23
|
+
alias on_csend on_send
|
|
23
24
|
|
|
24
25
|
private
|
|
25
26
|
|
|
26
|
-
# In a chain of method calls, we regard the top
|
|
27
|
+
# In a chain of method calls, we regard the top call node as the base
|
|
27
28
|
# for indentation of all lines following the first. For example:
|
|
28
29
|
# a.
|
|
29
30
|
# b c { block }. <-- b is indented relative to a
|
|
30
31
|
# d <-- d is indented relative to a
|
|
31
32
|
def left_hand_side(lhs)
|
|
32
|
-
while lhs.parent&.
|
|
33
|
+
while lhs.parent&.call_type? && lhs.parent.loc.dot && !lhs.parent.assignment_method?
|
|
33
34
|
lhs = lhs.parent
|
|
34
35
|
end
|
|
35
36
|
lhs
|
|
@@ -75,7 +75,7 @@ module RuboCop
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def aligned_token?(range, line)
|
|
78
|
-
aligned_words?(range, line) ||
|
|
78
|
+
aligned_words?(range, line) || aligned_assignment?(range, line)
|
|
79
79
|
end
|
|
80
80
|
|
|
81
81
|
def aligned_operator?(range, line)
|
|
@@ -83,13 +83,11 @@ module RuboCop
|
|
|
83
83
|
end
|
|
84
84
|
|
|
85
85
|
def aligned_words?(range, line)
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
def aligned_dot?(range, line)
|
|
90
|
-
char = line[range.column]
|
|
86
|
+
left_edge = range.column
|
|
87
|
+
return true if /\s\S/.match?(line[left_edge - 1, 2])
|
|
91
88
|
|
|
92
|
-
|
|
89
|
+
token = range.source
|
|
90
|
+
token == line[left_edge, token.length]
|
|
93
91
|
end
|
|
94
92
|
|
|
95
93
|
def aligned_assignment?(range, line)
|
|
@@ -136,7 +136,7 @@ module RuboCop
|
|
|
136
136
|
end
|
|
137
137
|
|
|
138
138
|
def filename_good?(basename)
|
|
139
|
-
basename = basename.
|
|
139
|
+
basename = basename.delete_prefix('.')
|
|
140
140
|
basename = basename.sub(/\.[^.]+$/, '')
|
|
141
141
|
# special handling for Action Pack Variants file names like
|
|
142
142
|
# some_file.xlsx+mobile.axlsx
|
|
@@ -80,6 +80,7 @@ module RuboCop
|
|
|
80
80
|
minimum_target_ruby_version 2.7
|
|
81
81
|
|
|
82
82
|
FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
|
|
83
|
+
ADDITIONAL_ARG_TYPES = %i[lvar arg].freeze
|
|
83
84
|
|
|
84
85
|
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
|
85
86
|
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
|
@@ -115,11 +116,11 @@ module RuboCop
|
|
|
115
116
|
end
|
|
116
117
|
|
|
117
118
|
def only_forwards_all?(send_classifications)
|
|
118
|
-
send_classifications.
|
|
119
|
+
send_classifications.all? { |_, c, _, _| c == :all }
|
|
119
120
|
end
|
|
120
121
|
|
|
121
122
|
def add_forward_all_offenses(node, send_classifications, forwardable_args)
|
|
122
|
-
send_classifications.each do |send_node,
|
|
123
|
+
send_classifications.each do |send_node, _c, forward_rest, _forward_kwrest|
|
|
123
124
|
register_forward_all_offense(send_node, send_node, forward_rest)
|
|
124
125
|
end
|
|
125
126
|
|
|
@@ -132,7 +133,7 @@ module RuboCop
|
|
|
132
133
|
|
|
133
134
|
rest_arg, kwrest_arg, _block_arg = *forwardable_args
|
|
134
135
|
|
|
135
|
-
send_classifications.each do |send_node,
|
|
136
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
|
|
136
137
|
if forward_rest
|
|
137
138
|
register_forward_args_offense(def_node.arguments, rest_arg)
|
|
138
139
|
register_forward_args_offense(send_node, forward_rest)
|
|
@@ -156,7 +157,7 @@ module RuboCop
|
|
|
156
157
|
end
|
|
157
158
|
|
|
158
159
|
def classify_send_nodes(def_node, send_nodes, referenced_lvars, forwardable_args)
|
|
159
|
-
send_nodes.
|
|
160
|
+
send_nodes.filter_map do |send_node|
|
|
160
161
|
classification_and_forwards = classification_and_forwards(
|
|
161
162
|
def_node,
|
|
162
163
|
send_node,
|
|
@@ -164,8 +165,10 @@ module RuboCop
|
|
|
164
165
|
forwardable_args
|
|
165
166
|
)
|
|
166
167
|
|
|
167
|
-
|
|
168
|
-
|
|
168
|
+
next unless classification_and_forwards
|
|
169
|
+
|
|
170
|
+
[send_node, *classification_and_forwards]
|
|
171
|
+
end
|
|
169
172
|
end
|
|
170
173
|
|
|
171
174
|
def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
|
|
@@ -212,7 +215,7 @@ module RuboCop
|
|
|
212
215
|
end
|
|
213
216
|
|
|
214
217
|
def arguments_range(node, first_node)
|
|
215
|
-
arguments = node.arguments
|
|
218
|
+
arguments = node.arguments.reject { |arg| ADDITIONAL_ARG_TYPES.include?(arg.type) }
|
|
216
219
|
|
|
217
220
|
start_node = first_node || arguments.first
|
|
218
221
|
|
|
@@ -279,7 +282,7 @@ module RuboCop
|
|
|
279
282
|
|
|
280
283
|
if can_forward_all?
|
|
281
284
|
:all
|
|
282
|
-
|
|
285
|
+
else
|
|
283
286
|
:rest_or_kwrest
|
|
284
287
|
end
|
|
285
288
|
end
|
|
@@ -290,7 +293,7 @@ module RuboCop
|
|
|
290
293
|
return false if any_arg_referenced?
|
|
291
294
|
return false if ruby_32_missing_rest_or_kwest?
|
|
292
295
|
return false unless offensive_block_forwarding?
|
|
293
|
-
return false if
|
|
296
|
+
return false if additional_kwargs_or_forwarded_kwargs?
|
|
294
297
|
|
|
295
298
|
no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
|
|
296
299
|
end
|
|
@@ -332,12 +335,20 @@ module RuboCop
|
|
|
332
335
|
end
|
|
333
336
|
|
|
334
337
|
def no_post_splat_args?
|
|
335
|
-
splat_index = arguments.index(forwarded_rest_arg)
|
|
336
|
-
arg_after_splat = arguments[splat_index + 1]
|
|
338
|
+
return true unless (splat_index = arguments.index(forwarded_rest_arg))
|
|
337
339
|
|
|
340
|
+
arg_after_splat = arguments[splat_index + 1]
|
|
338
341
|
[nil, :hash, :block_pass].include?(arg_after_splat&.type)
|
|
339
342
|
end
|
|
340
343
|
|
|
344
|
+
def additional_kwargs_or_forwarded_kwargs?
|
|
345
|
+
additional_kwargs? || forward_additional_kwargs?
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def additional_kwargs?
|
|
349
|
+
@def_node.arguments.any? { |a| a.kwarg_type? || a.kwoptarg_type? }
|
|
350
|
+
end
|
|
351
|
+
|
|
341
352
|
def forward_additional_kwargs?
|
|
342
353
|
return false unless forwarded_kwrest_arg
|
|
343
354
|
|
|
@@ -11,6 +11,15 @@ module RuboCop
|
|
|
11
11
|
# The `array1.intersect?(array2)` method is faster than
|
|
12
12
|
# `(array1 & array2).any?` and is more readable.
|
|
13
13
|
#
|
|
14
|
+
# In cases like the following, compatibility is not ensured,
|
|
15
|
+
# so it will not be detected when using block argument.
|
|
16
|
+
#
|
|
17
|
+
# [source,ruby]
|
|
18
|
+
# ----
|
|
19
|
+
# ([1] & [1,2]).any? { |x| false } # => false
|
|
20
|
+
# [1].intersect?([1,2]) { |x| false } # => true
|
|
21
|
+
# ----
|
|
22
|
+
#
|
|
14
23
|
# @safety
|
|
15
24
|
# This cop cannot guarantee that `array1` and `array2` are
|
|
16
25
|
# actually arrays while method `intersect?` is for arrays only.
|
|
@@ -68,16 +77,15 @@ module RuboCop
|
|
|
68
77
|
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
|
69
78
|
|
|
70
79
|
def on_send(node)
|
|
80
|
+
return if (parent = node.parent) && (parent.block_type? || parent.numblock_type?)
|
|
71
81
|
return unless (receiver, argument, method_name = bad_intersection_check?(node))
|
|
72
82
|
|
|
73
83
|
message = message(receiver.source, argument.source, method_name)
|
|
74
84
|
|
|
75
85
|
add_offense(node, message: message) do |corrector|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
corrector.replace(node, "!#{receiver.source}.intersect?(#{argument.source})")
|
|
80
|
-
end
|
|
86
|
+
bang = straight?(method_name) ? '' : '!'
|
|
87
|
+
|
|
88
|
+
corrector.replace(node, "#{bang}#{receiver.source}.intersect?(#{argument.source})")
|
|
81
89
|
end
|
|
82
90
|
end
|
|
83
91
|
|
|
@@ -8,6 +8,11 @@ module RuboCop
|
|
|
8
8
|
# `==`, `equal?`, and `eql?` custom method definitions are allowed by default.
|
|
9
9
|
# These are customizable with `AllowedMethods` option.
|
|
10
10
|
#
|
|
11
|
+
# @safety
|
|
12
|
+
# This cop's autocorrection is unsafe because there is no guarantee that
|
|
13
|
+
# the constant `Foo` exists when autocorrecting `var.class.name == 'Foo'` to
|
|
14
|
+
# `var.instance_of?(Foo)`.
|
|
15
|
+
#
|
|
11
16
|
# @example
|
|
12
17
|
# # bad
|
|
13
18
|
# var.class == Date
|
|
@@ -25,6 +25,7 @@ module RuboCop
|
|
|
25
25
|
# # bad
|
|
26
26
|
# items.collect
|
|
27
27
|
# items.collect!
|
|
28
|
+
# items.collect_concat
|
|
28
29
|
# items.inject
|
|
29
30
|
# items.detect
|
|
30
31
|
# items.find_all
|
|
@@ -33,6 +34,7 @@ module RuboCop
|
|
|
33
34
|
# # good
|
|
34
35
|
# items.map
|
|
35
36
|
# items.map!
|
|
37
|
+
# items.flat_map
|
|
36
38
|
# items.reduce
|
|
37
39
|
# items.find
|
|
38
40
|
# items.select
|
|
@@ -93,8 +93,9 @@ module RuboCop
|
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def same_collection_looping_block?(node, sibling)
|
|
96
|
-
(sibling
|
|
97
|
-
|
|
96
|
+
return false if sibling.nil? || (!sibling.block_type? && !sibling.numblock_type?)
|
|
97
|
+
|
|
98
|
+
sibling.method?(node.method_name) &&
|
|
98
99
|
sibling.receiver == node.receiver &&
|
|
99
100
|
sibling.send_node.arguments == node.send_node.arguments
|
|
100
101
|
end
|
|
@@ -40,9 +40,13 @@ module RuboCop
|
|
|
40
40
|
extend AutoCorrector
|
|
41
41
|
|
|
42
42
|
MSG = 'Do not use empty `case` condition, instead use an `if` expression.'
|
|
43
|
+
NOT_SUPPORTED_PARENT_TYPES = %i[return break next send csend].freeze
|
|
43
44
|
|
|
45
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
44
46
|
def on_case(case_node)
|
|
45
|
-
|
|
47
|
+
if case_node.condition || NOT_SUPPORTED_PARENT_TYPES.include?(case_node.parent&.type)
|
|
48
|
+
return
|
|
49
|
+
end
|
|
46
50
|
|
|
47
51
|
branch_bodies = [*case_node.when_branches.map(&:body), case_node.else_branch].compact
|
|
48
52
|
|
|
@@ -52,6 +56,7 @@ module RuboCop
|
|
|
52
56
|
|
|
53
57
|
add_offense(case_node.loc.keyword) { |corrector| autocorrect(corrector, case_node) }
|
|
54
58
|
end
|
|
59
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
55
60
|
|
|
56
61
|
private
|
|
57
62
|
|