rubocop 1.71.0 → 1.71.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  3. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  4. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  5. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  6. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  7. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  8. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  9. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +1 -0
  10. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  11. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  12. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  13. data/lib/rubocop/cop/layout/class_structure.rb +2 -2
  14. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  15. data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
  16. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -11
  17. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  18. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  19. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  20. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
  21. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  22. data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -5
  23. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  24. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  25. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  26. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  27. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  28. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  29. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  30. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  31. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  32. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  33. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  34. data/lib/rubocop/cop/lint/constant_reassignment.rb +2 -6
  35. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  36. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  37. data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
  38. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  39. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  40. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  41. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  42. data/lib/rubocop/cop/lint/nested_method_definition.rb +3 -3
  43. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  44. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  45. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -1
  46. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  47. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  48. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
  49. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  50. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  51. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  52. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -1
  53. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  54. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  55. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  56. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  57. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  58. data/lib/rubocop/cop/lint/void.rb +2 -7
  59. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  60. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  61. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -5
  62. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  63. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -4
  64. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -1
  65. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  66. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +22 -8
  67. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  68. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  69. data/lib/rubocop/cop/naming/block_forwarding.rb +18 -14
  70. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  71. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -4
  72. data/lib/rubocop/cop/style/arguments_forwarding.rb +38 -19
  73. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  74. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  75. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  76. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  77. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  78. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -3
  79. data/lib/rubocop/cop/style/documentation.rb +1 -1
  80. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  81. data/lib/rubocop/cop/style/each_with_object.rb +2 -3
  82. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  83. data/lib/rubocop/cop/style/explicit_block_argument.rb +15 -2
  84. data/lib/rubocop/cop/style/hash_each_methods.rb +2 -5
  85. data/lib/rubocop/cop/style/hash_except.rb +15 -0
  86. data/lib/rubocop/cop/style/hash_slice.rb +15 -0
  87. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  88. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  89. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  90. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  91. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  92. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  93. data/lib/rubocop/cop/style/inverse_methods.rb +6 -6
  94. data/lib/rubocop/cop/style/it_assignment.rb +1 -1
  95. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  96. data/lib/rubocop/cop/style/map_into_array.rb +1 -1
  97. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  98. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  99. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +10 -13
  100. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  101. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  102. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  103. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  104. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  105. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  106. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  107. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  108. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  109. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  110. data/lib/rubocop/cop/style/proc.rb +1 -2
  111. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  112. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  113. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  114. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  115. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  116. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  117. data/lib/rubocop/cop/style/redundant_parentheses.rb +6 -6
  118. data/lib/rubocop/cop/style/redundant_self_assignment.rb +12 -27
  119. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  120. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  121. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  122. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  123. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  124. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  125. data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -1
  126. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  127. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  128. data/lib/rubocop/cop/style/super_arguments.rb +4 -4
  129. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  130. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  131. data/lib/rubocop/cop/style/while_until_modifier.rb +0 -1
  132. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  133. data/lib/rubocop/cop/util.rb +2 -2
  134. data/lib/rubocop/cop/variable_force/variable.rb +14 -2
  135. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  136. data/lib/rubocop/rspec/support.rb +1 -2
  137. data/lib/rubocop/version.rb +1 -1
  138. metadata +9 -6
  139. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -103,7 +103,7 @@ module RuboCop
103
103
  expressions.pop unless in_void_context?(node)
104
104
  expressions.each do |expr|
105
105
  check_void_op(expr) do
106
- block_node = node.each_ancestor(:block).first
106
+ block_node = node.each_ancestor(:any_block).first
107
107
 
108
108
  block_node&.method?(:each)
109
109
  end
@@ -179,7 +179,7 @@ module RuboCop
179
179
  end
180
180
 
181
181
  def check_nonmutating(node)
182
- return if !node.send_type? && !node.block_type? && !node.numblock_type?
182
+ return unless node.type?(:send, :any_block)
183
183
 
184
184
  method_name = node.method_name
185
185
  return unless NONMUTATING_METHODS.include?(method_name)
@@ -201,11 +201,6 @@ module RuboCop
201
201
  # NOTE: the `begin` node case is already handled via `on_begin`
202
202
  return if body.begin_type?
203
203
 
204
- check_void_op(body) do
205
- block_node = node.each_ancestor(:block).first
206
- block_node&.method?(:each)
207
- end
208
-
209
204
  check_expression(body)
210
205
  end
211
206
 
@@ -52,7 +52,7 @@ module RuboCop
52
52
  def consider_node?(node)
53
53
  return true if NESTING_BLOCKS.include?(node.type)
54
54
 
55
- count_blocks? && (node.block_type? || node.numblock_type?)
55
+ count_blocks? && node.any_block_type?
56
56
  end
57
57
 
58
58
  def message(max)
@@ -50,7 +50,7 @@ module RuboCop
50
50
 
51
51
  # @!method module_definition?(node)
52
52
  def_node_matcher :module_definition?, <<~PATTERN
53
- (casgn nil? _ ({block numblock} (send (const {nil? cbase} :Module) :new) ...))
53
+ (casgn nil? _ (any_block (send (const {nil? cbase} :Module) :new) ...))
54
54
  PATTERN
55
55
 
56
56
  def message(length, max_length)
@@ -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.array_type? || node.hash_type?
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.call_type? || node.array_type?
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.hash_type? || ancestor.array_type?
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 (ancestor.hash_type? || ancestor.array_type?) &&
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 (node.str_type? || node.dstr_type? || node.xstr_type?) && node.heredoc?
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.block_type? || node.numblock_type?
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.send_type? || hash_value.lvar_type?
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(:send, :csend, :super, :yield).first
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.call_type? || ancestor.super_type? || ancestor.yield_type?
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.call_type? || parent.super_type? || parent.yield_type?
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.sym_type? || except_key.str_type?
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
@@ -35,7 +35,7 @@ module RuboCop
35
35
 
36
36
  # @!method define_method?(node)
37
37
  def_node_matcher :define_method?, <<~PATTERN
38
- ({block numblock}
38
+ (any_block
39
39
  (send nil? :define_method ({sym str} $_)) _ _)
40
40
  PATTERN
41
41
 
@@ -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
- # we don't want to operate on equals signs which are part of an
160
- # optarg in a method definition
161
- # e.g.: def method(optarg = default_val); end
162
- tokens = remove_optarg_equals(tokens, processed_source)
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 remove_optarg_equals(asgn_tokens, processed_source)
199
- optargs = processed_source.ast.each_node(:optarg)
200
- optarg_eql = optargs.to_set { |o| o.loc.operator.begin_pos }
201
- asgn_tokens.reject { |t| optarg_eql.include?(t.begin_pos) }
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.dstr_type? || a.dsym_type? || a.regexp_type? }
36
+ .any? { |a| a.type?(:dstr, :dsym, :regexp) }
37
37
  end
38
38
  end
39
39
  end
@@ -181,7 +181,7 @@ module RuboCop
181
181
  # ...
182
182
  # SOURCE
183
183
  # })
184
- return heredoc?(node.children.last) if node.pair_type? || node.hash_type?
184
+ return heredoc?(node.children.last) if node.type?(:pair, :hash)
185
185
 
186
186
  false
187
187
  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
- # Prevents the following syntax error:
94
- #
95
- # # foo.rb
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(:block, :numblock).any?
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/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
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.masgn_type? || child_node.lvasgn_type?
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/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
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
- ALLOWED_NODE_TYPES.include?(node.parent&.type) ||
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(:block, :class, :module).first)
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(:send, :csend, :super, :yield).to_a
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
- # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
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 if send_inside_block?(send_classifications)
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 outside_block?(forward_rest)
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 outside_block?(forward_kwrest)
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
- # Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
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
- def outside_block?(node)
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(:block, :numblock).none?
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.kwarg_type? || a.kwoptarg_type? }
533
+ @def_node.arguments.any? { |a| a.type?(:kwarg, :kwoptarg) }
515
534
  end
516
535
 
517
536
  def forward_additional_kwargs?
@@ -481,7 +481,7 @@ module RuboCop
481
481
  end
482
482
 
483
483
  def array_or_range?(node)
484
- node.array_type? || node.range_type?
484
+ node.type?(:array, :range)
485
485
  end
486
486
 
487
487
  def begin_required?(block_node)
@@ -161,7 +161,7 @@ module RuboCop
161
161
 
162
162
  def check_compact_style(node, body)
163
163
  parent = node.parent
164
- return if parent&.class_type? || parent&.module_type?
164
+ return if parent&.type?(:class, :module)
165
165
 
166
166
  return unless needs_compacting?(body)
167
167
 
@@ -55,7 +55,7 @@ module RuboCop
55
55
  def defined_calls(nodes)
56
56
  nodes.filter_map do |defined_node|
57
57
  subject = defined_node.first_argument
58
- subject if subject.const_type? || subject.call_type?
58
+ subject if subject.type?(:const, :call)
59
59
  end
60
60
  end
61
61
 
@@ -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? || (!sibling.block_type? && !sibling.numblock_type?)
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&.block_type? || node.right_sibling&.numblock_type?
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.str_type? || child.sym_type? }
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
- !(parent.mlhs_type? || parent.resbody_type?)
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.case_type? || node.case_match_type?
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.case_type? || condition.case_match_type?
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.cbase_type? || node.self_type? || node.call_type? || node.variable?
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.pair_type? || last_child.hash_type? || last_child.parent.array_type?
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.def_type? || parent.defs_type?
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.pair_type? || parent.hash_type? || parent.array_type?
150
+ if parent.type?(:pair, :hash, :array)
151
151
  find_parent_not_enumerable(parent)
152
152
  else
153
153
  parent
@@ -58,7 +58,7 @@ module RuboCop
58
58
 
59
59
  # @!method each_with_object_block_candidate?(node)
60
60
  def_node_matcher :each_with_object_block_candidate?, <<~PATTERN
61
- (block $(call _ {:inject :reduce} _) $_ $_)
61
+ (block $(call _ {:inject :reduce} _) $(args _ _) $_)
62
62
  PATTERN
63
63
 
64
64
  # @!method each_with_object_numblock_candidate?(node)
@@ -71,8 +71,7 @@ module RuboCop
71
71
 
72
72
  first_arg, second_arg = *node.arguments
73
73
 
74
- corrector.replace(first_arg, second_arg.source)
75
- corrector.replace(second_arg, first_arg.source)
74
+ corrector.swap(first_arg, second_arg)
76
75
 
77
76
  if return_value_occupies_whole_line?(return_value)
78
77
  corrector.remove(whole_line_expression(return_value))
@@ -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 && (code.str_type? || code.dstr_type?)
89
+ return unless code&.type?(:str, :dstr)
90
90
 
91
91
  check_location(node, code)
92
92
  end