rubocop 1.57.2 → 1.62.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/LICENSE.txt +1 -1
- data/README.md +4 -4
- data/assets/output.css.erb +159 -0
- data/assets/output.html.erb +1 -160
- data/config/default.yml +87 -15
- data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli.rb +6 -1
- data/lib/rubocop/config.rb +4 -2
- data/lib/rubocop/config_finder.rb +12 -2
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_obsoletion.rb +11 -8
- data/lib/rubocop/config_validator.rb +14 -7
- data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
- data/lib/rubocop/cop/base.rb +17 -2
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
- data/lib/rubocop/cop/exclude_limit.rb +1 -1
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
- 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 +123 -29
- data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
- data/lib/rubocop/cop/layout/end_alignment.rb +8 -2
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
- 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/heredoc_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +16 -3
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.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/hash_compare_by_identity.rb +2 -1
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +54 -6
- data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
- data/lib/rubocop/cop/lint/script_permission.rb +3 -3
- data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
- data/lib/rubocop/cop/lint/syntax.rb +6 -3
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -2
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_times.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +20 -2
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- 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 +12 -4
- data/lib/rubocop/cop/naming/constant_name.rb +1 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +2 -2
- 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 +152 -21
- 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 +5 -5
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/class_vars.rb +3 -3
- data/lib/rubocop/cop/style/collection_compact.rb +18 -8
- data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +6 -7
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
- data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
- data/lib/rubocop/cop/style/hash_except.rb +2 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +44 -2
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
- data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
- 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/multiline_method_signature.rb +10 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +5 -3
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +5 -3
- data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
- data/lib/rubocop/cop/style/raise_args.rb +4 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +4 -3
- data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +4 -3
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +3 -3
- data/lib/rubocop/cop/style/redundant_each.rb +7 -4
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +27 -7
- data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -10
- data/lib/rubocop/cop/style/redundant_return.rb +7 -1
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
- data/lib/rubocop/cop/style/sample.rb +3 -4
- data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
- 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 +5 -2
- data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +15 -3
- data/lib/rubocop/directive_comment.rb +10 -8
- data/lib/rubocop/ext/regexp_node.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +31 -12
- data/lib/rubocop/formatter/json_formatter.rb +0 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
- data/lib/rubocop/formatter.rb +1 -1
- data/lib/rubocop/lsp/logger.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +2 -2
- data/lib/rubocop/lsp/runtime.rb +1 -1
- data/lib/rubocop/lsp/server.rb +5 -2
- data/lib/rubocop/lsp/severity.rb +1 -1
- data/lib/rubocop/lsp.rb +29 -0
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/options.rb +11 -8
- data/lib/rubocop/path_util.rb +6 -2
- data/lib/rubocop/result_cache.rb +0 -1
- data/lib/rubocop/rspec/cop_helper.rb +8 -2
- data/lib/rubocop/rspec/expect_offense.rb +8 -8
- data/lib/rubocop/rspec/shared_contexts.rb +40 -15
- data/lib/rubocop/rspec/support.rb +2 -0
- data/lib/rubocop/runner.rb +10 -3
- data/lib/rubocop/server/cache.rb +1 -2
- data/lib/rubocop/server/client_command/exec.rb +0 -1
- data/lib/rubocop/server/server_command/exec.rb +0 -1
- data/lib/rubocop/target_finder.rb +84 -78
- data/lib/rubocop/target_ruby.rb +82 -80
- data/lib/rubocop/version.rb +18 -3
- data/lib/rubocop.rb +4 -0
- metadata +18 -10
- /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -8,11 +8,26 @@ module RuboCop
|
|
8
8
|
# This cop identifies places where `do_something(*args, &block)`
|
9
9
|
# can be replaced by `do_something(...)`.
|
10
10
|
#
|
11
|
+
# In Ruby 3.1, anonymous block forwarding has been added.
|
12
|
+
#
|
13
|
+
# This cop identifies places where `do_something(&block)` can be replaced
|
14
|
+
# by `do_something(&)`; if desired, this functionality can be disabled
|
15
|
+
# by setting `UseAnonymousForwarding: false`.
|
16
|
+
#
|
11
17
|
# In Ruby 3.2, anonymous args/kwargs forwarding has been added.
|
12
18
|
#
|
13
19
|
# This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
|
14
20
|
# replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
|
15
|
-
# by setting UseAnonymousForwarding: false
|
21
|
+
# by setting `UseAnonymousForwarding: false`.
|
22
|
+
#
|
23
|
+
# And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
|
24
|
+
# and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
|
25
|
+
# that are sufficient for anonymizing meaningless naming.
|
26
|
+
#
|
27
|
+
# Meaningless names that are commonly used can be anonymized by default:
|
28
|
+
# e.g., `*args`, `**options`, `&block`, and so on.
|
29
|
+
#
|
30
|
+
# Names not on this list are likely to be meaningful and are allowed by default.
|
16
31
|
#
|
17
32
|
# @example
|
18
33
|
# # bad
|
@@ -32,22 +47,25 @@ module RuboCop
|
|
32
47
|
#
|
33
48
|
# @example UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2)
|
34
49
|
# # bad
|
35
|
-
# def foo(*args, **kwargs)
|
50
|
+
# def foo(*args, **kwargs, &block)
|
36
51
|
# args_only(*args)
|
37
52
|
# kwargs_only(**kwargs)
|
53
|
+
# block_only(&block)
|
38
54
|
# end
|
39
55
|
#
|
40
56
|
# # good
|
41
|
-
# def foo(*,
|
57
|
+
# def foo(*, **, &)
|
42
58
|
# args_only(*)
|
43
59
|
# kwargs_only(**)
|
60
|
+
# block_only(&)
|
44
61
|
# end
|
45
62
|
#
|
46
63
|
# @example UseAnonymousForwarding: false (only relevant for Ruby >= 3.2)
|
47
64
|
# # good
|
48
|
-
# def foo(*args, **kwargs)
|
65
|
+
# def foo(*args, **kwargs, &block)
|
49
66
|
# args_only(*args)
|
50
67
|
# kwargs_only(**kwargs)
|
68
|
+
# block_only(&block)
|
51
69
|
# end
|
52
70
|
#
|
53
71
|
# @example AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2)
|
@@ -72,6 +90,38 @@ module RuboCop
|
|
72
90
|
# bar(**kwargs)
|
73
91
|
# end
|
74
92
|
#
|
93
|
+
# @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
|
94
|
+
# # bad
|
95
|
+
# def foo(*args)
|
96
|
+
# bar(*args)
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# # good
|
100
|
+
# def foo(*)
|
101
|
+
# bar(*)
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
|
105
|
+
# # bad
|
106
|
+
# def foo(**kwargs)
|
107
|
+
# bar(**kwargs)
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# # good
|
111
|
+
# def foo(**)
|
112
|
+
# bar(**)
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
|
116
|
+
# # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`.
|
117
|
+
# def foo(&block)
|
118
|
+
# bar(&block)
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# # good
|
122
|
+
# def foo(&)
|
123
|
+
# bar(&)
|
124
|
+
# end
|
75
125
|
class ArgumentsForwarding < Base
|
76
126
|
include RangeHelp
|
77
127
|
extend AutoCorrector
|
@@ -85,17 +135,21 @@ module RuboCop
|
|
85
135
|
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
86
136
|
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
87
137
|
KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
|
138
|
+
BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
|
139
|
+
|
140
|
+
def self.autocorrect_incompatible_with
|
141
|
+
[Naming::BlockForwarding]
|
142
|
+
end
|
88
143
|
|
89
144
|
def on_def(node)
|
90
145
|
return unless node.body
|
91
146
|
|
92
|
-
|
147
|
+
restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
|
148
|
+
forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
149
|
+
send_nodes = node.each_descendant(:send).to_a
|
93
150
|
|
94
151
|
send_classifications = classify_send_nodes(
|
95
|
-
node,
|
96
|
-
node.each_descendant(:send).to_a,
|
97
|
-
non_splat_or_block_pass_lvar_references(node.body),
|
98
|
-
forwardable_args
|
152
|
+
node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
|
99
153
|
)
|
100
154
|
|
101
155
|
return if send_classifications.empty?
|
@@ -115,36 +169,71 @@ module RuboCop
|
|
115
169
|
[args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
|
116
170
|
end
|
117
171
|
|
172
|
+
def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
173
|
+
restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
|
174
|
+
kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
|
175
|
+
blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
|
176
|
+
|
177
|
+
[restarg_node, kwrestarg_node, blockarg_node]
|
178
|
+
end
|
179
|
+
|
118
180
|
def only_forwards_all?(send_classifications)
|
119
181
|
send_classifications.all? { |_, c, _, _| c == :all }
|
120
182
|
end
|
121
183
|
|
184
|
+
# rubocop:disable Metrics/MethodLength
|
122
185
|
def add_forward_all_offenses(node, send_classifications, forwardable_args)
|
123
|
-
|
124
|
-
|
186
|
+
_rest_arg, _kwrest_arg, block_arg = *forwardable_args
|
187
|
+
registered_block_arg_offense = false
|
188
|
+
|
189
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
190
|
+
if !forward_rest && !forward_kwrest
|
191
|
+
# Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
|
192
|
+
# in Ruby 3.3.0.
|
193
|
+
if outside_block?(forward_block_arg)
|
194
|
+
register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
|
195
|
+
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
196
|
+
end
|
197
|
+
registered_block_arg_offense = true
|
198
|
+
break
|
199
|
+
else
|
200
|
+
register_forward_all_offense(send_node, send_node, forward_rest)
|
201
|
+
end
|
125
202
|
end
|
126
203
|
|
204
|
+
return if registered_block_arg_offense
|
205
|
+
|
127
206
|
rest_arg, _kwrest_arg, _block_arg = *forwardable_args
|
128
207
|
register_forward_all_offense(node, node.arguments, rest_arg)
|
129
208
|
end
|
209
|
+
# rubocop:enable Metrics/MethodLength
|
130
210
|
|
211
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
131
212
|
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
132
213
|
return unless use_anonymous_forwarding?
|
133
214
|
|
134
|
-
rest_arg, kwrest_arg,
|
215
|
+
rest_arg, kwrest_arg, block_arg = *forwardable_args
|
135
216
|
|
136
|
-
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
|
137
|
-
if forward_rest
|
217
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
218
|
+
if outside_block?(forward_rest)
|
138
219
|
register_forward_args_offense(def_node.arguments, rest_arg)
|
139
220
|
register_forward_args_offense(send_node, forward_rest)
|
140
221
|
end
|
141
222
|
|
142
|
-
if forward_kwrest
|
223
|
+
if outside_block?(forward_kwrest)
|
143
224
|
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
144
225
|
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
145
226
|
end
|
227
|
+
|
228
|
+
# Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
|
229
|
+
# in Ruby 3.3.0.
|
230
|
+
if outside_block?(forward_block_arg)
|
231
|
+
register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
|
232
|
+
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
233
|
+
end
|
146
234
|
end
|
147
235
|
end
|
236
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
148
237
|
|
149
238
|
def non_splat_or_block_pass_lvar_references(body)
|
150
239
|
body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
|
@@ -173,10 +262,7 @@ module RuboCop
|
|
173
262
|
|
174
263
|
def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
|
175
264
|
classifier = SendNodeClassifier.new(
|
176
|
-
def_node,
|
177
|
-
send_node,
|
178
|
-
referenced_lvars,
|
179
|
-
forwardable_args,
|
265
|
+
def_node, send_node, referenced_lvars, forwardable_args,
|
180
266
|
target_ruby_version: target_ruby_version,
|
181
267
|
allow_only_rest_arguments: allow_only_rest_arguments?
|
182
268
|
)
|
@@ -185,7 +271,28 @@ module RuboCop
|
|
185
271
|
|
186
272
|
return unless classification
|
187
273
|
|
188
|
-
[
|
274
|
+
[
|
275
|
+
classification,
|
276
|
+
classifier.forwarded_rest_arg,
|
277
|
+
classifier.forwarded_kwrest_arg,
|
278
|
+
classifier.forwarded_block_arg
|
279
|
+
]
|
280
|
+
end
|
281
|
+
|
282
|
+
def redundant_named_arg(arg, config_name, keyword)
|
283
|
+
return nil unless arg
|
284
|
+
|
285
|
+
redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
|
286
|
+
"#{keyword}#{redundant_arg_name}"
|
287
|
+
end << keyword
|
288
|
+
|
289
|
+
redundant_arg_names.include?(arg.source) ? arg : nil
|
290
|
+
end
|
291
|
+
|
292
|
+
def outside_block?(node)
|
293
|
+
return false unless node
|
294
|
+
|
295
|
+
node.each_ancestor(:block, :numblock).none?
|
189
296
|
end
|
190
297
|
|
191
298
|
def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
|
@@ -204,6 +311,16 @@ module RuboCop
|
|
204
311
|
end
|
205
312
|
end
|
206
313
|
|
314
|
+
def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
|
315
|
+
return if target_ruby_version <= 3.0 || block_arg.source == '&' || explicit_block_name?
|
316
|
+
|
317
|
+
add_offense(block_arg, message: BLOCK_MSG) do |corrector|
|
318
|
+
add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
|
319
|
+
|
320
|
+
corrector.replace(block_arg, '&')
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
207
324
|
def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
|
208
325
|
arg_range = arguments_range(def_or_send, rest_or_splat)
|
209
326
|
|
@@ -278,7 +395,7 @@ module RuboCop
|
|
278
395
|
end
|
279
396
|
|
280
397
|
def classification
|
281
|
-
return nil unless forwarded_rest_arg || forwarded_kwrest_arg
|
398
|
+
return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
|
282
399
|
|
283
400
|
if can_forward_all?
|
284
401
|
:all
|
@@ -362,9 +479,23 @@ module RuboCop
|
|
362
479
|
def no_additional_args?
|
363
480
|
forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
|
364
481
|
|
482
|
+
return false if missing_rest_arg_or_kwrest_arg?
|
483
|
+
|
365
484
|
@def_node.arguments.size == forwardable_count &&
|
366
485
|
@send_node.arguments.size == forwardable_count
|
367
486
|
end
|
487
|
+
|
488
|
+
def missing_rest_arg_or_kwrest_arg?
|
489
|
+
(@rest_arg_name && !forwarded_rest_arg) ||
|
490
|
+
(@kwrest_arg_name && !forwarded_kwrest_arg)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
def explicit_block_name?
|
495
|
+
block_forwarding_config = config.for_cop('Naming/BlockForwarding')
|
496
|
+
return false unless block_forwarding_config['Enabled']
|
497
|
+
|
498
|
+
block_forwarding_config['EnforcedStyle'] == 'explicit'
|
368
499
|
end
|
369
500
|
end
|
370
501
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
|
7
|
+
# them to use `arr.first` and `arr.last` instead.
|
8
|
+
#
|
9
|
+
# The cop is disabled by default due to safety concerns.
|
10
|
+
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because `[0]` or `[-1]` can be called on a Hash,
|
13
|
+
# which returns a value for `0` or `-1` key, but changing these to use
|
14
|
+
# `.first` or `.last` will return first/last tuple instead. Also, String
|
15
|
+
# does not implement `first`/`last` methods.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# arr[0]
|
20
|
+
# arr[-1]
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# arr.first
|
24
|
+
# arr.last
|
25
|
+
# arr[0] = 2
|
26
|
+
# arr[0][-2]
|
27
|
+
#
|
28
|
+
class ArrayFirstLast < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
31
|
+
MSG = 'Use `%<preferred>s`.'
|
32
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
33
|
+
|
34
|
+
# rubocop:disable Metrics/AbcSize
|
35
|
+
def on_send(node)
|
36
|
+
return unless node.arguments.size == 1 && node.first_argument.int_type?
|
37
|
+
|
38
|
+
value = node.first_argument.value
|
39
|
+
return unless [0, -1].include?(value)
|
40
|
+
|
41
|
+
node = innermost_braces_node(node)
|
42
|
+
return if node.parent && brace_method?(node.parent)
|
43
|
+
|
44
|
+
preferred = (value.zero? ? 'first' : 'last')
|
45
|
+
add_offense(node.loc.selector, message: format(MSG, preferred: preferred)) do |corrector|
|
46
|
+
corrector.replace(node.loc.selector, ".#{preferred}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# rubocop:enable Metrics/AbcSize
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def innermost_braces_node(node)
|
54
|
+
node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
|
55
|
+
node
|
56
|
+
end
|
57
|
+
|
58
|
+
def brace_method?(node)
|
59
|
+
node.send_type? && (node.method?(:[]) || node.method?(:[]=))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -16,31 +16,38 @@ module RuboCop
|
|
16
16
|
# File.open('file') do |f|
|
17
17
|
# # ...
|
18
18
|
# end
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# f = Tempfile.open('temp')
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# Tempfile.open('temp') do |f|
|
25
|
+
# # ...
|
26
|
+
# end
|
19
27
|
class AutoResourceCleanup < Base
|
20
|
-
MSG = 'Use the block version of `%<
|
21
|
-
|
22
|
-
TARGET_METHODS = { File: :open }.freeze
|
28
|
+
MSG = 'Use the block version of `%<current>s`.'
|
29
|
+
RESTRICT_ON_SEND = %i[open].freeze
|
23
30
|
|
24
|
-
|
31
|
+
# @!method file_open_method?(node)
|
32
|
+
def_node_matcher :file_open_method?, <<~PATTERN
|
33
|
+
(send (const {nil? cbase} {:File :Tempfile}) :open ...)
|
34
|
+
PATTERN
|
25
35
|
|
26
36
|
def on_send(node)
|
27
|
-
|
28
|
-
next if node.method_name != target_method
|
37
|
+
return if !file_open_method?(node) || cleanup?(node)
|
29
38
|
|
30
|
-
|
31
|
-
next if node.receiver != target_receiver
|
39
|
+
current = node.receiver.source_range.begin.join(node.selector.end).source
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
add_offense(node, message: format(MSG, class: target_class, method: target_method))
|
36
|
-
end
|
41
|
+
add_offense(node, message: format(MSG, current: current))
|
37
42
|
end
|
38
43
|
|
39
44
|
private
|
40
45
|
|
41
46
|
def cleanup?(node)
|
42
|
-
|
43
|
-
|
47
|
+
return true if node.block_argument?
|
48
|
+
return false unless (parent = node.parent)
|
49
|
+
|
50
|
+
parent.block_type? || !parent.lvasgn_type?
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
def on_class(class_node)
|
34
34
|
@macros_to_rewrite[class_node] = Set.new
|
35
35
|
|
36
|
-
find_macros(class_node.body).
|
36
|
+
find_macros(class_node.body).each_value do |macros|
|
37
37
|
bisected = find_bisection(macros)
|
38
38
|
next unless bisected.any?
|
39
39
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
def find_macros(class_def)
|
75
75
|
# Find all the macros (`attr_reader`, `attr_writer`, etc.) in the class body
|
76
76
|
# and turn them into `Macro` objects so that they can be processed.
|
77
|
-
return
|
77
|
+
return {} if !class_def || class_def.def_type?
|
78
78
|
|
79
79
|
send_nodes =
|
80
80
|
if class_def.send_type?
|
@@ -125,7 +125,7 @@ module RuboCop
|
|
125
125
|
when :==, :eql?, :equal?
|
126
126
|
find_target_in_equality_node(node)
|
127
127
|
when :===
|
128
|
-
node.
|
128
|
+
node.first_argument
|
129
129
|
when :include?, :cover?
|
130
130
|
find_target_in_include_or_cover_node(node)
|
131
131
|
when :match, :match?, :=~
|
@@ -134,7 +134,7 @@ module RuboCop
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def find_target_in_equality_node(node)
|
137
|
-
argument = node.
|
137
|
+
argument = node.first_argument
|
138
138
|
receiver = node.receiver
|
139
139
|
return unless argument && receiver
|
140
140
|
|
@@ -152,7 +152,7 @@ module RuboCop
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def find_target_in_match_node(node)
|
155
|
-
argument = node.
|
155
|
+
argument = node.first_argument
|
156
156
|
receiver = node.receiver
|
157
157
|
return unless receiver
|
158
158
|
|
@@ -185,7 +185,7 @@ module RuboCop
|
|
185
185
|
def condition_from_send_node(node, target)
|
186
186
|
case node.method_name
|
187
187
|
when :is_a?
|
188
|
-
node.
|
188
|
+
node.first_argument if node.receiver == target
|
189
189
|
when :==, :eql?, :equal?
|
190
190
|
condition_from_equality_node(node, target)
|
191
191
|
when :=~, :match, :match?
|
@@ -230,7 +230,7 @@ module RuboCop
|
|
230
230
|
|
231
231
|
def branch_conditions(node)
|
232
232
|
conditions = []
|
233
|
-
while node&.if_type?
|
233
|
+
while node&.if_type? && !node.ternary?
|
234
234
|
conditions << node.condition
|
235
235
|
node = node.else_branch
|
236
236
|
end
|
@@ -54,9 +54,9 @@ module RuboCop
|
|
54
54
|
end
|
55
55
|
|
56
56
|
def on_send(node)
|
57
|
-
|
58
|
-
|
59
|
-
)
|
57
|
+
return unless (first_argument = node.first_argument)
|
58
|
+
|
59
|
+
add_offense(first_argument, message: format(MSG, class_var: first_argument.source))
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -23,6 +23,8 @@ module RuboCop
|
|
23
23
|
# array.reject { |e| e.nil? }
|
24
24
|
# array.delete_if { |e| e.nil? }
|
25
25
|
# array.select { |e| !e.nil? }
|
26
|
+
# array.grep_v(nil)
|
27
|
+
# array.grep_v(NilClass)
|
26
28
|
#
|
27
29
|
# # good
|
28
30
|
# array.compact
|
@@ -46,14 +48,14 @@ module RuboCop
|
|
46
48
|
extend TargetRubyVersion
|
47
49
|
|
48
50
|
MSG = 'Use `%<good>s` instead of `%<bad>s`.'
|
49
|
-
RESTRICT_ON_SEND = %i[reject delete_if reject! select select!].freeze
|
51
|
+
RESTRICT_ON_SEND = %i[reject delete_if reject! select select! grep_v].freeze
|
50
52
|
TO_ENUM_METHODS = %i[to_enum lazy].freeze
|
51
53
|
|
52
54
|
minimum_target_ruby_version 2.4
|
53
55
|
|
54
56
|
# @!method reject_method_with_block_pass?(node)
|
55
57
|
def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
|
56
|
-
(
|
58
|
+
(call !nil? {:reject :delete_if :reject!}
|
57
59
|
(block_pass
|
58
60
|
(sym :nil?)))
|
59
61
|
PATTERN
|
@@ -61,24 +63,29 @@ module RuboCop
|
|
61
63
|
# @!method reject_method?(node)
|
62
64
|
def_node_matcher :reject_method?, <<~PATTERN
|
63
65
|
(block
|
64
|
-
(
|
66
|
+
(call
|
65
67
|
!nil? {:reject :delete_if :reject!})
|
66
68
|
$(args ...)
|
67
|
-
(
|
69
|
+
(call
|
68
70
|
$(lvar _) :nil?))
|
69
71
|
PATTERN
|
70
72
|
|
71
73
|
# @!method select_method?(node)
|
72
74
|
def_node_matcher :select_method?, <<~PATTERN
|
73
75
|
(block
|
74
|
-
(
|
76
|
+
(call
|
75
77
|
!nil? {:select :select!})
|
76
78
|
$(args ...)
|
77
|
-
(
|
78
|
-
(
|
79
|
+
(call
|
80
|
+
(call
|
79
81
|
$(lvar _) :nil?) :!))
|
80
82
|
PATTERN
|
81
83
|
|
84
|
+
# @!method grep_v_with_nil?(node)
|
85
|
+
def_node_matcher :grep_v_with_nil?, <<~PATTERN
|
86
|
+
(send _ :grep_v {(nil) (const {nil? cbase} :NilClass)})
|
87
|
+
PATTERN
|
88
|
+
|
82
89
|
def on_send(node)
|
83
90
|
return unless (range = offense_range(node))
|
84
91
|
return if allowed_receiver?(node.receiver)
|
@@ -91,11 +98,13 @@ module RuboCop
|
|
91
98
|
|
92
99
|
add_offense(range, message: message) { |corrector| corrector.replace(range, good) }
|
93
100
|
end
|
101
|
+
alias on_csend on_send
|
94
102
|
|
95
103
|
private
|
96
104
|
|
105
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
97
106
|
def offense_range(node)
|
98
|
-
if reject_method_with_block_pass?(node)
|
107
|
+
if reject_method_with_block_pass?(node) || grep_v_with_nil?(node)
|
99
108
|
range(node, node)
|
100
109
|
else
|
101
110
|
block_node = node.parent
|
@@ -109,6 +118,7 @@ module RuboCop
|
|
109
118
|
range(node, block_node)
|
110
119
|
end
|
111
120
|
end
|
121
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
112
122
|
|
113
123
|
def to_enum_method?(node)
|
114
124
|
return false unless node.receiver.send_type?
|
@@ -59,8 +59,6 @@ module RuboCop
|
|
59
59
|
class CombinableLoops < Base
|
60
60
|
extend AutoCorrector
|
61
61
|
|
62
|
-
include RangeHelp
|
63
|
-
|
64
62
|
MSG = 'Combine this loop with the previous loop.'
|
65
63
|
|
66
64
|
def on_block(node)
|
@@ -105,11 +103,19 @@ module RuboCop
|
|
105
103
|
end
|
106
104
|
|
107
105
|
def combine_with_left_sibling(corrector, node)
|
108
|
-
corrector.
|
109
|
-
|
110
|
-
|
111
|
-
)
|
112
|
-
|
106
|
+
corrector.remove(node.left_sibling.body.source_range.end.join(node.left_sibling.loc.end))
|
107
|
+
corrector.remove(node.source_range.begin.join(node.body.source_range.begin))
|
108
|
+
|
109
|
+
correct_end_of_block(corrector, node)
|
110
|
+
end
|
111
|
+
|
112
|
+
def correct_end_of_block(corrector, node)
|
113
|
+
return unless node.left_sibling.respond_to?(:braces?)
|
114
|
+
return if node.right_sibling&.block_type? || node.right_sibling&.numblock_type?
|
115
|
+
|
116
|
+
end_of_block = node.left_sibling.braces? ? '}' : ' end'
|
117
|
+
corrector.remove(node.loc.end)
|
118
|
+
corrector.insert_before(node.source_range.end, end_of_block)
|
113
119
|
end
|
114
120
|
end
|
115
121
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative '../../directive_comment'
|
4
|
+
|
3
5
|
module RuboCop
|
4
6
|
module Cop
|
5
7
|
module Style
|
@@ -49,8 +51,9 @@ module RuboCop
|
|
49
51
|
KEYWORDS = %w[begin class def end module].freeze
|
50
52
|
KEYWORD_REGEXES = KEYWORDS.map { |w| /^\s*#{w}\s/ }.freeze
|
51
53
|
|
52
|
-
ALLOWED_COMMENTS = %w[:nodoc: :yields:
|
53
|
-
ALLOWED_COMMENT_REGEXES = ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ }
|
54
|
+
ALLOWED_COMMENTS = %w[:nodoc: :yields:].freeze
|
55
|
+
ALLOWED_COMMENT_REGEXES = (ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ } +
|
56
|
+
[DirectiveComment::DIRECTIVE_COMMENT_REGEXP]).freeze
|
54
57
|
|
55
58
|
REGEXP = /(?<keyword>\S+).*#/.freeze
|
56
59
|
|
@@ -115,8 +115,8 @@ module RuboCop
|
|
115
115
|
end
|
116
116
|
|
117
117
|
# Check for `if` and `case` statements where each branch is used for
|
118
|
-
#
|
119
|
-
# condition can be used instead.
|
118
|
+
# both the assignment and comparison of the same variable
|
119
|
+
# when using the return of the condition can be used instead.
|
120
120
|
#
|
121
121
|
# @example EnforcedStyle: assign_to_condition (default)
|
122
122
|
# # bad
|
@@ -233,7 +233,7 @@ module RuboCop
|
|
233
233
|
PATTERN
|
234
234
|
|
235
235
|
ASSIGNMENT_TYPES.each do |type|
|
236
|
-
define_method "on_#{type}" do |node|
|
236
|
+
define_method :"on_#{type}" do |node|
|
237
237
|
return if part_of_ignored_node?(node)
|
238
238
|
return if node.parent&.shorthand_asgn?
|
239
239
|
|
@@ -460,9 +460,8 @@ module RuboCop
|
|
460
460
|
|
461
461
|
def assignment(node)
|
462
462
|
*_, condition = *node
|
463
|
-
|
464
|
-
|
465
|
-
condition.source_range.begin_pos)
|
463
|
+
|
464
|
+
node.source_range.begin.join(condition.source_range.begin)
|
466
465
|
end
|
467
466
|
|
468
467
|
def correct_if_branches(corrector, cop, node)
|
@@ -534,7 +533,7 @@ module RuboCop
|
|
534
533
|
end
|
535
534
|
|
536
535
|
def element_assignment?(node)
|
537
|
-
node.send_type? && node.
|
536
|
+
node.send_type? && !node.method?(:[]=)
|
538
537
|
end
|
539
538
|
|
540
539
|
def extract_branches(node)
|