rubocop 1.68.0 → 1.69.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +41 -6
  4. data/lib/rubocop/cop/base.rb +1 -1
  5. data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
  6. data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
  7. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
  8. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
  9. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
  10. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +2 -4
  11. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
  12. data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +46 -0
  13. data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
  14. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  15. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -2
  16. data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
  17. data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
  18. data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
  19. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  20. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -3
  21. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +3 -4
  22. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +3 -1
  23. data/lib/rubocop/cop/layout/indentation_width.rb +7 -7
  24. data/lib/rubocop/cop/layout/leading_comment_space.rb +15 -0
  25. data/lib/rubocop/cop/layout/line_length.rb +118 -4
  26. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  27. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  28. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
  29. data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
  30. data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -35
  31. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -2
  32. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  33. data/lib/rubocop/cop/layout/space_around_operators.rb +16 -17
  34. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
  35. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
  36. data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
  37. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +11 -12
  38. data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -0
  39. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
  40. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  41. data/lib/rubocop/cop/lint/empty_file.rb +0 -2
  42. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  43. data/lib/rubocop/cop/lint/float_comparison.rb +14 -6
  44. data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -3
  45. data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
  46. data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
  47. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
  48. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
  49. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -5
  50. data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
  51. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
  52. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +1 -1
  53. data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
  54. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
  55. data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +106 -0
  56. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
  57. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
  58. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
  59. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +12 -7
  60. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
  61. data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
  62. data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
  63. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +2 -0
  64. data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
  65. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  66. data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
  67. data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
  68. data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
  69. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
  70. data/lib/rubocop/cop/lint/void.rb +3 -2
  71. data/lib/rubocop/cop/metrics/class_length.rb +7 -7
  72. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
  73. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -2
  74. data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
  75. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
  76. data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
  77. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -9
  78. data/lib/rubocop/cop/mixin/range_help.rb +0 -1
  79. data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
  80. data/lib/rubocop/cop/naming/constant_name.rb +6 -7
  81. data/lib/rubocop/cop/naming/file_name.rb +0 -2
  82. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
  83. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -11
  84. data/lib/rubocop/cop/naming/variable_name.rb +3 -4
  85. data/lib/rubocop/cop/naming/variable_number.rb +2 -3
  86. data/lib/rubocop/cop/style/access_modifier_declarations.rb +53 -24
  87. data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +1 -1
  88. data/lib/rubocop/cop/style/array_intersect.rb +5 -4
  89. data/lib/rubocop/cop/style/bitwise_predicate.rb +1 -1
  90. data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
  91. data/lib/rubocop/cop/style/case_like_if.rb +8 -11
  92. data/lib/rubocop/cop/style/commented_keyword.rb +11 -1
  93. data/lib/rubocop/cop/style/conditional_assignment.rb +19 -21
  94. data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
  95. data/lib/rubocop/cop/style/dig_chain.rb +90 -0
  96. data/lib/rubocop/cop/style/file_null.rb +73 -0
  97. data/lib/rubocop/cop/style/file_touch.rb +75 -0
  98. data/lib/rubocop/cop/style/for.rb +0 -1
  99. data/lib/rubocop/cop/style/global_vars.rb +1 -3
  100. data/lib/rubocop/cop/style/guard_clause.rb +1 -1
  101. data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
  102. data/lib/rubocop/cop/style/if_inside_else.rb +0 -1
  103. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -2
  104. data/lib/rubocop/cop/style/if_with_semicolon.rb +14 -5
  105. data/lib/rubocop/cop/style/inverse_methods.rb +0 -1
  106. data/lib/rubocop/cop/style/keyword_arguments_merging.rb +2 -2
  107. data/lib/rubocop/cop/style/lambda_call.rb +0 -1
  108. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
  109. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +7 -11
  110. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
  111. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  112. data/lib/rubocop/cop/style/mutable_constant.rb +4 -5
  113. data/lib/rubocop/cop/style/negated_if_else_condition.rb +6 -4
  114. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
  115. data/lib/rubocop/cop/style/not.rb +1 -1
  116. data/lib/rubocop/cop/style/one_line_conditional.rb +25 -4
  117. data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
  118. data/lib/rubocop/cop/style/or_assignment.rb +3 -6
  119. data/lib/rubocop/cop/style/parallel_assignment.rb +8 -13
  120. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  121. data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
  122. data/lib/rubocop/cop/style/redundant_condition.rb +36 -21
  123. data/lib/rubocop/cop/style/redundant_line_continuation.rb +7 -6
  124. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  125. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -0
  126. data/lib/rubocop/cop/style/redundant_return.rb +2 -2
  127. data/lib/rubocop/cop/style/redundant_self.rb +7 -14
  128. data/lib/rubocop/cop/style/redundant_self_assignment.rb +7 -5
  129. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
  130. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  131. data/lib/rubocop/cop/style/rescue_modifier.rb +2 -3
  132. data/lib/rubocop/cop/style/safe_navigation.rb +1 -1
  133. data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
  134. data/lib/rubocop/cop/style/self_assignment.rb +11 -17
  135. data/lib/rubocop/cop/style/signal_exception.rb +2 -3
  136. data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
  137. data/lib/rubocop/cop/style/single_line_do_end_block.rb +13 -3
  138. data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -3
  139. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  140. data/lib/rubocop/cop/style/string_concatenation.rb +0 -1
  141. data/lib/rubocop/cop/style/swap_values.rb +4 -15
  142. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
  143. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
  144. data/lib/rubocop/cop/variable_force.rb +4 -10
  145. data/lib/rubocop/cops_documentation_generator.rb +9 -1
  146. data/lib/rubocop/version.rb +1 -1
  147. data/lib/rubocop.rb +8 -0
  148. metadata +17 -8
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Checks for code on multiple lines that could be rewritten on a single line
6
+ # without changing semantics or exceeding the `Max` parameter of `Layout/LineLength`.
7
+ module CheckSingleLineSuitability
8
+ def suitable_as_single_line?(node)
9
+ !too_long?(node) &&
10
+ !comment_within?(node) &&
11
+ safe_to_split?(node)
12
+ end
13
+
14
+ private
15
+
16
+ def too_long?(node)
17
+ lines = processed_source.lines[(node.first_line - 1)...node.last_line]
18
+ to_single_line(lines.join("\n")).length > max_line_length
19
+ end
20
+
21
+ def to_single_line(source)
22
+ source
23
+ .gsub(/" *\\\n\s*'/, %q(" + ')) # Double quote, backslash, and then single quote
24
+ .gsub(/' *\\\n\s*"/, %q(' + ")) # Single quote, backslash, and then double quote
25
+ .gsub(/(["']) *\\\n\s*\1/, '') # Double or single quote, backslash, then same quote
26
+ .gsub(/\n\s*(?=(&)?\.\w)/, '') # Extra space within method chaining which includes `&.`
27
+ .gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
28
+ end
29
+
30
+ def max_line_length
31
+ config.for_cop('Layout/LineLength')['Max']
32
+ end
33
+
34
+ def comment_within?(node)
35
+ comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
36
+
37
+ comment_line_numbers.any? do |comment_line_number|
38
+ comment_line_number >= node.first_line && comment_line_number <= node.last_line
39
+ end
40
+ end
41
+
42
+ def safe_to_split?(node)
43
+ node.each_descendant(:if, :case, :kwbegin, :def, :defs).none? &&
44
+ node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
45
+ node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Help methods for working with `Enumerable#dig` in cops.
6
+ # Used by `Style::DigChain` and `Style::SingleArgumentDig`
7
+ module DigHelp
8
+ extend NodePattern::Macros
9
+
10
+ # @!method dig?(node)
11
+ def_node_matcher :dig?, <<~PATTERN
12
+ (call _ :dig !{hash block_pass}+)
13
+ PATTERN
14
+
15
+ # @!method single_argument_dig?(node)
16
+ def_node_matcher :single_argument_dig?, <<~PATTERN
17
+ (send _ :dig $!splat)
18
+ PATTERN
19
+
20
+ private
21
+
22
+ def dig_chain_enabled?
23
+ @config.for_cop('Style/DigChain')['Enabled']
24
+ end
25
+ end
26
+ end
27
+ end
@@ -121,12 +121,10 @@ module RuboCop
121
121
 
122
122
  def indented_keyword_expression(node)
123
123
  if node.for_type?
124
- expression = node.collection
124
+ node.collection
125
125
  else
126
- expression, = *node
126
+ node.children.first
127
127
  end
128
-
129
- expression
130
128
  end
131
129
 
132
130
  def argument_in_method_call(node, kind) # rubocop:todo Metrics/CyclomaticComplexity
@@ -187,12 +185,10 @@ module RuboCop
187
185
 
188
186
  def assignment_rhs(node)
189
187
  case node.type
190
- when :casgn then _scope, _lhs, rhs = *node
191
- when :op_asgn then _lhs, _op, rhs = *node
192
- when :send, :csend then rhs = node.last_argument
193
- else _lhs, rhs = *node
188
+ when :casgn, :op_asgn then node.rhs
189
+ when :send, :csend then node.last_argument
190
+ else node.children.last
194
191
  end
195
- rhs
196
192
  end
197
193
 
198
194
  def not_for_this_cop?(node)
@@ -56,7 +56,6 @@ module RuboCop
56
56
  range: NOT_GIVEN, side: :both, newlines: true,
57
57
  whitespace: false, continuations: false,
58
58
  buffer: @processed_source.buffer)
59
-
60
59
  range = range_positional unless range_positional == NOT_GIVEN
61
60
 
62
61
  src = buffer.source
@@ -8,12 +8,28 @@ module RuboCop
8
8
  @minimum_target_ruby_version
9
9
  end
10
10
 
11
+ def required_maximum_ruby_version
12
+ @maximum_target_ruby_version
13
+ end
14
+
11
15
  def minimum_target_ruby_version(version)
12
16
  @minimum_target_ruby_version = version
13
17
  end
14
18
 
19
+ def maximum_target_ruby_version(version)
20
+ @maximum_target_ruby_version = version
21
+ end
22
+
15
23
  def support_target_ruby_version?(version)
16
- required_minimum_ruby_version <= version
24
+ # By default, no minimum or maximum versions of ruby are required
25
+ # to run any cop. In order to do a simple numerical comparison of
26
+ # the requested version against any requirements, we use 0 and
27
+ # Infinity as the default values to indicate no minimum (0) and no
28
+ # maximum (Infinity).
29
+ min = required_minimum_ruby_version || 0
30
+ max = required_maximum_ruby_version || Float::INFINITY
31
+
32
+ min <= version && max >= version
17
33
  end
18
34
  end
19
35
  end
@@ -31,12 +31,11 @@ module RuboCop
31
31
  PATTERN
32
32
 
33
33
  def on_casgn(node)
34
- if node.parent&.or_asgn_type?
35
- lhs, value = *node.parent
36
- _scope, const_name = *lhs
37
- else
38
- _scope, const_name, value = *node
39
- end
34
+ value = if node.parent&.or_asgn_type?
35
+ node.parent.expression
36
+ else
37
+ node.expression
38
+ end
40
39
 
41
40
  # We cannot know the result of method calls like
42
41
  # NewClass = something_that_returns_a_class
@@ -46,7 +45,7 @@ module RuboCop
46
45
  # SomeClass = Class.new(...)
47
46
  # SomeClass = Struct.new(...)
48
47
  return if allowed_assignment?(value)
49
- return if SNAKE_CASE.match?(const_name)
48
+ return if SNAKE_CASE.match?(node.name)
50
49
 
51
50
  add_offense(node.loc.name)
52
51
  end
@@ -37,8 +37,6 @@ module RuboCop
37
37
  #
38
38
  # anything/using_snake_case.rake
39
39
  class FileName < Base
40
- include RangeHelp
41
-
42
40
  MSG_SNAKE_CASE = 'The name of this source file (`%<basename>s`) should use snake_case.'
43
41
  MSG_NO_DEFINITION = '`%<basename>s` should define a class or module called `%<namespace>s`.'
44
42
  MSG_REGEX = '`%<basename>s` should match `%<regex>s`.'
@@ -155,6 +155,7 @@ module RuboCop
155
155
  UNDERSCORE_REQUIRED = 'Memoized variable `%<var>s` does not start ' \
156
156
  'with `_`. Use `@%<suggested_var>s` instead.'
157
157
  DYNAMIC_DEFINE_METHODS = %i[define_method define_singleton_method].to_set.freeze
158
+ INITIALIZE_METHODS = %i[initialize initialize_clone initialize_copy initialize_dup].freeze
158
159
 
159
160
  # @!method method_definition?(node)
160
161
  def_node_matcher :method_definition?, <<~PATTERN
@@ -168,7 +169,7 @@ module RuboCop
168
169
  # rubocop:disable Metrics/AbcSize
169
170
  # rubocop:disable Metrics/MethodLength
170
171
  def on_or_asgn(node)
171
- lhs, _value = *node
172
+ lhs = node.lhs
172
173
  return unless lhs.ivasgn_type?
173
174
 
174
175
  method_node, method_name = find_definition(node)
@@ -181,8 +182,8 @@ module RuboCop
181
182
 
182
183
  suggested_var = suggested_var(method_name)
183
184
  msg = format(
184
- message(lhs.children.first.to_s),
185
- var: lhs.children.first.to_s,
185
+ message(lhs.name),
186
+ var: lhs.name,
186
187
  suggested_var: suggested_var,
187
188
  method: method_name
188
189
  )
@@ -209,14 +210,13 @@ module RuboCop
209
210
  method_node, method_name = find_definition(node)
210
211
  return false unless method_node
211
212
 
212
- var_name = arg.children.first
213
- defined_memoized?(method_node.body, var_name) do |defined_ivar, return_ivar, ivar_assign|
213
+ defined_memoized?(method_node.body, arg.name) do |defined_ivar, return_ivar, ivar_assign|
214
214
  return false if matches?(method_name, ivar_assign)
215
215
 
216
216
  suggested_var = suggested_var(method_name)
217
217
  msg = format(
218
- message(var_name.to_s),
219
- var: var_name.to_s,
218
+ message(arg.name),
219
+ var: arg.name,
220
220
  suggested_var: suggested_var,
221
221
  method: method_name
222
222
  )
@@ -251,11 +251,10 @@ module RuboCop
251
251
  end
252
252
 
253
253
  def matches?(method_name, ivar_assign)
254
- return true if ivar_assign.nil? || method_name == :initialize
254
+ return true if ivar_assign.nil? || INITIALIZE_METHODS.include?(method_name)
255
255
 
256
- method_name = method_name.to_s.delete('!?')
257
- variable = ivar_assign.children.first
258
- variable_name = variable.to_s.sub('@', '')
256
+ method_name = method_name.to_s.delete('!?=')
257
+ variable_name = ivar_assign.name.to_s.sub('@', '')
259
258
 
260
259
  variable_name_candidates(method_name).include?(variable_name)
261
260
  end
@@ -269,7 +268,7 @@ module RuboCop
269
268
  end
270
269
 
271
270
  def suggested_var(method_name)
272
- suggestion = method_name.to_s.delete('!?')
271
+ suggestion = method_name.to_s.delete('!?=')
273
272
 
274
273
  style == :required ? "_#{suggestion}" : suggestion
275
274
  end
@@ -109,7 +109,7 @@ module RuboCop
109
109
  variable_name_matches?(lvasgn_node, name)
110
110
  end
111
111
  else
112
- node.children.first == name
112
+ node.name == name
113
113
  end
114
114
  end
115
115
 
@@ -141,12 +141,7 @@ module RuboCop
141
141
  # Further `lvar` nodes will not be corrected though since they now refer to a
142
142
  # different variable.
143
143
  def correct_reassignment(corrector, node, offending_name, preferred_name)
144
- if node.lvasgn_type?
145
- correct_node(corrector, node.child_nodes.first, offending_name, preferred_name)
146
- elsif node.masgn_type?
147
- # With multiple assign, the assignments are in an array as the last child
148
- correct_node(corrector, node.children.last, offending_name, preferred_name)
149
- end
144
+ correct_node(corrector, node.rhs, offending_name, preferred_name)
150
145
  end
151
146
 
152
147
  def preferred_name(variable_name)
@@ -159,10 +154,7 @@ module RuboCop
159
154
  end
160
155
 
161
156
  def variable_name(node)
162
- asgn_node = node.exception_variable
163
- return unless asgn_node
164
-
165
- asgn_node.children.last
157
+ node.exception_variable&.name
166
158
  end
167
159
 
168
160
  def message(node)
@@ -40,11 +40,10 @@ module RuboCop
40
40
  end
41
41
 
42
42
  def on_lvasgn(node)
43
- name, = *node
44
- return unless name
45
- return if allowed_identifier?(name)
43
+ return unless node.name
44
+ return if allowed_identifier?(node.name)
46
45
 
47
- check_name(node, name, node.loc.name)
46
+ check_name(node, node.name, node.loc.name)
48
47
  end
49
48
  alias on_ivasgn on_lvasgn
50
49
  alias on_cvasgn on_lvasgn
@@ -113,10 +113,9 @@ module RuboCop
113
113
 
114
114
  def on_arg(node)
115
115
  @node = node
116
- name, = *node
117
- return if allowed_identifier?(name)
116
+ return if allowed_identifier?(node.name)
118
117
 
119
- check_name(node, name, node.loc.name)
118
+ check_name(node, node.name, node.loc.name)
120
119
  end
121
120
  alias on_lvasgn on_arg
122
121
  alias on_ivasgn on_arg
@@ -70,6 +70,7 @@ module RuboCop
70
70
  # private :bar, :baz
71
71
  # private *%i[qux quux]
72
72
  # private *METHOD_NAMES
73
+ # private *private_methods
73
74
  #
74
75
  # end
75
76
  #
@@ -80,6 +81,7 @@ module RuboCop
80
81
  # private :bar, :baz
81
82
  # private *%i[qux quux]
82
83
  # private *METHOD_NAMES
84
+ # private *private_methods
83
85
  #
84
86
  # end
85
87
  #
@@ -133,21 +135,18 @@ module RuboCop
133
135
  # @!method access_modifier_with_symbol?(node)
134
136
  def_node_matcher :access_modifier_with_symbol?, <<~PATTERN
135
137
  (send nil? {:private :protected :public :module_function}
136
- {(sym _) (splat {#percent_symbol_array? const})}
138
+ {(sym _)+ (splat {#percent_symbol_array? const send})}
137
139
  )
138
140
  PATTERN
139
141
 
140
142
  # @!method access_modifier_with_attr?(node)
141
143
  def_node_matcher :access_modifier_with_attr?, <<~PATTERN
142
144
  (send nil? {:private :protected :public :module_function}
143
- (send nil? {:attr :attr_reader :attr_writer :attr_accessor} _))
145
+ (send nil? {:attr :attr_reader :attr_writer :attr_accessor} _+))
144
146
  PATTERN
145
147
 
146
148
  def on_send(node)
147
- return unless node.access_modifier?
148
- return if ALLOWED_NODE_TYPES.include?(node.parent&.type)
149
- return if allow_modifiers_on_symbols?(node)
150
- return if allow_modifiers_on_attrs?(node)
149
+ return if allowed?(node)
151
150
 
152
151
  if offense?(node)
153
152
  add_offense(node.loc.selector) do |corrector|
@@ -161,15 +160,22 @@ module RuboCop
161
160
 
162
161
  private
163
162
 
163
+ def allowed?(node)
164
+ !node.access_modifier? ||
165
+ ALLOWED_NODE_TYPES.include?(node.parent&.type) ||
166
+ allow_modifiers_on_symbols?(node) ||
167
+ allow_modifiers_on_attrs?(node)
168
+ end
169
+
164
170
  def autocorrect(corrector, node)
165
171
  case style
166
172
  when :group
167
- def_node = find_corresponding_def_node(node)
168
- return unless def_node
173
+ def_nodes = find_corresponding_def_nodes(node)
174
+ return unless def_nodes.any?
169
175
 
170
- replace_def(corrector, node, def_node)
176
+ replace_defs(corrector, node, def_nodes)
171
177
  when :inline
172
- remove_node(corrector, node)
178
+ remove_nodes(corrector, node)
173
179
  select_grouped_def_nodes(node).each do |grouped_def_node|
174
180
  insert_inline_modifier(corrector, grouped_def_node, node.method_name)
175
181
  end
@@ -194,6 +200,13 @@ module RuboCop
194
200
  (inline_style? && access_modifier_is_not_inlined?(node))
195
201
  end
196
202
 
203
+ def correctable_group_offense?(node)
204
+ return false unless group_style?
205
+ return false if allowed?(node)
206
+
207
+ access_modifier_is_inlined?(node) && find_corresponding_def_nodes(node).any?
208
+ end
209
+
197
210
  def group_style?
198
211
  style == :group
199
212
  end
@@ -212,7 +225,11 @@ module RuboCop
212
225
 
213
226
  def right_siblings_same_inline_method?(node)
214
227
  node.right_siblings.any? do |sibling|
215
- sibling.send_type? && sibling.method?(node.method_name) && !sibling.arguments.empty?
228
+ sibling.send_type? &&
229
+ correctable_group_offense?(sibling) &&
230
+ sibling.method?(node.method_name) &&
231
+ !sibling.arguments.empty? &&
232
+ find_corresponding_def_nodes(sibling).any?
216
233
  end
217
234
  end
218
235
 
@@ -226,14 +243,22 @@ module RuboCop
226
243
  end
227
244
  end
228
245
 
229
- def find_corresponding_def_node(node)
246
+ def find_corresponding_def_nodes(node)
230
247
  if access_modifier_with_symbol?(node)
231
- method_name = node.first_argument.respond_to?(:value) && node.first_argument.value
232
- node.parent.each_child_node(:def).find do |child|
233
- child.method?(method_name)
248
+ method_names = node.arguments.filter_map do |argument|
249
+ next unless argument.sym_type?
250
+
251
+ argument.respond_to?(:value) && argument.value
252
+ end
253
+
254
+ def_nodes = node.parent.each_child_node(:def).select do |child|
255
+ method_names.include?(child.method_name)
234
256
  end
257
+
258
+ # If there isn't a `def` node for each symbol, we will skip autocorrection.
259
+ def_nodes.size == method_names.size ? def_nodes : []
235
260
  else
236
- node.first_argument
261
+ [node.first_argument]
237
262
  end
238
263
  end
239
264
 
@@ -251,8 +276,8 @@ module RuboCop
251
276
  end.select(&:def_type?)
252
277
  end
253
278
 
254
- def replace_def(corrector, node, def_node)
255
- source = def_source(node, def_node)
279
+ def replace_defs(corrector, node, def_nodes)
280
+ source = def_source(node, def_nodes)
256
281
  argument_less_modifier_node = find_argument_less_modifier_node(node)
257
282
  if argument_less_modifier_node
258
283
  corrector.insert_after(argument_less_modifier_node, "\n\n#{source}")
@@ -264,20 +289,24 @@ module RuboCop
264
289
  return
265
290
  end
266
291
 
267
- remove_node(corrector, def_node)
268
- remove_node(corrector, node)
292
+ remove_nodes(corrector, *def_nodes, node)
269
293
  end
270
294
 
271
295
  def insert_inline_modifier(corrector, node, modifier_name)
272
296
  corrector.insert_before(node, "#{modifier_name} ")
273
297
  end
274
298
 
275
- def remove_node(corrector, node)
276
- corrector.remove(range_with_comments_and_lines(node))
299
+ def remove_nodes(corrector, *nodes)
300
+ nodes.each do |node|
301
+ corrector.remove(range_with_comments_and_lines(node))
302
+ end
277
303
  end
278
304
 
279
- def def_source(node, def_node)
280
- [*processed_source.ast_with_comments[node].map(&:text), def_node.source].join("\n")
305
+ def def_source(node, def_nodes)
306
+ [
307
+ *processed_source.ast_with_comments[node].map(&:text),
308
+ *def_nodes.map(&:source)
309
+ ].join("\n")
281
310
  end
282
311
  end
283
312
  end
@@ -61,7 +61,7 @@ module RuboCop
61
61
  private
62
62
 
63
63
  def modifier_form?(operation)
64
- return true if operation.and_type? || operation.or_type?
64
+ return true if operation.operator_keyword?
65
65
 
66
66
  operation.modifier_form?
67
67
  end
@@ -28,6 +28,7 @@ module RuboCop
28
28
  # # bad
29
29
  # (array1 & array2).any?
30
30
  # (array1 & array2).empty?
31
+ # (array1 & array2).none?
31
32
  #
32
33
  # # good
33
34
  # array1.intersect?(array2)
@@ -57,7 +58,7 @@ module RuboCop
57
58
  (send
58
59
  (begin
59
60
  (send $(...) :& $(...))
60
- ) ${:any? :empty?}
61
+ ) ${:any? :empty? :none?}
61
62
  )
62
63
  PATTERN
63
64
 
@@ -66,18 +67,18 @@ module RuboCop
66
67
  (send
67
68
  (begin
68
69
  (send $(...) :& $(...))
69
- ) ${:present? :any? :blank? :empty?}
70
+ ) ${:present? :any? :blank? :empty? :none?}
70
71
  )
71
72
  PATTERN
72
73
 
73
74
  MSG = 'Use `%<negated>s%<receiver>s.intersect?(%<argument>s)` ' \
74
75
  'instead of `(%<receiver>s & %<argument>s).%<method_name>s`.'
75
76
  STRAIGHT_METHODS = %i[present? any?].freeze
76
- NEGATED_METHODS = %i[blank? empty?].freeze
77
+ NEGATED_METHODS = %i[blank? empty? none?].freeze
77
78
  RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
78
79
 
79
80
  def on_send(node)
80
- return if (parent = node.parent) && (parent.block_type? || parent.numblock_type?)
81
+ return if node.block_literal?
81
82
  return unless (receiver, argument, method_name = bad_intersection_check?(node))
82
83
 
83
84
  message = message(receiver.source, argument.source, method_name)
@@ -71,7 +71,7 @@ module RuboCop
71
71
  PATTERN
72
72
 
73
73
  def on_send(node)
74
- return unless node.receiver.begin_type?
74
+ return unless node.receiver&.begin_type?
75
75
  return unless (preferred_method = preferred_method(node))
76
76
 
77
77
  bit_operation = node.receiver.children.first
@@ -481,7 +481,7 @@ module RuboCop
481
481
  end
482
482
 
483
483
  def conditional?(node)
484
- node.if_type? || node.or_type? || node.and_type?
484
+ node.if_type? || node.operator_keyword?
485
485
  end
486
486
 
487
487
  def array_or_range?(node)
@@ -106,7 +106,7 @@ module RuboCop
106
106
  when :or
107
107
  find_target(node.lhs)
108
108
  when :match_with_lvasgn
109
- lhs, rhs = *node
109
+ lhs, rhs = *node # rubocop:disable InternalAffairs/NodeDestructuring
110
110
  if lhs.regexp_type?
111
111
  rhs
112
112
  elsif rhs.regexp_type?
@@ -172,7 +172,7 @@ module RuboCop
172
172
  return collect_conditions(node.lhs, target, conditions) &&
173
173
  collect_conditions(node.rhs, target, conditions)
174
174
  when :match_with_lvasgn
175
- lhs, rhs = *node
175
+ lhs, rhs = *node # rubocop:disable InternalAffairs/NodeDestructuring
176
176
  condition_from_binary_op(lhs, rhs, target)
177
177
  when :send
178
178
  condition_from_send_node(node, target)
@@ -191,8 +191,7 @@ module RuboCop
191
191
  when :=~, :match, :match?
192
192
  condition_from_match_node(node, target)
193
193
  when :===
194
- lhs, _method, rhs = *node
195
- lhs if rhs == target
194
+ node.receiver if node.first_argument == target
196
195
  when :include?, :cover?
197
196
  condition_from_include_or_cover_node(node, target)
198
197
  end
@@ -200,14 +199,12 @@ module RuboCop
200
199
  # rubocop:enable Metrics/CyclomaticComplexity
201
200
 
202
201
  def condition_from_equality_node(node, target)
203
- lhs, _method, rhs = *node
204
- condition = condition_from_binary_op(lhs, rhs, target)
202
+ condition = condition_from_binary_op(node.receiver, node.first_argument, target)
205
203
  condition if condition && !class_reference?(condition)
206
204
  end
207
205
 
208
206
  def condition_from_match_node(node, target)
209
- lhs, _method, rhs = *node
210
- condition_from_binary_op(lhs, rhs, target)
207
+ condition_from_binary_op(node.receiver, node.first_argument, target)
211
208
  end
212
209
 
213
210
  def condition_from_include_or_cover_node(node, target)
@@ -263,11 +260,11 @@ module RuboCop
263
260
  def regexp_with_working_captures?(node)
264
261
  case node.type
265
262
  when :match_with_lvasgn
266
- lhs, _rhs = *node
263
+ lhs, _rhs = *node # rubocop:disable InternalAffairs/NodeDestructuring
267
264
  node.loc.selector.source == '=~' && regexp_with_named_captures?(lhs)
268
265
  when :send
269
- lhs, method, rhs = *node
270
- method == :match && [lhs, rhs].any? { |n| regexp_with_named_captures?(n) }
266
+ node.method?(:match) &&
267
+ [node.receiver, node.first_argument].any? { |n| regexp_with_named_captures?(n) }
271
268
  end
272
269
  end
273
270
 
@@ -57,6 +57,9 @@ module RuboCop
57
57
 
58
58
  REGEXP = /(?<keyword>\S+).*#/.freeze
59
59
 
60
+ SUBCLASS_DEFINITION = /\A\s*class\s+\w+\s*<\s*\w+/.freeze
61
+ METHOD_DEFINITION = /\A\s*def\s/.freeze
62
+
60
63
  def on_new_investigation
61
64
  processed_source.comments.each do |comment|
62
65
  next unless offensive?(comment) && (match = source_line(comment).match(REGEXP))
@@ -93,7 +96,14 @@ module RuboCop
93
96
  end
94
97
 
95
98
  def rbs_inline_annotation?(line, comment)
96
- comment.text.start_with?('#:') && line.start_with?(/\A\s*def\s/)
99
+ case line
100
+ when SUBCLASS_DEFINITION
101
+ comment.text.start_with?(/#\[.+\]/)
102
+ when METHOD_DEFINITION
103
+ comment.text.start_with?('#:')
104
+ else
105
+ false
106
+ end
97
107
  end
98
108
  end
99
109
  end