rubocop 1.71.0 → 1.71.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (134) 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/empty_line_between_defs.rb +7 -5
  16. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  17. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  18. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  19. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
  20. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  21. data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -5
  22. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  23. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  24. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  25. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  26. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  27. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  28. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  29. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  30. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  31. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  32. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  33. data/lib/rubocop/cop/lint/constant_reassignment.rb +2 -6
  34. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  35. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  36. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  37. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  38. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  39. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  40. data/lib/rubocop/cop/lint/nested_method_definition.rb +3 -3
  41. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  42. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  43. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -1
  44. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  45. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  46. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
  47. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  48. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  49. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  50. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  51. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  52. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  53. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  54. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  55. data/lib/rubocop/cop/lint/void.rb +1 -1
  56. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  57. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  58. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -5
  59. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  60. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -4
  61. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -1
  62. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  63. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +22 -8
  64. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  65. data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
  66. data/lib/rubocop/cop/naming/block_forwarding.rb +18 -14
  67. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  68. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -4
  69. data/lib/rubocop/cop/style/arguments_forwarding.rb +38 -19
  70. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  71. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  72. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  73. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  74. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  75. data/lib/rubocop/cop/style/conditional_assignment.rb +3 -3
  76. data/lib/rubocop/cop/style/documentation.rb +1 -1
  77. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  78. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  79. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  80. data/lib/rubocop/cop/style/hash_each_methods.rb +2 -5
  81. data/lib/rubocop/cop/style/hash_except.rb +15 -0
  82. data/lib/rubocop/cop/style/hash_slice.rb +15 -0
  83. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  84. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  85. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  86. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  87. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  88. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  89. data/lib/rubocop/cop/style/inverse_methods.rb +6 -6
  90. data/lib/rubocop/cop/style/it_assignment.rb +1 -1
  91. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  92. data/lib/rubocop/cop/style/map_into_array.rb +1 -1
  93. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  94. data/lib/rubocop/cop/style/map_to_set.rb +1 -1
  95. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +10 -13
  96. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  97. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  98. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  99. data/lib/rubocop/cop/style/mutable_constant.rb +1 -1
  100. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  101. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  102. data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
  103. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  104. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  105. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  106. data/lib/rubocop/cop/style/proc.rb +1 -2
  107. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  108. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  109. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  110. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  111. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  112. data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
  113. data/lib/rubocop/cop/style/redundant_parentheses.rb +6 -6
  114. data/lib/rubocop/cop/style/redundant_self_assignment.rb +12 -27
  115. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  116. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  117. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  118. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  119. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  120. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  121. data/lib/rubocop/cop/style/sole_nested_conditional.rb +1 -1
  122. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  123. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  124. data/lib/rubocop/cop/style/super_arguments.rb +4 -4
  125. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  126. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  127. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  128. data/lib/rubocop/cop/util.rb +2 -2
  129. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  130. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  131. data/lib/rubocop/rspec/support.rb +1 -2
  132. data/lib/rubocop/version.rb +1 -1
  133. metadata +9 -6
  134. 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.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
@@ -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
@@ -123,7 +123,7 @@ module RuboCop
123
123
  end
124
124
 
125
125
  def call_like?(node)
126
- node.call_type? || node.zsuper_type? || node.super_type?
126
+ node.type?(:call, :zsuper, :super)
127
127
  end
128
128
 
129
129
  def insert_argument(node, corrector, block_name)
@@ -44,7 +44,7 @@ module RuboCop
44
44
 
45
45
  # @!method kv_each(node)
46
46
  def_node_matcher :kv_each, <<~PATTERN
47
- ({block numblock} $(call (call _ ${:keys :values}) :each) ...)
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.call_type? ||
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) }