rubocop 1.77.0 → 1.79.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 +36 -20
- data/lib/rubocop/cli.rb +12 -1
- data/lib/rubocop/config_loader.rb +1 -38
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +99 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
- data/lib/rubocop/cop/lint/literal_as_condition.rb +3 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/naming/method_name.rb +102 -13
- data/lib/rubocop/cop/naming/predicate_method.rb +27 -2
- data/lib/rubocop/cop/security/eval.rb +2 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/array_intersect.rb +51 -23
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +1 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +8 -9
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +3 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -0
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +30 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +16 -7
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/server/cache.rb +4 -2
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +23 -6
@@ -20,6 +20,15 @@ module RuboCop
|
|
20
20
|
# In the example below, the safe navigation operator (`&.`) is unnecessary
|
21
21
|
# because `NilClass` has methods like `respond_to?` and `is_a?`.
|
22
22
|
#
|
23
|
+
# The `InferNonNilReceiver` option specifies whether to look into previous code
|
24
|
+
# paths to infer if the receiver can't be nil. This check is unsafe because the receiver
|
25
|
+
# can be redefined between the safe navigation call and previous regular method call.
|
26
|
+
# It does the inference only in the current scope, e.g. within the same method definition etc.
|
27
|
+
#
|
28
|
+
# The `AdditionalNilMethods` option specifies additional custom methods which are
|
29
|
+
# defined on `NilClass`. When `InferNonNilReceiver` is set, they are used to determine
|
30
|
+
# whether the receiver can be nil.
|
31
|
+
#
|
23
32
|
# @safety
|
24
33
|
# This cop is unsafe, because autocorrection can change the return type of
|
25
34
|
# the expression. An offending expression that previously could return `nil`
|
@@ -33,6 +42,20 @@ module RuboCop
|
|
33
42
|
# CamelCaseConst.do_something
|
34
43
|
#
|
35
44
|
# # bad
|
45
|
+
# foo.to_s&.strip
|
46
|
+
# foo.to_i&.zero?
|
47
|
+
# foo.to_f&.zero?
|
48
|
+
# foo.to_a&.size
|
49
|
+
# foo.to_h&.size
|
50
|
+
#
|
51
|
+
# # good
|
52
|
+
# foo.to_s.strip
|
53
|
+
# foo.to_i.zero?
|
54
|
+
# foo.to_f.zero?
|
55
|
+
# foo.to_a.size
|
56
|
+
# foo.to_h.size
|
57
|
+
#
|
58
|
+
# # bad
|
36
59
|
# do_something if attrs&.respond_to?(:[])
|
37
60
|
#
|
38
61
|
# # good
|
@@ -81,17 +104,59 @@ module RuboCop
|
|
81
104
|
# do_something if attrs.nil_safe_method(:[])
|
82
105
|
# do_something if attrs&.not_nil_safe_method(:[])
|
83
106
|
#
|
107
|
+
# @example InferNonNilReceiver: false (default)
|
108
|
+
# # good
|
109
|
+
# foo.bar
|
110
|
+
# foo&.baz
|
111
|
+
#
|
112
|
+
# @example InferNonNilReceiver: true
|
113
|
+
# # bad
|
114
|
+
# foo.bar
|
115
|
+
# foo&.baz # would raise on previous line if `foo` is nil
|
116
|
+
#
|
117
|
+
# # good
|
118
|
+
# foo.bar
|
119
|
+
# foo.baz
|
120
|
+
#
|
121
|
+
# # bad
|
122
|
+
# if foo.condition?
|
123
|
+
# foo&.bar
|
124
|
+
# end
|
125
|
+
#
|
126
|
+
# # good
|
127
|
+
# if foo.condition?
|
128
|
+
# foo.bar
|
129
|
+
# end
|
130
|
+
#
|
131
|
+
# # good (different scopes)
|
132
|
+
# def method1
|
133
|
+
# foo.bar
|
134
|
+
# end
|
135
|
+
#
|
136
|
+
# def method2
|
137
|
+
# foo&.bar
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# @example AdditionalNilMethods: [present?]
|
141
|
+
# # good
|
142
|
+
# foo.present?
|
143
|
+
# foo&.bar
|
144
|
+
#
|
84
145
|
class RedundantSafeNavigation < Base
|
85
146
|
include AllowedMethods
|
86
147
|
extend AutoCorrector
|
87
148
|
|
88
149
|
MSG = 'Redundant safe navigation detected, use `.` instead.'
|
89
150
|
MSG_LITERAL = 'Redundant safe navigation with default literal detected.'
|
151
|
+
MSG_NON_NIL = 'Redundant safe navigation on non-nil receiver (detected by analyzing ' \
|
152
|
+
'previous code/method invocations).'
|
90
153
|
|
91
154
|
NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
|
92
155
|
|
93
156
|
SNAKE_CASE = /\A[[:digit:][:upper:]_]+\z/.freeze
|
94
157
|
|
158
|
+
GUARANTEED_INSTANCE_METHODS = %i[to_s to_i to_f to_a to_h].freeze
|
159
|
+
|
95
160
|
# @!method respond_to_nil_specific_method?(node)
|
96
161
|
def_node_matcher :respond_to_nil_specific_method?, <<~PATTERN
|
97
162
|
(csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
|
@@ -111,15 +176,27 @@ module RuboCop
|
|
111
176
|
|
112
177
|
# rubocop:disable Metrics/AbcSize
|
113
178
|
def on_csend(node)
|
179
|
+
range = node.loc.dot
|
180
|
+
|
181
|
+
if infer_non_nil_receiver?
|
182
|
+
checker = Lint::Utils::NilReceiverChecker.new(node.receiver, additional_nil_methods)
|
183
|
+
|
184
|
+
if checker.cant_be_nil?
|
185
|
+
add_offense(range, message: MSG_NON_NIL) { |corrector| corrector.replace(range, '.') }
|
186
|
+
return
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
114
190
|
unless assume_receiver_instance_exists?(node.receiver)
|
115
|
-
return
|
191
|
+
return if !guaranteed_instance?(node.receiver) && !check?(node)
|
116
192
|
return if respond_to_nil_specific_method?(node)
|
117
193
|
end
|
118
194
|
|
119
|
-
range = node.loc.dot
|
120
195
|
add_offense(range) { |corrector| corrector.replace(range, '.') }
|
121
196
|
end
|
197
|
+
# rubocop:enable Metrics/AbcSize
|
122
198
|
|
199
|
+
# rubocop:disable Metrics/AbcSize
|
123
200
|
def on_or(node)
|
124
201
|
conversion_with_default?(node) do |send_node|
|
125
202
|
range = send_node.loc.dot.begin.join(node.source_range.end)
|
@@ -142,7 +219,20 @@ module RuboCop
|
|
142
219
|
receiver.self_type? || (receiver.literal? && !receiver.nil_type?)
|
143
220
|
end
|
144
221
|
|
222
|
+
def guaranteed_instance?(node)
|
223
|
+
receiver = if node.any_block_type?
|
224
|
+
node.send_node
|
225
|
+
else
|
226
|
+
node
|
227
|
+
end
|
228
|
+
return false unless receiver.send_type?
|
229
|
+
|
230
|
+
GUARANTEED_INSTANCE_METHODS.include?(receiver.method_name)
|
231
|
+
end
|
232
|
+
|
145
233
|
def check?(node)
|
234
|
+
return false unless allowed_method?(node.method_name)
|
235
|
+
|
146
236
|
parent = node.parent
|
147
237
|
return false unless parent
|
148
238
|
|
@@ -154,6 +244,15 @@ module RuboCop
|
|
154
244
|
def condition?(parent, node)
|
155
245
|
(parent.conditional? || parent.post_condition_loop?) && parent.condition == node
|
156
246
|
end
|
247
|
+
|
248
|
+
def infer_non_nil_receiver?
|
249
|
+
cop_config['InferNonNilReceiver']
|
250
|
+
end
|
251
|
+
|
252
|
+
def additional_nil_methods
|
253
|
+
@additional_nil_methods ||=
|
254
|
+
Array(cop_config.fetch('AdditionalNilMethods', []).map(&:to_sym))
|
255
|
+
end
|
157
256
|
end
|
158
257
|
end
|
159
258
|
end
|
@@ -185,9 +185,9 @@ module RuboCop
|
|
185
185
|
(hash (pair (sym :exception) false))
|
186
186
|
PATTERN
|
187
187
|
|
188
|
-
# rubocop:disable Metrics/AbcSize
|
188
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
189
189
|
def on_send(node)
|
190
|
-
return if hash_or_set_with_block?(node)
|
190
|
+
return if node.arguments.any? || hash_or_set_with_block?(node)
|
191
191
|
|
192
192
|
receiver = find_receiver(node)
|
193
193
|
return unless literal_receiver?(node, receiver) ||
|
@@ -198,10 +198,10 @@ module RuboCop
|
|
198
198
|
message = format(MSG, method: node.method_name)
|
199
199
|
|
200
200
|
add_offense(node.loc.selector, message: message) do |corrector|
|
201
|
-
corrector.remove(node.loc.dot.join(node.loc.selector))
|
201
|
+
corrector.remove(node.loc.dot.join(node.loc.end || node.loc.selector))
|
202
202
|
end
|
203
203
|
end
|
204
|
-
# rubocop:enable Metrics/AbcSize
|
204
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
205
205
|
alias on_csend on_send
|
206
206
|
|
207
207
|
private
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
def on_irange(node)
|
44
44
|
return if node.parent&.begin_type?
|
45
45
|
return unless node.begin && node.end
|
46
|
-
return if same_line?(node.
|
46
|
+
return if same_line?(node.loc.operator, node.end)
|
47
47
|
|
48
48
|
message = format(MSG, range: "#{node.begin.source}#{node.loc.operator.source}")
|
49
49
|
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
module Utils
|
7
|
+
# Utility class that checks if the receiver can't be nil.
|
8
|
+
class NilReceiverChecker
|
9
|
+
NIL_METHODS = (nil.methods + %i[!]).to_set.freeze
|
10
|
+
|
11
|
+
def initialize(receiver, additional_nil_methods)
|
12
|
+
@receiver = receiver
|
13
|
+
@additional_nil_methods = additional_nil_methods
|
14
|
+
@checked_nodes = {}.compare_by_identity
|
15
|
+
end
|
16
|
+
|
17
|
+
def cant_be_nil?
|
18
|
+
sole_condition_of_parent_if?(@receiver) || _cant_be_nil?(@receiver.parent, @receiver)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# rubocop:disable Metrics
|
24
|
+
def _cant_be_nil?(node, receiver)
|
25
|
+
return false unless node
|
26
|
+
|
27
|
+
# For some nodes, we check their parent and then some children for these parents.
|
28
|
+
# This is added to avoid infinite loops.
|
29
|
+
return false if @checked_nodes.key?(node)
|
30
|
+
|
31
|
+
@checked_nodes[node] = true
|
32
|
+
|
33
|
+
case node.type
|
34
|
+
when :def, :class, :module, :sclass
|
35
|
+
return false
|
36
|
+
when :send
|
37
|
+
return non_nil_method?(node.method_name) if node.receiver == receiver
|
38
|
+
|
39
|
+
node.arguments.each do |argument|
|
40
|
+
return true if _cant_be_nil?(argument, receiver)
|
41
|
+
end
|
42
|
+
|
43
|
+
return true if _cant_be_nil?(node.receiver, receiver)
|
44
|
+
when :begin
|
45
|
+
return true if _cant_be_nil?(node.children.first, receiver)
|
46
|
+
when :if, :case
|
47
|
+
return true if _cant_be_nil?(node.condition, receiver)
|
48
|
+
when :and, :or
|
49
|
+
return true if _cant_be_nil?(node.lhs, receiver)
|
50
|
+
when :pair
|
51
|
+
if _cant_be_nil?(node.key, receiver) ||
|
52
|
+
_cant_be_nil?(node.value, receiver)
|
53
|
+
return true
|
54
|
+
end
|
55
|
+
when :when
|
56
|
+
node.each_condition do |condition|
|
57
|
+
return true if _cant_be_nil?(condition, receiver)
|
58
|
+
end
|
59
|
+
when :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
|
60
|
+
return true if _cant_be_nil?(node.expression, receiver)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Due to how `if/else` are implemented (`elsif` is a child of `if` or another `elsif`),
|
64
|
+
# using left_siblings will not work correctly for them.
|
65
|
+
if !else_branch?(node) || (node.if_type? && !node.elsif?)
|
66
|
+
node.left_siblings.reverse_each do |sibling|
|
67
|
+
next unless sibling.is_a?(AST::Node)
|
68
|
+
|
69
|
+
return true if _cant_be_nil?(sibling, receiver)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
if node.parent
|
74
|
+
_cant_be_nil?(node.parent, receiver)
|
75
|
+
else
|
76
|
+
false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
# rubocop:enable Metrics
|
80
|
+
|
81
|
+
def non_nil_method?(method_name)
|
82
|
+
!NIL_METHODS.include?(method_name) && !@additional_nil_methods.include?(method_name)
|
83
|
+
end
|
84
|
+
|
85
|
+
# rubocop:disable Metrics/PerceivedComplexity
|
86
|
+
def sole_condition_of_parent_if?(node)
|
87
|
+
parent = node.parent
|
88
|
+
|
89
|
+
while parent
|
90
|
+
if parent.if_type?
|
91
|
+
if parent.condition == node
|
92
|
+
return true
|
93
|
+
elsif parent.elsif?
|
94
|
+
parent = find_top_if(parent)
|
95
|
+
end
|
96
|
+
elsif else_branch?(parent)
|
97
|
+
# Find the top `if` for `else`.
|
98
|
+
parent = parent.parent
|
99
|
+
end
|
100
|
+
|
101
|
+
parent = parent&.parent
|
102
|
+
end
|
103
|
+
|
104
|
+
false
|
105
|
+
end
|
106
|
+
# rubocop:enable Metrics/PerceivedComplexity
|
107
|
+
|
108
|
+
def else_branch?(node)
|
109
|
+
node.parent&.if_type? && node.parent.else_branch == node
|
110
|
+
end
|
111
|
+
|
112
|
+
def find_top_if(node)
|
113
|
+
node = node.parent while node.elsif?
|
114
|
+
|
115
|
+
node
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -39,6 +39,20 @@ module RuboCop
|
|
39
39
|
# # good
|
40
40
|
# def foo_bar; end
|
41
41
|
#
|
42
|
+
# # bad
|
43
|
+
# define_method :fooBar do
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# # good
|
47
|
+
# define_method :foo_bar do
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# # bad
|
51
|
+
# Struct.new(:fooBar)
|
52
|
+
#
|
53
|
+
# # good
|
54
|
+
# Struct.new(:foo_bar)
|
55
|
+
#
|
42
56
|
# @example EnforcedStyle: camelCase
|
43
57
|
# # bad
|
44
58
|
# def foo_bar; end
|
@@ -46,6 +60,20 @@ module RuboCop
|
|
46
60
|
# # good
|
47
61
|
# def fooBar; end
|
48
62
|
#
|
63
|
+
# # bad
|
64
|
+
# define_method :foo_bar do
|
65
|
+
# end
|
66
|
+
#
|
67
|
+
# # good
|
68
|
+
# define_method :fooBar do
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# # bad
|
72
|
+
# Struct.new(:foo_bar)
|
73
|
+
#
|
74
|
+
# # good
|
75
|
+
# Struct.new(:fooBar)
|
76
|
+
#
|
49
77
|
# @example ForbiddenIdentifiers: ['def', 'super']
|
50
78
|
# # bad
|
51
79
|
# def def; end
|
@@ -66,13 +94,66 @@ module RuboCop
|
|
66
94
|
MSG = 'Use %<style>s for method names.'
|
67
95
|
MSG_FORBIDDEN = '`%<identifier>s` is forbidden, use another method name instead.'
|
68
96
|
|
97
|
+
OPERATOR_METHODS = %i[| ^ & <=> == === =~ > >= < <= << >> + - * /
|
98
|
+
% ** ~ +@ -@ !@ ~@ [] []= ! != !~ `].to_set.freeze
|
99
|
+
|
69
100
|
# @!method sym_name(node)
|
70
101
|
def_node_matcher :sym_name, '(sym $_name)'
|
71
102
|
|
72
103
|
# @!method str_name(node)
|
73
104
|
def_node_matcher :str_name, '(str $_name)'
|
74
105
|
|
106
|
+
# @!method new_struct?(node)
|
107
|
+
def_node_matcher :new_struct?, '(send (const {nil? cbase} :Struct) :new ...)'
|
108
|
+
|
109
|
+
# @!method define_data?(node)
|
110
|
+
def_node_matcher :define_data?, '(send (const {nil? cbase} :Data) :define ...)'
|
111
|
+
|
75
112
|
def on_send(node)
|
113
|
+
if node.method?(:define_method) || node.method?(:define_singleton_method)
|
114
|
+
handle_define_method(node)
|
115
|
+
elsif new_struct?(node)
|
116
|
+
handle_new_struct(node)
|
117
|
+
elsif define_data?(node)
|
118
|
+
handle_define_data(node)
|
119
|
+
else
|
120
|
+
handle_attr_accessor(node)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def on_def(node)
|
125
|
+
return if node.operator_method? || matches_allowed_pattern?(node.method_name)
|
126
|
+
|
127
|
+
if forbidden_name?(node.method_name.to_s)
|
128
|
+
register_forbidden_name(node)
|
129
|
+
else
|
130
|
+
check_name(node, node.method_name, node.loc.name)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
alias on_defs on_def
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
def handle_define_method(node)
|
138
|
+
return unless node.first_argument&.type?(:str, :sym)
|
139
|
+
|
140
|
+
handle_method_name(node, node.first_argument.value)
|
141
|
+
end
|
142
|
+
|
143
|
+
def handle_new_struct(node)
|
144
|
+
arguments = node.first_argument&.str_type? ? node.arguments[1..] : node.arguments
|
145
|
+
arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
|
146
|
+
handle_method_name(name, name.value)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def handle_define_data(node)
|
151
|
+
node.arguments.select { |argument| argument.type?(:sym, :str) }.each do |name|
|
152
|
+
handle_method_name(name, name.value)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
def handle_attr_accessor(node)
|
76
157
|
return unless (attrs = node.attribute_accessor?)
|
77
158
|
|
78
159
|
attrs.last.each do |name_item|
|
@@ -87,45 +168,53 @@ module RuboCop
|
|
87
168
|
end
|
88
169
|
end
|
89
170
|
|
90
|
-
def
|
91
|
-
return if
|
171
|
+
def handle_method_name(node, name)
|
172
|
+
return if !name || matches_allowed_pattern?(name)
|
92
173
|
|
93
|
-
if forbidden_name?(
|
174
|
+
if forbidden_name?(name.to_s)
|
94
175
|
register_forbidden_name(node)
|
95
|
-
|
96
|
-
check_name(node,
|
176
|
+
elsif !OPERATOR_METHODS.include?(name)
|
177
|
+
check_name(node, name, range_position(node))
|
97
178
|
end
|
98
179
|
end
|
99
|
-
alias on_defs on_def
|
100
|
-
|
101
|
-
private
|
102
180
|
|
103
181
|
def forbidden_name?(name)
|
104
182
|
forbidden_identifier?(name) || forbidden_pattern?(name)
|
105
183
|
end
|
106
184
|
|
185
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
107
186
|
def register_forbidden_name(node)
|
108
187
|
if node.any_def_type?
|
109
188
|
name_node = node.loc.name
|
110
189
|
method_name = node.method_name
|
111
|
-
|
112
|
-
|
190
|
+
elsif node.literal?
|
191
|
+
name_node = node
|
192
|
+
method_name = node.value
|
193
|
+
elsif (attrs = node.attribute_accessor?)
|
113
194
|
name_node = attrs.last.last
|
114
195
|
method_name = attr_name(name_node)
|
196
|
+
else
|
197
|
+
name_node = node.first_argument
|
198
|
+
method_name = node.first_argument.value
|
115
199
|
end
|
116
200
|
message = format(MSG_FORBIDDEN, identifier: method_name)
|
117
201
|
add_offense(name_node, message: message)
|
118
202
|
end
|
203
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
119
204
|
|
120
205
|
def attr_name(name_item)
|
121
206
|
sym_name(name_item) || str_name(name_item)
|
122
207
|
end
|
123
208
|
|
124
209
|
def range_position(node)
|
125
|
-
|
126
|
-
|
210
|
+
if node.loc.respond_to?(:selector)
|
211
|
+
selector_end_pos = node.loc.selector.end_pos + 1
|
212
|
+
expr_end_pos = node.source_range.end_pos
|
127
213
|
|
128
|
-
|
214
|
+
range_between(selector_end_pos, expr_end_pos)
|
215
|
+
else
|
216
|
+
node.source_range
|
217
|
+
end
|
129
218
|
end
|
130
219
|
|
131
220
|
def message(style)
|
@@ -26,6 +26,11 @@ module RuboCop
|
|
26
26
|
# guidelines. By default, `call` is allowed. The cop also has `AllowedPatterns`
|
27
27
|
# configuration to allow method names by regular expression.
|
28
28
|
#
|
29
|
+
# Although returning a call to another predicate method is treated as a boolean value,
|
30
|
+
# certain method names can be known to not return a boolean, despite ending in a `?`
|
31
|
+
# (for example, `Numeric#nonzero?` returns `self` or `nil`). These methods can be
|
32
|
+
# configured using `NonBooleanPredicates`.
|
33
|
+
#
|
29
34
|
# The cop can furthermore be configured to allow all bang methods (method names
|
30
35
|
# ending with `!`), with `AllowBangMethods: true` (default false).
|
31
36
|
#
|
@@ -164,7 +169,7 @@ module RuboCop
|
|
164
169
|
def unknown_method_call?(value)
|
165
170
|
return false unless value.call_type?
|
166
171
|
|
167
|
-
!
|
172
|
+
!method_returning_boolean?(value)
|
168
173
|
end
|
169
174
|
|
170
175
|
def return_values(node)
|
@@ -190,7 +195,13 @@ module RuboCop
|
|
190
195
|
|
191
196
|
def boolean_return?(value)
|
192
197
|
return true if value.boolean_type?
|
198
|
+
|
199
|
+
method_returning_boolean?(value)
|
200
|
+
end
|
201
|
+
|
202
|
+
def method_returning_boolean?(value)
|
193
203
|
return false unless value.call_type?
|
204
|
+
return false if wayward_predicate?(value.method_name)
|
194
205
|
|
195
206
|
value.comparison_method? || value.predicate_method? || value.negation_method?
|
196
207
|
end
|
@@ -258,7 +269,10 @@ module RuboCop
|
|
258
269
|
node.body ? [last_value(node.body)] : [s(:nil)]
|
259
270
|
else
|
260
271
|
# Branches with no value act as an implicit `nil`.
|
261
|
-
node.branches.
|
272
|
+
branches = node.branches.map { |branch| branch ? last_value(branch) : s(:nil) }
|
273
|
+
# Missing else branches also act as an implicit `nil`.
|
274
|
+
branches.push(s(:nil)) unless node.else_branch
|
275
|
+
branches
|
262
276
|
end
|
263
277
|
end
|
264
278
|
|
@@ -275,6 +289,17 @@ module RuboCop
|
|
275
289
|
def allow_bang_methods?
|
276
290
|
cop_config.fetch('AllowBangMethods', false)
|
277
291
|
end
|
292
|
+
|
293
|
+
# If a method ending in `?` is known to not return a boolean value,
|
294
|
+
# (for example, `Numeric#nonzero?`) it should be treated as a non-boolean
|
295
|
+
# value, despite the method naming.
|
296
|
+
def wayward_predicate?(name)
|
297
|
+
wayward_predicates.include?(name.to_s)
|
298
|
+
end
|
299
|
+
|
300
|
+
def wayward_predicates
|
301
|
+
Array(cop_config.fetch('WaywardPredicates', []))
|
302
|
+
end
|
278
303
|
end
|
279
304
|
end
|
280
305
|
end
|
@@ -11,13 +11,14 @@ module RuboCop
|
|
11
11
|
#
|
12
12
|
# eval(something)
|
13
13
|
# binding.eval(something)
|
14
|
+
# Kernel.eval(something)
|
14
15
|
class Eval < Base
|
15
16
|
MSG = 'The use of `eval` is a serious security risk.'
|
16
17
|
RESTRICT_ON_SEND = %i[eval].freeze
|
17
18
|
|
18
19
|
# @!method eval?(node)
|
19
20
|
def_node_matcher :eval?, <<~PATTERN
|
20
|
-
(send {nil? (send nil? :binding)} :eval $!str ...)
|
21
|
+
(send {nil? (send nil? :binding) (const {cbase nil?} :Kernel)} :eval $!str ...)
|
21
22
|
PATTERN
|
22
23
|
|
23
24
|
def on_send(node)
|
@@ -348,7 +348,7 @@ module RuboCop
|
|
348
348
|
end
|
349
349
|
|
350
350
|
def remove_modifier_node_within_begin(corrector, modifier_node, begin_node)
|
351
|
-
def_node = begin_node.children[1]
|
351
|
+
def_node = begin_node.children[begin_node.children.index(modifier_node) + 1]
|
352
352
|
range = modifier_node.source_range.begin.join(def_node.source_range.begin)
|
353
353
|
corrector.remove(range)
|
354
354
|
end
|
@@ -84,7 +84,10 @@ module RuboCop
|
|
84
84
|
|
85
85
|
def autocorrect(corrector, node)
|
86
86
|
if (preferred_accessors = preferred_accessors(node))
|
87
|
-
corrector.replace(
|
87
|
+
corrector.replace(
|
88
|
+
grouped_style? ? node : range_with_trailing_argument_comment(node),
|
89
|
+
preferred_accessors
|
90
|
+
)
|
88
91
|
else
|
89
92
|
range = range_with_surrounding_space(node.source_range, side: :left)
|
90
93
|
corrector.remove(range)
|
@@ -196,6 +199,15 @@ module RuboCop
|
|
196
199
|
end
|
197
200
|
end.join("\n")
|
198
201
|
end
|
202
|
+
|
203
|
+
def range_with_trailing_argument_comment(node)
|
204
|
+
comment = processed_source.ast_with_comments[node.last_argument].last
|
205
|
+
if comment
|
206
|
+
add_range(node.source_range, comment.source_range)
|
207
|
+
else
|
208
|
+
node
|
209
|
+
end
|
210
|
+
end
|
199
211
|
end
|
200
212
|
end
|
201
213
|
end
|