rubocop 1.71.2 → 1.73.1

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +54 -11
  4. data/config/internal_affairs.yml +16 -0
  5. data/lib/rubocop/cli/command/suggest_extensions.rb +7 -1
  6. data/lib/rubocop/comment_config.rb +1 -1
  7. data/lib/rubocop/config.rb +4 -0
  8. data/lib/rubocop/config_loader.rb +44 -8
  9. data/lib/rubocop/config_loader_resolver.rb +23 -9
  10. data/lib/rubocop/config_validator.rb +1 -1
  11. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -2
  12. data/lib/rubocop/cop/internal_affairs/location_exists.rb +116 -0
  13. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -1
  14. data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
  15. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +7 -1
  16. data/lib/rubocop/cop/internal_affairs.rb +1 -16
  17. data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
  18. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +4 -4
  19. data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
  20. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  21. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +26 -1
  22. data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
  23. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  24. data/lib/rubocop/cop/layout/line_length.rb +3 -3
  25. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +2 -2
  26. data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
  27. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +84 -0
  28. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
  29. data/lib/rubocop/cop/lint/empty_conditional_body.rb +10 -5
  30. data/lib/rubocop/cop/lint/float_comparison.rb +1 -6
  31. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  32. data/lib/rubocop/cop/lint/literal_as_condition.rb +99 -9
  33. data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
  34. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  35. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +252 -0
  36. data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +111 -0
  37. data/lib/rubocop/cop/lint/useless_constant_scoping.rb +80 -0
  38. data/lib/rubocop/cop/lint/void.rb +6 -0
  39. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
  40. data/lib/rubocop/cop/mixin/alignment.rb +2 -2
  41. data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
  42. data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
  43. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +18 -18
  44. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
  45. data/lib/rubocop/cop/mixin/hash_transform_method.rb +74 -74
  46. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
  47. data/lib/rubocop/cop/mixin/range_help.rb +3 -3
  48. data/lib/rubocop/cop/mixin/string_help.rb +1 -1
  49. data/lib/rubocop/cop/mixin/trailing_comma.rb +12 -0
  50. data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
  51. data/lib/rubocop/cop/naming/predicate_name.rb +44 -0
  52. data/lib/rubocop/cop/naming/variable_name.rb +64 -6
  53. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  54. data/lib/rubocop/cop/style/arguments_forwarding.rb +3 -3
  55. data/lib/rubocop/cop/style/commented_keyword.rb +1 -1
  56. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  57. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  58. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
  59. data/lib/rubocop/cop/style/redundant_condition.rb +46 -0
  60. data/lib/rubocop/cop/style/redundant_format.rb +250 -0
  61. data/lib/rubocop/cop/style/redundant_parentheses.rb +18 -4
  62. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
  63. data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
  64. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  65. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  66. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  67. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  68. data/lib/rubocop/cop/util.rb +1 -1
  69. data/lib/rubocop/cop/utils/format_string.rb +7 -5
  70. data/lib/rubocop/cops_documentation_generator.rb +12 -1
  71. data/lib/rubocop/directive_comment.rb +35 -2
  72. data/lib/rubocop/lsp/runtime.rb +2 -0
  73. data/lib/rubocop/lsp/server.rb +0 -2
  74. data/lib/rubocop/options.rb +26 -11
  75. data/lib/rubocop/path_util.rb +4 -0
  76. data/lib/rubocop/plugin/configuration_integrator.rb +143 -0
  77. data/lib/rubocop/plugin/load_error.rb +26 -0
  78. data/lib/rubocop/plugin/loader.rb +100 -0
  79. data/lib/rubocop/plugin/not_supported_error.rb +29 -0
  80. data/lib/rubocop/plugin.rb +46 -0
  81. data/lib/rubocop/rake_task.rb +4 -1
  82. data/lib/rubocop/rspec/cop_helper.rb +9 -0
  83. data/lib/rubocop/rspec/shared_contexts.rb +15 -0
  84. data/lib/rubocop/rspec/support.rb +1 -0
  85. data/lib/rubocop/server/cache.rb +35 -2
  86. data/lib/rubocop/server/cli.rb +2 -2
  87. data/lib/rubocop/version.rb +17 -2
  88. data/lib/rubocop.rb +5 -1
  89. data/lib/ruby_lsp/rubocop/addon.rb +7 -10
  90. data/lib/ruby_lsp/rubocop/{wraps_built_in_lsp_runtime.rb → runtime_adapter.rb} +5 -8
  91. metadata +35 -10
  92. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
@@ -73,6 +73,8 @@ module RuboCop
73
73
  # @!method block_end_align_target?(node, child)
74
74
  def_node_matcher :block_end_align_target?, <<~PATTERN
75
75
  {assignment?
76
+ def
77
+ defs
76
78
  splat
77
79
  and
78
80
  or
@@ -155,10 +155,10 @@ module RuboCop
155
155
  end
156
156
 
157
157
  def all_elements_aligned?(elements)
158
- elements.flat_map do |e|
159
- if e.hash_type?
160
- e.each_child_node.map { |child| child.loc.column }
161
- else
158
+ if elements.first.hash_type?
159
+ elements.first.each_child_node.map { |child| child.loc.column }
160
+ else
161
+ elements.flat_map do |e|
162
162
  e.loc.column
163
163
  end
164
164
  end.uniq.count == 1
@@ -49,7 +49,7 @@ module RuboCop
49
49
  end
50
50
 
51
51
  def on_rescue(node)
52
- return unless node.loc.respond_to?(:else) && node.loc.else
52
+ return unless node.loc?(:else)
53
53
 
54
54
  check_alignment(base_range_of_rescue(node), node.loc.else)
55
55
  end
@@ -189,7 +189,7 @@ module RuboCop
189
189
  end
190
190
 
191
191
  def offense_location(node)
192
- if node.loc.respond_to?(:end) && node.loc.end
192
+ if node.loc?(:end)
193
193
  node.loc.end
194
194
  else
195
195
  node
@@ -93,7 +93,7 @@ module RuboCop
93
93
  add_offense(node, message: message) do |corrector|
94
94
  line = range_by_whole_lines(node.source_range)
95
95
 
96
- corrector.insert_before(line, "\n") unless previous_line_empty?(node.first_line)
96
+ corrector.insert_before(line, "\n") if should_insert_line_before?(node)
97
97
 
98
98
  correct_next_line_if_denied_style(corrector, node, line)
99
99
  end
@@ -122,6 +122,8 @@ module RuboCop
122
122
  end
123
123
 
124
124
  def correct_next_line_if_denied_style(corrector, node, line)
125
+ return unless should_insert_line_after?(node)
126
+
125
127
  case style
126
128
  when :around
127
129
  corrector.insert_after(line, "\n") unless next_line_empty?(node.last_line)
@@ -205,6 +207,29 @@ module RuboCop
205
207
  format(MSG_BEFORE_FOR_ONLY_BEFORE, modifier: modifier)
206
208
  end
207
209
  end
210
+
211
+ def should_insert_line_before?(node)
212
+ return false if previous_line_empty?(node.first_line)
213
+ return true unless inside_block?(node) && no_empty_lines_around_block_body?
214
+ return true unless node.parent.begin_type?
215
+
216
+ node.parent.children.first != node
217
+ end
218
+
219
+ def should_insert_line_after?(node)
220
+ return true unless inside_block?(node) && no_empty_lines_around_block_body?
221
+
222
+ node.parent.children.last != node
223
+ end
224
+
225
+ def inside_block?(node)
226
+ node.parent.block_type? || (node.parent.begin_type? && node.parent.parent&.block_type?)
227
+ end
228
+
229
+ def no_empty_lines_around_block_body?
230
+ config.for_enabled_cop('Layout/EmptyLinesAroundBlockBody')['EnforcedStyle'] ==
231
+ 'no_empty_lines'
232
+ end
208
233
  end
209
234
  end
210
235
  end
@@ -27,9 +27,14 @@ module RuboCop
27
27
  KIND = 'method'
28
28
 
29
29
  def on_def(node)
30
- first_line = node.arguments.source_range&.last_line
30
+ if node.endless?
31
+ return unless offending_endless_method?(node)
31
32
 
32
- check(node, node.body, adjusted_first_line: first_line)
33
+ register_offense_for_endless_method(node)
34
+ else
35
+ first_line = node.arguments.source_range&.last_line
36
+ check(node, node.body, adjusted_first_line: first_line)
37
+ end
33
38
  end
34
39
  alias on_defs on_def
35
40
 
@@ -38,6 +43,21 @@ module RuboCop
38
43
  def style
39
44
  :no_empty_lines
40
45
  end
46
+
47
+ def offending_endless_method?(node)
48
+ node.body.first_line > node.loc.assignment.line + 1 &&
49
+ processed_source.lines[node.loc.assignment.line].empty?
50
+ end
51
+
52
+ def register_offense_for_endless_method(node)
53
+ range = processed_source.buffer.line_range(node.loc.assignment.line + 1).resize(1)
54
+
55
+ msg = message(MSG_EXTRA, 'beginning')
56
+
57
+ add_offense(range, message: msg) do |corrector|
58
+ corrector.remove(range)
59
+ end
60
+ end
41
61
  end
42
62
  end
43
63
  end
@@ -162,7 +162,7 @@ module RuboCop
162
162
 
163
163
  def end_keyword_before_closing_parenthesis?(parenthesized_send_node)
164
164
  parenthesized_send_node.ancestors.any? do |ancestor|
165
- ancestor.loc.respond_to?(:end) && ancestor.loc.end&.source == 'end'
165
+ ancestor.loc_is?(:end, 'end')
166
166
  end
167
167
  end
168
168
 
@@ -209,7 +209,7 @@ module RuboCop
209
209
  # are not bisected.
210
210
  # If the string contains spaces, use them to determine a place for a clean break;
211
211
  # otherwise, the string will be broken at the line length limit.
212
- def breakable_string_range(node) # rubocop:disable Metrics/AbcSize
212
+ def breakable_string_range(node)
213
213
  source_range = node.source_range
214
214
  relevant_substr = largest_possible_string(node)
215
215
 
@@ -221,13 +221,13 @@ module RuboCop
221
221
  adjustment = max - source_range.last_column - 3
222
222
  return if adjustment.abs > source_range.size
223
223
 
224
- source_range.adjust(end_pos: max - source_range.last_column - 3)
224
+ source_range.adjust(end_pos: adjustment)
225
225
  end
226
226
  end
227
227
 
228
228
  def breakable_dstr_begin_position(node)
229
229
  source_range = node.source_range
230
- source_range.begin_pos if source_range.begin_pos < max && source_range.end_pos >= max
230
+ source_range.begin_pos if source_range.column < max && source_range.last_column >= max
231
231
  end
232
232
 
233
233
  def breakable_range_by_line_index
@@ -216,7 +216,7 @@ module RuboCop
216
216
 
217
217
  def get_dot_right_above(node)
218
218
  node.each_ancestor.find do |a|
219
- dot = a.loc.respond_to?(:dot) && a.loc.dot
219
+ dot = a.loc.dot if a.loc?(:dot)
220
220
  next unless dot
221
221
 
222
222
  dot.line == node.loc.dot.line - 1 && dot.column == node.loc.dot.column
@@ -239,7 +239,7 @@ module RuboCop
239
239
  node = node.receiver while node.receiver
240
240
  # ascend to first call which has a dot
241
241
  node = node.parent
242
- node = node.parent until node.loc.respond_to?(:dot) && node.loc.dot
242
+ node = node.parent until node.loc?(:dot)
243
243
 
244
244
  node
245
245
  end
@@ -51,7 +51,7 @@ module RuboCop
51
51
  alias on_csend on_send
52
52
 
53
53
  def on_const(node)
54
- return unless node.loc.respond_to?(:double_colon) && node.loc.double_colon
54
+ return unless node.loc?(:double_colon)
55
55
 
56
56
  check_space_after_double_colon(node)
57
57
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rubocop:disable Lint/RedundantCopDisableDirective
4
+ # rubocop:disable Style/DoubleCopDisableDirective
5
+ module RuboCop
6
+ module Cop
7
+ module Lint
8
+ # Checks that `# rubocop:enable ...` and `# rubocop:disable ...` statements
9
+ # are strictly formatted.
10
+ #
11
+ # A comment can be added to the directive by prefixing it with `--`.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # # rubocop:disable Layout/LineLength Style/Encoding
16
+ # # ^ missing comma
17
+ #
18
+ # # bad
19
+ # # rubocop:disable
20
+ #
21
+ # # bad
22
+ # # rubocop:disable Layout/LineLength # rubocop:disable Style/Encoding
23
+ #
24
+ # # bad
25
+ # # rubocop:wrongmode Layout/LineLength
26
+ #
27
+ # # good
28
+ # # rubocop:disable Layout/LineLength
29
+ #
30
+ # # good
31
+ # # rubocop:disable Layout/LineLength, Style/Encoding
32
+ #
33
+ # # good
34
+ # # rubocop:disable all
35
+ #
36
+ # # good
37
+ # # rubocop:disable Layout/LineLength -- This is a good comment.
38
+ #
39
+ class CopDirectiveSyntax < Base
40
+ COMMON_MSG = 'Malformed directive comment detected.'
41
+
42
+ MISSING_MODE_NAME_MSG = 'The mode name is missing.'
43
+ INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, or `todo`.'
44
+ MISSING_COP_NAME_MSG = 'The cop name is missing.'
45
+ MALFORMED_COP_NAMES_MSG = 'Cop names must be separated by commas. ' \
46
+ 'Comment in the directive must start with `--`.'
47
+
48
+ def on_new_investigation
49
+ processed_source.comments.each do |comment|
50
+ directive_comment = DirectiveComment.new(comment)
51
+ next unless directive_comment.start_with_marker?
52
+ next unless directive_comment.malformed?
53
+
54
+ message = offense_message(directive_comment)
55
+ add_offense(comment, message: message)
56
+ end
57
+ end
58
+
59
+ private
60
+
61
+ # rubocop:disable Metrics/MethodLength
62
+ def offense_message(directive_comment)
63
+ comment = directive_comment.comment
64
+ after_marker = comment.text.sub(DirectiveComment::DIRECTIVE_MARKER_REGEXP, '')
65
+ mode = after_marker.split(' ', 2).first
66
+ additional_msg = if mode.nil?
67
+ MISSING_MODE_NAME_MSG
68
+ elsif !DirectiveComment::AVAILABLE_MODES.include?(mode)
69
+ INVALID_MODE_NAME_MSG
70
+ elsif directive_comment.missing_cop_name?
71
+ MISSING_COP_NAME_MSG
72
+ else
73
+ MALFORMED_COP_NAMES_MSG
74
+ end
75
+
76
+ "#{COMMON_MSG} #{additional_msg}"
77
+ end
78
+ # rubocop:enable Metrics/MethodLength
79
+ end
80
+ end
81
+ end
82
+ end
83
+ # rubocop:enable Lint/RedundantCopDisableDirective
84
+ # rubocop:enable Style/DoubleCopDisableDirective
@@ -54,14 +54,12 @@ module RuboCop
54
54
  # if a method definition is inside an if, it is very likely
55
55
  # that a different definition is used depending on platform, etc.
56
56
  return if node.each_ancestor.any?(&:if_type?)
57
- return if possible_dsl?(node)
58
57
 
59
58
  found_instance_method(node, node.method_name)
60
59
  end
61
60
 
62
61
  def on_defs(node)
63
62
  return if node.each_ancestor.any?(&:if_type?)
64
- return if possible_dsl?(node)
65
63
 
66
64
  if node.receiver.const_type?
67
65
  _, const_name = *node.receiver
@@ -79,7 +77,6 @@ module RuboCop
79
77
  def on_alias(node)
80
78
  return unless (name = method_alias?(node))
81
79
  return if node.ancestors.any?(&:if_type?)
82
- return if possible_dsl?(node)
83
80
 
84
81
  found_instance_method(node, name)
85
82
  end
@@ -94,7 +91,6 @@ module RuboCop
94
91
  def on_send(node)
95
92
  if (name = alias_method?(node))
96
93
  return if node.ancestors.any?(&:if_type?)
97
- return if possible_dsl?(node)
98
94
 
99
95
  found_instance_method(node, name)
100
96
  elsif (attr = node.attribute_accessor?)
@@ -237,16 +233,6 @@ module RuboCop
237
233
  end
238
234
  end
239
235
 
240
- def possible_dsl?(node)
241
- # DSL methods may evaluate a block in the context of a newly created
242
- # class or module
243
- # Assume that if a method definition is inside any block call which
244
- # we can't identify, it could be a DSL
245
- node.each_ancestor(:block).any? do |ancestor|
246
- !ancestor.method?(:class_eval) && !ancestor.class_constructor?
247
- end
248
- end
249
-
250
236
  def source_location(node)
251
237
  range = node.source_range
252
238
  path = smart_path(range.source_buffer.name)
@@ -67,7 +67,6 @@ module RuboCop
67
67
 
68
68
  MSG = 'Avoid `%<keyword>s` branches without a body.'
69
69
 
70
- # rubocop:disable Metrics/AbcSize
71
70
  def on_if(node)
72
71
  return if node.body || same_line?(node.loc.begin, node.loc.end)
73
72
  return if cop_config['AllowComments'] && contains_comments?(node)
@@ -75,15 +74,21 @@ module RuboCop
75
74
  range = offense_range(node)
76
75
 
77
76
  add_offense(range, message: format(MSG, keyword: node.keyword)) do |corrector|
78
- next if node.parent&.call_type?
79
-
80
- autocorrect(corrector, node)
77
+ autocorrect(corrector, node) if do_autocorrect?(node)
81
78
  end
82
79
  end
83
- # rubocop:enable Metrics/AbcSize
84
80
 
85
81
  private
86
82
 
83
+ def do_autocorrect?(node)
84
+ # if condition; end.do_something
85
+ return false if (parent = node.parent)&.call_type?
86
+ # x = if condition; end
87
+ return false if (parent&.assignment? || parent&.operator_keyword?) && node.children.one?
88
+
89
+ true
90
+ end
91
+
87
92
  def offense_range(node)
88
93
  if node.loc.else
89
94
  node.source_range.begin.join(node.loc.else.begin)
@@ -81,21 +81,16 @@ module RuboCop
81
81
  (node.numeric_type? && node.value.zero?) || node.nil_type?
82
82
  end
83
83
 
84
- # rubocop:disable Metrics/PerceivedComplexity
85
84
  def check_send(node)
86
85
  if node.arithmetic_operation?
87
86
  float?(node.receiver) || float?(node.first_argument)
88
87
  elsif FLOAT_RETURNING_METHODS.include?(node.method_name)
89
88
  true
90
89
  elsif node.receiver&.float_type?
91
- if FLOAT_INSTANCE_METHODS.include?(node.method_name)
92
- true
93
- else
90
+ FLOAT_INSTANCE_METHODS.include?(node.method_name) ||
94
91
  check_numeric_returning_method(node)
95
- end
96
92
  end
97
93
  end
98
- # rubocop:enable Metrics/PerceivedComplexity
99
94
 
100
95
  def check_numeric_returning_method(node)
101
96
  return false unless node.receiver
@@ -7,7 +7,7 @@ module RuboCop
7
7
  # expected fields for format/sprintf/#% and what is actually
8
8
  # passed as arguments.
9
9
  #
10
- # In addition it checks whether different formats are used in the same
10
+ # In addition, it checks whether different formats are used in the same
11
11
  # format string. Do not mix numbered, unnumbered, and named formats in
12
12
  # the same format string.
13
13
  #
@@ -18,12 +18,15 @@ module RuboCop
18
18
  # end
19
19
  #
20
20
  # # bad
21
- # if some_var && true
21
+ # # We're only interested in the left hand side being a truthy literal,
22
+ # # because it affects the evaluation of the &&, whereas the right hand
23
+ # # side will be conditionally executed/called and can be a literal.
24
+ # if true && some_var
22
25
  # do_something
23
26
  # end
24
27
  #
25
28
  # # good
26
- # if some_var && some_condition
29
+ # if some_var
27
30
  # do_something
28
31
  # end
29
32
  #
@@ -34,27 +37,90 @@ module RuboCop
34
37
  # end
35
38
  class LiteralAsCondition < Base
36
39
  include RangeHelp
40
+ extend AutoCorrector
37
41
 
38
42
  MSG = 'Literal `%<literal>s` appeared as a condition.'
39
43
  RESTRICT_ON_SEND = [:!].freeze
40
44
 
45
+ def on_and(node)
46
+ return unless node.lhs.truthy_literal?
47
+
48
+ add_offense(node.lhs) do |corrector|
49
+ corrector.replace(node, node.rhs.source)
50
+ end
51
+ end
52
+
41
53
  def on_if(node)
42
- check_for_literal(node)
54
+ cond = condition(node)
55
+
56
+ if node.unless?
57
+ correct_if_node(node, cond, true) if cond.falsey_literal?
58
+ correct_if_node(node, cond, false) if cond.truthy_literal?
59
+ else
60
+ correct_if_node(node, cond, true) if cond.truthy_literal?
61
+ correct_if_node(node, cond, false) if cond.falsey_literal?
62
+ end
43
63
  end
44
64
 
45
65
  def on_while(node)
46
- return if condition(node).true_type?
66
+ return if node.condition.source == 'true'
47
67
 
48
- check_for_literal(node)
68
+ if node.condition.truthy_literal?
69
+ add_offense(node.condition) do |corrector|
70
+ corrector.replace(node.condition, 'true')
71
+ end
72
+ elsif node.condition.falsey_literal?
73
+ add_offense(node.condition) do |corrector|
74
+ corrector.remove(node)
75
+ end
76
+ end
77
+ end
78
+
79
+ # rubocop:disable Metrics/AbcSize
80
+ def on_while_post(node)
81
+ return if node.condition.source == 'true'
82
+
83
+ if node.condition.truthy_literal?
84
+ add_offense(node.condition) do |corrector|
85
+ corrector.replace(node, node.source.sub(node.condition.source, 'true'))
86
+ end
87
+ elsif node.condition.falsey_literal?
88
+ add_offense(node.condition) do |corrector|
89
+ corrector.replace(node, node.body.child_nodes.map(&:source).join("\n"))
90
+ end
91
+ end
49
92
  end
50
- alias on_while_post on_while
93
+ # rubocop:enable Metrics/AbcSize
51
94
 
52
95
  def on_until(node)
53
- return if condition(node).false_type?
96
+ return if node.condition.source == 'false'
54
97
 
55
- check_for_literal(node)
98
+ if node.condition.falsey_literal?
99
+ add_offense(node.condition) do |corrector|
100
+ corrector.replace(node.condition, 'false')
101
+ end
102
+ elsif node.condition.truthy_literal?
103
+ add_offense(node.condition) do |corrector|
104
+ corrector.remove(node)
105
+ end
106
+ end
107
+ end
108
+
109
+ # rubocop:disable Metrics/AbcSize
110
+ def on_until_post(node)
111
+ return if node.condition.source == 'false'
112
+
113
+ if node.condition.falsey_literal?
114
+ add_offense(node.condition) do |corrector|
115
+ corrector.replace(node, node.source.sub(node.condition.source, 'false'))
116
+ end
117
+ elsif node.condition.truthy_literal?
118
+ add_offense(node.condition) do |corrector|
119
+ corrector.replace(node, node.body.child_nodes.map(&:source).join("\n"))
120
+ end
121
+ end
56
122
  end
57
- alias on_until_post on_until
123
+ # rubocop:enable Metrics/AbcSize
58
124
 
59
125
  def on_case(case_node)
60
126
  if case_node.condition
@@ -130,6 +196,8 @@ module RuboCop
130
196
 
131
197
  def handle_node(node)
132
198
  if node.literal?
199
+ return if node.parent.and_type?
200
+
133
201
  add_offense(node)
134
202
  elsif %i[send and or begin].include?(node.type)
135
203
  check_node(node)
@@ -159,6 +227,28 @@ module RuboCop
159
227
  when_node.conditions.last.source_range.end_pos
160
228
  )
161
229
  end
230
+
231
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
232
+ def correct_if_node(node, cond, result)
233
+ if result
234
+ add_offense(cond) do |corrector|
235
+ corrector.replace(node, node.if_branch.source)
236
+ end
237
+ elsif node.elsif_conditional?
238
+ add_offense(cond) do |corrector|
239
+ corrector.replace(node, "#{node.else_branch.source.sub('elsif', 'if')}\nend")
240
+ end
241
+ elsif node.else? || node.ternary?
242
+ add_offense(cond) do |corrector|
243
+ corrector.replace(node, node.else_branch.source)
244
+ end
245
+ else
246
+ add_offense(cond) do |corrector|
247
+ corrector.remove(node)
248
+ end
249
+ end
250
+ end
251
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
162
252
  end
163
253
  end
164
254
  end
@@ -79,7 +79,7 @@ module RuboCop
79
79
  end
80
80
 
81
81
  def range_pairs(expr)
82
- RuboCop::Cop::Utils::RegexpRanges.new(expr).pairs
82
+ expr.expressions.filter_map { |e| [e.expressions[0], e.expressions[1]] if e.type == :set }
83
83
  end
84
84
 
85
85
  def unsafe_range?(range_start, range_end)
@@ -94,7 +94,7 @@ module RuboCop
94
94
 
95
95
  def skip_range?(range_start, range_end)
96
96
  [range_start, range_end].any? do |bound|
97
- bound.type != :literal
97
+ bound&.type != :literal
98
98
  end
99
99
  end
100
100
 
@@ -17,17 +17,12 @@ module RuboCop
17
17
  # * 2.0+ ... `enumerator`
18
18
  # * 2.1+ ... `thread`
19
19
  # * 2.2+ ... Add `rational` and `complex` above
20
- # * 2.5+ ... Add `pp` above
21
20
  # * 2.7+ ... Add `ruby2_keywords` above
22
21
  # * 3.1+ ... Add `fiber` above
23
22
  # * 3.2+ ... `set`
24
23
  #
25
24
  # This cop target those features.
26
25
  #
27
- # @safety
28
- # This cop's autocorrection is unsafe because if `require 'pp'` is removed from one file,
29
- # `NameError` can be encountered when another file uses `PP.pp`.
30
- #
31
26
  # @example
32
27
  # # bad
33
28
  # require 'unloaded_feature'
@@ -42,10 +37,6 @@ module RuboCop
42
37
  MSG = 'Remove unnecessary `require` statement.'
43
38
  RESTRICT_ON_SEND = %i[require].freeze
44
39
  RUBY_22_LOADED_FEATURES = %w[rational complex].freeze
45
- PRETTY_PRINT_METHODS = %i[
46
- pretty_inspect pretty_print pretty_print_cycle
47
- pretty_print_inspect pretty_print_instance_variables
48
- ].freeze
49
40
 
50
41
  # @!method redundant_require_statement?(node)
51
42
  def_node_matcher :redundant_require_statement?, <<~PATTERN
@@ -53,11 +44,6 @@ module RuboCop
53
44
  (str #redundant_feature?))
54
45
  PATTERN
55
46
 
56
- # @!method pp_const?(node)
57
- def_node_matcher :pp_const?, <<~PATTERN
58
- (const {nil? cbase} :PP)
59
- PATTERN
60
-
61
47
  def on_send(node)
62
48
  return unless redundant_require_statement?(node)
63
49
 
@@ -81,18 +67,11 @@ module RuboCop
81
67
  feature_name == 'enumerator' ||
82
68
  (target_ruby_version >= 2.1 && feature_name == 'thread') ||
83
69
  (target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
84
- (target_ruby_version >= 2.5 && feature_name == 'pp' && !need_to_require_pp?) ||
85
70
  (target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
86
71
  (target_ruby_version >= 3.1 && feature_name == 'fiber') ||
87
72
  (target_ruby_version >= 3.2 && feature_name == 'set')
88
73
  end
89
74
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
90
-
91
- def need_to_require_pp?
92
- processed_source.ast.each_descendant(:send).any? do |node|
93
- pp_const?(node.receiver) || PRETTY_PRINT_METHODS.include?(node.method_name)
94
- end
95
- end
96
75
  end
97
76
  end
98
77
  end