rubocop 1.57.1 → 1.58.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 +2 -2
- data/config/default.yml +37 -2
- data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
- data/lib/rubocop/config_obsoletion.rb +11 -8
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +7 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +6 -6
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +4 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/debugger.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
- data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +64 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +43 -0
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +37 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +43 -12
- data/lib/rubocop/cop/metrics/class_length.rb +6 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +16 -12
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +2 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +68 -6
- data/lib/rubocop/cop/style/array_first_last.rb +64 -0
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
- data/lib/rubocop/cop/style/case_like_if.rb +4 -4
- data/lib/rubocop/cop/style/combinable_loops.rb +2 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +58 -10
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +9 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
- data/lib/rubocop/cop/style/map_to_hash.rb +9 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -2
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -10
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +4 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +2 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +28 -12
- data/lib/rubocop/cop/style/redundant_return.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +8 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +2 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
- data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/formatter/html_formatter.rb +5 -4
- data/lib/rubocop/result_cache.rb +0 -1
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +13 -23
@@ -50,6 +50,20 @@ module RuboCop
|
|
50
50
|
#
|
51
51
|
# # good
|
52
52
|
# a ** b
|
53
|
+
#
|
54
|
+
# @example EnforcedStyleForRationalLiterals: no_space (default)
|
55
|
+
# # bad
|
56
|
+
# 1 / 48r
|
57
|
+
#
|
58
|
+
# # good
|
59
|
+
# 1/48r
|
60
|
+
#
|
61
|
+
# @example EnforcedStyleForRationalLiterals: space
|
62
|
+
# # bad
|
63
|
+
# 1/48r
|
64
|
+
#
|
65
|
+
# # good
|
66
|
+
# 1 / 48r
|
53
67
|
class SpaceAroundOperators < Base
|
54
68
|
include PrecedingFollowingAlignment
|
55
69
|
include RangeHelp
|
@@ -64,7 +78,7 @@ module RuboCop
|
|
64
78
|
end
|
65
79
|
|
66
80
|
def on_sclass(node)
|
67
|
-
check_operator(:sclass, node.loc.operator, node
|
81
|
+
check_operator(:sclass, node.loc.operator, node)
|
68
82
|
end
|
69
83
|
|
70
84
|
def on_pair(node)
|
@@ -72,14 +86,14 @@ module RuboCop
|
|
72
86
|
|
73
87
|
return if hash_table_style? && !node.parent.pairs_on_same_line?
|
74
88
|
|
75
|
-
check_operator(:pair, node.loc.operator, node
|
89
|
+
check_operator(:pair, node.loc.operator, node)
|
76
90
|
end
|
77
91
|
|
78
92
|
def on_if(node)
|
79
93
|
return unless node.ternary?
|
80
94
|
|
81
|
-
check_operator(:if, node.loc.question, node.if_branch
|
82
|
-
check_operator(:if, node.loc.colon, node.else_branch
|
95
|
+
check_operator(:if, node.loc.question, node.if_branch)
|
96
|
+
check_operator(:if, node.loc.colon, node.else_branch)
|
83
97
|
end
|
84
98
|
|
85
99
|
def on_resbody(node)
|
@@ -87,7 +101,7 @@ module RuboCop
|
|
87
101
|
|
88
102
|
_, variable, = *node
|
89
103
|
|
90
|
-
check_operator(:resbody, node.loc.assoc, variable
|
104
|
+
check_operator(:resbody, node.loc.assoc, variable)
|
91
105
|
end
|
92
106
|
|
93
107
|
def on_send(node)
|
@@ -96,7 +110,7 @@ module RuboCop
|
|
96
110
|
if node.setter_method?
|
97
111
|
on_special_asgn(node)
|
98
112
|
elsif regular_operator?(node)
|
99
|
-
check_operator(:send, node.loc.selector, node.first_argument
|
113
|
+
check_operator(:send, node.loc.selector, node.first_argument)
|
100
114
|
end
|
101
115
|
end
|
102
116
|
|
@@ -105,7 +119,7 @@ module RuboCop
|
|
105
119
|
|
106
120
|
return unless rhs
|
107
121
|
|
108
|
-
check_operator(:assignment, node.loc.operator, rhs
|
122
|
+
check_operator(:assignment, node.loc.operator, rhs)
|
109
123
|
end
|
110
124
|
|
111
125
|
def on_casgn(node)
|
@@ -113,7 +127,7 @@ module RuboCop
|
|
113
127
|
|
114
128
|
return unless right
|
115
129
|
|
116
|
-
check_operator(:assignment, node.loc.operator, right
|
130
|
+
check_operator(:assignment, node.loc.operator, right)
|
117
131
|
end
|
118
132
|
|
119
133
|
def on_binary(node)
|
@@ -121,7 +135,7 @@ module RuboCop
|
|
121
135
|
|
122
136
|
return unless rhs
|
123
137
|
|
124
|
-
check_operator(:binary, node.loc.operator, rhs
|
138
|
+
check_operator(:binary, node.loc.operator, rhs)
|
125
139
|
end
|
126
140
|
|
127
141
|
def on_special_asgn(node)
|
@@ -129,13 +143,13 @@ module RuboCop
|
|
129
143
|
|
130
144
|
return unless right
|
131
145
|
|
132
|
-
check_operator(:special_asgn, node.loc.operator, right
|
146
|
+
check_operator(:special_asgn, node.loc.operator, right)
|
133
147
|
end
|
134
148
|
|
135
149
|
def on_match_pattern(node)
|
136
150
|
return if target_ruby_version < 3.0
|
137
151
|
|
138
|
-
check_operator(:match_pattern, node.loc.operator, node
|
152
|
+
check_operator(:match_pattern, node.loc.operator, node)
|
139
153
|
end
|
140
154
|
|
141
155
|
alias on_or on_binary
|
@@ -168,7 +182,7 @@ module RuboCop
|
|
168
182
|
|
169
183
|
offense(type, operator, with_space, right_operand) do |msg|
|
170
184
|
add_offense(operator, message: msg) do |corrector|
|
171
|
-
autocorrect(corrector, with_space)
|
185
|
+
autocorrect(corrector, with_space, right_operand)
|
172
186
|
end
|
173
187
|
end
|
174
188
|
end
|
@@ -178,11 +192,15 @@ module RuboCop
|
|
178
192
|
yield msg if msg
|
179
193
|
end
|
180
194
|
|
181
|
-
def autocorrect(corrector, range)
|
182
|
-
|
195
|
+
def autocorrect(corrector, range, right_operand)
|
196
|
+
range_source = range.source
|
197
|
+
|
198
|
+
if range_source.include?('**') && !space_around_exponent_operator?
|
183
199
|
corrector.replace(range, '**')
|
184
|
-
elsif
|
185
|
-
corrector.replace(range,
|
200
|
+
elsif range_source.include?('/') && !space_around_slash_operator?(right_operand)
|
201
|
+
corrector.replace(range, '/')
|
202
|
+
elsif range_source.end_with?("\n")
|
203
|
+
corrector.replace(range, " #{range_source.strip}\n")
|
186
204
|
else
|
187
205
|
enclose_operator_with_space(corrector, range)
|
188
206
|
end
|
@@ -202,14 +220,14 @@ module RuboCop
|
|
202
220
|
end
|
203
221
|
|
204
222
|
def offense_message(type, operator, with_space, right_operand)
|
205
|
-
if should_not_have_surrounding_space?(operator)
|
223
|
+
if should_not_have_surrounding_space?(operator, right_operand)
|
206
224
|
return if with_space.is?(operator.source)
|
207
225
|
|
208
226
|
"Space around operator `#{operator.source}` detected."
|
209
227
|
elsif !/^\s.*\s$/.match?(with_space.source)
|
210
228
|
"Surrounding space missing for operator `#{operator.source}`."
|
211
229
|
elsif excess_leading_space?(type, operator, with_space) ||
|
212
|
-
excess_trailing_space?(right_operand, with_space)
|
230
|
+
excess_trailing_space?(right_operand.source_range, with_space)
|
213
231
|
"Operator `#{operator.source}` should be surrounded " \
|
214
232
|
'by a single space.'
|
215
233
|
end
|
@@ -247,12 +265,24 @@ module RuboCop
|
|
247
265
|
cop_config['EnforcedStyleForExponentOperator'] == 'space'
|
248
266
|
end
|
249
267
|
|
268
|
+
def space_around_slash_operator?(right_operand)
|
269
|
+
return true unless right_operand.rational_type?
|
270
|
+
|
271
|
+
cop_config['EnforcedStyleForRationalLiterals'] == 'space'
|
272
|
+
end
|
273
|
+
|
250
274
|
def force_equal_sign_alignment?
|
251
275
|
config.for_cop('Layout/ExtraSpacing')['ForceEqualSignAlignment']
|
252
276
|
end
|
253
277
|
|
254
|
-
def should_not_have_surrounding_space?(operator)
|
255
|
-
operator.is?('**')
|
278
|
+
def should_not_have_surrounding_space?(operator, right_operand)
|
279
|
+
if operator.is?('**')
|
280
|
+
!space_around_exponent_operator?
|
281
|
+
elsif operator.is?('/')
|
282
|
+
!space_around_slash_operator?(right_operand)
|
283
|
+
else
|
284
|
+
false
|
285
|
+
end
|
256
286
|
end
|
257
287
|
end
|
258
288
|
end
|
@@ -17,24 +17,24 @@ module RuboCop
|
|
17
17
|
#
|
18
18
|
# @example
|
19
19
|
# # bad
|
20
|
-
# if some_var =
|
20
|
+
# if some_var = value
|
21
21
|
# do_something
|
22
22
|
# end
|
23
23
|
#
|
24
24
|
# # good
|
25
|
-
# if some_var ==
|
25
|
+
# if some_var == value
|
26
26
|
# do_something
|
27
27
|
# end
|
28
28
|
#
|
29
29
|
# @example AllowSafeAssignment: true (default)
|
30
30
|
# # good
|
31
|
-
# if (some_var =
|
31
|
+
# if (some_var = value)
|
32
32
|
# do_something
|
33
33
|
# end
|
34
34
|
#
|
35
35
|
# @example AllowSafeAssignment: false
|
36
36
|
# # bad
|
37
|
-
# if (some_var =
|
37
|
+
# if (some_var = value)
|
38
38
|
# do_something
|
39
39
|
# end
|
40
40
|
#
|
@@ -66,6 +66,7 @@ module RuboCop
|
|
66
66
|
# end
|
67
67
|
class Debugger < Base
|
68
68
|
MSG = 'Remove debugger entry point `%<source>s`.'
|
69
|
+
BLOCK_TYPES = %i[block numblock kwbegin].freeze
|
69
70
|
|
70
71
|
def on_send(node)
|
71
72
|
return if !debugger_method?(node) || assumed_usage_context?(node)
|
@@ -98,7 +99,7 @@ module RuboCop
|
|
98
99
|
return true if assumed_argument?(node)
|
99
100
|
|
100
101
|
node.each_ancestor.none? do |ancestor|
|
101
|
-
|
102
|
+
BLOCK_TYPES.include?(ancestor.type) || ancestor.lambda_or_proc?
|
102
103
|
end
|
103
104
|
end
|
104
105
|
|
@@ -253,7 +253,7 @@ module RuboCop
|
|
253
253
|
# Assume that if a method definition is inside any block call which
|
254
254
|
# we can't identify, it could be a DSL
|
255
255
|
node.each_ancestor(:block).any? do |ancestor|
|
256
|
-
ancestor.
|
256
|
+
!ancestor.method?(:class_eval) && !ancestor.class_constructor?
|
257
257
|
end
|
258
258
|
end
|
259
259
|
|
@@ -106,7 +106,7 @@ module RuboCop
|
|
106
106
|
private
|
107
107
|
|
108
108
|
def autocorrect(corrector, node)
|
109
|
-
str_arg = node.
|
109
|
+
str_arg = node.first_argument.source
|
110
110
|
|
111
111
|
kwargs = build_kwargs(node)
|
112
112
|
overridden_kwargs = override_by_legacy_args(kwargs, node)
|
@@ -121,11 +121,11 @@ module RuboCop
|
|
121
121
|
end
|
122
122
|
|
123
123
|
def build_kwargs(node)
|
124
|
-
return [nil, nil] unless node.
|
124
|
+
return [nil, nil] unless node.last_argument.hash_type?
|
125
125
|
|
126
126
|
trim_mode_arg, eoutvar_arg = nil
|
127
127
|
|
128
|
-
node.
|
128
|
+
node.last_argument.pairs.each do |pair|
|
129
129
|
case pair.key.source
|
130
130
|
when 'trim_mode'
|
131
131
|
trim_mode_arg = "trim_mode: #{pair.value.source}"
|
@@ -18,6 +18,10 @@ module RuboCop
|
|
18
18
|
# # good - using BigDecimal
|
19
19
|
# x.to_d == 0.1.to_d
|
20
20
|
#
|
21
|
+
# # good - comparing against zero
|
22
|
+
# x == 0.0
|
23
|
+
# x != 0.0
|
24
|
+
#
|
21
25
|
# # good
|
22
26
|
# (x - 0.1).abs < Float::EPSILON
|
23
27
|
#
|
@@ -39,6 +43,8 @@ module RuboCop
|
|
39
43
|
|
40
44
|
def on_send(node)
|
41
45
|
lhs, _method, rhs = *node
|
46
|
+
return if literal_zero?(lhs) || literal_zero?(rhs)
|
47
|
+
|
42
48
|
add_offense(node) if float?(lhs) || float?(rhs)
|
43
49
|
end
|
44
50
|
|
@@ -59,6 +65,10 @@ module RuboCop
|
|
59
65
|
end
|
60
66
|
end
|
61
67
|
|
68
|
+
def literal_zero?(node)
|
69
|
+
node&.numeric_type? && node.value.zero?
|
70
|
+
end
|
71
|
+
|
62
72
|
# rubocop:disable Metrics/PerceivedComplexity
|
63
73
|
def check_send(node)
|
64
74
|
if node.arithmetic_operation?
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for literal assignments in the conditions of `if`, `while`, and `until`.
|
7
|
+
# It emulates the following Ruby warning:
|
8
|
+
#
|
9
|
+
# [source,console]
|
10
|
+
# ----
|
11
|
+
# $ ruby -we 'if x = true; end'
|
12
|
+
# -e:1: warning: found `= literal' in conditional, should be ==
|
13
|
+
# ----
|
14
|
+
#
|
15
|
+
# As a lint cop, it cannot be determined if `==` is appropriate as intended,
|
16
|
+
# therefore this cop does not provide autocorrection.
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# if x = 42
|
22
|
+
# do_something
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# if x == 42
|
27
|
+
# do_something
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
# if x = y
|
32
|
+
# do_something
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
class LiteralAssignmentInCondition < Base
|
36
|
+
MSG = "Don't use literal assignment `= %<literal>s` in conditional, " \
|
37
|
+
'should be `==` or non-literal operand.'
|
38
|
+
|
39
|
+
def on_if(node)
|
40
|
+
traverse_node(node.condition) do |asgn_node|
|
41
|
+
next unless asgn_node.loc.operator
|
42
|
+
|
43
|
+
rhs = asgn_node.to_a.last
|
44
|
+
next unless rhs.respond_to?(:literal?) && rhs.literal?
|
45
|
+
|
46
|
+
range = asgn_node.loc.operator.join(rhs.source_range.end)
|
47
|
+
|
48
|
+
add_offense(range, message: format(MSG, literal: rhs.source))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
alias on_while on_if
|
52
|
+
alias on_until on_if
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def traverse_node(node, &block)
|
57
|
+
yield node if AST::Node::EQUALS_ASSIGNMENTS.include?(node.type)
|
58
|
+
|
59
|
+
node.each_child_node { |child| traverse_node(child, &block) }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -94,7 +94,7 @@ module RuboCop
|
|
94
94
|
parent_node = node.parent
|
95
95
|
|
96
96
|
add_offense(parent_node) do |corrector|
|
97
|
-
if parent_node.
|
97
|
+
if parent_node.last_argument&.block_pass_type?
|
98
98
|
correct_block_pass(corrector, parent_node)
|
99
99
|
else
|
100
100
|
correct_block(corrector, parent_node)
|
@@ -116,7 +116,7 @@ module RuboCop
|
|
116
116
|
|
117
117
|
def correct_block_pass(corrector, node)
|
118
118
|
if unsorted_dir_glob_pass?(node)
|
119
|
-
block_arg = node.
|
119
|
+
block_arg = node.last_argument
|
120
120
|
|
121
121
|
corrector.remove(last_arg_range(node))
|
122
122
|
corrector.insert_after(node, ".sort.each(#{block_arg.source})")
|
@@ -130,9 +130,7 @@ module RuboCop
|
|
130
130
|
# @return [Parser::Source::Range]
|
131
131
|
#
|
132
132
|
def last_arg_range(node)
|
133
|
-
node.
|
134
|
-
begin_pos: node.arguments[-2].source_range.end_pos
|
135
|
-
)
|
133
|
+
node.last_argument.source_range.with(begin_pos: node.arguments[-2].source_range.end_pos)
|
136
134
|
end
|
137
135
|
|
138
136
|
def unsorted_dir_loop?(node)
|
@@ -50,6 +50,22 @@ module RuboCop
|
|
50
50
|
# # good - without `&.` this will always return `true`
|
51
51
|
# foo&.respond_to?(:to_a)
|
52
52
|
#
|
53
|
+
# # bad - for `nil`s conversion methods return default values for the type
|
54
|
+
# foo&.to_h || {}
|
55
|
+
# foo&.to_h { |k, v| [k, v] } || {}
|
56
|
+
# foo&.to_a || []
|
57
|
+
# foo&.to_i || 0
|
58
|
+
# foo&.to_f || 0.0
|
59
|
+
# foo&.to_s || ''
|
60
|
+
#
|
61
|
+
# # good
|
62
|
+
# foo.to_h
|
63
|
+
# foo.to_h { |k, v| [k, v] }
|
64
|
+
# foo.to_a
|
65
|
+
# foo.to_i
|
66
|
+
# foo.to_f
|
67
|
+
# foo.to_s
|
68
|
+
#
|
53
69
|
# @example AllowedMethods: [nil_safe_method]
|
54
70
|
# # bad
|
55
71
|
# do_something if attrs&.nil_safe_method(:[])
|
@@ -64,6 +80,7 @@ module RuboCop
|
|
64
80
|
extend AutoCorrector
|
65
81
|
|
66
82
|
MSG = 'Redundant safe navigation detected.'
|
83
|
+
MSG_LITERAL = 'Redundant safe navigation with default literal detected.'
|
67
84
|
|
68
85
|
NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
|
69
86
|
|
@@ -74,6 +91,18 @@ module RuboCop
|
|
74
91
|
(csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
|
75
92
|
PATTERN
|
76
93
|
|
94
|
+
# @!method conversion_with_default?(node)
|
95
|
+
def_node_matcher :conversion_with_default?, <<~PATTERN
|
96
|
+
{
|
97
|
+
(or $(csend _ :to_h) (hash))
|
98
|
+
(or (block $(csend _ :to_h) ...) (hash))
|
99
|
+
(or $(csend _ :to_a) (array))
|
100
|
+
(or $(csend _ :to_i) (int 0))
|
101
|
+
(or $(csend _ :to_f) (float 0.0))
|
102
|
+
(or $(csend _ :to_s) (str empty?))
|
103
|
+
}
|
104
|
+
PATTERN
|
105
|
+
|
77
106
|
# rubocop:disable Metrics/AbcSize
|
78
107
|
def on_csend(node)
|
79
108
|
unless node.receiver.const_type? && !node.receiver.source.match?(SNAKE_CASE)
|
@@ -84,6 +113,20 @@ module RuboCop
|
|
84
113
|
range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
|
85
114
|
add_offense(range) { |corrector| corrector.replace(node.loc.dot, '.') }
|
86
115
|
end
|
116
|
+
|
117
|
+
def on_or(node)
|
118
|
+
conversion_with_default?(node) do |send_node|
|
119
|
+
range = range_between(send_node.loc.dot.begin_pos, node.source_range.end_pos)
|
120
|
+
|
121
|
+
add_offense(range, message: MSG_LITERAL) do |corrector|
|
122
|
+
corrector.replace(send_node.loc.dot, '.')
|
123
|
+
|
124
|
+
range_with_default = range_between(node.lhs.source_range.end.begin_pos,
|
125
|
+
node.source_range.end.end_pos)
|
126
|
+
corrector.remove(range_with_default)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
87
130
|
# rubocop:enable Metrics/AbcSize
|
88
131
|
|
89
132
|
private
|
@@ -45,10 +45,9 @@ module RuboCop
|
|
45
45
|
bad_method?(node) do |safe_nav, method|
|
46
46
|
return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
node.source_range.end_pos)
|
48
|
+
begin_range = node.loc.dot || safe_nav.source_range.end
|
49
|
+
location = begin_range.join(node.source_range.end)
|
50
|
+
|
52
51
|
add_offense(location) do |corrector|
|
53
52
|
autocorrect(corrector, offense_range: location, send_node: node)
|
54
53
|
end
|
@@ -10,11 +10,18 @@ module RuboCop
|
|
10
10
|
# foo = foo
|
11
11
|
# foo, bar = foo, bar
|
12
12
|
# Foo = Foo
|
13
|
+
# hash['foo'] = hash['foo']
|
14
|
+
# obj.attr = obj.attr
|
13
15
|
#
|
14
16
|
# # good
|
15
17
|
# foo = bar
|
16
18
|
# foo, bar = bar, foo
|
17
19
|
# Foo = Bar
|
20
|
+
# hash['foo'] = hash['bar']
|
21
|
+
# obj.attr = obj.attr2
|
22
|
+
#
|
23
|
+
# # good (method calls possibly can return different results)
|
24
|
+
# hash[foo] = hash[foo]
|
18
25
|
#
|
19
26
|
class SelfAssignment < Base
|
20
27
|
MSG = 'Self-assignment detected.'
|
@@ -26,6 +33,15 @@ module RuboCop
|
|
26
33
|
gvasgn: :gvar
|
27
34
|
}.freeze
|
28
35
|
|
36
|
+
def on_send(node)
|
37
|
+
if node.method?(:[]=)
|
38
|
+
handle_key_assignment(node) if node.arguments.size == 2
|
39
|
+
elsif node.assignment_method?
|
40
|
+
handle_attribute_assignment(node) if node.arguments.size == 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
alias on_csend on_send
|
44
|
+
|
29
45
|
def on_lvasgn(node)
|
30
46
|
lhs, rhs = *node
|
31
47
|
return unless rhs
|
@@ -72,6 +88,27 @@ module RuboCop
|
|
72
88
|
rhs.type == ASSIGNMENT_TYPE_TO_RHS_TYPE[lhs.type] &&
|
73
89
|
rhs.children.first == lhs.children.first
|
74
90
|
end
|
91
|
+
|
92
|
+
def handle_key_assignment(node)
|
93
|
+
value_node = node.arguments[1]
|
94
|
+
|
95
|
+
if value_node.send_type? && value_node.method?(:[]) &&
|
96
|
+
node.receiver == value_node.receiver &&
|
97
|
+
!node.first_argument.call_type? &&
|
98
|
+
node.first_argument == value_node.first_argument
|
99
|
+
add_offense(node)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def handle_attribute_assignment(node)
|
104
|
+
first_argument = node.first_argument
|
105
|
+
|
106
|
+
if first_argument.call_type? &&
|
107
|
+
node.receiver == first_argument.receiver &&
|
108
|
+
first_argument.method_name.to_s == node.method_name.to_s.delete_suffix('=')
|
109
|
+
add_offense(node)
|
110
|
+
end
|
111
|
+
end
|
75
112
|
end
|
76
113
|
end
|
77
114
|
end
|
@@ -19,6 +19,7 @@ module RuboCop
|
|
19
19
|
# 'underscored_string'.to_sym
|
20
20
|
# :'underscored_symbol'
|
21
21
|
# 'hyphenated-string'.to_sym
|
22
|
+
# "string_#{interpolation}".to_sym
|
22
23
|
#
|
23
24
|
# # good
|
24
25
|
# :string
|
@@ -26,6 +27,7 @@ module RuboCop
|
|
26
27
|
# :underscored_string
|
27
28
|
# :underscored_symbol
|
28
29
|
# :'hyphenated-string'
|
30
|
+
# :"string_#{interpolation}"
|
29
31
|
#
|
30
32
|
# @example EnforcedStyle: strict (default)
|
31
33
|
#
|
@@ -75,9 +77,12 @@ module RuboCop
|
|
75
77
|
|
76
78
|
def on_send(node)
|
77
79
|
return unless node.receiver
|
78
|
-
return unless node.receiver.str_type? || node.receiver.sym_type?
|
79
80
|
|
80
|
-
|
81
|
+
if node.receiver.str_type? || node.receiver.sym_type?
|
82
|
+
register_offense(node, correction: node.receiver.value.to_sym.inspect)
|
83
|
+
elsif node.receiver.dstr_type?
|
84
|
+
register_offense(node, correction: ":\"#{node.receiver.value.to_sym}\"")
|
85
|
+
end
|
81
86
|
end
|
82
87
|
|
83
88
|
def on_sym(node)
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
MSG = 'Avoid leaving a trailing comma in attribute declarations.'
|
35
35
|
|
36
36
|
def on_send(node)
|
37
|
-
return unless node.attribute_accessor? && node.
|
37
|
+
return unless node.attribute_accessor? && node.last_argument.def_type?
|
38
38
|
|
39
39
|
trailing_comma = trailing_comma_range(node)
|
40
40
|
|
@@ -256,7 +256,7 @@ module RuboCop
|
|
256
256
|
|
257
257
|
def any_method_definition?(child)
|
258
258
|
cop_config.fetch('MethodCreatingMethods', []).any? do |m|
|
259
|
-
matcher_name = "#{m}_method?"
|
259
|
+
matcher_name = :"#{m}_method?"
|
260
260
|
unless respond_to?(matcher_name)
|
261
261
|
self.class.def_node_matcher matcher_name, <<~PATTERN
|
262
262
|
{def (send nil? :#{m} ...)}
|
@@ -279,7 +279,7 @@ module RuboCop
|
|
279
279
|
|
280
280
|
def any_context_creating_methods?(child)
|
281
281
|
cop_config.fetch('ContextCreatingMethods', []).any? do |m|
|
282
|
-
matcher_name = "#{m}_block?"
|
282
|
+
matcher_name = :"#{m}_block?"
|
283
283
|
unless respond_to?(matcher_name)
|
284
284
|
self.class.def_node_matcher matcher_name, <<~PATTERN
|
285
285
|
({block numblock} (send {nil? const} {:#{m}} ...) ...)
|