rubocop 1.72.2 → 1.73.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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +21 -11
  4. data/config/internal_affairs.yml +16 -0
  5. data/lib/rubocop/config_loader_resolver.rb +2 -2
  6. data/lib/rubocop/config_validator.rb +1 -1
  7. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +26 -1
  8. data/lib/rubocop/cop/layout/line_length.rb +3 -3
  9. data/lib/rubocop/cop/lint/duplicate_methods.rb +0 -14
  10. data/lib/rubocop/cop/lint/float_comparison.rb +1 -6
  11. data/lib/rubocop/cop/lint/literal_as_condition.rb +104 -7
  12. data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
  13. data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
  14. data/lib/rubocop/cop/lint/redundant_type_conversion.rb +23 -2
  15. data/lib/rubocop/cop/lint/void.rb +6 -0
  16. data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
  17. data/lib/rubocop/cop/mixin/trailing_comma.rb +12 -0
  18. data/lib/rubocop/cop/naming/variable_name.rb +64 -6
  19. data/lib/rubocop/cop/style/accessor_grouping.rb +19 -5
  20. data/lib/rubocop/cop/style/endless_method.rb +163 -18
  21. data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
  22. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
  23. data/lib/rubocop/cop/style/redundant_condition.rb +34 -0
  24. data/lib/rubocop/cop/style/redundant_format.rb +23 -11
  25. data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
  26. data/lib/rubocop/cop/style/single_line_methods.rb +3 -3
  27. data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
  28. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
  29. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
  30. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  31. data/lib/rubocop/cops_documentation_generator.rb +12 -1
  32. data/lib/rubocop/plugin/load_error.rb +1 -1
  33. data/lib/rubocop/plugin.rb +9 -2
  34. data/lib/rubocop/rspec/shared_contexts.rb +15 -0
  35. data/lib/rubocop/rspec/support.rb +1 -0
  36. data/lib/rubocop/version.rb +1 -1
  37. data/lib/rubocop.rb +0 -1
  38. metadata +4 -5
  39. data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4a6ff0f849d961da13d2131ff60e0ed49dce01a4c2d32caa8484a2344344609b
4
- data.tar.gz: 9da9fc43212c62cd6542649c90423e9365f50cb00e82b6337be1a241c6a17283
3
+ metadata.gz: e3d6b4b7f7dd2a3128259ff94614da64550ae7c4148106a681987a9ee739b905
4
+ data.tar.gz: 023ed07c7e4445c1dc44b3062cf0199321e3cc7fc6d4abf55287d281519bdb11
5
5
  SHA512:
6
- metadata.gz: 7ff34957554167b3b1e30645e3754094968fae93d0284a3882460b3e24f44fd64bcf358b23fd0e8154489206fd9c95fc6555b551f1af5ac810805fac2b6d27be
7
- data.tar.gz: 48e989049de37523554c740ba1368e32de38bc0f879c1fc717924a758a1ba465ef4413cba80a42be59ccaaf87616b52c0ad437256702bf5fd091c4a5818f428a
6
+ metadata.gz: cfc82c25468c882682017c7ab8f750970896dcacae270fc00fc6482e4a7d12a20c97f7f56509811fec8c811981be457fc450c977c058d72700490ae72a4aff0a
7
+ data.tar.gz: 04cfd985c5527d40ba6fd11e33e64278f37b8fcd78a63cfcdf5fef317bef248bfc8771febfa39a05a474372c1ad56190766dc7a188ea9e17bc72031f16d672da
data/README.md CHANGED
@@ -52,7 +52,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
52
52
  in your `Gemfile`:
53
53
 
54
54
  ```rb
55
- gem 'rubocop', '~> 1.72', require: false
55
+ gem 'rubocop', '~> 1.73', require: false
56
56
  ```
57
57
 
58
58
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -241,9 +241,9 @@ Become a sponsor and get your logo on our README on GitHub with a link to your s
241
241
  <a href="https://opencollective.com/rubocop/organization/28/website" target="_blank"><img src="https://opencollective.com/rubocop/organization/28/avatar.svg"></a>
242
242
  <a href="https://opencollective.com/rubocop/organization/29/website" target="_blank"><img src="https://opencollective.com/rubocop/organization/29/avatar.svg"></a>
243
243
 
244
- ## Changelog
244
+ ## Release Notes
245
245
 
246
- RuboCop's changelog is available [here](CHANGELOG.md).
246
+ RuboCop's release notes are available [here](https://github.com/rubocop/rubocop/releases).
247
247
 
248
248
  ## Copyright
249
249
 
data/config/default.yml CHANGED
@@ -2046,6 +2046,7 @@ Lint/LambdaWithoutLiteralBlock:
2046
2046
  Lint/LiteralAsCondition:
2047
2047
  Description: 'Checks of literals used in conditions.'
2048
2048
  Enabled: true
2049
+ AutoCorrect: contextual
2049
2050
  VersionAdded: '0.51'
2050
2051
 
2051
2052
  Lint/LiteralAssignmentInCondition:
@@ -2259,9 +2260,8 @@ Lint/RedundantRegexpQuantifiers:
2259
2260
  Lint/RedundantRequireStatement:
2260
2261
  Description: 'Checks for unnecessary `require` statement.'
2261
2262
  Enabled: true
2262
- SafeAutoCorrect: false
2263
2263
  VersionAdded: '0.76'
2264
- VersionChanged: '1.57'
2264
+ VersionChanged: '1.73'
2265
2265
 
2266
2266
  Lint/RedundantSafeNavigation:
2267
2267
  Description: 'Checks for redundant safe navigation calls.'
@@ -3081,13 +3081,15 @@ Naming/VariableName:
3081
3081
  StyleGuide: '#snake-case-symbols-methods-vars'
3082
3082
  Enabled: true
3083
3083
  VersionAdded: '0.50'
3084
- VersionChanged: '1.8'
3084
+ VersionChanged: '1.73'
3085
3085
  EnforcedStyle: snake_case
3086
3086
  SupportedStyles:
3087
3087
  - snake_case
3088
3088
  - camelCase
3089
3089
  AllowedIdentifiers: []
3090
3090
  AllowedPatterns: []
3091
+ ForbiddenIdentifiers: []
3092
+ ForbiddenPatterns: []
3091
3093
 
3092
3094
  Naming/VariableNumber:
3093
3095
  Description: 'Use the configured style when numbering symbols, methods and variables.'
@@ -3922,6 +3924,8 @@ Style/EndlessMethod:
3922
3924
  - allow_single_line
3923
3925
  - allow_always
3924
3926
  - disallow
3927
+ - require_single_line
3928
+ - require_always
3925
3929
 
3926
3930
  Style/EnvHome:
3927
3931
  Description: "Checks for consistent usage of `ENV['HOME']`."
@@ -5701,14 +5705,17 @@ Style/TrailingCommaInArrayLiteral:
5701
5705
  StyleGuide: '#no-trailing-array-commas'
5702
5706
  Enabled: true
5703
5707
  VersionAdded: '0.53'
5704
- # If `comma`, the cop requires a comma after the last item in an array,
5705
- # but only when each item is on its own line.
5706
- # If `consistent_comma`, the cop requires a comma after the last item of all
5707
- # non-empty, multiline array literals.
5708
+ # If `comma`, the cop requires a comma after the last item in an array, but only when each item is
5709
+ # on its own line.
5710
+ # If `consistent_comma`, the cop requires a comma after the last item of all non-empty, multiline
5711
+ # array literals.
5712
+ # If `diff_comma`, the cop requires a comma after the last item of all non-empty, multiline array
5713
+ # literals, but only when that last item immediately precedes a newline.
5708
5714
  EnforcedStyleForMultiline: no_comma
5709
5715
  SupportedStylesForMultiline:
5710
5716
  - comma
5711
5717
  - consistent_comma
5718
+ - diff_comma
5712
5719
  - no_comma
5713
5720
 
5714
5721
  Style/TrailingCommaInBlockArgs:
@@ -5720,14 +5727,17 @@ Style/TrailingCommaInBlockArgs:
5720
5727
  Style/TrailingCommaInHashLiteral:
5721
5728
  Description: 'Checks for trailing comma in hash literals.'
5722
5729
  Enabled: true
5723
- # If `comma`, the cop requires a comma after the last item in a hash,
5724
- # but only when each item is on its own line.
5725
- # If `consistent_comma`, the cop requires a comma after the last item of all
5726
- # non-empty, multiline hash literals.
5730
+ # If `comma`, the cop requires a comma after the last item in a hash, but only when each item is
5731
+ # on its own line.
5732
+ # If `consistent_comma`, the cop requires a comma after the last item of all non-empty, multiline
5733
+ # hash literals.
5734
+ # If `diff_comma`, the cop requires a comma after the last item of all non-empty, multiline hash
5735
+ # literals, but only when that last item immediately precedes a newline.
5727
5736
  EnforcedStyleForMultiline: no_comma
5728
5737
  SupportedStylesForMultiline:
5729
5738
  - comma
5730
5739
  - consistent_comma
5740
+ - diff_comma
5731
5741
  - no_comma
5732
5742
  VersionAdded: '0.53'
5733
5743
 
@@ -6,6 +6,22 @@ InternalAffairs/CopDescription:
6
6
  Include:
7
7
  - 'lib/rubocop/cop/**/*.rb'
8
8
 
9
+ InternalAffairs/ExampleHeredocDelimiter:
10
+ Include:
11
+ - 'spec/rubocop/cop/**/*.rb'
12
+
13
+ InternalAffairs/ExampleDescription:
14
+ Include:
15
+ - 'spec/rubocop/cop/**/*.rb'
16
+
17
+ InternalAffairs/OnSendWithoutOnCSend:
18
+ Include:
19
+ - 'lib/rubocop/cop/**/*.rb'
20
+
21
+ InternalAffairs/UndefinedConfig:
22
+ Include:
23
+ - 'lib/rubocop/cop/**/*.rb'
24
+
9
25
  InternalAffairs/UselessMessageAssertion:
10
26
  Include:
11
27
  - '**/*_spec.rb'
@@ -123,7 +123,7 @@ module RuboCop
123
123
  elsif merge_hashes?(base_hash, derived_hash, key)
124
124
  result[key] = merge(base_hash[key], derived_hash[key], **opts)
125
125
  elsif should_union?(derived_hash, base_hash, opts[:inherit_mode], key)
126
- result[key] = base_hash[key] | derived_hash[key]
126
+ result[key] = Array(base_hash[key]) | Array(derived_hash[key])
127
127
  elsif opts[:debug]
128
128
  warn_on_duplicate_setting(base_hash, derived_hash, key, **opts)
129
129
  end
@@ -205,7 +205,7 @@ module RuboCop
205
205
  end
206
206
 
207
207
  def should_union?(derived_hash, base_hash, root_mode, key)
208
- return false unless base_hash[key].is_a?(Array)
208
+ return false unless base_hash[key].is_a?(Array) || derived_hash[key].is_a?(Array)
209
209
 
210
210
  derived_mode = derived_hash['inherit_mode']
211
211
  return false if should_override?(derived_mode, key)
@@ -9,7 +9,7 @@ module RuboCop
9
9
 
10
10
  # @api private
11
11
  COMMON_PARAMS = %w[Exclude Include Severity inherit_mode AutoCorrect StyleGuide Details
12
- Enabled].freeze
12
+ Enabled Reference].freeze
13
13
  # @api private
14
14
  INTERNAL_PARAMS = %w[Description StyleGuide
15
15
  VersionAdded VersionChanged VersionRemoved
@@ -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
@@ -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
@@ -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)
@@ -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
@@ -34,27 +34,100 @@ module RuboCop
34
34
  # end
35
35
  class LiteralAsCondition < Base
36
36
  include RangeHelp
37
+ extend AutoCorrector
37
38
 
38
39
  MSG = 'Literal `%<literal>s` appeared as a condition.'
39
40
  RESTRICT_ON_SEND = [:!].freeze
40
41
 
42
+ # rubocop:disable Metrics/AbcSize
43
+ def on_and(node)
44
+ if node.lhs.truthy_literal? && node.rhs.truthy_literal?
45
+ add_offense(node) do |corrector|
46
+ corrector.replace(node, 'true')
47
+ end
48
+ elsif node.lhs.truthy_literal?
49
+ add_offense(node.lhs) do |corrector|
50
+ corrector.replace(node, node.rhs.source)
51
+ end
52
+ elsif node.rhs.truthy_literal?
53
+ add_offense(node.rhs) do |corrector|
54
+ corrector.replace(node, node.lhs.source)
55
+ end
56
+ end
57
+ end
58
+ # rubocop:enable Metrics/AbcSize
59
+
41
60
  def on_if(node)
42
- check_for_literal(node)
61
+ cond = condition(node)
62
+
63
+ if node.unless?
64
+ correct_if_node(node, cond, true) if cond.falsey_literal?
65
+ correct_if_node(node, cond, false) if cond.truthy_literal?
66
+ else
67
+ correct_if_node(node, cond, true) if cond.truthy_literal?
68
+ correct_if_node(node, cond, false) if cond.falsey_literal?
69
+ end
43
70
  end
44
71
 
45
72
  def on_while(node)
46
- return if condition(node).true_type?
73
+ return if node.condition.source == 'true'
47
74
 
48
- check_for_literal(node)
75
+ if node.condition.truthy_literal?
76
+ add_offense(node.condition) do |corrector|
77
+ corrector.replace(node.condition, 'true')
78
+ end
79
+ elsif node.condition.falsey_literal?
80
+ add_offense(node.condition) do |corrector|
81
+ corrector.remove(node)
82
+ end
83
+ end
84
+ end
85
+
86
+ # rubocop:disable Metrics/AbcSize
87
+ def on_while_post(node)
88
+ return if node.condition.source == 'true'
89
+
90
+ if node.condition.truthy_literal?
91
+ add_offense(node.condition) do |corrector|
92
+ corrector.replace(node, node.source.sub(node.condition.source, 'true'))
93
+ end
94
+ elsif node.condition.falsey_literal?
95
+ add_offense(node.condition) do |corrector|
96
+ corrector.replace(node, node.body.child_nodes.map(&:source).join("\n"))
97
+ end
98
+ end
49
99
  end
50
- alias on_while_post on_while
100
+ # rubocop:enable Metrics/AbcSize
51
101
 
52
102
  def on_until(node)
53
- return if condition(node).false_type?
103
+ return if node.condition.source == 'false'
54
104
 
55
- check_for_literal(node)
105
+ if node.condition.falsey_literal?
106
+ add_offense(node.condition) do |corrector|
107
+ corrector.replace(node.condition, 'false')
108
+ end
109
+ elsif node.condition.truthy_literal?
110
+ add_offense(node.condition) do |corrector|
111
+ corrector.remove(node)
112
+ end
113
+ end
114
+ end
115
+
116
+ # rubocop:disable Metrics/AbcSize
117
+ def on_until_post(node)
118
+ return if node.condition.source == 'false'
119
+
120
+ if node.condition.falsey_literal?
121
+ add_offense(node.condition) do |corrector|
122
+ corrector.replace(node, node.source.sub(node.condition.source, 'false'))
123
+ end
124
+ elsif node.condition.truthy_literal?
125
+ add_offense(node.condition) do |corrector|
126
+ corrector.replace(node, node.body.child_nodes.map(&:source).join("\n"))
127
+ end
128
+ end
56
129
  end
57
- alias on_until_post on_until
130
+ # rubocop:enable Metrics/AbcSize
58
131
 
59
132
  def on_case(case_node)
60
133
  if case_node.condition
@@ -130,6 +203,8 @@ module RuboCop
130
203
 
131
204
  def handle_node(node)
132
205
  if node.literal?
206
+ return if node.parent.and_type?
207
+
133
208
  add_offense(node)
134
209
  elsif %i[send and or begin].include?(node.type)
135
210
  check_node(node)
@@ -159,6 +234,28 @@ module RuboCop
159
234
  when_node.conditions.last.source_range.end_pos
160
235
  )
161
236
  end
237
+
238
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
239
+ def correct_if_node(node, cond, result)
240
+ if result
241
+ add_offense(cond) do |corrector|
242
+ corrector.replace(node, node.if_branch.source)
243
+ end
244
+ elsif node.elsif_conditional?
245
+ add_offense(cond) do |corrector|
246
+ corrector.replace(node, "#{node.else_branch.source.sub('elsif', 'if')}\nend")
247
+ end
248
+ elsif node.else? || node.ternary?
249
+ add_offense(cond) do |corrector|
250
+ corrector.replace(node, node.else_branch.source)
251
+ end
252
+ else
253
+ add_offense(cond) do |corrector|
254
+ corrector.remove(node)
255
+ end
256
+ end
257
+ end
258
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
162
259
  end
163
260
  end
164
261
  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)
@@ -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
@@ -39,7 +39,7 @@ module RuboCop
39
39
  # 1i.to_c
40
40
  # [].to_a
41
41
  # {}.to_h
42
- # Set.new.to_s
42
+ # Set.new.to_set
43
43
  #
44
44
  # # good
45
45
  # "text"
@@ -52,6 +52,16 @@ module RuboCop
52
52
  # {}
53
53
  # Set.new
54
54
  #
55
+ # # bad
56
+ # Integer(var).to_i
57
+ #
58
+ # # good
59
+ # Integer(var)
60
+ #
61
+ # # good - chaining to a type constructor with exceptions suppressed
62
+ # # in this case, `Integer()` could return `nil`
63
+ # Integer(var, exception: false).to_i
64
+ #
55
65
  # # bad - chaining the same conversion
56
66
  # foo.to_s.to_s
57
67
  #
@@ -161,6 +171,11 @@ module RuboCop
161
171
  }
162
172
  PATTERN
163
173
 
174
+ # @!method exception_false_keyword_argument?(node)
175
+ def_node_matcher :exception_false_keyword_argument?, <<~PATTERN
176
+ (hash (pair (sym :exception) false))
177
+ PATTERN
178
+
164
179
  # rubocop:disable Metrics/AbcSize
165
180
  def on_send(node)
166
181
  return if hash_or_set_with_block?(node)
@@ -211,7 +226,13 @@ module RuboCop
211
226
  matcher = CONSTRUCTOR_MAPPING[node.method_name]
212
227
  return false unless matcher
213
228
 
214
- public_send(matcher, receiver)
229
+ public_send(matcher, receiver) && !constructor_suppresses_exceptions?(receiver)
230
+ end
231
+
232
+ def constructor_suppresses_exceptions?(receiver)
233
+ # If the constructor suppresses exceptions with `exception: false`, it is possible
234
+ # it could return `nil`, and therefore a chained conversion is not redundant.
235
+ receiver.arguments.any? { |arg| exception_false_keyword_argument?(arg) }
215
236
  end
216
237
 
217
238
  def chained_conversion?(node, receiver)
@@ -125,9 +125,14 @@ module RuboCop
125
125
  check_nonmutating(expr)
126
126
  end
127
127
 
128
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
128
129
  def check_void_op(node, &block)
129
130
  node = node.children.first while node.begin_type?
130
131
  return unless node.call_type? && OPERATORS.include?(node.method_name)
132
+ if !UNARY_OPERATORS.include?(node.method_name) && node.loc.dot && node.arguments.none?
133
+ return
134
+ end
135
+
131
136
  return if block && yield(node)
132
137
 
133
138
  add_offense(node.loc.selector,
@@ -135,6 +140,7 @@ module RuboCop
135
140
  autocorrect_void_op(corrector, node)
136
141
  end
137
142
  end
143
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
138
144
 
139
145
  def check_var(node)
140
146
  return unless node.variable? || node.const_type?
@@ -23,7 +23,7 @@ module RuboCop
23
23
  (call _ _)
24
24
  (args
25
25
  $(arg _key)
26
- (arg _))
26
+ $(arg _))
27
27
  {
28
28
  $(send
29
29
  {(lvar _key) $_ _ | _ $_ (lvar _key)})
@@ -67,7 +67,7 @@ module RuboCop
67
67
  end
68
68
 
69
69
  def extracts_hash_subset?(block)
70
- block_with_first_arg_check?(block) do |key_arg, send_node, method|
70
+ block_with_first_arg_check?(block) do |key_arg, value_arg, send_node, method|
71
71
  # Only consider methods that have one argument
72
72
  return false unless send_node.arguments.one?
73
73
 
@@ -76,15 +76,22 @@ module RuboCop
76
76
 
77
77
  case method
78
78
  when :include?, :exclude?
79
- send_node.first_argument.source == key_arg.source
79
+ slices_key?(send_node, :first_argument, key_arg, value_arg)
80
80
  when :in?
81
- send_node.receiver.source == key_arg.source
81
+ slices_key?(send_node, :receiver, key_arg, value_arg)
82
82
  else
83
83
  true
84
84
  end
85
85
  end
86
86
  end
87
87
 
88
+ def slices_key?(send_node, method, key_arg, value_arg)
89
+ return false if using_value_variable?(send_node, value_arg)
90
+
91
+ node = method == :receiver ? send_node.receiver : send_node.first_argument
92
+ node.source == key_arg.source
93
+ end
94
+
88
95
  def range_include?(send_node)
89
96
  # When checking `include?`, `exclude?` and `in?` for offenses, if the receiver
90
97
  # or first argument is a range, an offense should not be registered.
@@ -97,6 +104,14 @@ module RuboCop
97
104
  receiver.range_type?
98
105
  end
99
106
 
107
+ def using_value_variable?(send_node, value_arg)
108
+ # If the receiver of `include?` or `exclude?`, or the first argument of `in?` is the
109
+ # hash value block argument, an offense should not be registered.
110
+ # ie. `v.include?(k)` or `k.in?(v)`
111
+ (send_node.receiver.lvar_type? && send_node.receiver.name == value_arg.name) ||
112
+ (send_node.first_argument.lvar_type? && send_node.first_argument.name == value_arg.name)
113
+ end
114
+
100
115
  def supported_subset_method?(method)
101
116
  if active_support_extensions_enabled?
102
117
  ACTIVE_SUPPORT_SUBSET_METHODS.include?(method)