rubocop 1.43.0 → 1.44.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +50 -0
  4. data/lib/rubocop/config_loader.rb +12 -15
  5. data/lib/rubocop/cop/corrector.rb +10 -2
  6. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
  7. data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
  8. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
  9. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
  10. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
  11. data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
  12. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +0 -2
  13. data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
  14. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
  15. data/lib/rubocop/cop/lint/else_layout.rb +2 -6
  16. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -7
  17. data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
  18. data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
  19. data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
  20. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
  21. data/lib/rubocop/cop/lint/useless_rescue.rb +15 -1
  22. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +9 -1
  23. data/lib/rubocop/cop/lint/void.rb +19 -10
  24. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  25. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  26. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +2 -5
  27. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  28. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +40 -18
  29. data/lib/rubocop/cop/mixin/line_length_help.rb +3 -1
  30. data/lib/rubocop/cop/naming/block_forwarding.rb +4 -0
  31. data/lib/rubocop/cop/registry.rb +12 -7
  32. data/lib/rubocop/cop/style/access_modifier_declarations.rb +18 -10
  33. data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
  34. data/lib/rubocop/cop/style/class_and_module_children.rb +2 -9
  35. data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
  36. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
  37. data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
  38. data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -0
  39. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -5
  40. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
  41. data/lib/rubocop/cop/style/min_max_comparison.rb +11 -1
  42. data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
  43. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  44. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
  45. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
  46. data/lib/rubocop/cop/style/operator_method_call.rb +1 -1
  47. data/lib/rubocop/cop/style/parallel_assignment.rb +3 -1
  48. data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
  49. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -10
  50. data/lib/rubocop/cop/style/require_order.rb +2 -9
  51. data/lib/rubocop/cop/style/self_assignment.rb +2 -2
  52. data/lib/rubocop/cop/style/semicolon.rb +24 -2
  53. data/lib/rubocop/cop/variable_force/variable_table.rb +3 -1
  54. data/lib/rubocop/cop/variable_force.rb +1 -1
  55. data/lib/rubocop/formatter.rb +0 -1
  56. data/lib/rubocop/rspec/expect_offense.rb +6 -4
  57. data/lib/rubocop/server/cache.rb +3 -1
  58. data/lib/rubocop/version.rb +1 -1
  59. data/lib/rubocop.rb +3 -0
  60. metadata +6 -3
@@ -0,0 +1,125 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Enforces the use of `Comparable#clamp` instead of comparison by minimum and maximum.
7
+ #
8
+ # This cop supports autocorrection for `if/elsif/else` bad style only.
9
+ # Because `ArgumentError` occurs if the minimum and maximum of `clamp` arguments are reversed.
10
+ # When these are variables, it is not possible to determine which is the minimum and maximum:
11
+ #
12
+ # [source,ruby]
13
+ # ----
14
+ # [1, [2, 3].max].min # => 1
15
+ # 1.clamp(3, 1) # => min argument must be smaller than max argument (ArgumentError)
16
+ # ----
17
+ #
18
+ # @example
19
+ #
20
+ # # bad
21
+ # [[x, low].max, high].min
22
+ #
23
+ # # bad
24
+ # if x < low
25
+ # low
26
+ # elsif high < x
27
+ # high
28
+ # else
29
+ # x
30
+ # end
31
+ #
32
+ # # good
33
+ # x.clamp(low, high)
34
+ #
35
+ class ComparableClamp < Base
36
+ include Alignment
37
+ extend AutoCorrector
38
+ extend TargetRubyVersion
39
+
40
+ minimum_target_ruby_version 2.4
41
+
42
+ MSG = 'Use `%<prefer>s` instead of `if/elsif/else`.'
43
+ MSG_MIN_MAX = 'Use `Comparable#clamp` instead.'
44
+ RESTRICT_ON_SEND = %i[min max].freeze
45
+
46
+ # @!method if_elsif_else_condition?(node)
47
+ def_node_matcher :if_elsif_else_condition?, <<~PATTERN
48
+ {
49
+ (if (send _x :< _min) _min (if (send _max :< _x) _max _x))
50
+ (if (send _min :> _x) _min (if (send _max :< _x) _max _x))
51
+ (if (send _x :< _min) _min (if (send _x :> _max) _max _x))
52
+ (if (send _min :> _x) _min (if (send _x :> _max) _max _x))
53
+ (if (send _max :< _x) _max (if (send _x :< _min) _min _x))
54
+ (if (send _x :> _max) _max (if (send _x :< _min) _min _x))
55
+ (if (send _max :< _x) _max (if (send _min :> _x) _min _x))
56
+ (if (send _x :> _max) _max (if (send _min :> _x) _min _x))
57
+ }
58
+ PATTERN
59
+
60
+ # @!method array_min_max?(node)
61
+ def_node_matcher :array_min_max?, <<~PATTERN
62
+ {
63
+ (send
64
+ (array
65
+ (send (array _ _) :max) _) :min)
66
+ (send
67
+ (array
68
+ _ (send (array _ _) :max)) :min)
69
+ (send
70
+ (array
71
+ (send (array _ _) :min) _) :max)
72
+ (send
73
+ (array
74
+ _ (send (array _ _) :min)) :max)
75
+ }
76
+ PATTERN
77
+
78
+ def on_if(node)
79
+ return unless if_elsif_else_condition?(node)
80
+
81
+ if_body, elsif_body, else_body = *node.branches
82
+
83
+ else_body_source = else_body.source
84
+
85
+ if min_condition?(node.condition, else_body_source)
86
+ min = if_body.source
87
+ max = elsif_body.source
88
+ else
89
+ min = elsif_body.source
90
+ max = if_body.source
91
+ end
92
+
93
+ prefer = "#{else_body_source}.clamp(#{min}, #{max})"
94
+
95
+ add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
96
+ autocorrect(corrector, node, prefer)
97
+ end
98
+ end
99
+
100
+ def on_send(node)
101
+ return unless array_min_max?(node)
102
+
103
+ add_offense(node, message: MSG_MIN_MAX)
104
+ end
105
+
106
+ private
107
+
108
+ def autocorrect(corrector, node, prefer)
109
+ if node.elsif?
110
+ corrector.insert_before(node, "else\n")
111
+ corrector.replace(node, "#{indentation(node)}#{prefer}")
112
+ else
113
+ corrector.replace(node, prefer)
114
+ end
115
+ end
116
+
117
+ def min_condition?(if_condition, else_body)
118
+ lhs, op, rhs = *if_condition
119
+
120
+ (lhs.source == else_body && op == :<) || (rhs.source == else_body && op == :>)
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -218,11 +218,9 @@ module RuboCop
218
218
  VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
219
219
  ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
220
220
  LINE_LENGTH = 'Layout/LineLength'
221
- INDENTATION_WIDTH = 'Layout/IndentationWidth'
222
221
  ENABLED = 'Enabled'
223
222
  MAX = 'Max'
224
223
  SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'
225
- WIDTH = 'Width'
226
224
 
227
225
  # The shovel operator `<<` does not have its own type. It is a `send`
228
226
  # type.
@@ -428,10 +426,6 @@ module RuboCop
428
426
  config.for_cop(LINE_LENGTH)[MAX]
429
427
  end
430
428
 
431
- def indentation_width
432
- config.for_cop(INDENTATION_WIDTH)[WIDTH] || 2
433
- end
434
-
435
429
  def single_line_conditions_only?
436
430
  cop_config[SINGLE_LINE_CONDITIONS_ONLY]
437
431
  end
@@ -21,6 +21,7 @@ module RuboCop
21
21
  # work
22
22
  # end
23
23
  class InfiniteLoop < Base
24
+ include Alignment
24
25
  extend AutoCorrector
25
26
 
26
27
  LEADING_SPACE = /\A(\s*)/.freeze
@@ -106,7 +107,7 @@ module RuboCop
106
107
  else
107
108
  indentation = body.source_range.source_line[LEADING_SPACE]
108
109
 
109
- ['loop do', body.source.gsub(/^/, configured_indent), 'end'].join("\n#{indentation}")
110
+ ['loop do', body.source.gsub(/^/, indentation(node)), 'end'].join("\n#{indentation}")
110
111
  end
111
112
  end
112
113
 
@@ -120,10 +121,6 @@ module RuboCop
120
121
 
121
122
  start_range.join(end_range)
122
123
  end
123
-
124
- def configured_indent
125
- ' ' * config.for_cop('Layout/IndentationWidth')['Width']
126
- end
127
124
  end
128
125
  end
129
126
  end
@@ -0,0 +1,114 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Checks for usages of `unless` which can be replaced by `if` with inverted condition.
7
+ # Code without `unless` is easier to read, but that is subjective, so this cop
8
+ # is disabled by default.
9
+ #
10
+ # Methods that can be inverted should be defined in `InverseMethods`. Note that
11
+ # the relationship of inverse methods needs to be defined in both directions.
12
+ # For example,
13
+ # InverseMethods:
14
+ # :!=: :==
15
+ # :even?: :odd?
16
+ # :odd?: :even?
17
+ #
18
+ # will suggest both `even?` and `odd?` to be inverted, but only `!=` (and not `==`).
19
+ #
20
+ # @safety
21
+ # This cop is unsafe because it cannot be guaranteed that the method
22
+ # and its inverse method are both defined on receiver, and also are
23
+ # actually inverse of each other.
24
+ #
25
+ # @example
26
+ # # bad (simple condition)
27
+ # foo unless !bar
28
+ # foo unless x != y
29
+ # foo unless x >= 10
30
+ # foo unless x.even?
31
+ #
32
+ # # good
33
+ # foo if bar
34
+ # foo if x == y
35
+ # foo if x < 10
36
+ # foo if x.odd?
37
+ #
38
+ # # bad (complex condition)
39
+ # foo unless x != y || x.even?
40
+ #
41
+ # # good
42
+ # foo if x == y && x.odd?
43
+ #
44
+ # # good (if)
45
+ # foo if !condition
46
+ #
47
+ class InvertibleUnlessCondition < Base
48
+ extend AutoCorrector
49
+
50
+ MSG = 'Favor `if` with inverted condition over `unless`.'
51
+
52
+ def on_if(node)
53
+ return unless node.unless?
54
+
55
+ condition = node.condition
56
+ return unless invertible?(condition)
57
+
58
+ add_offense(node) do |corrector|
59
+ corrector.replace(node.loc.keyword, node.inverse_keyword)
60
+ autocorrect(corrector, condition)
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def invertible?(node)
67
+ case node.type
68
+ when :begin
69
+ invertible?(node.children.first)
70
+ when :send
71
+ return if inheritance_check?(node)
72
+
73
+ node.method?(:!) || inverse_methods.key?(node.method_name)
74
+ when :or, :and
75
+ invertible?(node.lhs) && invertible?(node.rhs)
76
+ else
77
+ false
78
+ end
79
+ end
80
+
81
+ def inheritance_check?(node)
82
+ argument = node.first_argument
83
+ node.method?(:<) &&
84
+ (argument.const_type? && argument.short_name.to_s.upcase != argument.short_name.to_s)
85
+ end
86
+
87
+ def autocorrect(corrector, node)
88
+ case node.type
89
+ when :begin
90
+ autocorrect(corrector, node.children.first)
91
+ when :send
92
+ autocorrect_send_node(corrector, node)
93
+ when :or, :and
94
+ corrector.replace(node.loc.operator, node.inverse_operator)
95
+ autocorrect(corrector, node.lhs)
96
+ autocorrect(corrector, node.rhs)
97
+ end
98
+ end
99
+
100
+ def autocorrect_send_node(corrector, node)
101
+ if node.method?(:!)
102
+ corrector.remove(node.loc.selector)
103
+ else
104
+ corrector.replace(node.loc.selector, inverse_methods[node.method_name])
105
+ end
106
+ end
107
+
108
+ def inverse_methods
109
+ @inverse_methods ||= cop_config['InverseMethods']
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -13,8 +13,7 @@ module RuboCop
13
13
 
14
14
  private
15
15
 
16
- # rubocop:disable Metrics/PerceivedComplexity
17
- def omit_parentheses(node)
16
+ def omit_parentheses(node) # rubocop:disable Metrics/PerceivedComplexity
18
17
  return unless node.parenthesized?
19
18
  return if inside_endless_method_def?(node)
20
19
  return if require_parentheses_for_hash_value_omission?(node)
@@ -28,7 +27,6 @@ module RuboCop
28
27
  autocorrect(corrector, node)
29
28
  end
30
29
  end
31
- # rubocop:enable Metrics/PerceivedComplexity
32
30
 
33
31
  def autocorrect(corrector, node)
34
32
  if parentheses_at_the_end_of_multiline_call?(node)
@@ -90,7 +88,7 @@ module RuboCop
90
88
  .end_with?('(')
91
89
  end
92
90
 
93
- def legitimate_call_with_parentheses?(node)
91
+ def legitimate_call_with_parentheses?(node) # rubocop:disable Metrics/PerceivedComplexity
94
92
  call_in_literals?(node) ||
95
93
  call_with_ambiguous_arguments?(node) ||
96
94
  call_in_logical_operators?(node) ||
@@ -98,7 +96,8 @@ module RuboCop
98
96
  call_in_single_line_inheritance?(node) ||
99
97
  allowed_multiline_call_with_parentheses?(node) ||
100
98
  allowed_chained_call_with_parentheses?(node) ||
101
- assignment_in_condition?(node)
99
+ assignment_in_condition?(node) ||
100
+ forwards_anonymous_rest_arguments?(node)
102
101
  end
103
102
 
104
103
  def call_in_literals?(node)
@@ -216,6 +215,13 @@ module RuboCop
216
215
 
217
216
  parent.assignment? && (grandparent.conditional? || grandparent.when_type?)
218
217
  end
218
+
219
+ def forwards_anonymous_rest_arguments?(node)
220
+ return false unless (last_argument = node.last_argument)
221
+ return true if last_argument.forwarded_restarg_type?
222
+
223
+ last_argument.hash_type? && last_argument.children.first&.forwarded_kwrestarg_type?
224
+ end
219
225
  end
220
226
  # rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
221
227
  end
@@ -62,6 +62,8 @@ module RuboCop
62
62
  end
63
63
 
64
64
  def same_name_assignment?(node)
65
+ return false if node.receiver
66
+
65
67
  any_assignment?(node) do |asgn_node|
66
68
  next variable_in_mass_assignment?(node.method_name, asgn_node) if asgn_node.masgn_type?
67
69
 
@@ -36,6 +36,7 @@ module RuboCop
36
36
  #
37
37
  class MinMaxComparison < Base
38
38
  extend AutoCorrector
39
+ include RangeHelp
39
40
 
40
41
  MSG = 'Use `%<prefer>s` instead.'
41
42
  GRATER_OPERATORS = %i[> >=].freeze
@@ -54,7 +55,7 @@ module RuboCop
54
55
  replacement = "[#{lhs.source}, #{rhs.source}].#{preferred_method}"
55
56
 
56
57
  add_offense(node, message: format(MSG, prefer: replacement)) do |corrector|
57
- corrector.replace(node, replacement)
58
+ autocorrect(corrector, node, replacement)
58
59
  end
59
60
  end
60
61
 
@@ -67,6 +68,15 @@ module RuboCop
67
68
  LESS_OPERATORS.include?(operator) ? 'max' : 'min'
68
69
  end
69
70
  end
71
+
72
+ def autocorrect(corrector, node, replacement)
73
+ if node.elsif?
74
+ corrector.remove(range_between(node.parent.loc.else.begin_pos, node.loc.else.begin_pos))
75
+ corrector.replace(node.else_branch, replacement)
76
+ else
77
+ corrector.replace(node, replacement)
78
+ end
79
+ end
70
80
  end
71
81
  end
72
82
  end
@@ -40,10 +40,6 @@ module RuboCop
40
40
  [condition, indented_body, indented_end].join("\n")
41
41
  end
42
42
 
43
- def configured_indentation_width
44
- super || 2
45
- end
46
-
47
43
  def indented_body(body, node)
48
44
  body_source = "#{offset(node)}#{body.source}"
49
45
  body_source.each_line.map do |line|
@@ -31,6 +31,7 @@ module RuboCop
31
31
  # baz
32
32
  # )
33
33
  class MultilineMemoization < Base
34
+ include Alignment
34
35
  include ConfigurableEnforcedStyle
35
36
  extend AutoCorrector
36
37
 
@@ -75,11 +76,10 @@ module RuboCop
75
76
  end
76
77
 
77
78
  def keyword_begin_str(node, node_buf)
78
- indent = config.for_cop('Layout/IndentationWidth')['Width'] || 2
79
79
  if node_buf.source[node.loc.begin.end_pos] == "\n"
80
80
  'begin'
81
81
  else
82
- "begin\n#{' ' * (node.loc.column + indent)}"
82
+ "begin\n#{' ' * (node.loc.column + configured_indentation_width)}"
83
83
  end
84
84
  end
85
85
 
@@ -103,11 +103,7 @@ module RuboCop
103
103
  if node.if_branch.nil?
104
104
  corrector.remove(range_by_whole_lines(node.loc.else, include_final_newline: true))
105
105
  else
106
- if_range = if_range(node)
107
- else_range = else_range(node)
108
-
109
- corrector.replace(if_range, else_range.source)
110
- corrector.replace(else_range, if_range.source)
106
+ corrector.swap(if_range(node), else_range(node))
111
107
  end
112
108
  end
113
109
 
@@ -31,6 +31,7 @@ module RuboCop
31
31
  # baz
32
32
  # end
33
33
  class OneLineConditional < Base
34
+ include Alignment
34
35
  include ConfigurableEnforcedStyle
35
36
  include OnNormalIfUnless
36
37
  extend AutoCorrector
@@ -57,7 +58,7 @@ module RuboCop
57
58
 
58
59
  def autocorrect(corrector, node)
59
60
  if always_multiline? || cannot_replace_to_ternary?(node)
60
- IfThenCorrector.new(node, indentation: indentation_width).call(corrector)
61
+ IfThenCorrector.new(node, indentation: configured_indentation_width).call(corrector)
61
62
  else
62
63
  corrector.replace(node, ternary_correction(node))
63
64
  end
@@ -67,7 +68,7 @@ module RuboCop
67
68
  replaced_node = ternary_replacement(node)
68
69
 
69
70
  return replaced_node unless node.parent
70
- return "(#{replaced_node})" if %i[and or].include?(node.parent.type)
71
+ return "(#{replaced_node})" if node.parent.operator_keyword?
71
72
  return "(#{replaced_node})" if node.parent.send_type? && node.parent.operator_method?
72
73
 
73
74
  replaced_node
@@ -116,10 +117,6 @@ module RuboCop
116
117
 
117
118
  node.respond_to?(:arguments?) && node.arguments? && !node.parenthesized_call?
118
119
  end
119
-
120
- def indentation_width
121
- @config.for_cop('Layout/IndentationWidth')['Width']
122
- end
123
120
  end
124
121
  end
125
122
  end
@@ -47,7 +47,7 @@ module RuboCop
47
47
 
48
48
  def anonymous_forwarding?(argument)
49
49
  return true if argument.forwarded_args_type? || argument.forwarded_restarg_type?
50
- return true if argument.children.first&.forwarded_kwrestarg_type?
50
+ return true if argument.hash_type? && argument.children.first&.forwarded_kwrestarg_type?
51
51
 
52
52
  argument.block_pass_type? && argument.source == '&'
53
53
  end
@@ -172,7 +172,9 @@ module RuboCop
172
172
  end
173
173
 
174
174
  def modifier_statement?(node)
175
- node && %i[if while until].include?(node.type) && node.modifier_form?
175
+ return false unless node
176
+
177
+ node.basic_conditional? && node.modifier_form?
176
178
  end
177
179
 
178
180
  # An internal class for correcting parallel assignment
@@ -86,10 +86,6 @@ module RuboCop
86
86
  def indented_else_node(expression, node)
87
87
  "else\n#{indentation(node)}#{expression}"
88
88
  end
89
-
90
- def configured_indentation_width
91
- super || 2
92
- end
93
89
  end
94
90
  end
95
91
  end
@@ -18,21 +18,27 @@ module RuboCop
18
18
 
19
19
  MSG = 'Remove the redundant double splat and braces, use keyword arguments directly.'
20
20
 
21
- # @!method double_splat_hash_braces?(node)
22
- def_node_matcher :double_splat_hash_braces?, <<~PATTERN
23
- (hash (kwsplat (hash ...)))
24
- PATTERN
25
-
26
21
  def on_hash(node)
27
22
  return if node.pairs.empty? || node.pairs.any?(&:hash_rocket?)
23
+ return unless (parent = node.parent)
24
+ return unless parent.kwsplat_type?
28
25
 
29
- grandparent = node.parent&.parent
30
- return unless double_splat_hash_braces?(grandparent)
31
-
32
- add_offense(grandparent) do |corrector|
33
- corrector.replace(grandparent, node.children.map(&:source).join(', '))
26
+ add_offense(parent) do |corrector|
27
+ corrector.remove(parent.loc.operator)
28
+ corrector.remove(opening_brace(node))
29
+ corrector.remove(closing_brace(node))
34
30
  end
35
31
  end
32
+
33
+ private
34
+
35
+ def opening_brace(node)
36
+ node.loc.begin.join(node.children.first.loc.expression.begin)
37
+ end
38
+
39
+ def closing_brace(node)
40
+ node.children.last.loc.expression.end.join(node.loc.end)
41
+ end
36
42
  end
37
43
  end
38
44
  end
@@ -88,10 +88,9 @@ module RuboCop
88
88
  return unless previous_older_sibling
89
89
 
90
90
  add_offense(node, message: format(MSG, name: node.method_name)) do |corrector|
91
- swap(
91
+ corrector.swap(
92
92
  range_with_comments_and_lines(previous_older_sibling),
93
- range_with_comments_and_lines(node.parent.if_type? ? node.parent : node),
94
- corrector: corrector
93
+ range_with_comments_and_lines(node.parent.if_type? ? node.parent : node)
95
94
  )
96
95
  end
97
96
  end
@@ -130,12 +129,6 @@ module RuboCop
130
129
  end_pos: node2.location.expression.end_pos
131
130
  ).source.include?("\n\n")
132
131
  end
133
-
134
- def swap(range1, range2, corrector:)
135
- inserted = range2.source
136
- corrector.insert_before(range1, inserted)
137
- corrector.remove(range2)
138
- end
139
132
  end
140
133
  end
141
134
  end
@@ -42,7 +42,7 @@ module RuboCop
42
42
 
43
43
  if rhs.send_type?
44
44
  check_send_node(node, rhs, var_name, var_type)
45
- elsif %i[and or].include?(rhs.type)
45
+ elsif rhs.operator_keyword?
46
46
  check_boolean_node(node, rhs, var_name, var_type)
47
47
  end
48
48
  end
@@ -76,7 +76,7 @@ module RuboCop
76
76
 
77
77
  if rhs.send_type?
78
78
  autocorrect_send_node(corrector, node, rhs)
79
- elsif %i[and or].include?(rhs.type)
79
+ elsif rhs.operator_keyword?
80
80
  autocorrect_boolean_node(corrector, node, rhs)
81
81
  end
82
82
  end
@@ -72,8 +72,10 @@ module RuboCop
72
72
 
73
73
  def each_semicolon
74
74
  tokens_for_lines.each do |line, tokens|
75
- yield line, tokens.last.column, tokens[-2] if tokens.last.semicolon?
76
- yield line, tokens.first.column if tokens.first.semicolon?
75
+ semicolon_pos = semicolon_position(tokens)
76
+ after_expr_pos = semicolon_pos == -1 ? -2 : semicolon_pos
77
+
78
+ yield line, tokens[semicolon_pos].column, tokens[after_expr_pos] if semicolon_pos
77
79
  end
78
80
  end
79
81
 
@@ -81,6 +83,26 @@ module RuboCop
81
83
  processed_source.tokens.group_by(&:line)
82
84
  end
83
85
 
86
+ def semicolon_position(tokens)
87
+ if tokens.last.semicolon?
88
+ -1
89
+ elsif tokens.first.semicolon?
90
+ 0
91
+ elsif exist_semicolon_before_right_curly_brace?(tokens)
92
+ -3
93
+ elsif exist_semicolon_after_left_curly_brace?(tokens)
94
+ 2
95
+ end
96
+ end
97
+
98
+ def exist_semicolon_before_right_curly_brace?(tokens)
99
+ tokens[-2]&.right_curly_brace? && tokens[-3]&.semicolon?
100
+ end
101
+
102
+ def exist_semicolon_after_left_curly_brace?(tokens)
103
+ tokens[1]&.left_curly_brace? && tokens[2]&.semicolon?
104
+ end
105
+
84
106
  def register_semicolon(line, column, after_expression, token_before_semicolon = nil)
85
107
  range = source_range(processed_source.buffer, line, column)
86
108
 
@@ -97,8 +97,10 @@ module RuboCop
97
97
  scope_stack.reverse_each do |scope|
98
98
  variable = scope.variables[name]
99
99
  return variable if variable
100
+
100
101
  # Only block scope allows referencing outer scope variables.
101
- return nil unless scope.node.block_type?
102
+ node = scope.node
103
+ return nil unless node.block_type? || node.numblock_type?
102
104
  end
103
105
 
104
106
  nil
@@ -50,7 +50,7 @@ module RuboCop
50
50
 
51
51
  ZERO_ARITY_SUPER_TYPE = :zsuper
52
52
 
53
- TWISTED_SCOPE_TYPES = %i[block class sclass defs module].freeze
53
+ TWISTED_SCOPE_TYPES = %i[block numblock class sclass defs module].freeze
54
54
  SCOPE_TYPES = (TWISTED_SCOPE_TYPES + [:def]).freeze
55
55
 
56
56
  SEND_TYPE = :send
@@ -2,7 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  # The bootstrap module for formatter.
5
- # @api private
6
5
  module Formatter
7
6
  require_relative 'formatter/text_util'
8
7