rubocop 1.50.2 → 1.52.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -3
  3. data/config/default.yml +38 -5
  4. data/lib/rubocop/config.rb +4 -0
  5. data/lib/rubocop/config_obsoletion.rb +2 -2
  6. data/lib/rubocop/cop/base.rb +5 -1
  7. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
  8. data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
  9. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  10. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  11. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
  12. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +12 -1
  13. data/lib/rubocop/cop/lint/erb_new_arguments.rb +2 -2
  14. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -2
  15. data/lib/rubocop/cop/lint/inherit_exception.rb +7 -0
  16. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
  17. data/lib/rubocop/cop/lint/missing_super.rb +3 -0
  18. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
  19. data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
  20. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +2 -2
  21. data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
  22. data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
  23. data/lib/rubocop/cop/lint/useless_assignment.rb +58 -1
  24. data/lib/rubocop/cop/lint/void.rb +62 -6
  25. data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
  26. data/lib/rubocop/cop/mixin/comments_help.rb +6 -2
  27. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  28. data/lib/rubocop/cop/naming/constant_name.rb +1 -1
  29. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +22 -7
  30. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
  31. data/lib/rubocop/cop/naming/variable_name.rb +6 -1
  32. data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
  33. data/lib/rubocop/cop/style/attr.rb +11 -1
  34. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  35. data/lib/rubocop/cop/style/collection_compact.rb +16 -6
  36. data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
  37. data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
  38. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
  39. data/lib/rubocop/cop/style/copyright.rb +5 -2
  40. data/lib/rubocop/cop/style/documentation.rb +1 -1
  41. data/lib/rubocop/cop/style/eval_with_location.rb +2 -2
  42. data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
  43. data/lib/rubocop/cop/style/guard_clause.rb +2 -0
  44. data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
  45. data/lib/rubocop/cop/style/hash_except.rb +19 -8
  46. data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
  47. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
  48. data/lib/rubocop/cop/style/invertible_unless_condition.rb +9 -5
  49. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -2
  50. data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
  51. data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
  52. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  53. data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
  54. data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
  55. data/lib/rubocop/cop/style/redundant_line_continuation.rb +5 -1
  56. data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
  57. data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
  58. data/lib/rubocop/cop/style/require_order.rb +11 -5
  59. data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
  60. data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
  61. data/lib/rubocop/cop/style/semicolon.rb +12 -1
  62. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  63. data/lib/rubocop/cop/style/special_global_vars.rb +2 -2
  64. data/lib/rubocop/cop/team.rb +1 -1
  65. data/lib/rubocop/cop/variable_force/assignment.rb +20 -1
  66. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
  67. data/lib/rubocop/cop/variable_force.rb +1 -0
  68. data/lib/rubocop/result_cache.rb +1 -1
  69. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  70. data/lib/rubocop/server/client_command/exec.rb +2 -1
  71. data/lib/rubocop/target_ruby.rb +3 -2
  72. data/lib/rubocop/version.rb +10 -6
  73. data/lib/rubocop.rb +5 -0
  74. metadata +13 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67accbc10c4c2ae80033ab2a3713fce8a190d772234cbd52c5584e5c69895915
4
- data.tar.gz: 69e7f99ee66c192619b2dc26df6d0ac73c794bb088bade8182f3eceb1cb8d8c0
3
+ metadata.gz: 5301525d37bb844594d465a40a1e5643646f2b85a3bbd7258ce92af20c1d82bd
4
+ data.tar.gz: 3a1ba98652dc97a41f5ee5828160a9a74b59c806b3da618742e879a92d5ba596
5
5
  SHA512:
6
- metadata.gz: 21005d0d16a207a998640686ee7dcf251683899ab8e746baa861888fd26f2e58791733b48869a085b1b365ce2b67e64b216b4cfe6c1a2e26a2ecc699da0ea085
7
- data.tar.gz: 461a588bb95269c194efee4ee8570c166ce009695664aa31181f1f0806220f451e4685d4feff8751d4135f196d3cb42ec100c171b905526e06ed968cd9bb47f9
6
+ metadata.gz: 939d1acac3b8dd67e286c2a10c2cf4f81d2c7029eda506b186546198dbdaa1726fe9d70c32bb6ea09d22de3dcdc4224b4e4e061b590f5b0bced0e7f693fa29fe
7
+ data.tar.gz: 1b449beeac25c4475ff5deb915b045349283e35f1aff9bd526e9dda73a957a44df8e7ba7ec3c8a1b3c360a5bbc05120ca4cdbda62f15be0c4c0b45f46882bc9e
data/README.md CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
53
53
  in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 1.50', require: false
56
+ gem 'rubocop', '~> 1.52', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -75,8 +75,8 @@ You can read a lot more about RuboCop in its [official docs](https://docs.ruboco
75
75
 
76
76
  RuboCop officially supports the following runtime Ruby implementations:
77
77
 
78
- * MRI 2.6+
79
- * JRuby 9.3+
78
+ * MRI 2.7+
79
+ * JRuby 9.4+
80
80
 
81
81
  Targets Ruby 2.0+ code analysis.
82
82
 
data/config/default.yml CHANGED
@@ -140,7 +140,7 @@ AllCops:
140
140
  # or gems.locked file. (Although the Ruby version is specified in the Gemfile
141
141
  # or gems.rb file, RuboCop reads the final value from the lock file.) If the
142
142
  # Ruby version is still unresolved, RuboCop will use the oldest officially
143
- # supported Ruby version (currently Ruby 2.6).
143
+ # supported Ruby version (currently Ruby 2.7).
144
144
  TargetRubyVersion: ~
145
145
  # Determines if a notification for extension libraries should be shown when
146
146
  # rubocop is run. Keys are the name of the extension, and values are an array
@@ -154,6 +154,7 @@ AllCops:
154
154
  rubocop-rake: [rake]
155
155
  rubocop-graphql: [graphql]
156
156
  rubocop-capybara: [capybara]
157
+ rubocop-factory_bot: [factory_bot, factory_bot_rails]
157
158
  # Enable/Disable checking the methods extended by Active Support.
158
159
  ActiveSupportExtensionsEnabled: false
159
160
 
@@ -2343,6 +2344,9 @@ Lint/TopLevelReturnWithArgument:
2343
2344
  Description: 'Detects top level return statements with argument.'
2344
2345
  Enabled: true
2345
2346
  VersionAdded: '0.89'
2347
+ # These codes are `eval`-ed in method and their return values may be used.
2348
+ Exclude:
2349
+ - '**/*.jb'
2346
2350
 
2347
2351
  Lint/TrailingCommaInAttributeDeclaration:
2348
2352
  Description: 'Checks for trailing commas in attribute declarations.'
@@ -2451,6 +2455,8 @@ Lint/UselessAssignment:
2451
2455
  StyleGuide: '#underscore-unused-vars'
2452
2456
  Enabled: true
2453
2457
  VersionAdded: '0.11'
2458
+ VersionChanged: '1.51'
2459
+ SafeAutoCorrect: false
2454
2460
 
2455
2461
  Lint/UselessElseWithoutRescue:
2456
2462
  Description: 'Checks for useless `else` in `begin..end` without `rescue`.'
@@ -2478,10 +2484,9 @@ Lint/UselessRuby2Keywords:
2478
2484
  Lint/UselessSetterCall:
2479
2485
  Description: 'Checks for useless setter call to a local variable.'
2480
2486
  Enabled: true
2481
- SafeAutoCorrect: false
2487
+ Safe: false
2482
2488
  VersionAdded: '0.13'
2483
2489
  VersionChanged: '1.2'
2484
- Safe: false
2485
2490
 
2486
2491
  Lint/UselessTimes:
2487
2492
  Description: 'Checks for useless `Integer#times` calls.'
@@ -2942,7 +2947,9 @@ Naming/VariableNumber:
2942
2947
  Security/CompoundHash:
2943
2948
  Description: 'When overwriting Object#hash to combine values, prefer delegating to Array#hash over writing a custom implementation.'
2944
2949
  Enabled: pending
2950
+ Safe: false
2945
2951
  VersionAdded: '1.28'
2952
+ VersionChanged: '1.51'
2946
2953
 
2947
2954
  Security/Eval:
2948
2955
  Description: 'The use of eval represents a serious security risk.'
@@ -3355,6 +3362,7 @@ Style/CollectionCompact:
3355
3362
  Safe: false
3356
3363
  VersionAdded: '1.2'
3357
3364
  VersionChanged: '1.3'
3365
+ AllowedReceivers: []
3358
3366
 
3359
3367
  # Align with the style guide.
3360
3368
  Style/CollectionMethods:
@@ -3515,7 +3523,9 @@ Style/DataInheritance:
3515
3523
  Description: 'Checks for inheritance from Data.define.'
3516
3524
  StyleGuide: '#no-extend-data-define'
3517
3525
  Enabled: pending
3526
+ SafeAutoCorrect: false
3518
3527
  VersionAdded: '1.49'
3528
+ VersionChanged: '1.51'
3519
3529
 
3520
3530
  Style/DateTime:
3521
3531
  Description: 'Use Time over DateTime.'
@@ -3706,6 +3716,11 @@ Style/EvenOdd:
3706
3716
  VersionAdded: '0.12'
3707
3717
  VersionChanged: '0.29'
3708
3718
 
3719
+ Style/ExactRegexpMatch:
3720
+ Description: 'Checks for exact regexp match inside Regexp literals.'
3721
+ Enabled: pending
3722
+ VersionAdded: '1.51'
3723
+
3709
3724
  Style/ExpandPathArguments:
3710
3725
  Description: "Use `expand_path(__dir__)` instead of `expand_path('..', __FILE__)`."
3711
3726
  Enabled: true
@@ -4092,8 +4107,6 @@ Style/InvertibleUnlessCondition:
4092
4107
  # :blank?: :present?
4093
4108
  # :include?: :exclude?
4094
4109
  # :exclude?: :include?
4095
- # :one?: :many?
4096
- # :many?: :one?
4097
4110
 
4098
4111
  Style/IpAddresses:
4099
4112
  Description: "Don't include literal IP addresses in code."
@@ -4370,6 +4383,7 @@ Style/MultipleComparison:
4370
4383
  VersionAdded: '0.49'
4371
4384
  VersionChanged: '1.1'
4372
4385
  AllowMethodComparison: true
4386
+ ComparisonsThreshold: 2
4373
4387
 
4374
4388
  Style/MutableConstant:
4375
4389
  Description: 'Do not assign mutable objects to constants.'
@@ -4624,7 +4638,9 @@ Style/OpenStructUse:
4624
4638
  - https://docs.ruby-lang.org/en/3.0.0/OpenStruct.html#class-OpenStruct-label-Caveats
4625
4639
 
4626
4640
  Enabled: pending
4641
+ Safe: false
4627
4642
  VersionAdded: '1.23'
4643
+ VersionChanged: '1.51'
4628
4644
 
4629
4645
  Style/OperatorMethodCall:
4630
4646
  Description: 'Checks for redundant dot before operator method call.'
@@ -4790,6 +4806,11 @@ Style/RedundantArgument:
4790
4806
  # String#chomp!
4791
4807
  chomp!: "\n"
4792
4808
 
4809
+ Style/RedundantArrayConstructor:
4810
+ Description: 'Checks for the instantiation of array using redundant `Array` constructor.'
4811
+ Enabled: pending
4812
+ VersionAdded: '1.52'
4813
+
4793
4814
  Style/RedundantAssignment:
4794
4815
  Description: 'Checks for redundant assignment before returning.'
4795
4816
  Enabled: true
@@ -4861,6 +4882,13 @@ Style/RedundantFileExtensionInRequire:
4861
4882
  Enabled: true
4862
4883
  VersionAdded: '0.88'
4863
4884
 
4885
+ Style/RedundantFilterChain:
4886
+ Description: >-
4887
+ Identifies usages of `any?`, `empty?`, `none?` or `one?` predicate methods chained to
4888
+ `select`/`filter`/`find_all` and change them to use predicate method instead.
4889
+ Enabled: pending
4890
+ VersionAdded: '1.52'
4891
+
4864
4892
  Style/RedundantFreeze:
4865
4893
  Description: "Checks usages of Object#freeze on immutable objects."
4866
4894
  Enabled: true
@@ -4908,6 +4936,11 @@ Style/RedundantRegexpCharacterClass:
4908
4936
  Enabled: true
4909
4937
  VersionAdded: '0.85'
4910
4938
 
4939
+ Style/RedundantRegexpConstructor:
4940
+ Description: 'Checks for the instantiation of regexp using redundant `Regexp.new` or `Regexp.compile`.'
4941
+ Enabled: pending
4942
+ VersionAdded: '1.52'
4943
+
4911
4944
  Style/RedundantRegexpEscape:
4912
4945
  Description: 'Checks for redundant escapes in Regexps.'
4913
4946
  Enabled: true
@@ -284,6 +284,10 @@ module RuboCop
284
284
  end
285
285
  end
286
286
 
287
+ def inspect # :nodoc:
288
+ "#<#{self.class.name}:#{object_id} @loaded_path=#{loaded_path}>"
289
+ end
290
+
287
291
  private
288
292
 
289
293
  def target_rails_version_from_bundler_lock_file
@@ -68,11 +68,11 @@ module RuboCop
68
68
  # Cop rules are keyed by the name of the original cop
69
69
  def load_cop_rules(rules)
70
70
  rules.flat_map do |rule_type, data|
71
- data.map do |cop_name, configuration|
71
+ data.filter_map do |cop_name, configuration|
72
72
  next unless configuration # allow configurations to be disabled with `CopName: ~`
73
73
 
74
74
  COP_RULE_CLASSES[rule_type].new(@config, cop_name, configuration)
75
- end.compact
75
+ end
76
76
  end
77
77
  end
78
78
 
@@ -284,7 +284,7 @@ module RuboCop
284
284
  # @api private
285
285
  def self.callbacks_needed
286
286
  @callbacks_needed ||= public_instance_methods.select do |m|
287
- m.match?(/^on_|^after_/) &&
287
+ m.start_with?(/on_|after_/) &&
288
288
  !Base.method_defined?(m) # exclude standard "callbacks" like 'on_begin_investigation'
289
289
  end
290
290
  end
@@ -305,6 +305,10 @@ module RuboCop
305
305
  @current_original = original
306
306
  end
307
307
 
308
+ def inspect # :nodoc:
309
+ "#<#{self.class.name}:#{object_id} @config=#{@config} @options=#{@options}>"
310
+ end
311
+
308
312
  private
309
313
 
310
314
  ### Reserved for Cop::Cop
@@ -54,7 +54,7 @@ module RuboCop
54
54
  def inside_string_ranges(node)
55
55
  return [] unless node.is_a?(Parser::AST::Node)
56
56
 
57
- node.each_node(:str, :dstr, :xstr).map { |n| inside_string_range(n) }.compact
57
+ node.each_node(:str, :dstr, :xstr).filter_map { |n| inside_string_range(n) }
58
58
  end
59
59
 
60
60
  def inside_string_range(node)
@@ -75,7 +75,7 @@ module RuboCop
75
75
 
76
76
  # @!method add_development_dependency?(node)
77
77
  def_node_matcher :add_development_dependency?, <<~PATTERN
78
- (send _ :add_development_dependency (str #forbidden_gem? ...))
78
+ (send _ :add_development_dependency (str #forbidden_gem? ...) _? _?)
79
79
  PATTERN
80
80
 
81
81
  # @!method gem?(node)
@@ -59,12 +59,12 @@ module RuboCop
59
59
  def method_directives(node)
60
60
  comments = processed_source.ast_with_comments[node]
61
61
 
62
- comments.map do |comment|
62
+ comments.filter_map do |comment|
63
63
  match = comment.text.match(REGEXP)
64
64
  next unless match
65
65
 
66
66
  { node: comment, method_name: match[:method_name], args: match[:args] }
67
- end.compact
67
+ end
68
68
  end
69
69
 
70
70
  def too_many_directives(node)
@@ -228,9 +228,9 @@ module RuboCop
228
228
  end
229
229
 
230
230
  def find_most_bottom_of_heredoc_end(arguments)
231
- arguments.map do |argument|
231
+ arguments.filter_map do |argument|
232
232
  argument.loc.heredoc_end.end_pos if argument.loc.respond_to?(:heredoc_end)
233
- end.compact.max
233
+ end.max
234
234
  end
235
235
 
236
236
  # Internal trailing comma helpers.
@@ -236,6 +236,8 @@ module RuboCop
236
236
  end
237
237
 
238
238
  def offense(begin_pos, end_pos, msg, style_param = 'EnforcedStyle')
239
+ return if begin_pos > end_pos
240
+
239
241
  range = range_between(begin_pos, end_pos)
240
242
  add_offense(range, message: msg) do |corrector|
241
243
  case range.source
@@ -52,6 +52,8 @@ module RuboCop
52
52
  # expect { do_something }.to not_change { object.attribute }
53
53
  #
54
54
  class AmbiguousBlockAssociation < Base
55
+ extend AutoCorrector
56
+
55
57
  include AllowedMethods
56
58
  include AllowedPattern
57
59
 
@@ -68,7 +70,9 @@ module RuboCop
68
70
 
69
71
  message = message(node)
70
72
 
71
- add_offense(node, message: message)
73
+ add_offense(node, message: message) do |corrector|
74
+ wrap_in_parentheses(corrector, node)
75
+ end
72
76
  end
73
77
  alias on_csend on_send
74
78
 
@@ -89,6 +93,13 @@ module RuboCop
89
93
 
90
94
  format(MSG, param: block_param.source, method: block_param.send_node.source)
91
95
  end
96
+
97
+ def wrap_in_parentheses(corrector, node)
98
+ range = node.loc.selector.end.join(node.first_argument.source_range.begin)
99
+
100
+ corrector.replace(range, '(')
101
+ corrector.insert_after(node.last_argument, ')')
102
+ end
92
103
  end
93
104
  end
94
105
  end
@@ -8,9 +8,9 @@ module RuboCop
8
8
  #
9
9
  # [source,console]
10
10
  # ----
11
- # % cat example.rb
11
+ # $ cat example.rb
12
12
  # ERB.new('hi', nil, '-', '@output_buffer')
13
- # % ruby -rerb example.rb
13
+ # $ ruby -rerb example.rb
14
14
  # example.rb:1: warning: Passing safe_level with the 2nd argument of ERB.new is
15
15
  # deprecated. Do not use it, and specify other arguments as keyword arguments.
16
16
  # example.rb:1: warning: Passing trim_mode with the 3rd argument of ERB.new is
@@ -6,6 +6,9 @@ module RuboCop
6
6
  #
7
7
  # This cop checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
8
8
  #
9
+ # When an array of IO objects waiting for an exception (the third argument of `IO.select`)
10
+ # is used as an argument, there is no alternative API, so offenses are not registered.
11
+ #
9
12
  # NOTE: When the method is successful the return value of `IO.select` is `[[IO]]`,
10
13
  # and the return value of `io.wait_readable` and `io.wait_writable` are `self`.
11
14
  # They are not autocorrected when assigning a return value because these types are different.
@@ -42,8 +45,8 @@ module RuboCop
42
45
  PATTERN
43
46
 
44
47
  def on_send(node)
45
- read, write, _excepts, timeout = *io_select(node)
46
- return unless read
48
+ read, write, excepts, timeout = *io_select(node)
49
+ return if excepts && !excepts.children.empty?
47
50
  return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read)
48
51
 
49
52
  preferred = preferred_method(read, write, timeout)
@@ -58,6 +58,7 @@ module RuboCop
58
58
 
59
59
  def on_class(node)
60
60
  return unless node.parent_class && exception_class?(node.parent_class)
61
+ return if inherit_exception_class_with_omitted_namespace?(node)
61
62
 
62
63
  message = message(node.parent_class)
63
64
 
@@ -87,6 +88,12 @@ module RuboCop
87
88
  class_node.const_name == 'Exception'
88
89
  end
89
90
 
91
+ def inherit_exception_class_with_omitted_namespace?(class_node)
92
+ return false if class_node.parent_class.namespace&.cbase_type?
93
+
94
+ class_node.left_siblings.any? { |sibling| exception_class?(sibling.identifier) }
95
+ end
96
+
90
97
  def preferred_base_class
91
98
  PREFERRED_BASE_CLASS[style]
92
99
  end
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Checks uses of lambda without a literal block.
7
7
  # It emulates the following warning in Ruby 3.0:
8
8
  #
9
- # % ruby -vwe 'lambda(&proc {})'
9
+ # $ ruby -vwe 'lambda(&proc {})'
10
10
  # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
11
11
  # -e:1: warning: lambda without a literal block is deprecated; use the proc without
12
12
  # lambda instead
@@ -11,6 +11,9 @@ module RuboCop
11
11
  # missing method. In other cases, the theoretical ideal handling could be
12
12
  # challenging or verbose for no actual gain.
13
13
  #
14
+ # Autocorrection is not supported because the position of `super` cannot be
15
+ # determined automatically.
16
+ #
14
17
  # @example
15
18
  # # bad
16
19
  # class Employee < Person
@@ -6,13 +6,13 @@ module RuboCop
6
6
  # Checks for uses of numbered parameter assignment.
7
7
  # It emulates the following warning in Ruby 2.7:
8
8
  #
9
- # % ruby -ve '_1 = :value'
9
+ # $ ruby -ve '_1 = :value'
10
10
  # ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
11
11
  # -e:1: warning: `_1' is reserved for numbered parameter; consider another name
12
12
  #
13
13
  # Assigning to a numbered parameter (from `_1` to `_9`) causes an error in Ruby 3.0.
14
14
  #
15
- # % ruby -ve '_1 = :value'
15
+ # $ ruby -ve '_1 = :value'
16
16
  # ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
17
17
  # -e:1: _1 is reserved for numbered parameter
18
18
  #
@@ -65,13 +65,13 @@ module RuboCop
65
65
  def on_when(node)
66
66
  regexp_conditions = node.conditions.select(&:regexp_type?)
67
67
 
68
- @valid_ref = regexp_conditions.map { |condition| check_regexp(condition) }.compact.max
68
+ @valid_ref = regexp_conditions.filter_map { |condition| check_regexp(condition) }.max
69
69
  end
70
70
 
71
71
  def on_in_pattern(node)
72
72
  regexp_patterns = regexp_patterns(node)
73
73
 
74
- @valid_ref = regexp_patterns.map { |pattern| check_regexp(pattern) }.compact.max
74
+ @valid_ref = regexp_patterns.filter_map { |pattern| check_regexp(pattern) }.max
75
75
  end
76
76
 
77
77
  def on_nth_ref(node)
@@ -49,7 +49,7 @@ module RuboCop
49
49
  # do_something if attrs&.not_nil_safe_method(:[])
50
50
  #
51
51
  class RedundantSafeNavigation < Base
52
- include AllowedMethods
52
+ include NilMethods
53
53
  include RangeHelp
54
54
  extend AutoCorrector
55
55
 
@@ -63,7 +63,7 @@ module RuboCop
63
63
  PATTERN
64
64
 
65
65
  def on_csend(node)
66
- return unless check?(node) && allowed_method?(node.method_name)
66
+ return unless check?(node) && nil_methods.include?(node.method_name)
67
67
  return if respond_to_nil_specific_method?(node)
68
68
 
69
69
  range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
@@ -47,7 +47,7 @@ module RuboCop
47
47
  return if node.receiver
48
48
 
49
49
  node.each_child_node(:send) do |child|
50
- next unless child.method?(:to_s)
50
+ next if !child.method?(:to_s) || child.arguments.any?
51
51
 
52
52
  register_offense(child, "`#{node.method_name}`")
53
53
  end
@@ -8,25 +8,39 @@ module RuboCop
8
8
  # always ignored. This is detected automatically since Ruby 2.7.
9
9
  #
10
10
  # @example
11
+ # # bad
12
+ # return 1
11
13
  #
12
- # # Detected since Ruby 2.7
13
- # return 1 # 1 is always ignored.
14
+ # # good
15
+ # return
14
16
  class TopLevelReturnWithArgument < Base
15
- # This cop works by validating the ancestors of the return node. A
16
- # top-level return node's ancestors should not be of block, def, or
17
- # defs type.
17
+ extend AutoCorrector
18
18
 
19
19
  MSG = 'Top level return with argument detected.'
20
20
 
21
21
  def on_return(return_node)
22
- add_offense(return_node) if return_node.arguments? && ancestors_valid?(return_node)
22
+ return unless top_level_return_with_any_argument?(return_node)
23
+
24
+ add_offense(return_node) do |corrector|
25
+ remove_arguments(corrector, return_node)
26
+ end
23
27
  end
24
28
 
25
29
  private
26
30
 
27
- def ancestors_valid?(return_node)
28
- prohibited_ancestors = return_node.each_ancestor(:block, :def, :defs)
29
- prohibited_ancestors.none?
31
+ def top_level_return_with_any_argument?(return_node)
32
+ top_level_return?(return_node) && return_node.arguments?
33
+ end
34
+
35
+ def remove_arguments(corrector, return_node)
36
+ corrector.replace(return_node, 'return')
37
+ end
38
+
39
+ # This cop works by validating the ancestors of the return node. A
40
+ # top-level return node's ancestors should not be of block, def, or
41
+ # defs type.
42
+ def top_level_return?(return_node)
43
+ return_node.each_ancestor(:block, :def, :defs).none?
30
44
  end
31
45
  end
32
46
  end
@@ -13,6 +13,12 @@ module RuboCop
13
13
  # reassignments and properly handles varied cases such as branch, loop,
14
14
  # rescue, ensure, etc.
15
15
  #
16
+ # @safety
17
+ # This cop's autocorrection is unsafe because removing assignment from
18
+ # operator assignment can cause NameError if this assignment has been used to declare
19
+ # local variable. For example, replacing `a ||= 1` to `a || 1` may cause
20
+ # "undefined local variable or method `a' for main:Object (NameError)".
21
+ #
16
22
  # @example
17
23
  #
18
24
  # # bad
@@ -31,6 +37,10 @@ module RuboCop
31
37
  # do_something(some_var)
32
38
  # end
33
39
  class UselessAssignment < Base
40
+ extend AutoCorrector
41
+
42
+ include RangeHelp
43
+
34
44
  MSG = 'Useless assignment to variable - `%<variable>s`.'
35
45
 
36
46
  def self.joining_forces
@@ -55,7 +65,9 @@ module RuboCop
55
65
  assignment.node.loc.name
56
66
  end
57
67
 
58
- add_offense(location, message: message)
68
+ add_offense(location, message: message) do |corrector|
69
+ autocorrect(corrector, assignment)
70
+ end
59
71
  end
60
72
  end
61
73
 
@@ -119,6 +131,51 @@ module RuboCop
119
131
 
120
132
  node.receiver.nil? && !node.arguments?
121
133
  end
134
+
135
+ # rubocop:disable Metrics/AbcSize
136
+ def autocorrect(corrector, assignment)
137
+ if assignment.exception_assignment?
138
+ remove_exception_assignment_part(corrector, assignment.node)
139
+ elsif assignment.multiple_assignment? || assignment.rest_assignment?
140
+ rename_variable_with_underscore(corrector, assignment.node)
141
+ elsif assignment.operator_assignment?
142
+ remove_trailing_character_from_operator(corrector, assignment.node)
143
+ elsif assignment.regexp_named_capture?
144
+ replace_named_capture_group_with_non_capturing_group(corrector, assignment.node,
145
+ assignment.variable.name)
146
+ else
147
+ remove_local_variable_assignment_part(corrector, assignment.node)
148
+ end
149
+ end
150
+ # rubocop:enable Metrics/AbcSize
151
+
152
+ def remove_exception_assignment_part(corrector, node)
153
+ corrector.remove(
154
+ range_between(
155
+ (node.parent.children.first&.source_range || node.parent.location.keyword).end_pos,
156
+ node.source_range.end_pos
157
+ )
158
+ )
159
+ end
160
+
161
+ def rename_variable_with_underscore(corrector, node)
162
+ corrector.replace(node, '_')
163
+ end
164
+
165
+ def remove_trailing_character_from_operator(corrector, node)
166
+ corrector.remove(node.parent.location.operator.end.adjust(begin_pos: -1))
167
+ end
168
+
169
+ def replace_named_capture_group_with_non_capturing_group(corrector, node, variable_name)
170
+ corrector.replace(
171
+ node.children.first,
172
+ node.children.first.source.sub(/\(\?<#{variable_name}>/, '(?:')
173
+ )
174
+ end
175
+
176
+ def remove_local_variable_assignment_part(corrector, node)
177
+ corrector.replace(node, node.expression.source)
178
+ end
122
179
  end
123
180
  end
124
181
  end