rubocop 1.75.5 → 1.76.2
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 +20 -14
- data/config/default.yml +55 -7
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/cop/autocorrect_logic.rb +18 -10
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +50 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
- data/lib/rubocop/cop/layout/class_structure.rb +35 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +7 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -32
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +1 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +84 -2
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +27 -0
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +16 -24
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +21 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +2 -0
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +245 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/comparable_between.rb +3 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
- data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +22 -4
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
- data/lib/rubocop/cop/style/it_block_parameter.rb +33 -14
- data/lib/rubocop/cop/style/map_to_hash.rb +11 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_format.rb +6 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +23 -5
- data/lib/rubocop/cop/style/redundant_self.rb +5 -5
- data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +24 -11
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -2
- data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -0
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +6 -1
- metadata +13 -11
@@ -39,9 +39,52 @@ module RuboCop
|
|
39
39
|
# end
|
40
40
|
#
|
41
41
|
# alias bar foo
|
42
|
+
#
|
43
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
44
|
+
#
|
45
|
+
# # good
|
46
|
+
# def foo
|
47
|
+
# 1
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# delegate :foo, to: :bar
|
51
|
+
#
|
52
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
53
|
+
#
|
54
|
+
# # bad
|
55
|
+
# def foo
|
56
|
+
# 1
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# delegate :foo, to: :bar
|
60
|
+
#
|
61
|
+
# # good
|
62
|
+
# def foo
|
63
|
+
# 1
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
# delegate :baz, to: :bar
|
67
|
+
#
|
68
|
+
# # good - delegate with splat arguments is ignored
|
69
|
+
# def foo
|
70
|
+
# 1
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# delegate :foo, **options
|
74
|
+
#
|
75
|
+
# # good - delegate inside a condition is ignored
|
76
|
+
# def foo
|
77
|
+
# 1
|
78
|
+
# end
|
79
|
+
#
|
80
|
+
# if cond
|
81
|
+
# delegate :foo, to: :bar
|
82
|
+
# end
|
83
|
+
#
|
42
84
|
class DuplicateMethods < Base
|
43
85
|
MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
|
44
|
-
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr
|
86
|
+
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr
|
87
|
+
delegate].freeze
|
45
88
|
|
46
89
|
def initialize(config = nil, options = nil)
|
47
90
|
super
|
@@ -85,15 +128,28 @@ module RuboCop
|
|
85
128
|
(send nil? :alias_method (sym $_name) _)
|
86
129
|
PATTERN
|
87
130
|
|
131
|
+
# @!method delegate_method?(node)
|
132
|
+
def_node_matcher :delegate_method?, <<~PATTERN
|
133
|
+
(send nil? :delegate
|
134
|
+
({sym str} $_)+
|
135
|
+
(hash <(pair (sym :to) {sym str}) ...>)
|
136
|
+
)
|
137
|
+
PATTERN
|
138
|
+
|
88
139
|
# @!method sym_name(node)
|
89
140
|
def_node_matcher :sym_name, '(sym $_name)'
|
90
|
-
|
141
|
+
|
142
|
+
def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
91
143
|
if (name = alias_method?(node))
|
92
144
|
return if node.ancestors.any?(&:if_type?)
|
93
145
|
|
94
146
|
found_instance_method(node, name)
|
95
147
|
elsif (attr = node.attribute_accessor?)
|
96
148
|
on_attr(node, *attr)
|
149
|
+
elsif active_support_extensions_enabled? && (names = delegate_method?(node))
|
150
|
+
return if node.ancestors.any?(&:if_type?)
|
151
|
+
|
152
|
+
on_delegate(node, names)
|
97
153
|
end
|
98
154
|
end
|
99
155
|
|
@@ -118,6 +174,32 @@ module RuboCop
|
|
118
174
|
current: source_location(node))
|
119
175
|
end
|
120
176
|
|
177
|
+
def on_delegate(node, method_names)
|
178
|
+
name_prefix = delegate_prefix(node)
|
179
|
+
|
180
|
+
method_names.each do |name|
|
181
|
+
name = "#{name_prefix}_#{name}" if name_prefix
|
182
|
+
|
183
|
+
found_instance_method(node, name)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def delegate_prefix(node)
|
188
|
+
kwargs_node = node.last_argument
|
189
|
+
|
190
|
+
return unless (prefix = hash_value(kwargs_node, :prefix))
|
191
|
+
|
192
|
+
if prefix.true_type?
|
193
|
+
hash_value(kwargs_node, :to).value
|
194
|
+
elsif prefix.type?(:sym, :str)
|
195
|
+
prefix.value
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def hash_value(node, key)
|
200
|
+
node.pairs.find { |pair| pair.key.value == key }&.value
|
201
|
+
end
|
202
|
+
|
121
203
|
def found_instance_method(node, name)
|
122
204
|
return found_sclass_method(node, name) unless (scope = node.parent_module_name)
|
123
205
|
|
@@ -19,7 +19,9 @@ module RuboCop
|
|
19
19
|
MSG = 'Empty interpolation detected.'
|
20
20
|
|
21
21
|
def on_interpolation(begin_node)
|
22
|
-
|
22
|
+
node_children = begin_node.children.dup
|
23
|
+
node_children.delete_if { |e| e.nil_type? || (e.basic_literal? && e.str_content&.empty?) }
|
24
|
+
return unless node_children.empty?
|
23
25
|
|
24
26
|
add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
|
25
27
|
end
|
@@ -15,6 +15,14 @@ module RuboCop
|
|
15
15
|
# x == 0.1
|
16
16
|
# x != 0.1
|
17
17
|
#
|
18
|
+
# # bad
|
19
|
+
# case value
|
20
|
+
# when 1.0
|
21
|
+
# foo
|
22
|
+
# when 2.0
|
23
|
+
# bar
|
24
|
+
# end
|
25
|
+
#
|
18
26
|
# # good - using BigDecimal
|
19
27
|
# x.to_d == 0.1.to_d
|
20
28
|
#
|
@@ -32,12 +40,21 @@ module RuboCop
|
|
32
40
|
# # good - comparing against nil
|
33
41
|
# Float(x, exception: false) == nil
|
34
42
|
#
|
43
|
+
# # good - using epsilon comparison in case expression
|
44
|
+
# case
|
45
|
+
# when (value - 1.0).abs < Float::EPSILON
|
46
|
+
# foo
|
47
|
+
# when (value - 2.0).abs < Float::EPSILON
|
48
|
+
# bar
|
49
|
+
# end
|
50
|
+
#
|
35
51
|
# # Or some other epsilon based type of comparison:
|
36
52
|
# # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
|
37
53
|
#
|
38
54
|
class FloatComparison < Base
|
39
55
|
MSG_EQUALITY = 'Avoid equality comparisons of floats as they are unreliable.'
|
40
56
|
MSG_INEQUALITY = 'Avoid inequality comparisons of floats as they are unreliable.'
|
57
|
+
MSG_CASE = 'Avoid float literal comparisons in case statements as they are unreliable.'
|
41
58
|
|
42
59
|
EQUALITY_METHODS = %i[== != eql? equal?].freeze
|
43
60
|
FLOAT_RETURNING_METHODS = %i[to_f Float fdiv].freeze
|
@@ -58,6 +75,16 @@ module RuboCop
|
|
58
75
|
end
|
59
76
|
alias on_csend on_send
|
60
77
|
|
78
|
+
def on_case(node)
|
79
|
+
node.when_branches.each do |when_branch|
|
80
|
+
when_branch.each_condition do |condition|
|
81
|
+
next if !float?(condition) || literal_safe?(condition)
|
82
|
+
|
83
|
+
add_offense(condition, message: MSG_CASE)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
61
88
|
private
|
62
89
|
|
63
90
|
def float?(node)
|
@@ -11,39 +11,43 @@ module RuboCop
|
|
11
11
|
# @example
|
12
12
|
# # bad
|
13
13
|
# foo.object_id == bar.object_id
|
14
|
+
# foo.object_id != baz.object_id
|
14
15
|
#
|
15
16
|
# # good
|
16
17
|
# foo.equal?(bar)
|
18
|
+
# !foo.equal?(baz)
|
17
19
|
#
|
18
20
|
class IdentityComparison < Base
|
19
21
|
extend AutoCorrector
|
20
22
|
|
21
|
-
MSG = 'Use
|
22
|
-
RESTRICT_ON_SEND = %i[==].freeze
|
23
|
+
MSG = 'Use `%<bang>sequal?` instead of `%<comparison_method>s` when comparing `object_id`.'
|
24
|
+
RESTRICT_ON_SEND = %i[== !=].freeze
|
25
|
+
|
26
|
+
# @!method object_id_comparison(node)
|
27
|
+
def_node_matcher :object_id_comparison, <<~PATTERN
|
28
|
+
(send
|
29
|
+
(send
|
30
|
+
_lhs_receiver :object_id) ${:== :!=}
|
31
|
+
(send
|
32
|
+
_rhs_receiver :object_id))
|
33
|
+
PATTERN
|
23
34
|
|
24
35
|
def on_send(node)
|
25
|
-
return unless
|
36
|
+
return unless (comparison_method = object_id_comparison(node))
|
26
37
|
|
27
|
-
|
38
|
+
bang = comparison_method == :== ? '' : '!'
|
39
|
+
add_offense(node,
|
40
|
+
message: format(MSG, comparison_method: comparison_method,
|
41
|
+
bang: bang)) do |corrector|
|
28
42
|
receiver = node.receiver.receiver
|
29
43
|
argument = node.first_argument.receiver
|
30
44
|
return unless receiver && argument
|
31
45
|
|
32
|
-
replacement = "#{receiver.source}.equal?(#{argument.source})"
|
46
|
+
replacement = "#{bang}#{receiver.source}.equal?(#{argument.source})"
|
33
47
|
|
34
48
|
corrector.replace(node, replacement)
|
35
49
|
end
|
36
50
|
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def compare_between_object_id_by_double_equal?(node)
|
41
|
-
object_id_method?(node.receiver) && object_id_method?(node.first_argument)
|
42
|
-
end
|
43
|
-
|
44
|
-
def object_id_method?(node)
|
45
|
-
node.send_type? && node.method?(:object_id)
|
46
|
-
end
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
@@ -240,30 +240,22 @@ module RuboCop
|
|
240
240
|
def correct_if_node(node, cond)
|
241
241
|
result = condition_evaluation(node, cond)
|
242
242
|
|
243
|
-
if node.elsif? && result
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
elsif node.else? || node.ternary?
|
260
|
-
add_offense(cond) do |corrector|
|
261
|
-
corrector.replace(node, node.else_branch.source)
|
262
|
-
end
|
263
|
-
else
|
264
|
-
add_offense(cond) do |corrector|
|
265
|
-
corrector.remove(node)
|
266
|
-
end
|
243
|
+
new_node = if node.elsif? && result
|
244
|
+
"else\n #{range_with_comments(node.if_branch).source}"
|
245
|
+
elsif node.elsif? && !result
|
246
|
+
"else\n #{node.else_branch.source}"
|
247
|
+
elsif node.if_branch && result
|
248
|
+
node.if_branch.source
|
249
|
+
elsif node.elsif_conditional?
|
250
|
+
"#{node.else_branch.source.sub('elsif', 'if')}\nend"
|
251
|
+
elsif node.else? || node.ternary?
|
252
|
+
node.else_branch.source
|
253
|
+
else
|
254
|
+
'' # Equivalent to removing the node
|
255
|
+
end
|
256
|
+
|
257
|
+
add_offense(cond) do |corrector|
|
258
|
+
corrector.replace(node, new_node)
|
267
259
|
end
|
268
260
|
end
|
269
261
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
@@ -97,7 +97,7 @@ module RuboCop
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def require_parentheses?(send_node)
|
100
|
-
return true if
|
100
|
+
return true if operator_inside_collection_literal?(send_node)
|
101
101
|
return false unless send_node.comparison_method?
|
102
102
|
return false unless (node = send_node.parent)
|
103
103
|
|
@@ -105,10 +105,10 @@ module RuboCop
|
|
105
105
|
(node.respond_to?(:comparison_method?) && node.comparison_method?)
|
106
106
|
end
|
107
107
|
|
108
|
-
def
|
109
|
-
# If an operator call (without a dot) is inside a hash, it needs
|
108
|
+
def operator_inside_collection_literal?(send_node)
|
109
|
+
# If an operator call (without a dot) is inside an array or a hash, it needs
|
110
110
|
# to be parenthesized when converted to safe navigation.
|
111
|
-
send_node.parent&.
|
111
|
+
send_node.parent&.type?(:array, :pair) && !send_node.loc.dot
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
@@ -8,6 +8,11 @@ module RuboCop
|
|
8
8
|
# given by `ruby -cw` prior to Ruby 2.6:
|
9
9
|
# "shadowing outer local variable - foo".
|
10
10
|
#
|
11
|
+
# The cop is now disabled by default to match the upstream Ruby behavior.
|
12
|
+
# It's useful, however, if you'd like to avoid shadowing variables from outer
|
13
|
+
# scopes, which some people consider an anti-pattern that makes it harder
|
14
|
+
# to keep track of what's going on in a program.
|
15
|
+
#
|
11
16
|
# NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
|
12
17
|
# because `Ractor` should not access outer variables.
|
13
18
|
# eg. following style is encouraged:
|
@@ -4,10 +4,10 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
6
|
# Checks for redundant access modifiers, including those with no
|
7
|
-
# code, those which are repeated,
|
8
|
-
# class or module body.
|
9
|
-
#
|
10
|
-
# are not redundant.
|
7
|
+
# code, those which are repeated, those which are on top-level, and
|
8
|
+
# leading `public` modifiers in a class or module body.
|
9
|
+
# Conditionally-defined methods are considered as always being defined,
|
10
|
+
# and thus access modifiers guarding such methods are not redundant.
|
11
11
|
#
|
12
12
|
# This cop has `ContextCreatingMethods` option. The default setting value
|
13
13
|
# is an empty array that means no method is specified.
|
@@ -58,6 +58,12 @@ module RuboCop
|
|
58
58
|
# private # this is redundant (no following methods are defined)
|
59
59
|
# end
|
60
60
|
#
|
61
|
+
# # bad
|
62
|
+
# private # this is useless (access modifiers have no effect on top-level)
|
63
|
+
#
|
64
|
+
# def method
|
65
|
+
# end
|
66
|
+
#
|
61
67
|
# # good
|
62
68
|
# class Foo
|
63
69
|
# private # this is not redundant (a method is defined)
|
@@ -145,6 +151,17 @@ module RuboCop
|
|
145
151
|
alias on_numblock on_block
|
146
152
|
alias on_itblock on_block
|
147
153
|
|
154
|
+
def on_begin(node)
|
155
|
+
return if node.parent
|
156
|
+
|
157
|
+
node.child_nodes.each do |child|
|
158
|
+
next unless child.send_type? && access_modifier?(child)
|
159
|
+
|
160
|
+
# This call always registers an offense for access modifier `child.method_name`
|
161
|
+
check_send_node(child, child.method_name, true)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
148
165
|
private
|
149
166
|
|
150
167
|
def autocorrect(corrector, node)
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for usage of method `fetch` or `Array.new` with default value argument
|
7
|
+
# and block. In such cases, block will always be used as default value.
|
8
|
+
#
|
9
|
+
# This cop emulates Ruby warning "block supersedes default value argument" which
|
10
|
+
# applies to `Array.new`, `Array#fetch`, `Hash#fetch`, `ENV.fetch` and
|
11
|
+
# `Thread#fetch`.
|
12
|
+
#
|
13
|
+
# A `fetch` call without a receiver is considered a custom method and does not register
|
14
|
+
# an offense.
|
15
|
+
#
|
16
|
+
# @safety
|
17
|
+
# This cop is unsafe because the receiver could have nonstandard implementation
|
18
|
+
# of `fetch`, or be a class other than the one listed above.
|
19
|
+
#
|
20
|
+
# It is also unsafe because default value argument could have side effects:
|
21
|
+
#
|
22
|
+
# [source,ruby]
|
23
|
+
# ----
|
24
|
+
# def x(a) = puts "side effect"
|
25
|
+
# Array.new(5, x(1)) { 2 }
|
26
|
+
# ----
|
27
|
+
#
|
28
|
+
# so removing it would change behavior.
|
29
|
+
#
|
30
|
+
# @example
|
31
|
+
# # bad
|
32
|
+
# x.fetch(key, default_value) { block_value }
|
33
|
+
# Array.new(size, default_value) { block_value }
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# x.fetch(key) { block_value }
|
37
|
+
# Array.new(size) { block_value }
|
38
|
+
#
|
39
|
+
# # also good - in case default value argument is desired instead
|
40
|
+
# x.fetch(key, default_value)
|
41
|
+
# Array.new(size, default_value)
|
42
|
+
#
|
43
|
+
# # good - keyword arguments aren't registered as offenses
|
44
|
+
# x.fetch(key, keyword: :arg) { block_value }
|
45
|
+
#
|
46
|
+
# @example AllowedReceivers: ['Rails.cache']
|
47
|
+
# # good
|
48
|
+
# Rails.cache.fetch(name, options) { block }
|
49
|
+
#
|
50
|
+
class UselessDefaultValueArgument < Base
|
51
|
+
include AllowedReceivers
|
52
|
+
extend AutoCorrector
|
53
|
+
|
54
|
+
MSG = 'Block supersedes default value argument.'
|
55
|
+
|
56
|
+
RESTRICT_ON_SEND = %i[fetch new].freeze
|
57
|
+
|
58
|
+
# @!method default_value_argument_and_block(node)
|
59
|
+
def_node_matcher :default_value_argument_and_block, <<~PATTERN
|
60
|
+
(any_block
|
61
|
+
{
|
62
|
+
(call !nil? :fetch $_key $_default_value)
|
63
|
+
(send (const _ :Array) :new $_size $_default_value)
|
64
|
+
}
|
65
|
+
_args
|
66
|
+
_block_body)
|
67
|
+
PATTERN
|
68
|
+
|
69
|
+
def on_send(node)
|
70
|
+
unless (prev_arg_node, default_value_node = default_value_argument_and_block(node.parent))
|
71
|
+
return
|
72
|
+
end
|
73
|
+
return if allowed_receiver?(node.receiver)
|
74
|
+
return if hash_without_braces?(default_value_node)
|
75
|
+
|
76
|
+
add_offense(default_value_node) do |corrector|
|
77
|
+
corrector.remove(prev_arg_node.source_range.end.join(default_value_node.source_range))
|
78
|
+
end
|
79
|
+
end
|
80
|
+
alias on_csend on_send
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def hash_without_braces?(node)
|
85
|
+
node.hash_type? && !node.braces?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for useless OR (`||` and `or`) expressions.
|
7
|
+
#
|
8
|
+
# Some methods always return a truthy value, even when called
|
9
|
+
# on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
|
10
|
+
# appended after these methods will never evaluate.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# x.to_a || fallback
|
16
|
+
# x.to_c || fallback
|
17
|
+
# x.to_d || fallback
|
18
|
+
# x.to_i || fallback
|
19
|
+
# x.to_f || fallback
|
20
|
+
# x.to_h || fallback
|
21
|
+
# x.to_r || fallback
|
22
|
+
# x.to_s || fallback
|
23
|
+
# x.to_sym || fallback
|
24
|
+
# x.intern || fallback
|
25
|
+
# x.inspect || fallback
|
26
|
+
# x.hash || fallback
|
27
|
+
# x.object_id || fallback
|
28
|
+
# x.__id__ || fallback
|
29
|
+
#
|
30
|
+
# x.to_s or fallback
|
31
|
+
#
|
32
|
+
# # good - if fallback is same as return value of method called on nil
|
33
|
+
# x.to_a # nil.to_a returns []
|
34
|
+
# x.to_c # nil.to_c returns (0+0i)
|
35
|
+
# x.to_d # nil.to_d returns 0.0
|
36
|
+
# x.to_i # nil.to_i returns 0
|
37
|
+
# x.to_f # nil.to_f returns 0.0
|
38
|
+
# x.to_h # nil.to_h returns {}
|
39
|
+
# x.to_r # nil.to_r returns (0/1)
|
40
|
+
# x.to_s # nil.to_s returns ''
|
41
|
+
# x.to_sym # nil.to_sym raises an error
|
42
|
+
# x.intern # nil.intern raises an error
|
43
|
+
# x.inspect # nil.inspect returns "nil"
|
44
|
+
# x.hash # nil.hash returns an Integer
|
45
|
+
# x.object_id # nil.object_id returns an Integer
|
46
|
+
# x.__id__ # nil.object_id returns an Integer
|
47
|
+
#
|
48
|
+
# # good - if the intention is not to call the method on nil
|
49
|
+
# x&.to_a || fallback
|
50
|
+
# x&.to_c || fallback
|
51
|
+
# x&.to_d || fallback
|
52
|
+
# x&.to_i || fallback
|
53
|
+
# x&.to_f || fallback
|
54
|
+
# x&.to_h || fallback
|
55
|
+
# x&.to_r || fallback
|
56
|
+
# x&.to_s || fallback
|
57
|
+
# x&.to_sym || fallback
|
58
|
+
# x&.intern || fallback
|
59
|
+
# x&.inspect || fallback
|
60
|
+
# x&.hash || fallback
|
61
|
+
# x&.object_id || fallback
|
62
|
+
# x&.__id__ || fallback
|
63
|
+
#
|
64
|
+
# x&.to_s or fallback
|
65
|
+
#
|
66
|
+
class UselessOr < Base
|
67
|
+
MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
|
68
|
+
|
69
|
+
TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
|
70
|
+
:to_s, :to_sym, :intern, :inspect, :hash, :object_id,
|
71
|
+
:__id__].freeze
|
72
|
+
|
73
|
+
# @!method truthy_return_value_method?(node)
|
74
|
+
def_node_matcher :truthy_return_value_method?, <<~PATTERN
|
75
|
+
(send _ %TRUTHY_RETURN_VALUE_METHODS)
|
76
|
+
PATTERN
|
77
|
+
|
78
|
+
def on_or(node)
|
79
|
+
if truthy_return_value_method?(node.lhs)
|
80
|
+
report_offense(node, node.lhs)
|
81
|
+
elsif truthy_return_value_method?(node.rhs)
|
82
|
+
parent = node.parent
|
83
|
+
parent = parent.parent if parent&.begin_type?
|
84
|
+
|
85
|
+
report_offense(parent, node.rhs) if parent&.or_type?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def report_offense(or_node, truthy_node)
|
92
|
+
add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
|
93
|
+
message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -39,7 +39,7 @@ module RuboCop
|
|
39
39
|
class AbcSize < Base
|
40
40
|
include MethodComplexity
|
41
41
|
|
42
|
-
MSG = 'Assignment Branch Condition size for
|
42
|
+
MSG = 'Assignment Branch Condition size for `%<method>s` is too high. ' \
|
43
43
|
'[%<abc_vector>s %<complexity>.4g/%<max>.4g]'
|
44
44
|
|
45
45
|
private
|
@@ -89,7 +89,7 @@ module RuboCop
|
|
89
89
|
|
90
90
|
if first_non_comment_token
|
91
91
|
# `line` is 1-indexed so we need to subtract 1 to get the array index
|
92
|
-
processed_source.lines[0...first_non_comment_token.line - 1]
|
92
|
+
processed_source.lines[0...(first_non_comment_token.line - 1)]
|
93
93
|
else
|
94
94
|
processed_source.lines
|
95
95
|
end
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
24
24
|
gem_canonical_name(string_a) < gem_canonical_name(string_b)
|
25
25
|
end
|
26
26
|
|
27
|
-
def consecutive_lines(previous, current)
|
27
|
+
def consecutive_lines?(previous, current)
|
28
28
|
first_line = get_source_range(current, treat_comments_as_separators).first_line
|
29
29
|
previous.source_range.last_line == first_line - 1
|
30
30
|
end
|