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
@@ -77,7 +77,7 @@ module RuboCop
77
77
  private
78
78
 
79
79
  def ambiguous_block_association?(send_node)
80
- send_node.last_argument.block_type? && !send_node.last_argument.send_node.arguments?
80
+ send_node.last_argument.any_block_type? && !send_node.last_argument.send_node.arguments?
81
81
  end
82
82
 
83
83
  def allowed_method_pattern?(node)
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for an array literal interpolated inside a regexp.
7
+ #
8
+ # When interpolating an array literal, it is converted to a string. This means
9
+ # that when inside a regexp, it acts as a character class but with additional
10
+ # quotes, spaces and commas that are likely not intended. For example,
11
+ # `/#{%w[a b c]}/` parses as `/["a", "b", "c"]/` (or `/["a, bc]/` without
12
+ # repeated characters).
13
+ #
14
+ # The cop can autocorrect to a character class (if all items in the array are a
15
+ # single character) or alternation (if the array contains longer items).
16
+ #
17
+ # NOTE: This only considers interpolated arrays that contain only strings, symbols,
18
+ # integers, and floats. Any other type is not easily convertible to a character class
19
+ # or regexp alternation.
20
+ #
21
+ # @safety
22
+ # Autocorrection is unsafe because it will change the regexp pattern, by
23
+ # removing the additional quotes, spaces and commas from the character class.
24
+ #
25
+ # @example
26
+ # # bad
27
+ # /#{%w[a b c]}/
28
+ #
29
+ # # good
30
+ # /[abc]/
31
+ #
32
+ # # bad
33
+ # /#{%w[foo bar baz]}/
34
+ #
35
+ # # good
36
+ # /(?:foo|bar|baz)/
37
+ #
38
+ # # bad - construct a regexp rather than interpolate an array of identifiers
39
+ # /#{[foo, bar]}/
40
+ #
41
+ class ArrayLiteralInRegexp < Base
42
+ include Interpolation
43
+ extend AutoCorrector
44
+
45
+ LITERAL_TYPES = %i[str sym int float true false nil].freeze
46
+ private_constant :LITERAL_TYPES
47
+
48
+ MSG_CHARACTER_CLASS = 'Use a character class instead of interpolating an array in a regexp.'
49
+ MSG_ALTERNATION = 'Use alternation instead of interpolating an array in a regexp.'
50
+ MSG_UNKNOWN = 'Use alternation or a character class instead of interpolating an array ' \
51
+ 'in a regexp.'
52
+
53
+ def on_interpolation(begin_node)
54
+ final_node = begin_node.children.last
55
+
56
+ return unless begin_node.parent.regexp_type?
57
+ return unless final_node.array_type?
58
+
59
+ if array_of_literal_values?(final_node)
60
+ register_array_of_literal_values(begin_node, final_node)
61
+ else
62
+ register_array_of_nonliteral_values(begin_node)
63
+ end
64
+ end
65
+
66
+ private
67
+
68
+ def array_of_literal_values?(node)
69
+ node.each_value.all? { |value| value.type?(*LITERAL_TYPES) }
70
+ end
71
+
72
+ def register_array_of_literal_values(begin_node, node)
73
+ array_values = array_values(node)
74
+
75
+ if character_class?(array_values)
76
+ message = MSG_CHARACTER_CLASS
77
+ replacement = character_class_for(array_values)
78
+ else
79
+ message = MSG_ALTERNATION
80
+ replacement = alternation_for(array_values)
81
+ end
82
+
83
+ add_offense(begin_node, message: message) do |corrector|
84
+ corrector.replace(begin_node, replacement)
85
+ end
86
+ end
87
+
88
+ def register_array_of_nonliteral_values(node)
89
+ # Add offense but do not correct if the array contains any nonliteral values.
90
+ add_offense(node, message: MSG_UNKNOWN)
91
+ end
92
+
93
+ def array_values(node)
94
+ node.each_value.map do |value|
95
+ value.respond_to?(:value) ? value.value : value.source
96
+ end
97
+ end
98
+
99
+ def character_class?(values)
100
+ values.all? { |v| v.to_s.length == 1 }
101
+ end
102
+
103
+ def character_class_for(values)
104
+ "[#{escape_values(values).join}]"
105
+ end
106
+
107
+ def alternation_for(values)
108
+ "(?:#{escape_values(values).join('|')})"
109
+ end
110
+
111
+ def escape_values(values)
112
+ # This may add extraneous escape characters, but they can be cleaned up
113
+ # by `Style/RedundantRegexpEscape`.
114
+ values.map { |value| Regexp.escape(value.to_s) }
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -53,8 +53,6 @@ module RuboCop
53
53
  ASGN_TYPES = [:begin, *AST::Node::EQUALS_ASSIGNMENTS, :send, :csend].freeze
54
54
 
55
55
  def on_if(node)
56
- return if node.condition.block_type?
57
-
58
56
  traverse_node(node.condition) do |asgn_node|
59
57
  next :skip_children if skip_children?(asgn_node)
60
58
  next if allowed_construct?(asgn_node)
@@ -95,7 +93,7 @@ module RuboCop
95
93
 
96
94
  def traverse_node(node, &block)
97
95
  # if the node is a block, any assignments are irrelevant
98
- return if node.block_type?
96
+ return if node.any_block_type?
99
97
 
100
98
  result = yield node if ASGN_TYPES.include?(node.type)
101
99
 
@@ -14,7 +14,7 @@ module RuboCop
14
14
  # Although these can be rewritten in a different way, it should not be necessary to
15
15
  # do so. Operations such as `-` or `/` where the result will always be the same
16
16
  # (`x - x` will always be 0; `x / x` will always be 1) are offenses, but these
17
- # are covered by Lint/NumericOperationWithConstantResult instead.
17
+ # are covered by `Lint/NumericOperationWithConstantResult` instead.
18
18
  #
19
19
  # @safety
20
20
  # This cop is unsafe as it does not consider side effects when calling methods
@@ -68,12 +68,12 @@ module RuboCop
68
68
 
69
69
  # @!method constant_assigned_in_block?(node)
70
70
  def_node_matcher :constant_assigned_in_block?, <<~PATTERN
71
- ({^block_type? [^begin_type? ^^block_type?]} nil? ...)
71
+ ({^any_block [^begin ^^any_block]} nil? ...)
72
72
  PATTERN
73
73
 
74
74
  # @!method module_defined_in_block?(node)
75
75
  def_node_matcher :module_defined_in_block?, <<~PATTERN
76
- ({^block_type? [^begin_type? ^^block_type?]} ...)
76
+ ({^any_block [^begin ^^any_block]} ...)
77
77
  PATTERN
78
78
 
79
79
  def on_casgn(node)
@@ -92,7 +92,7 @@ module RuboCop
92
92
  private
93
93
 
94
94
  def method_name(node)
95
- node.ancestors.find(&:block_type?).method_name
95
+ node.ancestors.find(&:any_block_type?).method_name
96
96
  end
97
97
  end
98
98
  end
@@ -96,22 +96,18 @@ module RuboCop
96
96
  private
97
97
 
98
98
  def fixed_constant_path?(node)
99
- node.each_path.all? { |path| path.cbase_type? || path.const_type? || path.self_type? }
99
+ node.each_path.all? { |path| path.type?(:cbase, :const, :self) }
100
100
  end
101
101
 
102
102
  def simple_assignment?(node)
103
103
  node.ancestors.all? do |ancestor|
104
- return true if namespace_definition?(ancestor)
104
+ return true if ancestor.type?(:module, :class)
105
105
 
106
106
  ancestor.begin_type? || ancestor.literal? || ancestor.casgn_type? ||
107
107
  freeze_method?(ancestor)
108
108
  end
109
109
  end
110
110
 
111
- def namespace_definition?(node)
112
- node.module_type? || node.class_type?
113
- end
114
-
115
111
  def freeze_method?(node)
116
112
  node.send_type? && node.method?(:freeze)
117
113
  end
@@ -116,7 +116,7 @@ module RuboCop
116
116
 
117
117
  def assumed_usage_context?(node)
118
118
  # Basically, debugger methods are not used as a method argument without arguments.
119
- return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any?
119
+ return false unless node.arguments.empty? && node.each_ancestor(:call).any?
120
120
  return true if assumed_argument?(node)
121
121
 
122
122
  node.each_ancestor.none? do |ancestor|
@@ -106,7 +106,7 @@ module RuboCop
106
106
  private
107
107
 
108
108
  def pattern_identity(pattern)
109
- pattern_source = if pattern.hash_pattern_type? || pattern.match_alt_type?
109
+ pattern_source = if pattern.type?(:hash_pattern, :match_alt)
110
110
  pattern.children.map(&:source).sort.to_s
111
111
  else
112
112
  pattern.source
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for duplicate elements in Regexp character classes.
6
+ # Checks for duplicate elements in `Regexp` character classes.
7
7
  #
8
8
  # @example
9
9
  #
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for duplicate literal, constant, or variable elements in Set and SortedSet.
6
+ # Checks for duplicate literal, constant, or variable elements in `Set` and `SortedSet`.
7
7
  #
8
8
  # @example
9
9
  #
@@ -36,7 +36,8 @@ module RuboCop
36
36
  # # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
37
37
  #
38
38
  class FloatComparison < Base
39
- MSG = 'Avoid (in)equality comparisons of floats as they are unreliable.'
39
+ MSG_EQUALITY = 'Avoid equality comparisons of floats as they are unreliable.'
40
+ MSG_INEQUALITY = 'Avoid inequality comparisons of floats as they are unreliable.'
40
41
 
41
42
  EQUALITY_METHODS = %i[== != eql? equal?].freeze
42
43
  FLOAT_RETURNING_METHODS = %i[to_f Float fdiv].freeze
@@ -52,8 +53,10 @@ module RuboCop
52
53
 
53
54
  return if literal_safe?(lhs) || literal_safe?(rhs)
54
55
 
55
- add_offense(node) if float?(lhs) || float?(rhs)
56
+ message = node.method?(:!=) ? MSG_INEQUALITY : MSG_EQUALITY
57
+ add_offense(node, message: message) if float?(lhs) || float?(rhs)
56
58
  end
59
+ alias on_csend on_send
57
60
 
58
61
  private
59
62
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Identifies Float literals which are, like, really really really
6
+ # Identifies `Float` literals which are, like, really really really
7
7
  # really really really really really big. Too big. No-one needs Floats
8
8
  # that big. If you need a float that big, something is wrong with you.
9
9
  #
@@ -73,7 +73,7 @@ module RuboCop
73
73
 
74
74
  first_arg = node.first_argument
75
75
  return false if num_of_expected_fields.zero? &&
76
- (first_arg.dstr_type? || first_arg.array_type?)
76
+ first_arg.type?(:dstr, :array)
77
77
 
78
78
  matched_arguments_count?(num_of_expected_fields, num_of_format_args)
79
79
  end
@@ -82,7 +82,7 @@ module RuboCop
82
82
  end
83
83
 
84
84
  def string_literal?(node)
85
- node.str_type? || node.dstr_type?
85
+ node.type?(:str, :dstr)
86
86
  end
87
87
 
88
88
  def string_literals?(node1, node2)
@@ -5,6 +5,9 @@ module RuboCop
5
5
  module Lint
6
6
  # Checks for interpolated literals.
7
7
  #
8
+ # NOTE: Array literals interpolated in regexps are not handled by this cop, but
9
+ # by `Lint/ArrayLiteralInRegexp` instead.
10
+ #
8
11
  # @example
9
12
  #
10
13
  # # bad
@@ -55,8 +58,10 @@ module RuboCop
55
58
  node &&
56
59
  !special_keyword?(node) &&
57
60
  prints_as_self?(node) &&
58
- # Special case for Layout/TrailingWhitespace
59
- !(space_literal?(node) && ends_heredoc_line?(node))
61
+ # Special case for `Layout/TrailingWhitespace`
62
+ !(space_literal?(node) && ends_heredoc_line?(node)) &&
63
+ # Handled by `Lint/ArrayLiteralInRegexp`
64
+ !array_in_regexp?(node)
60
65
  end
61
66
 
62
67
  def special_keyword?(node)
@@ -64,6 +69,11 @@ module RuboCop
64
69
  (node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
65
70
  end
66
71
 
72
+ def array_in_regexp?(node)
73
+ grandparent = node.parent.parent
74
+ node.array_type? && grandparent.regexp_type?
75
+ end
76
+
67
77
  # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
68
78
  def autocorrected_value(node)
69
79
  case node.type
@@ -189,7 +199,7 @@ module RuboCop
189
199
 
190
200
  def in_array_percent_literal?(node)
191
201
  parent = node.parent
192
- return false unless parent.dstr_type? || parent.dsym_type?
202
+ return false unless parent.type?(:dstr, :dsym)
193
203
 
194
204
  grandparent = parent.parent
195
205
  grandparent&.array_type? && grandparent.percent_literal?
@@ -97,7 +97,7 @@ module RuboCop
97
97
 
98
98
  # @!method class_new_block(node)
99
99
  def_node_matcher :class_new_block, <<~RUBY
100
- ({block numblock}
100
+ (any_block
101
101
  (send
102
102
  (const {nil? cbase} :Class) :new $_) ...)
103
103
  RUBY
@@ -135,7 +135,7 @@ module RuboCop
135
135
  end
136
136
 
137
137
  def inside_class_with_stateful_parent?(node)
138
- if (block_node = node.each_ancestor(:block, :numblock).first)
138
+ if (block_node = node.each_ancestor(:any_block).first)
139
139
  return false unless (super_class = class_new_block(block_node))
140
140
 
141
141
  !allowed_class?(super_class)
@@ -8,7 +8,7 @@ module RuboCop
8
8
  # Offenses are registered for regexp character classes like `/[A-z]/`
9
9
  # as well as range objects like `('A'..'z')`.
10
10
  #
11
- # NOTE: Range objects cannot be autocorrected.
11
+ # NOTE: `Range` objects cannot be autocorrected.
12
12
  #
13
13
  # @safety
14
14
  # The cop autocorrects regexp character classes
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Do not mix named captures and numbered captures in a Regexp literal
6
+ # Do not mix named captures and numbered captures in a `Regexp` literal
7
7
  # because numbered capture is ignored if they're mixed.
8
8
  # Replace numbered captures with non-capturing groupings or
9
9
  # named captures.
@@ -102,7 +102,7 @@ module RuboCop
102
102
  return unless def_ancestor
103
103
 
104
104
  within_scoping_def =
105
- node.each_ancestor(:block, :numblock, :sclass).any? do |ancestor|
105
+ node.each_ancestor(:any_block, :sclass).any? do |ancestor|
106
106
  scoping_method_call?(ancestor)
107
107
  end
108
108
 
@@ -129,12 +129,12 @@ module RuboCop
129
129
 
130
130
  # @!method eval_call?(node)
131
131
  def_node_matcher :eval_call?, <<~PATTERN
132
- ({block numblock} (send _ {:instance_eval :class_eval :module_eval} ...) ...)
132
+ (any_block (send _ {:instance_eval :class_eval :module_eval} ...) ...)
133
133
  PATTERN
134
134
 
135
135
  # @!method exec_call?(node)
136
136
  def_node_matcher :exec_call?, <<~PATTERN
137
- ({block numblock} (send _ {:instance_exec :class_exec :module_exec} ...) ...)
137
+ (any_block (send _ {:instance_exec :class_exec :module_exec} ...) ...)
138
138
  PATTERN
139
139
  end
140
140
  end
@@ -43,7 +43,7 @@ module RuboCop
43
43
  PATTERN
44
44
 
45
45
  def parent_block_node(node)
46
- node.each_ancestor(:block, :numblock).first
46
+ node.each_ancestor(:any_block).first
47
47
  end
48
48
  end
49
49
  end
@@ -66,7 +66,7 @@ module RuboCop
66
66
  private
67
67
 
68
68
  def scoped_node?(node)
69
- node.def_type? || node.defs_type? || node.lambda?
69
+ node.type?(:def, :defs) || node.lambda?
70
70
  end
71
71
 
72
72
  def return_value?(return_node)
@@ -9,10 +9,10 @@ module RuboCop
9
9
  # As such, they can be replaced with that result.
10
10
  # These are probably leftover from debugging, or are mistakes.
11
11
  # Other numeric operations that are similarly leftover from debugging or mistakes
12
- # are handled by Lint/UselessNumericOperation.
12
+ # are handled by `Lint/UselessNumericOperation`.
13
13
  #
14
14
  # NOTE: This cop doesn't detect offenses for the `-` and `%` operator because it
15
- # can't determine the type of `x`. If `x` is an Array or String, it doesn't perform
15
+ # can't determine the type of `x`. If `x` is an `Array` or `String`, it doesn't perform
16
16
  # a numeric operation.
17
17
  #
18
18
  # @example
@@ -50,43 +50,38 @@ module RuboCop
50
50
 
51
51
  # @!method operation_with_constant_result?(node)
52
52
  def_node_matcher :operation_with_constant_result?,
53
- '(send (send nil? $_) $_ ({int | send nil?} $_))'
53
+ '(call (call nil? $_lhs) $_operation ({int | call nil?} $_rhs))'
54
54
 
55
55
  # @!method abbreviated_assignment_with_constant_result?(node)
56
56
  def_node_matcher :abbreviated_assignment_with_constant_result?,
57
- '(op-asgn (lvasgn $_) $_ ({int | lvar} $_))'
57
+ '(op-asgn (lvasgn $_lhs) $_operation ({int lvar} $_rhs))'
58
58
 
59
59
  def on_send(node)
60
- return unless operation_with_constant_result?(node)
61
-
62
- variable, operation, number = operation_with_constant_result?(node)
63
- result = constant_result?(variable, operation, number)
64
- return unless result
60
+ return unless (lhs, operation, rhs = operation_with_constant_result?(node))
61
+ return unless (result = constant_result?(lhs, operation, rhs))
65
62
 
66
63
  add_offense(node) do |corrector|
67
64
  corrector.replace(node, result.to_s)
68
65
  end
69
66
  end
67
+ alias on_csend on_send
70
68
 
71
69
  def on_op_asgn(node)
72
- return unless abbreviated_assignment_with_constant_result?(node)
73
-
74
- variable, operation, number = abbreviated_assignment_with_constant_result?(node)
75
- result = constant_result?(variable, operation, number)
76
- return unless result
70
+ return unless (lhs, operation, rhs = abbreviated_assignment_with_constant_result?(node))
71
+ return unless (result = constant_result?(lhs, operation, rhs))
77
72
 
78
73
  add_offense(node) do |corrector|
79
- corrector.replace(node, "#{variable} = #{result}")
74
+ corrector.replace(node, "#{lhs} = #{result}")
80
75
  end
81
76
  end
82
77
 
83
78
  private
84
79
 
85
- def constant_result?(variable, operation, number)
86
- if number.to_s == '0'
80
+ def constant_result?(lhs, operation, rhs)
81
+ if rhs.to_s == '0'
87
82
  return 0 if operation == :*
88
83
  return 1 if operation == :**
89
- elsif number == variable
84
+ elsif rhs == lhs
90
85
  return 1 if operation == :/
91
86
  end
92
87
  # If we weren't able to find any matches, return false so we can bail out.
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Looks for references of Regexp captures that are out of range
6
+ # Looks for references of `Regexp` captures that are out of range
7
7
  # and thus always returns nil.
8
8
  #
9
9
  # @safety
@@ -61,6 +61,7 @@ module RuboCop
61
61
  check_regexp(node.receiver)
62
62
  end
63
63
  end
64
+ alias after_csend after_send
64
65
 
65
66
  def on_when(node)
66
67
  regexp_conditions = node.conditions.select(&:regexp_type?)
@@ -38,16 +38,12 @@ module RuboCop
38
38
 
39
39
  def valid_context?(node)
40
40
  return true unless node.arguments.one? && node.first_argument.parenthesized_call?
41
- return true if first_argument_block_type?(node.first_argument)
41
+ return true if node.first_argument.any_block_type?
42
42
 
43
43
  node.operator_method? || node.setter_method? || chained_calls?(node) ||
44
44
  valid_first_argument?(node.first_argument)
45
45
  end
46
46
 
47
- def first_argument_block_type?(first_arg)
48
- first_arg.block_type? || first_arg.numblock_type?
49
- end
50
-
51
47
  def valid_first_argument?(first_arg)
52
48
  first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg) ||
53
49
  compound_range?(first_arg)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for redundant quantifiers inside Regexp literals.
6
+ # Checks for redundant quantifiers inside `Regexp` literals.
7
7
  #
8
8
  # It is always allowed when interpolation is used in a regexp literal,
9
9
  # because it's unknown what kind of string will be expanded as a result:
@@ -29,7 +29,7 @@ module RuboCop
29
29
  RESTRICT_ON_SEND = %i[print puts warn].freeze
30
30
 
31
31
  # @!method to_s_without_args?(node)
32
- def_node_matcher :to_s_without_args?, '(send _ :to_s)'
32
+ def_node_matcher :to_s_without_args?, '(call _ :to_s)'
33
33
 
34
34
  def on_interpolation(begin_node)
35
35
  final_node = begin_node.children.last
@@ -42,7 +42,7 @@ module RuboCop
42
42
  def on_send(node)
43
43
  return if node.receiver
44
44
 
45
- node.each_child_node(:send) do |child|
45
+ node.each_child_node(:call) do |child|
46
46
  next if !child.method?(:to_s) || child.arguments.any?
47
47
 
48
48
  register_offense(child, "`#{node.method_name}`")
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for `rescue` blocks targeting the Exception class.
6
+ # Checks for `rescue` blocks targeting the `Exception` class.
7
7
  #
8
8
  # @example
9
9
  #
@@ -33,7 +33,7 @@ module RuboCop
33
33
  def_node_matcher :bad_method?, <<~PATTERN
34
34
  {
35
35
  (send $(csend ...) $_ ...)
36
- (send $({block numblock} (csend ...) ...) $_ ...)
36
+ (send $(any_block (csend ...) ...) $_ ...)
37
37
  }
38
38
  PATTERN
39
39
 
@@ -97,12 +97,19 @@ module RuboCop
97
97
  end
98
98
 
99
99
  def require_parentheses?(send_node)
100
+ return true if operator_inside_hash?(send_node)
100
101
  return false unless send_node.comparison_method?
101
102
  return false unless (node = send_node.parent)
102
103
 
103
104
  (node.respond_to?(:logical_operator?) && node.logical_operator?) ||
104
105
  (node.respond_to?(:comparison_method?) && node.comparison_method?)
105
106
  end
107
+
108
+ def operator_inside_hash?(send_node)
109
+ # If an operator call (without a dot) is inside a hash, it needs
110
+ # to be parenthesized when converted to safe navigation.
111
+ send_node.parent&.pair_type? && !send_node.loc.dot
112
+ end
106
113
  end
107
114
  end
108
115
  end
@@ -3,11 +3,11 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for Hash creation with a mutable default value.
7
- # Creating a Hash in such a way will share the default value
6
+ # Checks for `Hash` creation with a mutable default value.
7
+ # Creating a `Hash` in such a way will share the default value
8
8
  # across all keys, causing unexpected behavior when modifying it.
9
9
  #
10
- # For example, when the Hash was created with an Array as the argument,
10
+ # For example, when the `Hash` was created with an `Array` as the argument,
11
11
  # calling `hash[:foo] << 'bar'` will also change the value of all
12
12
  # other keys that have not been explicitly assigned to.
13
13
  #
@@ -116,7 +116,7 @@ module RuboCop
116
116
  private
117
117
 
118
118
  def comment_between_rescue_and_end?(node)
119
- ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block, :numblock).first
119
+ ancestor = node.each_ancestor(:kwbegin, :def, :defs, :any_block).first
120
120
  return false unless ancestor
121
121
 
122
122
  end_line = ancestor.loc.end&.line || ancestor.loc.last_line
@@ -78,7 +78,7 @@ module RuboCop
78
78
  def on_send(node)
79
79
  return unless node.receiver
80
80
 
81
- if node.receiver.str_type? || node.receiver.sym_type?
81
+ if node.receiver.type?(:str, :sym)
82
82
  register_offense(node, correction: node.receiver.value.to_sym.inspect)
83
83
  elsif node.receiver.dstr_type?
84
84
  register_offense(node, correction: ":\"#{node.receiver.value.to_sym}\"")
@@ -81,7 +81,7 @@ module RuboCop
81
81
  node.arguments.count do |arg|
82
82
  return Float::INFINITY if arg.restarg_type?
83
83
 
84
- arg.arg_type? || arg.optarg_type? || arg.mlhs_type?
84
+ arg.type?(:arg, :optarg, :mlhs)
85
85
  end
86
86
  end
87
87
  end