rubocop 1.75.8 → 1.79.1
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 -16
- data/config/default.yml +107 -26
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/cli.rb +12 -1
- data/lib/rubocop/config_loader.rb +1 -38
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
- 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/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +99 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +26 -5
- 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/layout/space_before_brackets.rb +2 -9
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
- data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- 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/safe_navigation_chain.rb +4 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +25 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/method_name.rb +127 -13
- data/lib/rubocop/cop/naming/predicate_method.rb +306 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
- 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/arguments_forwarding.rb +11 -17
- data/lib/rubocop/cop/style/array_intersect.rb +53 -23
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -2
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
- data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
- data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
- 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 +36 -15
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
- data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -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_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +35 -5
- data/lib/rubocop/cop/style/redundant_self.rb +8 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +24 -11
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +32 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +18 -7
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/lsp/diagnostic.rb +4 -4
- data/lib/rubocop/lsp/routes.rb +4 -4
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- 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 +11 -1
- data/lib/ruby_lsp/rubocop/addon.rb +2 -2
- metadata +21 -8
@@ -0,0 +1,306 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Naming
|
6
|
+
# Checks that predicate methods end with `?` and non-predicate methods do not.
|
7
|
+
#
|
8
|
+
# The names of predicate methods (methods that return a boolean value) should end
|
9
|
+
# in a question mark. Methods that don't return a boolean, shouldn't
|
10
|
+
# end in a question mark.
|
11
|
+
#
|
12
|
+
# The cop assesses a predicate method as one that returns boolean values. Likewise,
|
13
|
+
# a method that only returns literal values is assessed as non-predicate. Other predicate
|
14
|
+
# method calls are assumed to return boolean values. The cop does not make an assessment
|
15
|
+
# if the return type is unknown (non-predicate method calls, variables, etc.).
|
16
|
+
#
|
17
|
+
# NOTE: Operator methods (`def ==`, etc.) are ignored.
|
18
|
+
#
|
19
|
+
# By default, the cop runs in `conservative` mode, which allows a method to be named
|
20
|
+
# with a question mark as long as at least one return value is boolean. In `aggressive`
|
21
|
+
# mode, methods with a question mark will register an offense if any known non-boolean
|
22
|
+
# return values are detected.
|
23
|
+
#
|
24
|
+
# The cop also has `AllowedMethods` configuration in order to prevent the cop from
|
25
|
+
# registering an offense from a method name that does not confirm to the naming
|
26
|
+
# guidelines. By default, `call` is allowed. The cop also has `AllowedPatterns`
|
27
|
+
# configuration to allow method names by regular expression.
|
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
|
+
#
|
34
|
+
# The cop can furthermore be configured to allow all bang methods (method names
|
35
|
+
# ending with `!`), with `AllowBangMethods: true` (default false).
|
36
|
+
#
|
37
|
+
# @example Mode: conservative (default)
|
38
|
+
# # bad
|
39
|
+
# def foo
|
40
|
+
# bar == baz
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# # good
|
44
|
+
# def foo?
|
45
|
+
# bar == baz
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# # bad
|
49
|
+
# def foo?
|
50
|
+
# 5
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# # good
|
54
|
+
# def foo
|
55
|
+
# 5
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# # bad
|
59
|
+
# def foo
|
60
|
+
# x == y
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# # good
|
64
|
+
# def foo?
|
65
|
+
# x == y
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# # bad
|
69
|
+
# def foo
|
70
|
+
# !x
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# # good
|
74
|
+
# def foo?
|
75
|
+
# !x
|
76
|
+
# end
|
77
|
+
#
|
78
|
+
# # bad - returns the value of another predicate method
|
79
|
+
# def foo
|
80
|
+
# bar?
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# # good
|
84
|
+
# def foo?
|
85
|
+
# bar?
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
# # good - operator method
|
89
|
+
# def ==(other)
|
90
|
+
# hash == other.hash
|
91
|
+
# end
|
92
|
+
#
|
93
|
+
# # good - at least one return value is boolean
|
94
|
+
# def foo?
|
95
|
+
# return unless bar?
|
96
|
+
# true
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# # ok - return type is not known
|
100
|
+
# def foo?
|
101
|
+
# bar
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# # ok - return type is not known
|
105
|
+
# def foo
|
106
|
+
# bar?
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# @example Mode: aggressive
|
110
|
+
# # bad - the method returns nil in some cases
|
111
|
+
# def foo?
|
112
|
+
# return unless bar?
|
113
|
+
# true
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# @example AllowBangMethods: false (default)
|
117
|
+
# # bad
|
118
|
+
# def save!
|
119
|
+
# true
|
120
|
+
# end
|
121
|
+
#
|
122
|
+
# @example AllowBangMethods: true
|
123
|
+
# # good
|
124
|
+
# def save!
|
125
|
+
# true
|
126
|
+
# end
|
127
|
+
#
|
128
|
+
class PredicateMethod < Base
|
129
|
+
include AllowedMethods
|
130
|
+
include AllowedPattern
|
131
|
+
|
132
|
+
MSG_PREDICATE = 'Predicate method names should end with `?`.'
|
133
|
+
MSG_NON_PREDICATE = 'Non-predicate method names should not end with `?`.'
|
134
|
+
|
135
|
+
def on_def(node)
|
136
|
+
return if allowed?(node)
|
137
|
+
|
138
|
+
return_values = return_values(node.body)
|
139
|
+
return if acceptable?(return_values)
|
140
|
+
|
141
|
+
if node.predicate_method? && potential_non_predicate?(return_values)
|
142
|
+
add_offense(node.loc.name, message: MSG_NON_PREDICATE)
|
143
|
+
elsif !node.predicate_method? && all_return_values_boolean?(return_values)
|
144
|
+
add_offense(node.loc.name, message: MSG_PREDICATE)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
alias on_defs on_def
|
148
|
+
|
149
|
+
private
|
150
|
+
|
151
|
+
def allowed?(node)
|
152
|
+
allowed_method?(node.method_name) ||
|
153
|
+
matches_allowed_pattern?(node.method_name) ||
|
154
|
+
allowed_bang_method?(node) ||
|
155
|
+
node.operator_method? ||
|
156
|
+
node.body.nil?
|
157
|
+
end
|
158
|
+
|
159
|
+
def acceptable?(return_values)
|
160
|
+
# In `conservative` mode, if the method returns `super`, `zsuper`, or a
|
161
|
+
# non-comparison method call, the method name is acceptable.
|
162
|
+
return false unless conservative?
|
163
|
+
|
164
|
+
return_values.any? do |value|
|
165
|
+
value.type?(:super, :zsuper) || unknown_method_call?(value)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def unknown_method_call?(value)
|
170
|
+
return false unless value.call_type?
|
171
|
+
|
172
|
+
!method_returning_boolean?(value)
|
173
|
+
end
|
174
|
+
|
175
|
+
def return_values(node)
|
176
|
+
# Collect all the (implicit and explicit) return values of a node
|
177
|
+
return_values = Set.new(node.begin_type? ? [] : [extract_return_value(node)])
|
178
|
+
|
179
|
+
node.each_descendant(:return) do |return_node|
|
180
|
+
return_values << extract_return_value(return_node)
|
181
|
+
end
|
182
|
+
|
183
|
+
last_value = last_value(node)
|
184
|
+
return_values << last_value if last_value
|
185
|
+
|
186
|
+
process_return_values(return_values)
|
187
|
+
end
|
188
|
+
|
189
|
+
def all_return_values_boolean?(return_values)
|
190
|
+
values = return_values.reject { |value| value.type?(:super, :zsuper) }
|
191
|
+
return false if values.empty?
|
192
|
+
|
193
|
+
values.all? { |value| boolean_return?(value) }
|
194
|
+
end
|
195
|
+
|
196
|
+
def boolean_return?(value)
|
197
|
+
return true if value.boolean_type?
|
198
|
+
|
199
|
+
method_returning_boolean?(value)
|
200
|
+
end
|
201
|
+
|
202
|
+
def method_returning_boolean?(value)
|
203
|
+
return false unless value.call_type?
|
204
|
+
return false if wayward_predicate?(value.method_name)
|
205
|
+
|
206
|
+
value.comparison_method? || value.predicate_method? || value.negation_method?
|
207
|
+
end
|
208
|
+
|
209
|
+
def potential_non_predicate?(return_values)
|
210
|
+
# Assumes a method to be non-predicate if all return values are non-boolean literals.
|
211
|
+
#
|
212
|
+
# In `Mode: conservative`, if any of the return values is a boolean,
|
213
|
+
# the method name is acceptable.
|
214
|
+
# In `Mode: aggressive`, all return values must be booleans for a predicate
|
215
|
+
# method, or else an offense will be registered.
|
216
|
+
return false if conservative? && return_values.any? { |value| boolean_return?(value) }
|
217
|
+
|
218
|
+
return_values.any? do |value|
|
219
|
+
value.literal? && !value.boolean_type?
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def extract_return_value(node)
|
224
|
+
return node unless node.return_type?
|
225
|
+
|
226
|
+
# `return` without a value is a `nil` return.
|
227
|
+
return s(:nil) if node.arguments.empty?
|
228
|
+
|
229
|
+
# When there's a multiple return, it cannot be a predicate
|
230
|
+
# so just return an `array` sexp for simplicity.
|
231
|
+
return s(:array) unless node.arguments.one?
|
232
|
+
|
233
|
+
node.first_argument
|
234
|
+
end
|
235
|
+
|
236
|
+
def last_value(node)
|
237
|
+
value = node.begin_type? ? node.children.last : node
|
238
|
+
value&.return_type? ? extract_return_value(value) : value
|
239
|
+
end
|
240
|
+
|
241
|
+
def process_return_values(return_values)
|
242
|
+
return_values.flat_map do |value|
|
243
|
+
if value.conditional?
|
244
|
+
process_return_values(extract_conditional_branches(value))
|
245
|
+
elsif and_or?(value)
|
246
|
+
process_return_values(extract_and_or_clauses(value))
|
247
|
+
else
|
248
|
+
value
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def and_or?(node)
|
254
|
+
node.type?(:and, :or)
|
255
|
+
end
|
256
|
+
|
257
|
+
def extract_and_or_clauses(node)
|
258
|
+
# Recursively traverse an `and` or `or` node to collect all clauses within
|
259
|
+
return node unless and_or?(node)
|
260
|
+
|
261
|
+
[extract_and_or_clauses(node.lhs), extract_and_or_clauses(node.rhs)].flatten
|
262
|
+
end
|
263
|
+
|
264
|
+
def extract_conditional_branches(node)
|
265
|
+
return node unless node.conditional?
|
266
|
+
|
267
|
+
if node.type?(:while, :until)
|
268
|
+
# If there is no body, act as implicit `nil`.
|
269
|
+
node.body ? [last_value(node.body)] : [s(:nil)]
|
270
|
+
else
|
271
|
+
# Branches with no value act as an implicit `nil`.
|
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
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def conservative?
|
280
|
+
cop_config.fetch('Mode', :conservative).to_sym == :conservative
|
281
|
+
end
|
282
|
+
|
283
|
+
def allowed_bang_method?(node)
|
284
|
+
return false unless allow_bang_methods?
|
285
|
+
|
286
|
+
node.bang_method?
|
287
|
+
end
|
288
|
+
|
289
|
+
def allow_bang_methods?
|
290
|
+
cop_config.fetch('AllowBangMethods', false)
|
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
|
303
|
+
end
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
@@ -100,12 +100,12 @@ module RuboCop
|
|
100
100
|
# # good
|
101
101
|
# def_node_matcher(:even?) { |value| }
|
102
102
|
#
|
103
|
-
class
|
103
|
+
class PredicatePrefix < Base
|
104
104
|
include AllowedMethods
|
105
105
|
|
106
106
|
# @!method dynamic_method_define(node)
|
107
107
|
def_node_matcher :dynamic_method_define, <<~PATTERN
|
108
|
-
(send nil? #
|
108
|
+
(send nil? #method_definition_macro?
|
109
109
|
(sym $_)
|
110
110
|
...)
|
111
111
|
PATTERN
|
@@ -143,7 +143,7 @@ module RuboCop
|
|
143
143
|
next if predicate_prefixes.include?(forbidden_prefix)
|
144
144
|
|
145
145
|
raise ValidationError, <<~MSG.chomp
|
146
|
-
The `Naming/
|
146
|
+
The `Naming/PredicatePrefix` cop is misconfigured. Prefix #{forbidden_prefix} must be included in NamePrefix because it is included in ForbiddenPrefixes.
|
147
147
|
MSG
|
148
148
|
end
|
149
149
|
end
|
@@ -195,7 +195,7 @@ module RuboCop
|
|
195
195
|
cop_config['UseSorbetSigs']
|
196
196
|
end
|
197
197
|
|
198
|
-
def
|
198
|
+
def method_definition_macro?(macro_name)
|
199
199
|
cop_config['MethodDefinitionMacros'].include?(macro_name.to_s)
|
200
200
|
end
|
201
201
|
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
|
@@ -146,7 +146,6 @@ module RuboCop
|
|
146
146
|
minimum_target_ruby_version 2.7
|
147
147
|
|
148
148
|
FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
|
149
|
-
ADDITIONAL_ARG_TYPES = %i[lvar arg optarg].freeze
|
150
149
|
|
151
150
|
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
152
151
|
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
@@ -198,9 +197,9 @@ module RuboCop
|
|
198
197
|
send_classifications.all? { |_, c, _, _| all_classifications.include?(c) }
|
199
198
|
end
|
200
199
|
|
201
|
-
# rubocop:disable Metrics/MethodLength
|
200
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
202
201
|
def add_forward_all_offenses(node, send_classifications, forwardable_args)
|
203
|
-
|
202
|
+
rest_arg, kwrest_arg, block_arg = *forwardable_args
|
204
203
|
registered_block_arg_offense = false
|
205
204
|
|
206
205
|
send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
@@ -212,16 +211,20 @@ module RuboCop
|
|
212
211
|
registered_block_arg_offense = true
|
213
212
|
break
|
214
213
|
else
|
215
|
-
|
214
|
+
first_arg = forward_rest || forward_kwrest || forward_all_first_argument(send_node)
|
215
|
+
register_forward_all_offense(send_node, send_node, first_arg)
|
216
216
|
end
|
217
217
|
end
|
218
218
|
|
219
219
|
return if registered_block_arg_offense
|
220
220
|
|
221
|
-
|
222
|
-
|
221
|
+
register_forward_all_offense(node, node.arguments, rest_arg || kwrest_arg)
|
222
|
+
end
|
223
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
224
|
+
|
225
|
+
def forward_all_first_argument(node)
|
226
|
+
node.arguments.reverse_each.find(&:forwarded_restarg_type?)
|
223
227
|
end
|
224
|
-
# rubocop:enable Metrics/MethodLength
|
225
228
|
|
226
229
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
227
230
|
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
@@ -361,18 +364,9 @@ module RuboCop
|
|
361
364
|
end
|
362
365
|
end
|
363
366
|
|
364
|
-
# rubocop:disable Metrics/AbcSize
|
365
367
|
def arguments_range(node, first_node)
|
366
|
-
|
367
|
-
next true if ADDITIONAL_ARG_TYPES.include?(arg.type) || arg.variable? || arg.call_type?
|
368
|
-
|
369
|
-
arg.literal? && arg.each_descendant(:kwsplat).none?
|
370
|
-
end
|
371
|
-
|
372
|
-
start_node = first_node || arguments.first
|
373
|
-
start_node.source_range.begin.join(arguments.last.source_range.end)
|
368
|
+
first_node.source_range.begin.join(node.last_argument.source_range.end)
|
374
369
|
end
|
375
|
-
# rubocop:enable Metrics/AbcSize
|
376
370
|
|
377
371
|
def allow_only_rest_arguments?
|
378
372
|
cop_config.fetch('AllowOnlyRestArgument', true)
|
@@ -5,12 +5,15 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# In Ruby 3.1, `Array#intersect?` has been added.
|
7
7
|
#
|
8
|
-
# This cop identifies places where
|
9
|
-
# or `(array1.intersection(array2)).any?` can be replaced by
|
10
|
-
# `array1.intersect?(array2)`.
|
8
|
+
# This cop identifies places where:
|
11
9
|
#
|
12
|
-
#
|
13
|
-
# `(array1
|
10
|
+
# * `(array1 & array2).any?`
|
11
|
+
# * `(array1.intersection(array2)).any?`
|
12
|
+
# * `array1.any? { |elem| array2.member?(elem) }`
|
13
|
+
#
|
14
|
+
# can be replaced with `array1.intersect?(array2)`.
|
15
|
+
#
|
16
|
+
# `array1.intersect?(array2)` is faster and more readable.
|
14
17
|
#
|
15
18
|
# In cases like the following, compatibility is not ensured,
|
16
19
|
# so it will not be detected when using block argument.
|
@@ -40,6 +43,10 @@ module RuboCop
|
|
40
43
|
# array1.intersection(array2).empty?
|
41
44
|
# array1.intersection(array2).none?
|
42
45
|
#
|
46
|
+
# # bad
|
47
|
+
# array1.any? { |elem| array2.member?(elem) }
|
48
|
+
# array1.none? { |elem| array2.member?(elem) }
|
49
|
+
#
|
43
50
|
# # good
|
44
51
|
# array1.intersect?(array2)
|
45
52
|
# !array1.intersect?(array2)
|
@@ -77,8 +84,26 @@ module RuboCop
|
|
77
84
|
)
|
78
85
|
PATTERN
|
79
86
|
|
80
|
-
|
81
|
-
|
87
|
+
# @!method any_none_block_intersection(node)
|
88
|
+
def_node_matcher :any_none_block_intersection, <<~PATTERN
|
89
|
+
{
|
90
|
+
(block
|
91
|
+
(call $_receiver ${:any? :none?})
|
92
|
+
(args (arg _key))
|
93
|
+
(send $_argument :member? (lvar _key))
|
94
|
+
)
|
95
|
+
(numblock
|
96
|
+
(call $_receiver ${:any? :none?}) 1
|
97
|
+
(send $_argument :member? (lvar :_1))
|
98
|
+
)
|
99
|
+
(itblock
|
100
|
+
(call $_receiver ${:any? :none?}) :it
|
101
|
+
(send $_argument :member? (lvar :it))
|
102
|
+
)
|
103
|
+
}
|
104
|
+
PATTERN
|
105
|
+
|
106
|
+
MSG = 'Use `%<replacement>s` instead of `%<existing>s`.'
|
82
107
|
STRAIGHT_METHODS = %i[present? any?].freeze
|
83
108
|
NEGATED_METHODS = %i[blank? empty? none?].freeze
|
84
109
|
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
@@ -88,16 +113,25 @@ module RuboCop
|
|
88
113
|
return unless (receiver, argument, method_name = bad_intersection?(node))
|
89
114
|
|
90
115
|
dot = node.loc.dot.source
|
91
|
-
|
92
|
-
|
93
|
-
add_offense(node, message: message) do |corrector|
|
94
|
-
bang = straight?(method_name) ? '' : '!'
|
116
|
+
bang = straight?(method_name) ? '' : '!'
|
117
|
+
replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
|
95
118
|
|
96
|
-
|
97
|
-
end
|
119
|
+
register_offense(node, replacement)
|
98
120
|
end
|
99
121
|
alias on_csend on_send
|
100
122
|
|
123
|
+
def on_block(node)
|
124
|
+
return unless (receiver, method_name, argument = any_none_block_intersection(node))
|
125
|
+
|
126
|
+
dot = node.send_node.loc.dot.source
|
127
|
+
bang = method_name == :any? ? '' : '!'
|
128
|
+
replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
|
129
|
+
|
130
|
+
register_offense(node, replacement)
|
131
|
+
end
|
132
|
+
alias on_numblock on_block
|
133
|
+
alias on_itblock on_block
|
134
|
+
|
101
135
|
private
|
102
136
|
|
103
137
|
def bad_intersection?(node)
|
@@ -114,16 +148,12 @@ module RuboCop
|
|
114
148
|
STRAIGHT_METHODS.include?(method_name.to_sym)
|
115
149
|
end
|
116
150
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
argument: argument,
|
124
|
-
dot: dot,
|
125
|
-
existing: existing
|
126
|
-
)
|
151
|
+
def register_offense(node, replacement)
|
152
|
+
message = format(MSG, replacement: replacement, existing: node.source)
|
153
|
+
|
154
|
+
add_offense(node, message: message) do |corrector|
|
155
|
+
corrector.replace(node, replacement)
|
156
|
+
end
|
127
157
|
end
|
128
158
|
end
|
129
159
|
end
|