rubocop 1.26.1 → 1.27.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +15 -2
  4. data/lib/rubocop/config_obsoletion/extracted_cop.rb +3 -1
  5. data/lib/rubocop/cop/autocorrect_logic.rb +4 -0
  6. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -5
  7. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -5
  8. data/lib/rubocop/cop/layout/indentation_width.rb +1 -2
  9. data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -4
  10. data/lib/rubocop/cop/lint/ambiguous_operator.rb +6 -6
  11. data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
  12. data/lib/rubocop/cop/lint/empty_in_pattern.rb +3 -1
  13. data/lib/rubocop/cop/lint/empty_when.rb +3 -1
  14. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +11 -4
  15. data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +8 -1
  16. data/lib/rubocop/cop/lint/refinement_import_methods.rb +51 -0
  17. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +10 -0
  18. data/lib/rubocop/cop/lint/syntax.rb +1 -2
  19. data/lib/rubocop/cop/lint/unused_method_argument.rb +1 -1
  20. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
  21. data/lib/rubocop/cop/mixin/comments_help.rb +22 -2
  22. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -2
  23. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -2
  24. data/lib/rubocop/cop/mixin/surrounding_space.rb +4 -2
  25. data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
  26. data/lib/rubocop/cop/style/double_negation.rb +32 -1
  27. data/lib/rubocop/cop/style/empty_case_condition.rb +1 -2
  28. data/lib/rubocop/cop/style/file_write.rb +12 -0
  29. data/lib/rubocop/cop/style/raise_args.rb +5 -2
  30. data/lib/rubocop/cop/style/redundant_capital_w.rb +1 -2
  31. data/lib/rubocop/cop/style/redundant_initialize.rb +119 -0
  32. data/lib/rubocop/cop/style/safe_navigation.rb +12 -7
  33. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -2
  34. data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -4
  35. data/lib/rubocop/formatter/offense_count_formatter.rb +6 -2
  36. data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -2
  37. data/lib/rubocop/result_cache.rb +9 -1
  38. data/lib/rubocop/version.rb +1 -1
  39. data/lib/rubocop.rb +2 -0
  40. metadata +5 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 10e6b8905d81b2204fd3d0bf60d3278cd902d0cefc2ed387bf2c317062b46034
4
- data.tar.gz: f27011464d465728f1fa470c85c4779c2b148b3cdc872247c5a25d421f269076
3
+ metadata.gz: d48fd91bc57ba3589a331c3c0141d3e168c7631e5db47238a88cecbd10b12292
4
+ data.tar.gz: 9393d3cab7e09e86a9276ca4614f8f2c4fc2895f2070bd3364096569c2cd5828
5
5
  SHA512:
6
- metadata.gz: 215ee2bb6f0699fdedcd82c7795c40e2350c33fdfbd48117dbb2fdcaa957bcbff9a65ad9c95b9666d4b9c70d6a2e2d8b6ec6904c3c3f01cbbfa8fee2319c9518
7
- data.tar.gz: 0b33b7c3aecf2b7482e19cdbf1a94a56f21d3cb14035c68c62ce0572385edb34a59faa1ea5fb21d9504b04e18f797b0419c6ade76ff70604311b9f899e28b39d
6
+ metadata.gz: 13d85485214ca48904b07a6da11f89d2e2ef33fceab05912fb4c4f4c1e025da4be79139845d13724a749f97eb837b943eef5515639a5116299b6a164d7517944
7
+ data.tar.gz: 668abbcaedb1f06c43a2e5f61774909d684767659979bc3787c0827ca22adf42be0edf1d30544909a74fc6aac18bcd3758c7c5f77352cb97b51fd96acd24ab18
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.26', require: false
56
+ gem 'rubocop', '~> 1.27', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -2058,6 +2058,12 @@ Lint/RedundantWithObject:
2058
2058
  Enabled: true
2059
2059
  VersionAdded: '0.51'
2060
2060
 
2061
+ Lint/RefinementImportMethods:
2062
+ Description: 'Use `Refinement#import_methods` when using `include` or `prepend` in `refine` block.'
2063
+ Enabled: pending
2064
+ SafeAutoCorrect: false
2065
+ VersionAdded: '1.27'
2066
+
2061
2067
  Lint/RegexpAsCondition:
2062
2068
  Description: >-
2063
2069
  Do not use regexp literal as a condition.
@@ -2327,8 +2333,8 @@ Lint/UselessMethodDefinition:
2327
2333
  Description: 'Checks for useless method definitions.'
2328
2334
  Enabled: true
2329
2335
  VersionAdded: '0.90'
2336
+ VersionChanged: '0.91'
2330
2337
  Safe: false
2331
- AllowComments: true
2332
2338
 
2333
2339
  Lint/UselessRuby2Keywords:
2334
2340
  Description: 'Finds unnecessary uses of `ruby2_keywords`.'
@@ -4524,6 +4530,11 @@ Style/RedundantFreeze:
4524
4530
  VersionAdded: '0.34'
4525
4531
  VersionChanged: '0.66'
4526
4532
 
4533
+ Style/RedundantInitialize:
4534
+ Description: 'Checks for redundant `initialize` methods.'
4535
+ Enabled: pending
4536
+ VersionAdded: '1.27'
4537
+
4527
4538
  Style/RedundantInterpolation:
4528
4539
  Description: 'Checks for strings that are just an interpolated expression.'
4529
4540
  Enabled: true
@@ -4645,7 +4656,7 @@ Style/SafeNavigation:
4645
4656
  be `nil` or truthy, but never `false`.
4646
4657
  Enabled: true
4647
4658
  VersionAdded: '0.43'
4648
- VersionChanged: '0.77'
4659
+ VersionChanged: '1.27'
4649
4660
  # Safe navigation may cause a statement to start returning `nil` in addition
4650
4661
  # to whatever it used to return.
4651
4662
  ConvertCodeThatCanStartToReturnNil: false
@@ -4656,6 +4667,8 @@ Style/SafeNavigation:
4656
4667
  - try
4657
4668
  - try!
4658
4669
  SafeAutoCorrect: false
4670
+ # Maximum length of method chains for register an offense.
4671
+ MaxChainLength: 2
4659
4672
 
4660
4673
  Style/Sample:
4661
4674
  Description: >-
@@ -33,7 +33,9 @@ module RuboCop
33
33
  return old_name unless old_name.end_with?('*')
34
34
 
35
35
  # Handle whole departments (expressed as `Department/*`)
36
- config.keys.grep(Regexp.new("^#{department}"))
36
+ config.keys.select do |key|
37
+ key == department || key.start_with?("#{department}/")
38
+ end
37
39
  end
38
40
 
39
41
  def feature_loaded?
@@ -8,6 +8,10 @@ module RuboCop
8
8
  autocorrect_requested? && correctable? && autocorrect_enabled?
9
9
  end
10
10
 
11
+ def autocorrect_with_disable_uncorrectable?
12
+ autocorrect_requested? && disable_uncorrectable? && autocorrect_enabled?
13
+ end
14
+
11
15
  def autocorrect_requested?
12
16
  @options.fetch(:auto_correct, false)
13
17
  end
@@ -46,11 +46,7 @@ module RuboCop
46
46
 
47
47
  duplicated_gem_nodes.each do |nodes|
48
48
  nodes[1..-1].each do |node|
49
- register_offense(
50
- node,
51
- node.first_argument.to_a.first,
52
- nodes.first.first_line
53
- )
49
+ register_offense(node, node.first_argument.to_a.first, nodes.first.first_line)
54
50
  end
55
51
  end
56
52
  end
@@ -52,11 +52,7 @@ module RuboCop
52
52
 
53
53
  duplicated_assignment_method_nodes.each do |nodes|
54
54
  nodes[1..-1].each do |node|
55
- register_offense(
56
- node,
57
- node.method_name,
58
- nodes.first.first_line
59
- )
55
+ register_offense(node, node.method_name, nodes.first.first_line)
60
56
  end
61
57
  end
62
58
  end
@@ -185,8 +185,7 @@ module RuboCop
185
185
 
186
186
  def check_members_for_indented_internal_methods_style(members)
187
187
  each_member(members) do |member, previous_modifier|
188
- check_indentation(previous_modifier, member,
189
- indentation_consistency_style)
188
+ check_indentation(previous_modifier, member, indentation_consistency_style)
190
189
  end
191
190
  end
192
191
 
@@ -105,10 +105,9 @@ module RuboCop
105
105
  end
106
106
 
107
107
  def convertible_block?(node)
108
- return false unless node.parent&.block_type?
109
-
110
- send_node = node.parent&.send_node
111
- send_node.parenthesized? || !send_node.arguments?
108
+ parent = node.parent
109
+ parent&.block_type? && node == parent.send_node &&
110
+ (node.parenthesized? || !node.arguments?)
112
111
  end
113
112
 
114
113
  def comment_within?(node)
@@ -24,11 +24,11 @@ module RuboCop
24
24
  extend AutoCorrector
25
25
 
26
26
  AMBIGUITIES = {
27
- '+' => { actual: 'positive number', possible: 'addition' },
28
- '-' => { actual: 'negative number', possible: 'subtraction' },
29
- '*' => { actual: 'splat', possible: 'multiplication' },
30
- '&' => { actual: 'block', possible: 'binary AND' },
31
- '**' => { actual: 'keyword splat', possible: 'exponent' }
27
+ '+' => { actual: 'positive number', possible: 'an addition' },
28
+ '-' => { actual: 'negative number', possible: 'a subtraction' },
29
+ '*' => { actual: 'splat', possible: 'a multiplication' },
30
+ '&' => { actual: 'block', possible: 'a binary AND' },
31
+ '**' => { actual: 'keyword splat', possible: 'an exponent' }
32
32
  }.each do |key, hash|
33
33
  hash[:operator] = key
34
34
  end
@@ -36,7 +36,7 @@ module RuboCop
36
36
  MSG_FORMAT = 'Ambiguous %<actual>s operator. Parenthesize the method ' \
37
37
  "arguments if it's surely a %<actual>s operator, or add " \
38
38
  'a whitespace to the right of the `%<operator>s` if it ' \
39
- 'should be a %<possible>s.'
39
+ 'should be %<possible>s.'
40
40
 
41
41
  def on_new_investigation
42
42
  processed_source.diagnostics.each do |diagnostic|
@@ -53,11 +53,13 @@ module RuboCop
53
53
  # end
54
54
  #
55
55
  class EmptyConditionalBody < Base
56
+ include CommentsHelp
57
+
56
58
  MSG = 'Avoid `%<keyword>s` branches without a body.'
57
59
 
58
60
  def on_if(node)
59
61
  return if node.body
60
- return if cop_config['AllowComments'] && comment_lines?(node)
62
+ return if cop_config['AllowComments'] && contains_comments?(node)
61
63
 
62
64
  add_offense(node, message: format(MSG, keyword: node.keyword))
63
65
  end
@@ -44,6 +44,7 @@ module RuboCop
44
44
  #
45
45
  class EmptyInPattern < Base
46
46
  extend TargetRubyVersion
47
+ include CommentsHelp
47
48
 
48
49
  MSG = 'Avoid `in` branches without a body.'
49
50
 
@@ -51,7 +52,8 @@ module RuboCop
51
52
 
52
53
  def on_case_match(node)
53
54
  node.in_pattern_branches.each do |branch|
54
- next if branch.body || (cop_config['AllowComments'] && comment_lines?(node))
55
+ next if branch.body
56
+ next if cop_config['AllowComments'] && contains_comments?(branch)
55
57
 
56
58
  add_offense(branch)
57
59
  end
@@ -45,12 +45,14 @@ module RuboCop
45
45
  # end
46
46
  #
47
47
  class EmptyWhen < Base
48
+ include CommentsHelp
49
+
48
50
  MSG = 'Avoid `when` branches without a body.'
49
51
 
50
52
  def on_case(node)
51
53
  node.each_when do |when_node|
52
54
  next if when_node.body
53
- next if cop_config['AllowComments'] && comment_lines?(node)
55
+ next if cop_config['AllowComments'] && contains_comments?(when_node)
54
56
 
55
57
  add_offense(when_node)
56
58
  end
@@ -6,6 +6,15 @@ 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
+ # NOTE: When the method is successful the return value of `IO.select` is `[[IO]]`,
10
+ # and the return value of `io.wait_readable` and `io.wait_writable` are `self`.
11
+ # They are not auto-corrected when assigning a return value because these types are different.
12
+ # It's up to user how to handle the return value.
13
+ #
14
+ # @safety
15
+ # This cop's autocorrection is unsafe because `NoMethodError` occurs
16
+ # if `require 'io/wait'` is not called.
17
+ #
9
18
  # @example
10
19
  #
11
20
  # # bad
@@ -20,10 +29,6 @@ module RuboCop
20
29
  # # good
21
30
  # io.wait_writable(timeout)
22
31
  #
23
- # @safety
24
- # This cop's autocorrection is unsafe because `NoMethodError` occurs
25
- # if `require 'io/wait'` is not called.
26
- #
27
32
  class IncompatibleIoSelectWithFiberScheduler < Base
28
33
  extend AutoCorrector
29
34
 
@@ -45,6 +50,8 @@ module RuboCop
45
50
  message = format(MSG, preferred: preferred, current: node.source)
46
51
 
47
52
  add_offense(node, message: message) do |corrector|
53
+ next if node.parent&.assignment?
54
+
48
55
  corrector.replace(node, preferred)
49
56
  end
50
57
  end
@@ -31,8 +31,15 @@ module RuboCop
31
31
  MSG = 'lambda without a literal block is deprecated; use the proc without lambda instead.'
32
32
  RESTRICT_ON_SEND = %i[lambda].freeze
33
33
 
34
+ # @!method lambda_with_symbol_proc?(node)
35
+ def_node_matcher :lambda_with_symbol_proc?, <<~PATTERN
36
+ (send nil? :lambda (block_pass (sym _)))
37
+ PATTERN
38
+
34
39
  def on_send(node)
35
- return if node.parent&.block_type? || !node.first_argument
40
+ if node.parent&.block_type? || !node.first_argument || lambda_with_symbol_proc?(node)
41
+ return
42
+ end
36
43
 
37
44
  add_offense(node) do |corrector|
38
45
  corrector.replace(node, node.first_argument.source.delete('&'))
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks if `include` or `prepend` is called in `refine` block.
7
+ # These methods are deprecated and should be replaced with `Refinement#import_methods`.
8
+ #
9
+ # It emulates deprecation warnings in Ruby 3.1.
10
+ #
11
+ # @safety
12
+ # This cop's autocorrection is unsafe because `include M` will affect the included class
13
+ # if any changes are made to module `M`.
14
+ # On the other hand, `import_methods M` uses a snapshot of method definitions,
15
+ # thus it will not be affected if module `M` changes.
16
+ #
17
+ # @example
18
+ #
19
+ # # bad
20
+ # refine Foo do
21
+ # include Bar
22
+ # end
23
+ #
24
+ # # bad
25
+ # refine Foo do
26
+ # prepend Bar
27
+ # end
28
+ #
29
+ # # good
30
+ # refine Foo do
31
+ # import_methods Bar
32
+ # end
33
+ #
34
+ class RefinementImportMethods < Base
35
+ extend TargetRubyVersion
36
+
37
+ MSG = 'Use `import_methods` instead of `%<current>s` because it is deprecated in Ruby 3.1.'
38
+ RESTRICT_ON_SEND = %i[include prepend].freeze
39
+
40
+ minimum_target_ruby_version 3.1
41
+
42
+ def on_send(node)
43
+ return if node.receiver
44
+ return unless node.parent.block_type? && node.parent.method?(:refine)
45
+
46
+ add_offense(node.loc.selector, message: format(MSG, current: node.method_name))
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -57,10 +57,20 @@ module RuboCop
57
57
 
58
58
  outer_local_variable = variable_table.find_variable(variable.name)
59
59
  return unless outer_local_variable
60
+ return if same_conditions_node_different_branch?(variable, outer_local_variable)
60
61
 
61
62
  message = format(MSG, variable: variable.name)
62
63
  add_offense(variable.declaration_node, message: message)
63
64
  end
65
+
66
+ def same_conditions_node_different_branch?(variable, outer_local_variable)
67
+ variable_node = variable.scope.node.parent
68
+ return false unless variable_node.conditional?
69
+
70
+ outer_local_variable_node = outer_local_variable.scope.node
71
+
72
+ outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
73
+ end
64
74
  end
65
75
  end
66
76
  end
@@ -9,8 +9,7 @@ module RuboCop
9
9
  def on_other_file
10
10
  add_offense_from_error(processed_source.parser_error) if processed_source.parser_error
11
11
  processed_source.diagnostics.each do |diagnostic|
12
- add_offense_from_diagnostic(diagnostic,
13
- processed_source.ruby_version)
12
+ add_offense_from_diagnostic(diagnostic, processed_source.ruby_version)
14
13
  end
15
14
  super
16
15
  end
@@ -64,7 +64,7 @@ module RuboCop
64
64
 
65
65
  # @!method not_implemented?(node)
66
66
  def_node_matcher :not_implemented?, <<~PATTERN
67
- {(send nil? :raise (const {nil? cbase} :NotImplementedError))
67
+ {(send nil? :raise (const {nil? cbase} :NotImplementedError) ...)
68
68
  (send nil? :fail ...)}
69
69
  PATTERN
70
70
 
@@ -101,8 +101,7 @@ module RuboCop
101
101
  children = node.masgn_type? ? node.children[0].children : node.children
102
102
 
103
103
  will_be_miscounted = children.count do |child|
104
- child.respond_to?(:setter_method?) &&
105
- !child.setter_method?
104
+ child.respond_to?(:setter_method?) && !child.setter_method?
106
105
  end
107
106
  @assignment += will_be_miscounted
108
107
 
@@ -4,8 +4,6 @@ module RuboCop
4
4
  module Cop
5
5
  # Help methods for working with nodes containing comments.
6
6
  module CommentsHelp
7
- include VisibilityHelp
8
-
9
7
  def source_range_with_comment(node)
10
8
  begin_pos = begin_pos_with_comment(node)
11
9
  end_pos = end_position_for(node)
@@ -13,6 +11,13 @@ module RuboCop
13
11
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
14
12
  end
15
13
 
14
+ def contains_comments?(node)
15
+ start_line = node.source_range.line
16
+ end_line = find_end_line(node)
17
+
18
+ processed_source.each_comment_in_lines(start_line...end_line).any?
19
+ end
20
+
16
21
  private
17
22
 
18
23
  def end_position_for(node)
@@ -37,6 +42,21 @@ module RuboCop
37
42
  def buffer
38
43
  processed_source.buffer
39
44
  end
45
+
46
+ # Returns the end line of a node, which might be a comment and not part of the AST
47
+ # End line is considered either the line at which another node starts, or
48
+ # the line at which the parent node ends.
49
+ def find_end_line(node)
50
+ if node.if_type? && node.loc.else
51
+ node.loc.else.line
52
+ elsif (next_sibling = node.right_sibling)
53
+ next_sibling.loc.line
54
+ elsif (parent = node.parent)
55
+ parent.loc.end.line
56
+ else
57
+ node.loc.end.line
58
+ end
59
+ end
40
60
  end
41
61
  end
42
62
  end
@@ -65,9 +65,8 @@ module RuboCop
65
65
 
66
66
  def use_modifier_form_without_parenthesized_method_call?(ancestor)
67
67
  return false if ancestor.respond_to?(:parenthesized?) && ancestor.parenthesized?
68
- return false unless (parent = ancestor.parent)
69
68
 
70
- parent.respond_to?(:modifier_form?) && parent.modifier_form?
69
+ ancestor.ancestors.any? { |node| node.respond_to?(:modifier_form?) && node.modifier_form? }
71
70
  end
72
71
 
73
72
  def without_parentheses_call_expr_follows?(ancestor)
@@ -196,8 +196,7 @@ module RuboCop
196
196
 
197
197
  def not_for_this_cop?(node)
198
198
  node.ancestors.any? do |ancestor|
199
- grouped_expression?(ancestor) ||
200
- inside_arg_list_parentheses?(node, ancestor)
199
+ grouped_expression?(ancestor) || inside_arg_list_parentheses?(node, ancestor)
201
200
  end
202
201
  end
203
202
 
@@ -44,7 +44,8 @@ module RuboCop
44
44
  if extra_space?(left_token, :left) && !start_ok
45
45
  space_offense(node, left_token, :right, message, NO_SPACE_COMMAND)
46
46
  end
47
- return if !extra_space?(right_token, :right) || end_ok
47
+ return if (!extra_space?(right_token, :right) || end_ok) ||
48
+ (autocorrect_with_disable_uncorrectable? && !start_ok)
48
49
 
49
50
  space_offense(node, right_token, :left, message, NO_SPACE_COMMAND)
50
51
  end
@@ -58,7 +59,8 @@ module RuboCop
58
59
  unless extra_space?(left_token, :left) || start_ok
59
60
  space_offense(node, left_token, :none, message, SPACE_COMMAND)
60
61
  end
61
- return if extra_space?(right_token, :right) || end_ok
62
+ return if (extra_space?(right_token, :right) || end_ok) ||
63
+ (autocorrect_with_disable_uncorrectable? && !start_ok)
62
64
 
63
65
  space_offense(node, right_token, :none, message, SPACE_COMMAND)
64
66
  end
@@ -107,7 +107,7 @@ module RuboCop
107
107
  def use_block_argument_as_local_variable?(node, last_argument)
108
108
  return if node.body.nil?
109
109
 
110
- node.body.each_descendant(:lvar).any? do |lvar|
110
+ node.body.each_descendant(:lvar, :lvasgn).any? do |lvar|
111
111
  !lvar.parent.block_pass_type? && lvar.source == last_argument
112
112
  end
113
113
  end
@@ -72,9 +72,14 @@ module RuboCop
72
72
  def end_of_method_definition?(node)
73
73
  return false unless (def_node = find_def_node_from_ascendant(node))
74
74
 
75
+ conditional_node = find_conditional_node_from_ascendant(node)
75
76
  last_child = find_last_child(def_node.body)
76
77
 
77
- last_child.last_line == node.last_line
78
+ if conditional_node
79
+ double_negative_condition_return_value?(node, last_child, conditional_node)
80
+ else
81
+ last_child.last_line == node.last_line
82
+ end
78
83
  end
79
84
 
80
85
  def find_def_node_from_ascendant(node)
@@ -84,6 +89,13 @@ module RuboCop
84
89
  find_def_node_from_ascendant(node.parent)
85
90
  end
86
91
 
92
+ def find_conditional_node_from_ascendant(node)
93
+ return unless (parent = node.parent)
94
+ return parent if parent.conditional?
95
+
96
+ find_conditional_node_from_ascendant(parent)
97
+ end
98
+
87
99
  def find_last_child(node)
88
100
  case node.type
89
101
  when :rescue
@@ -94,6 +106,25 @@ module RuboCop
94
106
  node.child_nodes.last
95
107
  end
96
108
  end
109
+
110
+ def double_negative_condition_return_value?(node, last_child, conditional_node)
111
+ parent = find_parent_not_enumerable(node)
112
+ if parent.begin_type?
113
+ node.loc.line == parent.loc.last_line
114
+ else
115
+ last_child.last_line <= conditional_node.last_line
116
+ end
117
+ end
118
+
119
+ def find_parent_not_enumerable(node)
120
+ return unless (parent = node.parent)
121
+
122
+ if parent.pair_type? || parent.hash_type? || parent.array_type?
123
+ find_parent_not_enumerable(parent)
124
+ else
125
+ parent
126
+ end
127
+ end
97
128
  end
98
129
  end
99
130
  end
@@ -47,8 +47,7 @@ module RuboCop
47
47
  branch_bodies = [*case_node.when_branches.map(&:body), case_node.else_branch].compact
48
48
 
49
49
  return if branch_bodies.any? do |body|
50
- body.return_type? ||
51
- body.each_descendant.any?(&:return_type?)
50
+ body.return_type? || body.each_descendant.any?(&:return_type?)
52
51
  end
53
52
 
54
53
  add_offense(case_node.loc.keyword) { |corrector| autocorrect(corrector, case_node) }
@@ -5,6 +5,17 @@ module RuboCop
5
5
  module Style
6
6
  # Favor `File.(bin)write` convenience methods.
7
7
  #
8
+ # NOTE: There are different method signatures between `File.write` (class method)
9
+ # and `File#write` (instance method). The following case will be allowed because
10
+ # static analysis does not know the contents of the splat argument:
11
+ #
12
+ # [source,ruby]
13
+ # ----
14
+ # File.open(filename, 'w') do |f|
15
+ # f.write(*objects)
16
+ # end
17
+ # ----
18
+ #
8
19
  # @example
9
20
  # ## text mode
10
21
  # # bad
@@ -85,6 +96,7 @@ module RuboCop
85
96
  content = send_write?(node) || block_write?(node) do |block_arg, lvar, write_arg|
86
97
  write_arg if block_arg == lvar
87
98
  end
99
+ return false if content&.splat_type?
88
100
 
89
101
  yield(content) if content
90
102
  end
@@ -107,8 +107,7 @@ module RuboCop
107
107
 
108
108
  first_arg = node.first_argument
109
109
 
110
- return unless first_arg.send_type? && first_arg.method?(:new)
111
- return if acceptable_exploded_args?(first_arg.arguments)
110
+ return if !use_new_method?(first_arg) || acceptable_exploded_args?(first_arg.arguments)
112
111
 
113
112
  return if allowed_non_exploded_type?(first_arg)
114
113
 
@@ -120,6 +119,10 @@ module RuboCop
120
119
  end
121
120
  end
122
121
 
122
+ def use_new_method?(first_arg)
123
+ first_arg.send_type? && first_arg.receiver && first_arg.method?(:new)
124
+ end
125
+
123
126
  def acceptable_exploded_args?(args)
124
127
  # Allow code like `raise Ex.new(arg1, arg2)`.
125
128
  return true if args.size > 1
@@ -37,8 +37,7 @@ module RuboCop
37
37
 
38
38
  def requires_interpolation?(node)
39
39
  node.child_nodes.any? do |string|
40
- string.dstr_type? ||
41
- double_quotes_required?(string.source)
40
+ string.dstr_type? || double_quotes_required?(string.source)
42
41
  end
43
42
  end
44
43
  end
@@ -0,0 +1,119 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for `initialize` methods that are redundant.
7
+ #
8
+ # An initializer is redundant if it does not do anything, or if it only
9
+ # calls `super` with the same arguments given to it. If the initializer takes
10
+ # an argument that accepts multiple values (`restarg`, `kwrestarg`, etc.) it
11
+ # will not register an offense, because it allows the initializer to take a different
12
+ # number of arguments as its superclass potentially does.
13
+ #
14
+ # NOTE: If an initializer argument has a default value, RuboCop assumes it
15
+ # to *not* be redundant.
16
+ #
17
+ # NOTE: Empty initializers are registered as offenses, but it is possible
18
+ # to purposely create an empty `initialize` method to override a superclass's
19
+ # initializer.
20
+ #
21
+ # @example
22
+ # # bad
23
+ # def initialize
24
+ # end
25
+ #
26
+ # # bad
27
+ # def initialize
28
+ # super
29
+ # end
30
+ #
31
+ # # bad
32
+ # def initialize(a, b)
33
+ # super
34
+ # end
35
+ #
36
+ # # bad
37
+ # def initialize(a, b)
38
+ # super(a, b)
39
+ # end
40
+ #
41
+ # # good
42
+ # def initialize
43
+ # do_something
44
+ # end
45
+ #
46
+ # # good
47
+ # def initialize
48
+ # do_something
49
+ # super
50
+ # end
51
+ #
52
+ # # good (different number of parameters)
53
+ # def initialize(a, b)
54
+ # super(a)
55
+ # end
56
+ #
57
+ # # good (default value)
58
+ # def initialize(a, b = 5)
59
+ # super
60
+ # end
61
+ #
62
+ # # good (default value)
63
+ # def initialize(a, b: 5)
64
+ # super
65
+ # end
66
+ #
67
+ # # good (changes the parameter requirements)
68
+ # def initialize(*)
69
+ # end
70
+ #
71
+ # # good (changes the parameter requirements)
72
+ # def initialize(**)
73
+ # end
74
+ #
75
+ # # good (changes the parameter requirements)
76
+ # def initialize(...)
77
+ # end
78
+ #
79
+ class RedundantInitialize < Base
80
+ MSG = 'Remove unnecessary `initialize` method.'
81
+ MSG_EMPTY = 'Remove unnecessary empty `initialize` method.'
82
+
83
+ # @!method initialize_forwards?(node)
84
+ def_node_matcher :initialize_forwards?, <<~PATTERN
85
+ (def _ (args $arg*) $({super zsuper} ...))
86
+ PATTERN
87
+
88
+ def on_def(node)
89
+ return unless node.method?(:initialize)
90
+ return if forwards?(node)
91
+
92
+ if node.body.nil?
93
+ add_offense(node, message: MSG_EMPTY)
94
+ else
95
+ return if node.body.begin_type?
96
+
97
+ if (args, super_node = initialize_forwards?(node))
98
+ return unless same_args?(super_node, args)
99
+
100
+ add_offense(node)
101
+ end
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def forwards?(node)
108
+ node.arguments.each_child_node(:restarg, :kwrestarg, :forward_args, :forward_arg).any?
109
+ end
110
+
111
+ def same_args?(super_node, args)
112
+ return true if super_node.zsuper_type?
113
+
114
+ args.map(&:name) == super_node.arguments.map { |a| a.children[0] }
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -7,8 +7,7 @@ module RuboCop
7
7
  # check for the variable whose method is being called to
8
8
  # safe navigation (`&.`). If there is a method chain, all of the methods
9
9
  # in the chain need to be checked for safety, and all of the methods will
10
- # need to be changed to use safe navigation. We have limited the cop to
11
- # not register an offense for method chains that exceed 2 methods.
10
+ # need to be changed to use safe navigation.
12
11
  #
13
12
  # The default for `ConvertCodeThatCanStartToReturnNil` is `false`.
14
13
  # When configured to `true`, this will
@@ -18,6 +17,10 @@ module RuboCop
18
17
  # `foo&.bar` can start returning `nil` as well as what the method
19
18
  # returns.
20
19
  #
20
+ # The default for `MaxChainLength` is `2`
21
+ # We have limited the cop to not register an offense for method chains
22
+ # that exceed this option is set.
23
+ #
21
24
  # @safety
22
25
  # Autocorrection is unsafe because if a value is `false`, the resulting
23
26
  # code will have different behaviour or raise an error.
@@ -116,9 +119,7 @@ module RuboCop
116
119
  checked_variable, receiver, method_chain, method = extract_parts(node)
117
120
  return unless receiver == checked_variable
118
121
  return if use_var_only_in_unless_modifier?(node, checked_variable)
119
- # method is already a method call so this is actually checking for a
120
- # chain greater than 2
121
- return if chain_size(method_chain, method) > 1
122
+ return if chain_length(method_chain, method) > max_chain_length
122
123
  return if unsafe_method_used?(method_chain, method)
123
124
  return if method_chain.method?(:empty?)
124
125
 
@@ -225,8 +226,8 @@ module RuboCop
225
226
  find_matching_receiver_invocation(receiver, checked_variable)
226
227
  end
227
228
 
228
- def chain_size(method_chain, method)
229
- method.each_ancestor(:send).inject(0) do |total, ancestor|
229
+ def chain_length(method_chain, method)
230
+ method.each_ancestor(:send).inject(1) do |total, ancestor|
230
231
  break total + 1 if ancestor == method_chain
231
232
 
232
233
  total + 1
@@ -281,6 +282,10 @@ module RuboCop
281
282
  break if ancestor == method_chain
282
283
  end
283
284
  end
285
+
286
+ def max_chain_length
287
+ cop_config.fetch('MaxChainLength', 2)
288
+ end
284
289
  end
285
290
  end
286
291
  end
@@ -184,8 +184,7 @@ module RuboCop
184
184
 
185
185
  def unsafe_autocorrect?(condition)
186
186
  condition.children.any? do |child|
187
- unparenthesized_method_call?(child) ||
188
- below_ternary_precedence?(child)
187
+ unparenthesized_method_call?(child) || below_ternary_precedence?(child)
189
188
  end
190
189
  end
191
190
 
@@ -42,10 +42,7 @@ module RuboCop
42
42
  return if node.endless? || !trailing_end?(node)
43
43
 
44
44
  add_offense(node.loc.end) do |corrector|
45
- corrector.insert_before(
46
- node.loc.end,
47
- "\n#{' ' * node.loc.keyword.column}"
48
- )
45
+ corrector.insert_before(node.loc.end, "\n#{' ' * node.loc.keyword.column}")
49
46
  end
50
47
  end
51
48
 
@@ -17,6 +17,7 @@ module RuboCop
17
17
  def started(target_files)
18
18
  super
19
19
  @offense_counts = Hash.new(0)
20
+ @style_guide_links = {}
20
21
 
21
22
  return unless output.tty?
22
23
 
@@ -37,6 +38,9 @@ module RuboCop
37
38
 
38
39
  def file_finished(_file, offenses)
39
40
  offenses.each { |o| @offense_counts[o.cop_name] += 1 }
41
+ if options[:display_style_guide]
42
+ offenses.each { |o| @style_guide_links[o.cop_name] ||= o.message[/ \(http\S+\)\Z/] }
43
+ end
40
44
  @progressbar.increment if instance_variable_defined?(:@progressbar)
41
45
  end
42
46
 
@@ -52,8 +56,8 @@ module RuboCop
52
56
  output.puts
53
57
 
54
58
  per_cop_counts.each do |cop_name, count|
55
- output.puts "#{count.to_s.ljust(total_count.to_s.length + 2)}" \
56
- "#{cop_name}\n"
59
+ output.puts "#{count.to_s.ljust(total_count.to_s.length + 2)}#{cop_name}" \
60
+ "#{@style_guide_links[cop_name]}\n"
57
61
  end
58
62
  output.puts '--'
59
63
  output.puts "#{total_count} Total"
@@ -40,8 +40,7 @@ module RuboCop
40
40
  output.puts
41
41
 
42
42
  per_file_counts.each do |file_name, count|
43
- output.puts "#{count.to_s.ljust(total_count.to_s.length + 2)}" \
44
- "#{file_name}\n"
43
+ output.puts "#{count.to_s.ljust(total_count.to_s.length + 2)}#{file_name}\n"
45
44
  end
46
45
  output.puts '--'
47
46
  output.puts "#{total_count} Total"
@@ -73,7 +73,15 @@ module RuboCop
73
73
  # access.
74
74
  File.join(ENV['XDG_CACHE_HOME'], Process.uid.to_s)
75
75
  else
76
- File.join(ENV['HOME'], '.cache')
76
+ # On FreeBSD, the /home path is a symbolic link to /usr/home
77
+ # and the $HOME environment variable returns the /home path.
78
+ #
79
+ # As $HOME is a built-in environment variable, FreeBSD users
80
+ # always get a warning message.
81
+ #
82
+ # To avoid raising warn log messages on FreeBSD, we retrieve
83
+ # the real path of the home folder.
84
+ File.join(File.realpath(ENV['HOME']), '.cache')
77
85
  end
78
86
  File.join(root, 'rubocop_cache')
79
87
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.26.1'
6
+ STRING = '1.27.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, '\
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
data/lib/rubocop.rb CHANGED
@@ -348,6 +348,7 @@ require_relative 'rubocop/cop/lint/redundant_splat_expansion'
348
348
  require_relative 'rubocop/cop/lint/redundant_string_coercion'
349
349
  require_relative 'rubocop/cop/lint/redundant_with_index'
350
350
  require_relative 'rubocop/cop/lint/redundant_with_object'
351
+ require_relative 'rubocop/cop/lint/refinement_import_methods'
351
352
  require_relative 'rubocop/cop/lint/regexp_as_condition'
352
353
  require_relative 'rubocop/cop/lint/require_parentheses'
353
354
  require_relative 'rubocop/cop/lint/require_relative_self_path'
@@ -527,6 +528,7 @@ require_relative 'rubocop/cop/style/open_struct_use'
527
528
  require_relative 'rubocop/cop/style/redundant_assignment'
528
529
  require_relative 'rubocop/cop/style/redundant_fetch_block'
529
530
  require_relative 'rubocop/cop/style/redundant_file_extension_in_require'
531
+ require_relative 'rubocop/cop/style/redundant_initialize'
530
532
  require_relative 'rubocop/cop/style/redundant_self_assignment'
531
533
  require_relative 'rubocop/cop/style/redundant_self_assignment_branch'
532
534
  require_relative 'rubocop/cop/style/sole_nested_conditional'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.26.1
4
+ version: 1.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2022-03-22 00:00:00.000000000 Z
13
+ date: 2022-04-08 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -460,6 +460,7 @@ files:
460
460
  - lib/rubocop/cop/lint/redundant_string_coercion.rb
461
461
  - lib/rubocop/cop/lint/redundant_with_index.rb
462
462
  - lib/rubocop/cop/lint/redundant_with_object.rb
463
+ - lib/rubocop/cop/lint/refinement_import_methods.rb
463
464
  - lib/rubocop/cop/lint/regexp_as_condition.rb
464
465
  - lib/rubocop/cop/lint/require_parentheses.rb
465
466
  - lib/rubocop/cop/lint/require_relative_self_path.rb
@@ -778,6 +779,7 @@ files:
778
779
  - lib/rubocop/cop/style/redundant_fetch_block.rb
779
780
  - lib/rubocop/cop/style/redundant_file_extension_in_require.rb
780
781
  - lib/rubocop/cop/style/redundant_freeze.rb
782
+ - lib/rubocop/cop/style/redundant_initialize.rb
781
783
  - lib/rubocop/cop/style/redundant_interpolation.rb
782
784
  - lib/rubocop/cop/style/redundant_parentheses.rb
783
785
  - lib/rubocop/cop/style/redundant_percent_q.rb
@@ -913,7 +915,7 @@ metadata:
913
915
  homepage_uri: https://rubocop.org/
914
916
  changelog_uri: https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md
915
917
  source_code_uri: https://github.com/rubocop/rubocop/
916
- documentation_uri: https://docs.rubocop.org/rubocop/1.26/
918
+ documentation_uri: https://docs.rubocop.org/rubocop/1.27/
917
919
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues
918
920
  rubygems_mfa_required: 'true'
919
921
  post_install_message: