rubocop 1.70.0 → 1.71.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +17 -0
  4. data/lib/rubocop/cli/command/show_cops.rb +24 -2
  5. data/lib/rubocop/comment_config.rb +1 -1
  6. data/lib/rubocop/cop/autocorrect_logic.rb +1 -1
  7. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  8. data/lib/rubocop/cop/internal_affairs/location_expression.rb +2 -1
  9. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +3 -2
  10. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  11. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +63 -0
  12. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +131 -0
  13. data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +229 -0
  14. data/lib/rubocop/cop/internal_affairs/node_type_multiple_predicates.rb +126 -0
  15. data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +90 -0
  16. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +3 -1
  17. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  18. data/lib/rubocop/cop/internal_affairs.rb +3 -0
  19. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +1 -1
  20. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  21. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  22. data/lib/rubocop/cop/layout/class_structure.rb +9 -9
  23. data/lib/rubocop/cop/layout/dot_position.rb +1 -1
  24. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +7 -5
  25. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -1
  26. data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
  27. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  28. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  29. data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +1 -1
  30. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +2 -2
  31. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +1 -1
  32. data/lib/rubocop/cop/layout/multiline_hash_key_line_breaks.rb +1 -1
  33. data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +1 -0
  34. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -0
  35. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  36. data/lib/rubocop/cop/layout/redundant_line_break.rb +6 -5
  37. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  38. data/lib/rubocop/cop/layout/single_line_block_chain.rb +1 -1
  39. data/lib/rubocop/cop/layout/space_after_colon.rb +2 -2
  40. data/lib/rubocop/cop/layout/space_after_comma.rb +1 -1
  41. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  42. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -0
  43. data/lib/rubocop/cop/layout/space_before_comma.rb +1 -1
  44. data/lib/rubocop/cop/layout/space_before_semicolon.rb +1 -1
  45. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  46. data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +119 -0
  47. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -3
  48. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +1 -1
  49. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +3 -3
  50. data/lib/rubocop/cop/lint/constant_reassignment.rb +2 -6
  51. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  52. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +1 -1
  53. data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +1 -1
  54. data/lib/rubocop/cop/lint/duplicate_set_element.rb +1 -1
  55. data/lib/rubocop/cop/lint/float_comparison.rb +5 -2
  56. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
  57. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  58. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
  59. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +13 -3
  60. data/lib/rubocop/cop/lint/missing_super.rb +2 -2
  61. data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
  62. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -1
  63. data/lib/rubocop/cop/lint/nested_method_definition.rb +3 -3
  64. data/lib/rubocop/cop/lint/next_without_accumulator.rb +1 -1
  65. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +1 -1
  66. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +13 -18
  67. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -1
  68. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -5
  69. data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
  70. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +2 -2
  71. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  72. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +8 -1
  73. data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -3
  74. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  75. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  76. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +1 -1
  77. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  78. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  79. data/lib/rubocop/cop/lint/useless_access_modifier.rb +4 -4
  80. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  81. data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
  82. data/lib/rubocop/cop/lint/useless_numeric_operation.rb +2 -1
  83. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +2 -2
  84. data/lib/rubocop/cop/lint/void.rb +1 -1
  85. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  86. data/lib/rubocop/cop/metrics/collection_literal_length.rb +7 -0
  87. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  88. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  89. data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
  90. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -5
  91. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  92. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
  93. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +4 -4
  94. data/lib/rubocop/cop/mixin/hash_subset.rb +188 -0
  95. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  96. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +22 -8
  97. data/lib/rubocop/cop/mixin/statement_modifier.rb +7 -2
  98. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  99. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -3
  100. data/lib/rubocop/cop/naming/block_forwarding.rb +18 -14
  101. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -3
  102. data/lib/rubocop/cop/security/compound_hash.rb +1 -0
  103. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -4
  104. data/lib/rubocop/cop/style/arguments_forwarding.rb +38 -19
  105. data/lib/rubocop/cop/style/array_first_last.rb +18 -2
  106. data/lib/rubocop/cop/style/block_delimiters.rb +7 -20
  107. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  108. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  109. data/lib/rubocop/cop/style/combinable_defined.rb +1 -1
  110. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  111. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
  112. data/lib/rubocop/cop/style/conditional_assignment.rb +6 -4
  113. data/lib/rubocop/cop/style/documentation.rb +1 -1
  114. data/lib/rubocop/cop/style/double_negation.rb +3 -3
  115. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  116. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  117. data/lib/rubocop/cop/style/exact_regexp_match.rb +1 -1
  118. data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
  119. data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
  120. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
  121. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -6
  122. data/lib/rubocop/cop/style/hash_except.rb +20 -131
  123. data/lib/rubocop/cop/style/hash_slice.rb +80 -0
  124. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  125. data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
  126. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  127. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  128. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
  129. data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
  130. data/lib/rubocop/cop/style/inverse_methods.rb +6 -6
  131. data/lib/rubocop/cop/style/it_assignment.rb +1 -1
  132. data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -1
  133. data/lib/rubocop/cop/style/map_into_array.rb +1 -1
  134. data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
  135. data/lib/rubocop/cop/style/map_to_set.rb +3 -2
  136. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +10 -13
  137. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -1
  138. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -4
  139. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  140. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  141. data/lib/rubocop/cop/style/mutable_constant.rb +2 -2
  142. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -1
  143. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  144. data/lib/rubocop/cop/style/open_struct_use.rb +5 -5
  145. data/lib/rubocop/cop/style/parallel_assignment.rb +1 -5
  146. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  147. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  148. data/lib/rubocop/cop/style/proc.rb +1 -2
  149. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  150. data/lib/rubocop/cop/style/redundant_begin.rb +1 -1
  151. data/lib/rubocop/cop/style/redundant_condition.rb +2 -2
  152. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -10
  153. data/lib/rubocop/cop/style/redundant_each.rb +1 -1
  154. data/lib/rubocop/cop/style/redundant_exception.rb +2 -2
  155. data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
  156. data/lib/rubocop/cop/style/redundant_line_continuation.rb +27 -10
  157. data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -6
  158. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  159. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +1 -1
  160. data/lib/rubocop/cop/style/redundant_self_assignment.rb +12 -27
  161. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  162. data/lib/rubocop/cop/style/redundant_string_escape.rb +2 -2
  163. data/lib/rubocop/cop/style/return_nil.rb +1 -1
  164. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  165. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  166. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  167. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  168. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -2
  169. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  170. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  171. data/lib/rubocop/cop/style/string_methods.rb +1 -1
  172. data/lib/rubocop/cop/style/super_arguments.rb +4 -4
  173. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  174. data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -1
  175. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +4 -1
  176. data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
  177. data/lib/rubocop/cop/util.rb +2 -2
  178. data/lib/rubocop/cop/variable_force/variable.rb +1 -1
  179. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -3
  180. data/lib/rubocop/cops_documentation_generator.rb +13 -13
  181. data/lib/rubocop/directive_comment.rb +9 -8
  182. data/lib/rubocop/options.rb +2 -1
  183. data/lib/rubocop/result_cache.rb +13 -13
  184. data/lib/rubocop/rspec/expect_offense.rb +6 -2
  185. data/lib/rubocop/rspec/support.rb +1 -2
  186. data/lib/rubocop/target_finder.rb +1 -0
  187. data/lib/rubocop/version.rb +1 -1
  188. data/lib/rubocop.rb +3 -0
  189. metadata +15 -11
  190. data/lib/rubocop/rspec/host_environment_simulation_helper.rb +0 -28
@@ -117,7 +117,7 @@ module RuboCop
117
117
  end
118
118
 
119
119
  def instance_eval_block?(node)
120
- node.block_type? && node.method?(:instance_eval)
120
+ node.any_block_type? && node.method?(:instance_eval)
121
121
  end
122
122
 
123
123
  def report_on_flow_command?(node)
@@ -108,7 +108,7 @@ module RuboCop
108
108
  private
109
109
 
110
110
  def loop_method?(node)
111
- return false unless node.block_type? || node.numblock_type?
111
+ return false unless node.any_block_type?
112
112
 
113
113
  send_node = node.send_node
114
114
  loopable = send_node.enumerable_method? || send_node.enumerator_method? ||
@@ -159,12 +159,12 @@ module RuboCop
159
159
 
160
160
  # @!method dynamic_method_definition?(node)
161
161
  def_node_matcher :dynamic_method_definition?, <<~PATTERN
162
- {(send nil? :define_method ...) ({block numblock} (send nil? :define_method ...) ...)}
162
+ {(send nil? :define_method ...) (any_block (send nil? :define_method ...) ...)}
163
163
  PATTERN
164
164
 
165
165
  # @!method class_or_instance_eval?(node)
166
166
  def_node_matcher :class_or_instance_eval?, <<~PATTERN
167
- ({block numblock} (send _ {:class_eval :instance_eval}) ...)
167
+ (any_block (send _ {:class_eval :instance_eval}) ...)
168
168
  PATTERN
169
169
 
170
170
  def check_node(node)
@@ -268,7 +268,7 @@ module RuboCop
268
268
  end
269
269
 
270
270
  def start_of_new_scope?(child)
271
- child.module_type? || child.class_type? || child.sclass_type? || eval_call?(child)
271
+ child.type?(:module, :class, :sclass) || eval_call?(child)
272
272
  end
273
273
 
274
274
  def eval_call?(child)
@@ -282,7 +282,7 @@ module RuboCop
282
282
  matcher_name = :"#{m}_block?"
283
283
  unless respond_to?(matcher_name)
284
284
  self.class.def_node_matcher matcher_name, <<~PATTERN
285
- ({block numblock} (send {nil? const} {:#{m}} ...) ...)
285
+ (any_block (send {nil? const} {:#{m}} ...) ...)
286
286
  PATTERN
287
287
  end
288
288
 
@@ -17,7 +17,7 @@ module RuboCop
17
17
  # rescue, ensure, etc.
18
18
  #
19
19
  # This cop's autocorrection avoids cases like `a ||= 1` because removing assignment from
20
- # operator assignment can cause NameError if this assignment has been used to declare
20
+ # operator assignment can cause `NameError` if this assignment has been used to declare
21
21
  # a local variable. For example, replacing `a ||= 1` with `a || 1` may cause
22
22
  # "undefined local variable or method `a' for main:Object (NameError)".
23
23
  #
@@ -59,7 +59,7 @@ module RuboCop
59
59
  end
60
60
 
61
61
  def use_rest_or_optional_args?(node)
62
- node.arguments.any? { |arg| arg.restarg_type? || arg.optarg_type? || arg.kwoptarg_type? }
62
+ node.arguments.any? { |arg| arg.type?(:restarg, :optarg, :kwoptarg) }
63
63
  end
64
64
 
65
65
  def delegating?(node, def_node)
@@ -35,7 +35,7 @@ module RuboCop
35
35
  RESTRICT_ON_SEND = %i[+ - * / **].freeze
36
36
 
37
37
  # @!method useless_operation?(node)
38
- def_node_matcher :useless_operation?, '(send (send nil? $_) $_ (int $_))'
38
+ def_node_matcher :useless_operation?, '(call (call nil? $_) $_ (int $_))'
39
39
 
40
40
  # @!method useless_abbreviated_assignment?(node)
41
41
  def_node_matcher :useless_abbreviated_assignment?, '(op-asgn (lvasgn $_) $_ (int $_))'
@@ -50,6 +50,7 @@ module RuboCop
50
50
  corrector.replace(node, variable)
51
51
  end
52
52
  end
53
+ alias on_csend on_send
53
54
 
54
55
  def on_op_asgn(node)
55
56
  return unless useless_abbreviated_assignment?(node)
@@ -72,7 +72,7 @@ module RuboCop
72
72
  def_node_matcher :method_definition, <<~PATTERN
73
73
  {
74
74
  (def %1 ...)
75
- ({block numblock} (send _ :define_method (sym %1)) ...)
75
+ (any_block (send _ :define_method (sym %1)) ...)
76
76
  }
77
77
  PATTERN
78
78
 
@@ -108,7 +108,7 @@ module RuboCop
108
108
 
109
109
  def find_method_definition(node, method_name)
110
110
  node.each_ancestor.lazy.map do |ancestor|
111
- ancestor.each_child_node(:def, :block, :numblock).find do |child|
111
+ ancestor.each_child_node(:def, :any_block).find do |child|
112
112
  method_definition(child, method_name)
113
113
  end
114
114
  end.find(&:itself)
@@ -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)
@@ -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)
@@ -52,12 +52,19 @@ module RuboCop
52
52
  'Prefer reading the data from an external source.'
53
53
  RESTRICT_ON_SEND = [:[]].freeze
54
54
 
55
+ # @!method set_const?(node)
56
+ def_node_matcher :set_const?, <<~PATTERN
57
+ (const {cbase nil?} :Set)
58
+ PATTERN
59
+
55
60
  def on_array(node)
56
61
  add_offense(node) if node.children.length >= collection_threshold
57
62
  end
58
63
  alias on_hash on_array
59
64
 
60
65
  def on_index(node)
66
+ return unless set_const?(node.receiver)
67
+
61
68
  add_offense(node) if node.arguments.length >= collection_threshold
62
69
  end
63
70
 
@@ -36,7 +36,7 @@ module RuboCop
36
36
  include MethodComplexity
37
37
  include Utils::IteratingBlock
38
38
 
39
- MSG = 'Cyclomatic complexity for %<method>s is too high. [%<complexity>d/%<max>d]'
39
+ MSG = 'Cyclomatic complexity for `%<method>s` is too high. [%<complexity>d/%<max>d]'
40
40
  COUNTED_NODES = %i[if while until for csend block block_pass
41
41
  rescue when in_pattern and or or_asgn and_asgn].freeze
42
42
 
@@ -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)
@@ -27,7 +27,7 @@ module RuboCop
27
27
  # end # ===
28
28
  # end # 7 complexity points
29
29
  class PerceivedComplexity < CyclomaticComplexity
30
- MSG = 'Perceived complexity for %<method>s is too high. [%<complexity>d/%<max>d]'
30
+ MSG = 'Perceived complexity for `%<method>s` is too high. [%<complexity>d/%<max>d]'
31
31
 
32
32
  COUNTED_NODES = (CyclomaticComplexity::COUNTED_NODES - [:when] + [:case]).freeze
33
33
 
@@ -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
@@ -6,7 +6,7 @@ module RuboCop
6
6
  module FrozenStringLiteral
7
7
  module_function
8
8
 
9
- FROZEN_STRING_LITERAL = '# frozen_string_literal:'
9
+ FROZEN_STRING_LITERAL_REGEXP = /#\s*frozen[-_]?string[-_]?literal:/i.freeze
10
10
  FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
11
11
  FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
12
12
 
@@ -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)
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for Style/HashExcept and Style/HashSlice cops.
6
+ # It registers an offense on methods with blocks that are equivalent
7
+ # to Hash#except or Hash#slice.
8
+ # rubocop:disable Metrics/ModuleLength
9
+ module HashSubset
10
+ include RangeHelp
11
+ extend NodePattern::Macros
12
+
13
+ RESTRICT_ON_SEND = %i[reject select filter].freeze
14
+
15
+ SUBSET_METHODS = %i[== != eql? include?].freeze
16
+ ACTIVE_SUPPORT_SUBSET_METHODS = (SUBSET_METHODS + %i[in? exclude?]).freeze
17
+
18
+ MSG = 'Use `%<prefer>s` instead.'
19
+
20
+ # @!method block_with_first_arg_check?(node)
21
+ def_node_matcher :block_with_first_arg_check?, <<~PATTERN
22
+ (block
23
+ (call _ _)
24
+ (args
25
+ $(arg _key)
26
+ (arg _))
27
+ {
28
+ $(send
29
+ {(lvar _key) $_ _ | _ $_ (lvar _key)})
30
+ (send
31
+ $(send
32
+ {(lvar _key) $_ _ | _ $_ (lvar _key)}) :!)
33
+ })
34
+ PATTERN
35
+
36
+ def on_send(node)
37
+ offense_range, key_source = extract_offense(node)
38
+
39
+ return unless offense_range
40
+ return unless semantically_subset_method?(node)
41
+
42
+ preferred_method = "#{preferred_method_name}(#{key_source})"
43
+ add_offense(offense_range, message: format(MSG, prefer: preferred_method)) do |corrector|
44
+ corrector.replace(offense_range, preferred_method)
45
+ end
46
+ end
47
+ alias on_csend on_send
48
+
49
+ private
50
+
51
+ def semantically_subset_method?(node)
52
+ raise NotImplementedError
53
+ end
54
+
55
+ def preferred_method_name
56
+ raise NotImplementedError
57
+ end
58
+
59
+ def extract_offense(node)
60
+ block = node.parent
61
+ return unless extracts_hash_subset?(block)
62
+
63
+ except_key = except_key(block)
64
+ return if except_key.nil? || !safe_to_register_offense?(block, except_key)
65
+
66
+ [offense_range(node), except_key_source(except_key)]
67
+ end
68
+
69
+ def extracts_hash_subset?(block)
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
+
74
+ return false unless supported_subset_method?(method)
75
+ return false if range_include?(send_node)
76
+
77
+ case method
78
+ when :include?, :exclude?
79
+ send_node.first_argument.source == key_arg.source
80
+ when :in?
81
+ send_node.receiver.source == key_arg.source
82
+ else
83
+ true
84
+ end
85
+ end
86
+ end
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
+
100
+ def supported_subset_method?(method)
101
+ if active_support_extensions_enabled?
102
+ ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)
103
+ else
104
+ SUBSET_METHODS.include?(method)
105
+ end
106
+ end
107
+
108
+ def semantically_except_method?(node)
109
+ block = node.parent
110
+ body, negated = extract_body_if_negated(block.body)
111
+
112
+ if node.method?('reject')
113
+ body.method?('==') || body.method?('eql?') || included?(body, negated)
114
+ else
115
+ body.method?('!=') || not_included?(body, negated)
116
+ end
117
+ end
118
+
119
+ def semantically_slice_method?(node)
120
+ !semantically_except_method?(node)
121
+ end
122
+
123
+ def included?(body, negated)
124
+ if negated
125
+ body.method?('exclude?')
126
+ else
127
+ body.method?('include?') || body.method?('in?')
128
+ end
129
+ end
130
+
131
+ def not_included?(body, negated)
132
+ included?(body, !negated)
133
+ end
134
+
135
+ def safe_to_register_offense?(block, except_key)
136
+ body = block.body
137
+
138
+ if body.method?('==') || body.method?('!=')
139
+ except_key.type?(:sym, :str)
140
+ else
141
+ true
142
+ end
143
+ end
144
+
145
+ def extract_body_if_negated(body)
146
+ if body.method?('!')
147
+ [body.receiver, true]
148
+ else
149
+ [body, false]
150
+ end
151
+ end
152
+
153
+ def except_key_source(key)
154
+ if key.array_type?
155
+ key = if key.percent_literal?
156
+ key.each_value.map { |v| decorate_source(v) }
157
+ else
158
+ key.each_value.map(&:source)
159
+ end
160
+ return key.join(', ')
161
+ end
162
+
163
+ key.literal? ? key.source : "*#{key.source}"
164
+ end
165
+
166
+ def decorate_source(value)
167
+ return ":\"#{value.source}\"" if value.dsym_type?
168
+ return "\"#{value.source}\"" if value.dstr_type?
169
+ return ":#{value.source}" if value.sym_type?
170
+
171
+ "'#{value.source}'"
172
+ end
173
+
174
+ def except_key(node)
175
+ key_arg = node.argument_list.first.source
176
+ body, = extract_body_if_negated(node.body)
177
+ lhs, _method_name, rhs = *body
178
+
179
+ lhs.source == key_arg ? rhs : lhs
180
+ end
181
+
182
+ def offense_range(node)
183
+ range_between(node.loc.selector.begin_pos, node.parent.loc.end.end_pos)
184
+ end
185
+ end
186
+ # rubocop:enable Metrics/ModuleLength
187
+ end
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
@@ -55,14 +55,19 @@ module RuboCop
55
55
  end
56
56
 
57
57
  def if_body_source(if_body)
58
- if if_body.call_type? &&
59
- if_body.last_argument&.hash_type? && if_body.last_argument.pairs.last&.value_omission?
58
+ if if_body.call_type? && !if_body.method?(:[]=) && omitted_value_in_last_hash_arg?(if_body)
60
59
  "#{method_source(if_body)}(#{if_body.arguments.map(&:source).join(', ')})"
61
60
  else
62
61
  if_body.source
63
62
  end
64
63
  end
65
64
 
65
+ def omitted_value_in_last_hash_arg?(if_body)
66
+ return false unless (last_argument = if_body.last_argument)
67
+
68
+ last_argument.hash_type? && last_argument.pairs.last&.value_omission?
69
+ end
70
+
66
71
  def method_source(if_body)
67
72
  end_range = if_body.implicit_call? ? if_body.loc.dot.end : if_body.loc.selector
68
73
 
@@ -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
@@ -2,8 +2,8 @@
2
2
 
3
3
  module RuboCop
4
4
  module Cop
5
- # Common methods shared by Style/TrailingCommaInArguments and
6
- # Style/TrailingCommaInLiteral
5
+ # Common methods shared by Style/TrailingCommaInArguments,
6
+ # Style/TrailingCommaInArrayLiteral and Style/TrailingCommaInHashLiteral
7
7
  module TrailingComma
8
8
  include ConfigurableEnforcedStyle
9
9
  include RangeHelp
@@ -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