rubocop 1.68.0 → 1.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Certain numeric operations have a constant result, usually 0 or 1.
7
+ # Subtracting a number from itself or multiplying it by 0 will always return 0.
8
+ # Additionally, a variable modulo 0 or itself will always return 0.
9
+ # Dividing a number by itself or raising it to the power of 0 will always return 1.
10
+ # As such, they can be replaced with that result.
11
+ # These are probably leftover from debugging, or are mistakes.
12
+ # Other numeric operations that are similarly leftover from debugging or mistakes
13
+ # are handled by Lint/UselessNumericOperation.
14
+ #
15
+ # @example
16
+ #
17
+ # # bad
18
+ # x - x
19
+ # x * 0
20
+ # x % 1
21
+ # x % x
22
+ #
23
+ # # good
24
+ # 0
25
+ #
26
+ # # bad
27
+ # x -= x
28
+ # x *= 0
29
+ # x %= 1
30
+ # x %= x
31
+ #
32
+ # # good
33
+ # x = 0
34
+ #
35
+ # # bad
36
+ # x / x
37
+ # x ** 0
38
+ #
39
+ # # good
40
+ # 1
41
+ #
42
+ # # bad
43
+ # x /= x
44
+ # x **= 0
45
+ #
46
+ # # good
47
+ # x = 1
48
+ #
49
+ class NumericOperationWithConstantResult < Base
50
+ extend AutoCorrector
51
+ MSG = 'Numeric operation with a constant result detected.'
52
+ RESTRICT_ON_SEND = %i[- * / % **].freeze
53
+
54
+ # @!method operation_with_constant_result?(node)
55
+ def_node_matcher :operation_with_constant_result?,
56
+ '(send (send nil? $_) $_ ({int | send nil?} $_))'
57
+
58
+ # @!method abbreviated_assignment_with_constant_result?(node)
59
+ def_node_matcher :abbreviated_assignment_with_constant_result?,
60
+ '(op-asgn (lvasgn $_) $_ ({int | lvar} $_))'
61
+
62
+ def on_send(node)
63
+ return unless operation_with_constant_result?(node)
64
+
65
+ variable, operation, number = operation_with_constant_result?(node)
66
+ result = constant_result?(variable, operation, number)
67
+ return unless result
68
+
69
+ add_offense(node) do |corrector|
70
+ corrector.replace(node, result.to_s)
71
+ end
72
+ end
73
+
74
+ def on_op_asgn(node)
75
+ return unless abbreviated_assignment_with_constant_result?(node)
76
+
77
+ variable, operation, number = abbreviated_assignment_with_constant_result?(node)
78
+ result = constant_result?(variable, operation, number)
79
+ return unless result
80
+
81
+ add_offense(node) do |corrector|
82
+ corrector.replace(node, "#{variable} = #{result}")
83
+ end
84
+ end
85
+
86
+ private
87
+
88
+ # rubocop :disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
89
+ def constant_result?(variable, operation, number)
90
+ if number.to_s == '0'
91
+ return 0 if operation == :*
92
+ return 1 if operation == :**
93
+ elsif number.to_s == '1'
94
+ return 0 if operation == :%
95
+ elsif number == variable
96
+ return 0 if %i[- %].include?(operation)
97
+ return 1 if operation == :/
98
+ end
99
+ # If we weren't able to find any matches, return false so we can bail out.
100
+ false
101
+ end
102
+ # rubocop :enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
103
+ end
104
+ end
105
+ end
106
+ end
@@ -27,8 +27,7 @@ module RuboCop
27
27
  MSG = 'Avoid using or-assignment with constants.'
28
28
 
29
29
  def on_or_asgn(node)
30
- lhs, _rhs = *node
31
- return unless lhs&.casgn_type?
30
+ return unless node.lhs&.casgn_type?
32
31
 
33
32
  add_offense(node.loc.operator) do |corrector|
34
33
  next if node.each_ancestor(:def, :defs).any?
@@ -75,7 +75,7 @@ module RuboCop
75
75
  end
76
76
 
77
77
  def on_nth_ref(node)
78
- backref, = *node
78
+ backref = node.children.first
79
79
  return if @valid_ref.nil? || backref <= @valid_ref
80
80
 
81
81
  message = format(
@@ -111,7 +111,7 @@ module RuboCop
111
111
  range_between(start + begin_pos - 1, start + end_pos)
112
112
  end
113
113
 
114
- # If the list of cops is comma-separated, but without a empty space after the comma,
114
+ # If the list of cops is comma-separated, but without an empty space after the comma,
115
115
  # we should **not** remove the prepending empty space, thus begin_pos += 1
116
116
  def range_with_comma_after(comment, start, begin_pos, end_pos)
117
117
  begin_pos += 1 if comment.source[end_pos + 1] != ' '
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks for redundant safe navigation calls.
7
7
  # Use cases where a constant, named in camel case for classes and modules is `nil` are rare,
8
8
  # and an offense is not detected when the receiver is a constant. The detection also applies
9
- # to literal receivers, except for `nil`.
9
+ # to `self`, and to literal receivers, except for `nil`.
10
10
  #
11
11
  # For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
12
12
  # and `equal?` methods are checked by default.
@@ -29,6 +29,9 @@ module RuboCop
29
29
  # # bad
30
30
  # CamelCaseConst&.do_something
31
31
  #
32
+ # # good
33
+ # CamelCaseConst.do_something
34
+ #
32
35
  # # bad
33
36
  # do_something if attrs&.respond_to?(:[])
34
37
  #
@@ -41,9 +44,6 @@ module RuboCop
41
44
  # end
42
45
  #
43
46
  # # good
44
- # CamelCaseConst.do_something
45
- #
46
- # # good
47
47
  # while node.is_a?(BeginNode)
48
48
  # node = node.parent
49
49
  # end
@@ -67,6 +67,12 @@ module RuboCop
67
67
  # foo.to_f
68
68
  # foo.to_s
69
69
  #
70
+ # # bad
71
+ # self&.foo
72
+ #
73
+ # # good
74
+ # self.foo
75
+ #
70
76
  # @example AllowedMethods: [nil_safe_method]
71
77
  # # bad
72
78
  # do_something if attrs&.nil_safe_method(:[])
@@ -133,7 +139,7 @@ module RuboCop
133
139
  def assume_receiver_instance_exists?(receiver)
134
140
  return true if receiver.const_type? && !receiver.short_name.match?(SNAKE_CASE)
135
141
 
136
- receiver.literal? && !receiver.nil_type?
142
+ receiver.self_type? || (receiver.literal? && !receiver.nil_type?)
137
143
  end
138
144
 
139
145
  def check?(node)
@@ -141,8 +147,7 @@ module RuboCop
141
147
  return false unless parent
142
148
 
143
149
  condition?(parent, node) ||
144
- parent.and_type? ||
145
- parent.or_type? ||
150
+ parent.operator_keyword? ||
146
151
  (parent.send_type? && parent.negation_method?)
147
152
  end
148
153
 
@@ -135,10 +135,10 @@ module RuboCop
135
135
  grandparent.array_type? && grandparent.children.size > 1
136
136
  end
137
137
 
138
+ # rubocop:disable Metrics/AbcSize
138
139
  def replacement_range_and_content(node)
139
- variable, = *node
140
- loc = node.loc
141
- expression = loc.expression
140
+ variable = node.children.first
141
+ expression = node.source_range
142
142
 
143
143
  if array_new?(variable)
144
144
  expression = node.parent.source_range if node.parent.array_type?
@@ -148,16 +148,17 @@ module RuboCop
148
148
  elsif redundant_brackets?(node)
149
149
  [expression, remove_brackets(variable)]
150
150
  else
151
- [loc.operator, '']
151
+ [node.loc.operator, '']
152
152
  end
153
153
  end
154
+ # rubocop:enable Metrics/AbcSize
154
155
 
155
156
  def array_splat?(node)
156
157
  node.children.first.array_type?
157
158
  end
158
159
 
159
160
  def method_argument?(node)
160
- node.parent.send_type?
161
+ node.parent.call_type?
161
162
  end
162
163
 
163
164
  def part_of_an_array?(node)
@@ -171,7 +172,7 @@ module RuboCop
171
172
  parent = node.parent
172
173
  grandparent = node.parent.parent
173
174
 
174
- parent.when_type? || parent.send_type? || part_of_an_array?(node) ||
175
+ parent.when_type? || method_argument?(node) || part_of_an_array?(node) ||
175
176
  grandparent&.resbody_type?
176
177
  end
177
178
 
@@ -196,7 +197,7 @@ module RuboCop
196
197
  def use_percent_literal_array_argument?(node)
197
198
  argument = node.children.first
198
199
 
199
- node.parent.send_type? &&
200
+ method_argument?(node) &&
200
201
  (argument.percent_literal?(:string) || argument.percent_literal?(:symbol))
201
202
  end
202
203
 
@@ -17,7 +17,6 @@ module RuboCop
17
17
  # do_something
18
18
  # end
19
19
  class RegexpAsCondition < Base
20
- include IgnoredNode
21
20
  extend AutoCorrector
22
21
 
23
22
  MSG = 'Do not use regexp literal as a condition. ' \
@@ -42,15 +42,11 @@ module RuboCop
42
42
  INVALID_TYPES = %i[array dstr float hash nil int str sym].freeze
43
43
 
44
44
  def on_resbody(node)
45
- rescued, _, _body = *node
46
- return if rescued.nil?
47
-
48
- exceptions = *rescued
49
- invalid_exceptions = invalid_exceptions(exceptions)
45
+ invalid_exceptions = invalid_exceptions(node.exceptions)
50
46
  return if invalid_exceptions.empty?
51
47
 
52
48
  add_offense(
53
- node.loc.keyword.join(rescued.source_range),
49
+ node.loc.keyword.join(node.children.first.source_range),
54
50
  message: format(MSG, invalid_exceptions: invalid_exceptions.map(&:source).join(', '))
55
51
  ) do |corrector|
56
52
  autocorrect(corrector, node)
@@ -58,7 +54,7 @@ module RuboCop
58
54
  end
59
55
 
60
56
  def autocorrect(corrector, node)
61
- rescued, _, _body = *node
57
+ rescued = node.children.first
62
58
  range = node.loc.keyword.end.join(rescued.source_range.end)
63
59
 
64
60
  corrector.replace(range, correction(*rescued))
@@ -83,6 +83,8 @@ module RuboCop
83
83
  def find_consistent_parts(grouped_operands)
84
84
  csend_in_and, csend_in_or, send_in_and, send_in_or = most_left_indices(grouped_operands)
85
85
 
86
+ return if csend_in_and && csend_in_or && csend_in_and < csend_in_or
87
+
86
88
  if csend_in_and
87
89
  ['.', (send_in_and ? [send_in_and, csend_in_and].min : csend_in_and) + 1]
88
90
  elsif send_in_or && csend_in_or
@@ -43,23 +43,21 @@ module RuboCop
43
43
  alias on_csend on_send
44
44
 
45
45
  def on_lvasgn(node)
46
- lhs, rhs = *node
47
- return unless rhs
46
+ return unless node.rhs
48
47
 
49
48
  rhs_type = ASSIGNMENT_TYPE_TO_RHS_TYPE[node.type]
50
49
 
51
- add_offense(node) if rhs.type == rhs_type && rhs.source == lhs.to_s
50
+ add_offense(node) if node.rhs.type == rhs_type && node.rhs.source == node.lhs.to_s
52
51
  end
53
52
  alias on_ivasgn on_lvasgn
54
53
  alias on_cvasgn on_lvasgn
55
54
  alias on_gvasgn on_lvasgn
56
55
 
57
56
  def on_casgn(node)
58
- lhs_scope, lhs_name, rhs = *node
59
- return unless rhs&.const_type?
57
+ return unless node.rhs&.const_type?
60
58
 
61
- rhs_scope, rhs_name = *rhs
62
- add_offense(node) if lhs_scope == rhs_scope && lhs_name == rhs_name
59
+ add_offense(node) if node.namespace == node.rhs.namespace &&
60
+ node.short_name == node.rhs.short_name
63
61
  end
64
62
 
65
63
  def on_masgn(node)
@@ -67,15 +65,15 @@ module RuboCop
67
65
  end
68
66
 
69
67
  def on_or_asgn(node)
70
- lhs, rhs = *node
71
- add_offense(node) if rhs_matches_lhs?(rhs, lhs)
68
+ add_offense(node) if rhs_matches_lhs?(node.rhs, node.lhs)
72
69
  end
73
70
  alias on_and_asgn on_or_asgn
74
71
 
75
72
  private
76
73
 
77
74
  def multiple_self_assignment?(node)
78
- lhs, rhs = *node
75
+ lhs = node.lhs
76
+ rhs = node.rhs
79
77
  return false unless rhs.array_type?
80
78
  return false unless lhs.children.size == rhs.children.size
81
79
 
@@ -67,7 +67,7 @@ module RuboCop
67
67
  def on_rescue(node)
68
68
  return if rescue_modifier?(node)
69
69
 
70
- _body, *rescues, _else = *node
70
+ rescues = node.resbody_branches
71
71
  rescued_groups = rescued_groups_for(rescues)
72
72
 
73
73
  rescue_group_rescues_multiple_levels = rescued_groups.any? do |group|
@@ -39,6 +39,8 @@ module RuboCop
39
39
  # end
40
40
  #
41
41
  # @example IgnoreNotImplementedMethods: true (default)
42
+ # # with default value of `NotImplementedExceptions: ['NotImplementedError']`
43
+ #
42
44
  # # good
43
45
  # def do_something(unused)
44
46
  # raise NotImplementedError
@@ -48,6 +50,14 @@ module RuboCop
48
50
  # fail "TODO"
49
51
  # end
50
52
  #
53
+ # @example IgnoreNotImplementedMethods: true
54
+ # # with `NotImplementedExceptions: ['AbstractMethodError']`
55
+ #
56
+ # # good
57
+ # def do_something(unused)
58
+ # raise AbstractMethodError
59
+ # end
60
+ #
51
61
  # @example IgnoreNotImplementedMethods: false
52
62
  # # bad
53
63
  # def do_something(unused)
@@ -57,14 +67,13 @@ module RuboCop
57
67
  # def do_something_else(unused)
58
68
  # fail "TODO"
59
69
  # end
60
- #
61
70
  class UnusedMethodArgument < Base
62
71
  include UnusedArgument
63
72
  extend AutoCorrector
64
73
 
65
74
  # @!method not_implemented?(node)
66
75
  def_node_matcher :not_implemented?, <<~PATTERN
67
- {(send nil? :raise (const {nil? cbase} :NotImplementedError) ...)
76
+ {(send nil? :raise #allowed_exception_class? ...)
68
77
  (send nil? :fail ...)}
69
78
  PATTERN
70
79
 
@@ -115,6 +124,13 @@ module RuboCop
115
124
 
116
125
  message
117
126
  end
127
+
128
+ def allowed_exception_class?(node)
129
+ return false unless node.const_type?
130
+
131
+ allowed_class_names = Array(cop_config.fetch('NotImplementedExceptions', []))
132
+ allowed_class_names.include?(node.const_name)
133
+ end
118
134
  end
119
135
  end
120
136
  end
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # Checks for calls to `defined?` with strings or symbols as the argument.
7
+ # Such calls will always return `'expression'`, you probably meant to
8
+ # check for the existence of a constant, method, or variable instead.
9
+ #
10
+ # `defined?` is part of the Ruby syntax and doesn't behave like normal methods.
11
+ # You can safely pass in what you are checking for directly, without encountering
12
+ # a `NameError`.
13
+ #
14
+ # When interpolation is used, oftentimes it is not possible to write the
15
+ # code with `defined?`. In these cases, switch to one of the more specific methods:
16
+ #
17
+ # * `class_variable_defined?`
18
+ # * `const_defined?`
19
+ # * `method_defined?`
20
+ # * `instance_variable_defined?`
21
+ # * `binding.local_variable_defined?`
22
+ #
23
+ # @example
24
+ #
25
+ # # bad
26
+ # defined?('FooBar')
27
+ # defined?(:FooBar)
28
+ # defined?(:foo_bar)
29
+ # defined?('foo_bar')
30
+ #
31
+ # # good
32
+ # defined?(FooBar)
33
+ # defined?(foo_bar)
34
+ #
35
+ # # bad - interpolation
36
+ # bar = 'Bar'
37
+ # defined?("Foo::#{bar}::Baz")
38
+ #
39
+ # # good
40
+ # bar = 'Bar'
41
+ # defined?(Foo) && Foo.const_defined?(bar) && Foo.const_get(bar).const_defined?(:Baz)
42
+ class UselessDefined < Base
43
+ MSG = 'Calling `defined?` with a %<type>s argument will always return a truthy value.'
44
+ TYPES = { str: 'string', dstr: 'string', sym: 'symbol', dsym: 'symbol' }.freeze
45
+
46
+ def on_defined?(node)
47
+ # NOTE: `defined?` always takes one argument. Anything else is a syntax error.
48
+ return unless (type = TYPES[node.first_argument.type])
49
+
50
+ add_offense(node, message: format(MSG, type: type))
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -75,7 +75,7 @@ module RuboCop
75
75
  def use_exception_variable_in_ensure?(resbody_node)
76
76
  return false unless (exception_variable = resbody_node.exception_variable)
77
77
  return false unless (ensure_node = resbody_node.each_ancestor(:ensure).first)
78
- return false unless (ensure_body = ensure_node.body)
78
+ return false unless (ensure_body = ensure_node.branch)
79
79
 
80
80
  ensure_body.each_descendant(:lvar).map(&:source).include?(exception_variable.source)
81
81
  end
@@ -102,24 +102,18 @@ module RuboCop
102
102
  when :op_asgn
103
103
  process_binary_operator_assignment(node)
104
104
  when *ASSIGNMENT_TYPES
105
- _, rhs_node = *node
106
- process_assignment(node, rhs_node) if rhs_node
105
+ process_assignment(node, node.rhs) if node.rhs
107
106
  end
108
107
  end
109
108
 
110
109
  def process_multiple_assignment(masgn_node)
111
- mlhs_node, mrhs_node = *masgn_node
112
-
113
- mlhs_node.children.each_with_index do |lhs_node, index|
110
+ masgn_node.assignments.each_with_index do |lhs_node, index|
114
111
  next unless ASSIGNMENT_TYPES.include?(lhs_node.type)
115
112
 
116
- lhs_variable_name, = *lhs_node
117
- rhs_node = mrhs_node.children[index]
118
-
119
- if mrhs_node.array_type? && rhs_node
120
- process_assignment(lhs_variable_name, rhs_node)
113
+ if masgn_node.rhs.array_type? && (rhs_node = masgn_node.rhs.children[index])
114
+ process_assignment(lhs_node, rhs_node)
121
115
  else
122
- @local[lhs_variable_name] = true
116
+ @local[lhs_node.name] = true
123
117
  end
124
118
  end
125
119
 
@@ -127,33 +121,28 @@ module RuboCop
127
121
  end
128
122
 
129
123
  def process_logical_operator_assignment(asgn_node)
130
- lhs_node, rhs_node = *asgn_node
131
- return unless ASSIGNMENT_TYPES.include?(lhs_node.type)
124
+ return unless ASSIGNMENT_TYPES.include?(asgn_node.lhs.type)
132
125
 
133
- process_assignment(lhs_node, rhs_node)
126
+ process_assignment(asgn_node.lhs, asgn_node.rhs)
134
127
 
135
128
  throw :skip_children
136
129
  end
137
130
 
138
131
  def process_binary_operator_assignment(op_asgn_node)
139
- lhs_node, = *op_asgn_node
132
+ lhs_node = op_asgn_node.lhs
140
133
  return unless ASSIGNMENT_TYPES.include?(lhs_node.type)
141
134
 
142
- lhs_variable_name, = *lhs_node
143
- @local[lhs_variable_name] = true
135
+ @local[lhs_node.name] = true
144
136
 
145
137
  throw :skip_children
146
138
  end
147
139
 
148
140
  def process_assignment(asgn_node, rhs_node)
149
- lhs_variable_name, = *asgn_node
150
-
151
- @local[lhs_variable_name] = if rhs_node.variable?
152
- rhs_variable_name, = *rhs_node
153
- @local[rhs_variable_name]
154
- else
155
- constructor?(rhs_node)
156
- end
141
+ @local[asgn_node.name] = if rhs_node.variable?
142
+ @local[rhs_node.name]
143
+ else
144
+ constructor?(rhs_node)
145
+ end
157
146
  end
158
147
 
159
148
  def constructor?(node)
@@ -126,7 +126,7 @@ module RuboCop
126
126
 
127
127
  def check_void_op(node, &block)
128
128
  node = node.children.first while node.begin_type?
129
- return unless node.send_type? && OPERATORS.include?(node.method_name)
129
+ return unless node.call_type? && OPERATORS.include?(node.method_name)
130
130
  return if block && yield(node)
131
131
 
132
132
  add_offense(node.loc.selector,
@@ -196,7 +196,7 @@ module RuboCop
196
196
  end
197
197
 
198
198
  def check_ensure(node)
199
- return unless (body = node.body)
199
+ return unless (body = node.branch)
200
200
  # NOTE: the `begin` node case is already handled via `on_begin`
201
201
  return if body.begin_type?
202
202
 
@@ -219,6 +219,7 @@ module RuboCop
219
219
  if node.arguments.empty?
220
220
  corrector.replace(node, node.receiver.source)
221
221
  else
222
+ corrector.remove(node.loc.dot) if node.loc.dot
222
223
  corrector.replace(
223
224
  range_with_surrounding_space(range: node.loc.selector, side: :both,
224
225
  newlines: false),
@@ -53,13 +53,13 @@ module RuboCop
53
53
  def on_casgn(node)
54
54
  parent = node.parent
55
55
 
56
- if parent&.assignment?
57
- block_node = parent.children[1]
58
- elsif parent&.parent&.masgn_type?
59
- block_node = parent.parent.children[1]
60
- else
61
- _scope, _name, block_node = *node
62
- end
56
+ block_node = if parent&.assignment?
57
+ parent.expression
58
+ elsif parent&.parent&.masgn_type?
59
+ parent.parent.expression
60
+ else
61
+ node.expression
62
+ end
63
63
 
64
64
  return unless block_node.respond_to?(:class_definition?) && block_node.class_definition?
65
65
 
@@ -95,7 +95,7 @@ module RuboCop
95
95
  def compound_assignment(node)
96
96
  # Methods setter cannot be detected for multiple assignments
97
97
  # and shorthand assigns, so we'll count them here instead
98
- children = node.masgn_type? ? node.children[0].children : node.children
98
+ children = node.masgn_type? ? node.assignments : node.children
99
99
 
100
100
  will_be_miscounted = children.count do |child|
101
101
  child.respond_to?(:setter_method?) && !child.setter_method?
@@ -148,8 +148,7 @@ module RuboCop
148
148
  when :class, :module, :sclass, :block, :numblock, :def, :defs
149
149
  node.body
150
150
  when :casgn
151
- _scope, _name, value = *node
152
- extract_body(value)
151
+ extract_body(node.expression)
153
152
  else
154
153
  node
155
154
  end
@@ -17,9 +17,7 @@ module RuboCop
17
17
  alias on_and_asgn on_lvasgn
18
18
 
19
19
  def on_send(node)
20
- rhs = extract_rhs(node)
21
-
22
- return unless rhs
20
+ return unless (rhs = extract_rhs(node))
23
21
 
24
22
  check_assignment(node, rhs)
25
23
  end
@@ -27,17 +25,11 @@ module RuboCop
27
25
  module_function
28
26
 
29
27
  def extract_rhs(node)
30
- if node.casgn_type?
31
- _scope, _lhs, rhs = *node
32
- elsif node.op_asgn_type?
33
- _lhs, _op, rhs = *node
34
- elsif node.call_type?
35
- rhs = node.last_argument
28
+ if node.call_type?
29
+ node.last_argument
36
30
  elsif node.assignment?
37
- _lhs, rhs = *node
31
+ node.expression
38
32
  end
39
-
40
- rhs
41
33
  end
42
34
  end
43
35
  end