rubocop 1.71.0 → 1.71.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
- data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +1 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -2
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -5
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -5
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
- data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
- data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +2 -6
- data/lib/rubocop/cop/lint/debugger.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +2 -2
- data/lib/rubocop/cop/lint/nested_method_definition.rb +3 -3
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
- data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +1 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
- data/lib/rubocop/cop/metrics/module_length.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -5
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -4
- data/lib/rubocop/cop/mixin/hash_subset.rb +19 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +22 -8
- data/lib/rubocop/cop/mixin/string_help.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +18 -14
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -4
- data/lib/rubocop/cop/style/arguments_forwarding.rb +38 -19
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
- data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
- data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -3
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +3 -3
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +2 -5
- data/lib/rubocop/cop/style/hash_except.rb +15 -0
- data/lib/rubocop/cop/style/hash_slice.rb +15 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +6 -6
- data/lib/rubocop/cop/style/it_assignment.rb +1 -1
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +1 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
- data/lib/rubocop/cop/style/map_to_set.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +10 -13
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/proc.rb +1 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
- data/lib/rubocop/cop/style/redundant_each.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +6 -6
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +12 -27
- data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
- data/lib/rubocop/cop/style/return_nil.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/string_literals.rb +1 -1
- data/lib/rubocop/cop/style/super_arguments.rb +4 -4
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
- data/lib/rubocop/cop/util.rb +2 -2
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
- data/lib/rubocop/rspec/support.rb +1 -2
- data/lib/rubocop/version.rb +1 -1
- metadata +9 -6
- data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -50,7 +50,7 @@ module RuboCop
|
|
50
50
|
return extract_breakable_node_from_elements(node, args, max)
|
51
51
|
elsif node.def_type?
|
52
52
|
return extract_breakable_node_from_elements(node, node.arguments, max)
|
53
|
-
elsif node.
|
53
|
+
elsif node.type?(:array, :hash)
|
54
54
|
return extract_breakable_node_from_elements(node, node.children, max)
|
55
55
|
end
|
56
56
|
nil
|
@@ -101,7 +101,7 @@ module RuboCop
|
|
101
101
|
# If a `send` or `csend` node contains a heredoc argument, splitting cannot happen
|
102
102
|
# after the heredoc or else it will cause a syntax error.
|
103
103
|
def shift_elements_for_heredoc_arg(node, elements, index)
|
104
|
-
return index unless node.
|
104
|
+
return index unless node.type?(:call, :array)
|
105
105
|
|
106
106
|
heredoc_index = elements.index { |arg| arg.respond_to?(:heredoc?) && arg.heredoc? }
|
107
107
|
return index unless heredoc_index
|
@@ -154,7 +154,7 @@ module RuboCop
|
|
154
154
|
# Ignore ancestors on different lines.
|
155
155
|
break if ancestor.first_line != node.first_line
|
156
156
|
|
157
|
-
if ancestor.
|
157
|
+
if ancestor.type?(:hash, :array)
|
158
158
|
elements = ancestor.children
|
159
159
|
elsif ancestor.call_type?
|
160
160
|
elements = process_args(ancestor.arguments)
|
@@ -171,7 +171,7 @@ module RuboCop
|
|
171
171
|
# @api private
|
172
172
|
def contained_by_multiline_collection_that_could_be_broken_up?(node)
|
173
173
|
node.each_ancestor.find do |ancestor|
|
174
|
-
if
|
174
|
+
if ancestor.type?(:hash, :array) &&
|
175
175
|
breakable_collection?(ancestor, ancestor.children)
|
176
176
|
return children_could_be_broken_up?(ancestor.children)
|
177
177
|
end
|
@@ -227,7 +227,7 @@ module RuboCop
|
|
227
227
|
|
228
228
|
def chained_to_heredoc?(node)
|
229
229
|
while (node = node.receiver)
|
230
|
-
return true if
|
230
|
+
return true if node.type?(:str, :dstr, :xstr) && node.heredoc?
|
231
231
|
end
|
232
232
|
|
233
233
|
false
|
@@ -76,7 +76,7 @@ module RuboCop
|
|
76
76
|
elsif node.if? && node.parent && parentheses?(node.parent)
|
77
77
|
node.parent.loc.end.line
|
78
78
|
end
|
79
|
-
elsif node.
|
79
|
+
elsif node.any_block_type?
|
80
80
|
node.loc.end.line
|
81
81
|
elsif (next_sibling = node.right_sibling) && next_sibling.is_a?(AST::Node) &&
|
82
82
|
next_sibling.source_range
|
@@ -86,7 +86,7 @@ module RuboCop
|
|
86
86
|
return true if !node.key.sym_type? || require_hash_value_for_around_hash_literal?(node)
|
87
87
|
|
88
88
|
hash_value = node.value
|
89
|
-
return true unless hash_value.
|
89
|
+
return true unless hash_value.type?(:send, :lvar)
|
90
90
|
|
91
91
|
hash_key_source != hash_value.source || hash_key_source.end_with?('!', '?')
|
92
92
|
end
|
@@ -109,7 +109,7 @@ module RuboCop
|
|
109
109
|
return if dispatch_node.parent && parentheses?(dispatch_node.parent)
|
110
110
|
return if last_expression?(dispatch_node) && !method_dispatch_as_argument?(dispatch_node)
|
111
111
|
|
112
|
-
def_node = node.each_ancestor(:
|
112
|
+
def_node = node.each_ancestor(:call, :super, :yield).first
|
113
113
|
|
114
114
|
DefNode.new(def_node) unless def_node && def_node.arguments.empty?
|
115
115
|
end
|
@@ -117,7 +117,7 @@ module RuboCop
|
|
117
117
|
|
118
118
|
def find_ancestor_method_dispatch_node(node)
|
119
119
|
return unless (ancestor = node.parent.parent)
|
120
|
-
return unless ancestor.
|
120
|
+
return unless ancestor.type?(:call, :super, :yield)
|
121
121
|
return if brackets?(ancestor)
|
122
122
|
|
123
123
|
ancestor
|
@@ -150,7 +150,7 @@ module RuboCop
|
|
150
150
|
parent = method_dispatch_node.parent
|
151
151
|
return false unless parent
|
152
152
|
|
153
|
-
parent.
|
153
|
+
parent.type?(:call, :super, :yield)
|
154
154
|
end
|
155
155
|
|
156
156
|
def breakdown_value_types_of_hash(hash_node)
|
@@ -5,6 +5,7 @@ module RuboCop
|
|
5
5
|
# Common functionality for Style/HashExcept and Style/HashSlice cops.
|
6
6
|
# It registers an offense on methods with blocks that are equivalent
|
7
7
|
# to Hash#except or Hash#slice.
|
8
|
+
# rubocop:disable Metrics/ModuleLength
|
8
9
|
module HashSubset
|
9
10
|
include RangeHelp
|
10
11
|
extend NodePattern::Macros
|
@@ -67,7 +68,11 @@ module RuboCop
|
|
67
68
|
|
68
69
|
def extracts_hash_subset?(block)
|
69
70
|
block_with_first_arg_check?(block) do |key_arg, send_node, method|
|
71
|
+
# Only consider methods that have one argument
|
72
|
+
return false unless send_node.arguments.one?
|
73
|
+
|
70
74
|
return false unless supported_subset_method?(method)
|
75
|
+
return false if range_include?(send_node)
|
71
76
|
|
72
77
|
case method
|
73
78
|
when :include?, :exclude?
|
@@ -80,6 +85,18 @@ module RuboCop
|
|
80
85
|
end
|
81
86
|
end
|
82
87
|
|
88
|
+
def range_include?(send_node)
|
89
|
+
# When checking `include?`, `exclude?` and `in?` for offenses, if the receiver
|
90
|
+
# or first argument is a range, an offense should not be registered.
|
91
|
+
# ie. `(1..5).include?(k)` or `k.in?('a'..'z')`
|
92
|
+
|
93
|
+
return true if send_node.first_argument.range_type?
|
94
|
+
|
95
|
+
receiver = send_node.receiver
|
96
|
+
receiver = receiver.child_nodes.first while receiver.begin_type?
|
97
|
+
receiver.range_type?
|
98
|
+
end
|
99
|
+
|
83
100
|
def supported_subset_method?(method)
|
84
101
|
if active_support_extensions_enabled?
|
85
102
|
ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)
|
@@ -119,7 +136,7 @@ module RuboCop
|
|
119
136
|
body = block.body
|
120
137
|
|
121
138
|
if body.method?('==') || body.method?('!=')
|
122
|
-
except_key.
|
139
|
+
except_key.type?(:sym, :str)
|
123
140
|
else
|
124
141
|
true
|
125
142
|
end
|
@@ -166,5 +183,6 @@ module RuboCop
|
|
166
183
|
range_between(node.loc.selector.begin_pos, node.parent.loc.end.end_pos)
|
167
184
|
end
|
168
185
|
end
|
186
|
+
# rubocop:enable Metrics/ModuleLength
|
169
187
|
end
|
170
188
|
end
|
@@ -4,6 +4,7 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common functionality for checking whether an AST node/token is aligned
|
6
6
|
# with something on a preceding or following line
|
7
|
+
# rubocop:disable Metrics/ModuleLength
|
7
8
|
module PrecedingFollowingAlignment
|
8
9
|
# Tokens that end with an `=`, as well as `<<`, that can be aligned together:
|
9
10
|
# `=`, `==`, `===`, `!=`, `<=`, `>=`, `<<` and operator assignment (`+=`, etc).
|
@@ -156,10 +157,14 @@ module RuboCop
|
|
156
157
|
@assignment_tokens ||= begin
|
157
158
|
tokens = processed_source.tokens.select(&:equal_sign?)
|
158
159
|
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
|
160
|
+
# We don't want to operate on equals signs which are part of an `optarg` in a
|
161
|
+
# method definition, or the separator of an endless method definition.
|
162
|
+
# For example (the equals sign to ignore is highlighted with ^):
|
163
|
+
# def method(optarg = default_val); end
|
164
|
+
# ^
|
165
|
+
# def method = foo
|
166
|
+
# ^
|
167
|
+
tokens = remove_equals_in_def(tokens, processed_source)
|
163
168
|
|
164
169
|
# Only attempt to align the first = on each line
|
165
170
|
Set.new(tokens.uniq(&:line))
|
@@ -195,11 +200,20 @@ module RuboCop
|
|
195
200
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
196
201
|
# rubocop:enable Metrics/PerceivedComplexity, Metrics/MethodLength
|
197
202
|
|
198
|
-
def
|
199
|
-
|
200
|
-
|
201
|
-
|
203
|
+
def remove_equals_in_def(asgn_tokens, processed_source)
|
204
|
+
nodes = processed_source.ast.each_node(:optarg, :def)
|
205
|
+
eqls_to_ignore = nodes.with_object([]) do |node, arr|
|
206
|
+
loc = if node.def_type?
|
207
|
+
node.loc.assignment if node.endless?
|
208
|
+
else
|
209
|
+
node.loc.operator
|
210
|
+
end
|
211
|
+
arr << loc.begin_pos if loc
|
212
|
+
end
|
213
|
+
|
214
|
+
asgn_tokens.reject { |t| eqls_to_ignore.include?(t.begin_pos) }
|
202
215
|
end
|
203
216
|
end
|
217
|
+
# rubocop:enable Metrics/ModuleLength
|
204
218
|
end
|
205
219
|
end
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
# A :begin node inside a :dstr, :dsym, or :regexp node is an interpolation.
|
34
34
|
node.ancestors
|
35
35
|
.drop_while { |a| !a.begin_type? }
|
36
|
-
.any? { |a| a.
|
36
|
+
.any? { |a| a.type?(:dstr, :dsym, :regexp) }
|
37
37
|
end
|
38
38
|
end
|
39
39
|
end
|
@@ -13,6 +13,20 @@ module RuboCop
|
|
13
13
|
# The default variable name is `block`. If the name is already in use, it will not be
|
14
14
|
# autocorrected.
|
15
15
|
#
|
16
|
+
# [NOTE]
|
17
|
+
# --
|
18
|
+
# Because of a bug in Ruby 3.3.0, when a block is referenced inside of another block,
|
19
|
+
# no offense will be registered until Ruby 3.4:
|
20
|
+
|
21
|
+
# [source,ruby]
|
22
|
+
# ----
|
23
|
+
# def foo(&block)
|
24
|
+
# # Using an anonymous block would be a syntax error on Ruby 3.3.0
|
25
|
+
# block_method { bar(&block) }
|
26
|
+
# end
|
27
|
+
# ----
|
28
|
+
# --
|
29
|
+
#
|
16
30
|
# @example EnforcedStyle: anonymous (default)
|
17
31
|
#
|
18
32
|
# # bad
|
@@ -90,21 +104,11 @@ module RuboCop
|
|
90
104
|
last_argument.source == block_pass_node.source
|
91
105
|
end
|
92
106
|
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
# def foo(&)
|
97
|
-
# block_method do
|
98
|
-
# bar(&)
|
99
|
-
# end
|
100
|
-
# end
|
101
|
-
#
|
102
|
-
# $ ruby -vc foo.rb
|
103
|
-
# ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin22]
|
104
|
-
# foo.rb: foo.rb:4: anonymous block parameter is also used within block (SyntaxError)
|
105
|
-
#
|
107
|
+
# Ruby 3.3.0 had a bug where accessing an anonymous block argument inside of a block
|
108
|
+
# was a syntax error in unambiguous cases: https://bugs.ruby-lang.org/issues/20090
|
109
|
+
# We disallow this also for earlier Ruby versions so that code is forwards compatible.
|
106
110
|
def invalidates_syntax?(block_pass_node)
|
107
|
-
block_pass_node.each_ancestor(:
|
111
|
+
target_ruby_version <= 3.3 && block_pass_node.each_ancestor(:any_block).any?
|
108
112
|
end
|
109
113
|
|
110
114
|
def use_kwarg_in_method_definition?(node)
|
@@ -113,7 +113,7 @@ module RuboCop
|
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
|
-
# rubocop:disable Metrics/
|
116
|
+
# rubocop:disable Metrics/MethodLength
|
117
117
|
def correct_node(corrector, node, offending_name, preferred_name)
|
118
118
|
return unless node
|
119
119
|
|
@@ -129,13 +129,13 @@ module RuboCop
|
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
132
|
-
if child_node.
|
132
|
+
if child_node.type?(:masgn, :lvasgn)
|
133
133
|
correct_reassignment(corrector, child_node, offending_name, preferred_name)
|
134
134
|
break
|
135
135
|
end
|
136
136
|
end
|
137
137
|
end
|
138
|
-
# rubocop:enable Metrics/
|
138
|
+
# rubocop:enable Metrics/MethodLength
|
139
139
|
|
140
140
|
# If the exception variable is reassigned, that assignment needs to be corrected.
|
141
141
|
# Further `lvar` nodes will not be corrected though since they now refer to a
|
@@ -150,8 +150,6 @@ module RuboCop
|
|
150
150
|
|
151
151
|
RESTRICT_ON_SEND = %i[private protected public module_function].freeze
|
152
152
|
|
153
|
-
ALLOWED_NODE_TYPES = %i[pair block].freeze
|
154
|
-
|
155
153
|
# @!method access_modifier_with_symbol?(node)
|
156
154
|
def_node_matcher :access_modifier_with_symbol?, <<~PATTERN
|
157
155
|
(send nil? {:private :protected :public :module_function}
|
@@ -188,7 +186,7 @@ module RuboCop
|
|
188
186
|
|
189
187
|
def allowed?(node)
|
190
188
|
!node.access_modifier? ||
|
191
|
-
|
189
|
+
node.parent&.type?(:pair, :any_block) ||
|
192
190
|
allow_modifiers_on_symbols?(node) ||
|
193
191
|
allow_modifiers_on_attrs?(node) ||
|
194
192
|
allow_modifiers_on_alias_method?(node)
|
@@ -312,7 +310,7 @@ module RuboCop
|
|
312
310
|
argument_less_modifier_node = find_argument_less_modifier_node(node)
|
313
311
|
if argument_less_modifier_node
|
314
312
|
corrector.insert_after(argument_less_modifier_node, "\n\n#{source}")
|
315
|
-
elsif (ancestor = node.each_ancestor(:
|
313
|
+
elsif (ancestor = node.each_ancestor(:class, :module).first)
|
316
314
|
|
317
315
|
corrector.insert_before(ancestor.loc.end, "#{node.method_name}\n\n#{source}\n")
|
318
316
|
else
|
@@ -31,6 +31,20 @@ module RuboCop
|
|
31
31
|
#
|
32
32
|
# This cop handles not only method forwarding but also forwarding to `super`.
|
33
33
|
#
|
34
|
+
# [NOTE]
|
35
|
+
# --
|
36
|
+
# Because of a bug in Ruby 3.3.0, when a block is referenced inside of another block,
|
37
|
+
# no offense will be registered until Ruby 3.4:
|
38
|
+
|
39
|
+
# [source,ruby]
|
40
|
+
# ----
|
41
|
+
# def foo(&block)
|
42
|
+
# # Using an anonymous block would be a syntax error on Ruby 3.3.0
|
43
|
+
# block_method { bar(&block) }
|
44
|
+
# end
|
45
|
+
# ----
|
46
|
+
# --
|
47
|
+
#
|
34
48
|
# @example
|
35
49
|
# # bad
|
36
50
|
# def foo(*args, &block)
|
@@ -148,7 +162,7 @@ module RuboCop
|
|
148
162
|
|
149
163
|
restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
|
150
164
|
forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
151
|
-
send_nodes = node.each_descendant(:
|
165
|
+
send_nodes = node.each_descendant(:call, :super, :yield).to_a
|
152
166
|
|
153
167
|
send_classifications = classify_send_nodes(
|
154
168
|
node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
|
@@ -191,9 +205,7 @@ module RuboCop
|
|
191
205
|
|
192
206
|
send_classifications.each do |send_node, c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
193
207
|
if !forward_rest && !forward_kwrest && c != :all_anonymous
|
194
|
-
|
195
|
-
# in Ruby 3.3.0.
|
196
|
-
if outside_block?(forward_block_arg)
|
208
|
+
if allow_anonymous_forwarding_in_block?(forward_block_arg)
|
197
209
|
register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
|
198
210
|
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
199
211
|
end
|
@@ -214,24 +226,22 @@ module RuboCop
|
|
214
226
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
215
227
|
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
216
228
|
return unless use_anonymous_forwarding?
|
217
|
-
return
|
229
|
+
return unless all_forwarding_offenses_correctable?(send_classifications)
|
218
230
|
|
219
231
|
rest_arg, kwrest_arg, block_arg = *forwardable_args
|
220
232
|
|
221
233
|
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
222
|
-
if
|
234
|
+
if allow_anonymous_forwarding_in_block?(forward_rest)
|
223
235
|
register_forward_args_offense(def_node.arguments, rest_arg)
|
224
236
|
register_forward_args_offense(send_node, forward_rest)
|
225
237
|
end
|
226
238
|
|
227
|
-
if
|
239
|
+
if allow_anonymous_forwarding_in_block?(forward_kwrest)
|
228
240
|
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
229
241
|
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
230
242
|
end
|
231
243
|
|
232
|
-
|
233
|
-
# in Ruby 3.3.0.
|
234
|
-
if outside_block?(forward_block_arg)
|
244
|
+
if allow_anonymous_forwarding_in_block?(forward_block_arg)
|
235
245
|
register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
|
236
246
|
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
237
247
|
end
|
@@ -293,10 +303,25 @@ module RuboCop
|
|
293
303
|
redundant_arg_names.include?(arg.source) ? arg : nil
|
294
304
|
end
|
295
305
|
|
296
|
-
|
306
|
+
# Checks if forwarding is uses both in blocks and outside of blocks.
|
307
|
+
# On Ruby 3.3.0, anonymous block forwarding in blocks can be is a syntax
|
308
|
+
# error, so we only want to register an offense if we can change all occurrences.
|
309
|
+
def all_forwarding_offenses_correctable?(send_classifications)
|
310
|
+
return true if target_ruby_version >= 3.4
|
311
|
+
|
312
|
+
send_classifications.none? do |send_node, *|
|
313
|
+
send_node.each_ancestor(:any_block).any?
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
# Ruby 3.3.0 had a bug where accessing an anonymous block argument inside of a block
|
318
|
+
# was a syntax error in unambiguous cases: https://bugs.ruby-lang.org/issues/20090
|
319
|
+
# We disallow this also for earlier Ruby versions so that code is forwards compatible.
|
320
|
+
def allow_anonymous_forwarding_in_block?(node)
|
297
321
|
return false unless node
|
322
|
+
return true if target_ruby_version >= 3.4
|
298
323
|
|
299
|
-
node.each_ancestor(:
|
324
|
+
node.each_ancestor(:any_block).none?
|
300
325
|
end
|
301
326
|
|
302
327
|
def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
|
@@ -357,12 +382,6 @@ module RuboCop
|
|
357
382
|
cop_config.fetch('UseAnonymousForwarding', false)
|
358
383
|
end
|
359
384
|
|
360
|
-
def send_inside_block?(send_classifications)
|
361
|
-
send_classifications.any? do |send_node, *|
|
362
|
-
send_node.each_ancestor(:block, :numblock).any?
|
363
|
-
end
|
364
|
-
end
|
365
|
-
|
366
385
|
def add_parens_if_missing(node, corrector)
|
367
386
|
return if parentheses?(node)
|
368
387
|
return if node.send_type? && node.method?(:[])
|
@@ -511,7 +530,7 @@ module RuboCop
|
|
511
530
|
end
|
512
531
|
|
513
532
|
def additional_kwargs?
|
514
|
-
@def_node.arguments.any? { |a| a.
|
533
|
+
@def_node.arguments.any? { |a| a.type?(:kwarg, :kwoptarg) }
|
515
534
|
end
|
516
535
|
|
517
536
|
def forward_additional_kwargs?
|
@@ -98,7 +98,7 @@ module RuboCop
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def same_collection_looping_block?(node, sibling)
|
101
|
-
return false if sibling.nil? ||
|
101
|
+
return false if sibling.nil? || !sibling.any_block_type?
|
102
102
|
|
103
103
|
sibling.method?(node.method_name) &&
|
104
104
|
sibling.receiver == node.receiver &&
|
@@ -118,7 +118,7 @@ module RuboCop
|
|
118
118
|
|
119
119
|
def correct_end_of_block(corrector, node)
|
120
120
|
return unless node.left_sibling.respond_to?(:braces?)
|
121
|
-
return if node.right_sibling&.
|
121
|
+
return if node.right_sibling&.any_block_type?
|
122
122
|
|
123
123
|
end_of_block = node.left_sibling.braces? ? '}' : ' end'
|
124
124
|
corrector.remove(node.loc.end)
|
@@ -86,7 +86,7 @@ module RuboCop
|
|
86
86
|
|
87
87
|
def percent_literals_includes_only_basic_literals?(node)
|
88
88
|
node.arguments.select(&:percent_literal?).all? do |arg|
|
89
|
-
arg.children.all? { |child| child.
|
89
|
+
arg.children.all? { |child| child.type?(:str, :sym) }
|
90
90
|
end
|
91
91
|
end
|
92
92
|
end
|
@@ -107,7 +107,7 @@ module RuboCop
|
|
107
107
|
parent = node.parent
|
108
108
|
return true unless parent
|
109
109
|
|
110
|
-
!
|
110
|
+
!parent.type?(:mlhs, :resbody)
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
@@ -326,7 +326,7 @@ module RuboCop
|
|
326
326
|
end
|
327
327
|
|
328
328
|
def move_assignment_outside_condition(corrector, node)
|
329
|
-
if node.
|
329
|
+
if node.type?(:case, :case_match)
|
330
330
|
CaseCorrector.correct(corrector, self, node)
|
331
331
|
elsif node.ternary?
|
332
332
|
TernaryCorrector.correct(corrector, node)
|
@@ -340,7 +340,7 @@ module RuboCop
|
|
340
340
|
|
341
341
|
if ternary_condition?(condition)
|
342
342
|
TernaryCorrector.move_assignment_inside_condition(corrector, node)
|
343
|
-
elsif condition.
|
343
|
+
elsif condition.type?(:case, :case_match)
|
344
344
|
CaseCorrector.move_assignment_inside_condition(corrector, node)
|
345
345
|
elsif condition.if_type?
|
346
346
|
IfCorrector.move_assignment_inside_condition(corrector, node)
|
@@ -186,7 +186,7 @@ module RuboCop
|
|
186
186
|
def qualify_const(node)
|
187
187
|
return if node.nil?
|
188
188
|
|
189
|
-
if node.
|
189
|
+
if node.type?(:cbase, :self, :call) || node.variable?
|
190
190
|
node.source
|
191
191
|
else
|
192
192
|
[qualify_const(node.namespace), node.short_name].compact
|
@@ -93,7 +93,7 @@ module RuboCop
|
|
93
93
|
|
94
94
|
if conditional_node
|
95
95
|
double_negative_condition_return_value?(node, last_child, conditional_node)
|
96
|
-
elsif last_child.
|
96
|
+
elsif last_child.type?(:pair, :hash) || last_child.parent.array_type?
|
97
97
|
false
|
98
98
|
else
|
99
99
|
last_child.last_line <= node.last_line
|
@@ -102,7 +102,7 @@ module RuboCop
|
|
102
102
|
|
103
103
|
def find_def_node_from_ascendant(node)
|
104
104
|
return unless (parent = node.parent)
|
105
|
-
return parent if parent.
|
105
|
+
return parent if parent.type?(:def, :defs)
|
106
106
|
return node.parent.child_nodes.first if define_method?(parent)
|
107
107
|
|
108
108
|
find_def_node_from_ascendant(node.parent)
|
@@ -147,7 +147,7 @@ module RuboCop
|
|
147
147
|
def find_parent_not_enumerable(node)
|
148
148
|
return unless (parent = node.parent)
|
149
149
|
|
150
|
-
if parent.
|
150
|
+
if parent.type?(:pair, :hash, :array)
|
151
151
|
find_parent_not_enumerable(parent)
|
152
152
|
else
|
153
153
|
parent
|
@@ -86,7 +86,7 @@ module RuboCop
|
|
86
86
|
return if node.method?(:eval) && !valid_eval_receiver?(node.receiver)
|
87
87
|
|
88
88
|
code = node.first_argument
|
89
|
-
return unless code
|
89
|
+
return unless code&.type?(:str, :dstr)
|
90
90
|
|
91
91
|
check_location(node, code)
|
92
92
|
end
|
@@ -44,7 +44,7 @@ module RuboCop
|
|
44
44
|
|
45
45
|
# @!method kv_each(node)
|
46
46
|
def_node_matcher :kv_each, <<~PATTERN
|
47
|
-
(
|
47
|
+
(any_block $(call (call _ ${:keys :values}) :each) ...)
|
48
48
|
PATTERN
|
49
49
|
|
50
50
|
# @!method each_arguments(node)
|
@@ -162,10 +162,7 @@ module RuboCop
|
|
162
162
|
|
163
163
|
def use_array_converter_method_as_preceding?(node)
|
164
164
|
return false unless (preceding_method = node.children.first.children.first)
|
165
|
-
unless preceding_method.
|
166
|
-
preceding_method.block_type? || preceding_method.numblock_type?
|
167
|
-
return false
|
168
|
-
end
|
165
|
+
return false unless preceding_method.type?(:call, :any_block)
|
169
166
|
|
170
167
|
ARRAY_CONVERTER_METHODS.include?(preceding_method.method_name)
|
171
168
|
end
|
@@ -32,6 +32,21 @@ module RuboCop
|
|
32
32
|
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].include?(k) }
|
33
33
|
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| !%i[bar].include?(k) }
|
34
34
|
#
|
35
|
+
# # good
|
36
|
+
# {foo: 1, bar: 2, baz: 3}.except(:bar)
|
37
|
+
#
|
38
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].exclude?(k) }
|
42
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| %i[bar].exclude?(k) }
|
43
|
+
#
|
44
|
+
# # good
|
45
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| k.in?(%i[bar]) }
|
46
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !k.in?(%i[bar]) }
|
47
|
+
#
|
48
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
49
|
+
#
|
35
50
|
# # bad
|
36
51
|
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].exclude?(k) }
|
37
52
|
# {foo: 1, bar: 2, baz: 3}.select {|k, v| %i[bar].exclude?(k) }
|
@@ -32,6 +32,21 @@ module RuboCop
|
|
32
32
|
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !%i[bar].include?(k) }
|
33
33
|
# {foo: 1, bar: 2, baz: 3}.filter {|k, v| %i[bar].include?(k) }
|
34
34
|
#
|
35
|
+
# # good
|
36
|
+
# {foo: 1, bar: 2, baz: 3}.slice(:bar)
|
37
|
+
#
|
38
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].exclude?(k) }
|
42
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[bar].exclude?(k) }
|
43
|
+
#
|
44
|
+
# # good
|
45
|
+
# {foo: 1, bar: 2, baz: 3}.select {|k, v| k.in?(%i[bar]) }
|
46
|
+
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| !k.in?(%i[bar]) }
|
47
|
+
#
|
48
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
49
|
+
#
|
35
50
|
# # bad
|
36
51
|
# {foo: 1, bar: 2, baz: 3}.select {|k, v| !%i[bar].exclude?(k) }
|
37
52
|
# {foo: 1, bar: 2, baz: 3}.reject {|k, v| %i[bar].exclude?(k) }
|