rubocop 1.81.7 → 1.82.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +21 -5
  4. data/config/obsoletion.yml +4 -0
  5. data/lib/rubocop/cli.rb +2 -1
  6. data/lib/rubocop/comment_config.rb +62 -17
  7. data/lib/rubocop/config_loader.rb +2 -1
  8. data/lib/rubocop/config_loader_resolver.rb +2 -2
  9. data/lib/rubocop/cop/autocorrect_logic.rb +4 -0
  10. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
  11. data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -3
  12. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
  13. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
  14. data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
  15. data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
  16. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
  17. data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
  18. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  19. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -4
  20. data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
  21. data/lib/rubocop/cop/layout/indentation_width.rb +12 -1
  22. data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
  23. data/lib/rubocop/cop/layout/line_length.rb +8 -4
  24. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  25. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -1
  26. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +5 -3
  27. data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
  28. data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
  29. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  30. data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
  31. data/lib/rubocop/cop/lint/cop_directive_syntax.rb +1 -1
  32. data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
  33. data/lib/rubocop/cop/lint/else_layout.rb +19 -0
  34. data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
  35. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
  36. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
  37. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
  38. data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
  39. data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
  40. data/lib/rubocop/cop/lint/self_assignment.rb +9 -1
  41. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
  42. data/lib/rubocop/cop/lint/useless_assignment.rb +44 -16
  43. data/lib/rubocop/cop/lint/useless_or.rb +15 -2
  44. data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +1 -1
  45. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
  46. data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -4
  47. data/lib/rubocop/cop/mixin/code_length.rb +1 -1
  48. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
  49. data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
  50. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  51. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
  52. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  53. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
  54. data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
  55. data/lib/rubocop/cop/mixin/trailing_comma.rb +7 -4
  56. data/lib/rubocop/cop/naming/method_name.rb +1 -1
  57. data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
  58. data/lib/rubocop/cop/style/case_equality.rb +11 -13
  59. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
  60. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -11
  61. data/lib/rubocop/cop/style/constant_visibility.rb +3 -3
  62. data/lib/rubocop/cop/style/empty_method.rb +0 -6
  63. data/lib/rubocop/cop/style/endless_method.rb +2 -2
  64. data/lib/rubocop/cop/style/guard_clause.rb +0 -11
  65. data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
  66. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
  67. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
  68. data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
  69. data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
  70. data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
  71. data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
  72. data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
  73. data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
  74. data/lib/rubocop/cop/style/redundant_regexp_argument.rb +5 -0
  75. data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
  76. data/lib/rubocop/cop/style/super_arguments.rb +2 -2
  77. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
  78. data/lib/rubocop/cop/util.rb +2 -3
  79. data/lib/rubocop/directive_comment.rb +46 -3
  80. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -0
  81. data/lib/rubocop/lsp/diagnostic.rb +12 -17
  82. data/lib/rubocop/lsp/routes.rb +9 -36
  83. data/lib/rubocop/lsp/runtime.rb +2 -2
  84. data/lib/rubocop/lsp/server.rb +2 -2
  85. data/lib/rubocop/magic_comment.rb +20 -0
  86. data/lib/rubocop/rake_task.rb +1 -1
  87. data/lib/rubocop/remote_config.rb +7 -8
  88. data/lib/rubocop/result_cache.rb +38 -27
  89. data/lib/rubocop/rspec/shared_contexts.rb +2 -2
  90. data/lib/rubocop/rspec/support.rb +1 -1
  91. data/lib/rubocop/runner.rb +4 -0
  92. data/lib/rubocop/target_ruby.rb +1 -1
  93. data/lib/rubocop/version.rb +1 -1
  94. data/lib/rubocop.rb +1 -0
  95. metadata +8 -7
@@ -29,7 +29,7 @@ module RuboCop
29
29
  MSG = '`%<kw_loc>s` at %<kw_loc_line>d, %<kw_loc_column>d is not ' \
30
30
  'aligned with `%<beginning>s` at ' \
31
31
  '%<begin_loc_line>d, %<begin_loc_column>d.'
32
- ANCESTOR_TYPES = %i[kwbegin any_def class module any_block].freeze
32
+ ANCESTOR_TYPES = %i[kwbegin any_def class module sclass any_block].freeze
33
33
  ALTERNATIVE_ACCESS_MODIFIERS = %i[public_class_method private_class_method].freeze
34
34
 
35
35
  def on_resbody(node)
@@ -91,7 +91,7 @@ module RuboCop
91
91
  )
92
92
  end
93
93
 
94
- # rubocop:disable Metrics/AbcSize
94
+ # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
95
95
  def alignment_source(node, starting_loc)
96
96
  ending_loc =
97
97
  case node.type
@@ -100,6 +100,8 @@ module RuboCop
100
100
  when :def, :defs, :class, :module,
101
101
  :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
102
102
  node.loc.name
103
+ when :sclass
104
+ node.identifier.source_range
103
105
  when :masgn
104
106
  node.lhs.source_range
105
107
  else
@@ -109,7 +111,7 @@ module RuboCop
109
111
 
110
112
  range_between(starting_loc.begin_pos, ending_loc.end_pos).source
111
113
  end
112
- # rubocop:enable Metrics/AbcSize
114
+ # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
113
115
 
114
116
  # We will use ancestor or wrapper with access modifier.
115
117
 
@@ -23,16 +23,8 @@ module RuboCop
23
23
  cfg['EnforcedStyle'] || 'space'
24
24
  end
25
25
 
26
- def kind(token)
27
- 'comma' if token.comma? && !before_semicolon?(token)
28
- end
29
-
30
- private
31
-
32
- def before_semicolon?(token)
33
- tokens = processed_source.tokens
34
-
35
- tokens[tokens.index(token) + 1].semicolon?
26
+ def kind(token, next_token)
27
+ 'comma' if token.comma? && !next_token.semicolon?
36
28
  end
37
29
  end
38
30
  end
@@ -20,7 +20,7 @@ module RuboCop
20
20
  cfg['EnforcedStyle'] || 'space'
21
21
  end
22
22
 
23
- def kind(token)
23
+ def kind(token, _next_token)
24
24
  'semicolon' if token.semicolon?
25
25
  end
26
26
 
@@ -167,7 +167,7 @@ module RuboCop
167
167
 
168
168
  def check(node, locations, begin_keyword = DO)
169
169
  locations.each do |loc|
170
- next unless node.loc.respond_to?(loc)
170
+ next unless node.loc?(loc)
171
171
 
172
172
  range = node.loc.public_send(loc)
173
173
  next unless range
@@ -35,6 +35,26 @@ module RuboCop
35
35
  # def cook(dry_ingredients = self.dry_ingredients)
36
36
  # dry_ingredients.combine
37
37
  # end
38
+ #
39
+ # # bad
40
+ # def foo(pie = pie = pie)
41
+ # pie.heat_up
42
+ # end
43
+ #
44
+ # # good
45
+ # def foo(pie)
46
+ # pie.heat_up
47
+ # end
48
+ #
49
+ # # bad
50
+ # def foo(pie = cake = pie)
51
+ # [pie, cake].each(&:heat_up)
52
+ # end
53
+ #
54
+ # # good
55
+ # def foo(cake = pie)
56
+ # [pie, cake].each(&:heat_up)
57
+ # end
38
58
  class CircularArgumentReference < Base
39
59
  extend TargetRubyVersion
40
60
 
@@ -51,11 +71,35 @@ module RuboCop
51
71
  private
52
72
 
53
73
  def check_for_circular_argument_references(arg_name, arg_value)
54
- return unless arg_value.lvar_type?
55
- return unless arg_value.to_a == [arg_name]
74
+ if arg_value.lvar_type? && arg_value.to_a == [arg_name]
75
+ add_offense(arg_value, message: format(MSG, arg_name: arg_name))
76
+
77
+ return
78
+ end
79
+
80
+ check_assignment_chain(arg_name, arg_value)
81
+ end
82
+
83
+ # rubocop:disable Metrics/AbcSize
84
+ def check_assignment_chain(arg_name, node)
85
+ return unless node.lvasgn_type?
86
+
87
+ seen_variables = Set[]
88
+ current_node = node
89
+
90
+ while current_node.lvasgn_type?
91
+ seen_variables << current_node.children.first if current_node.lvasgn_type?
92
+ current_node = current_node.children.last
93
+ end
94
+
95
+ return unless current_node.lvar_type?
96
+
97
+ variable_node = current_node.children.first
98
+ return unless seen_variables.include?(variable_node) || variable_node == arg_name
56
99
 
57
- add_offense(arg_value, message: format(MSG, arg_name: arg_name))
100
+ add_offense(current_node, message: format(MSG, arg_name: arg_name))
58
101
  end
102
+ # rubocop:enable Metrics/AbcSize
59
103
  end
60
104
  end
61
105
  end
@@ -46,7 +46,7 @@ module RuboCop
46
46
  COMMON_MSG = 'Malformed directive comment detected.'
47
47
 
48
48
  MISSING_MODE_NAME_MSG = 'The mode name is missing.'
49
- INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, or `todo`.'
49
+ INVALID_MODE_NAME_MSG = 'The mode name must be one of `enable`, `disable`, `todo`, `push`, or `pop`.' # rubocop:disable Layout/LineLength
50
50
  MISSING_COP_NAME_MSG = 'The cop name is missing.'
51
51
  MALFORMED_COP_NAMES_MSG = 'Cop names must be separated by commas. ' \
52
52
  'Comment in the directive must start with `--`.'
@@ -25,17 +25,17 @@ module RuboCop
25
25
  #
26
26
  # # bad - repeated alternate patterns with the same conditions don't depend on the order
27
27
  # case x
28
- # in foo | bar
28
+ # in 0 | 1
29
29
  # first_method
30
- # in bar | foo
30
+ # in 1 | 0
31
31
  # second_method
32
32
  # end
33
33
  #
34
34
  # # good
35
35
  # case x
36
- # in foo | bar
36
+ # in 0 | 1
37
37
  # first_method
38
- # in bar | baz
38
+ # in 2 | 3
39
39
  # second_method
40
40
  # end
41
41
  #
@@ -38,6 +38,24 @@ module RuboCop
38
38
  # elsif do_this
39
39
  # do_that
40
40
  # end
41
+ #
42
+ # # bad
43
+ #
44
+ # # For single-line conditionals using `then` the layout is disallowed
45
+ # # when the `else` body is multiline because it is treated as a lint offense.
46
+ # if something then on_the_same_line_as_then
47
+ # else first_line
48
+ # second_line
49
+ # end
50
+ #
51
+ # # good
52
+ #
53
+ # # For single-line conditional using `then` the layout is allowed
54
+ # # when `else` body is a single-line because it is treated as intentional.
55
+ #
56
+ # if something then on_the_same_line_as_then
57
+ # else single_line
58
+ # end
41
59
  class ElseLayout < Base
42
60
  include Alignment
43
61
  include RangeHelp
@@ -47,6 +65,7 @@ module RuboCop
47
65
 
48
66
  def on_if(node)
49
67
  return if node.ternary?
68
+ return if node.then? && !node.else_branch&.begin_type?
50
69
 
51
70
  # If the if is on a single line, it'll be handled by `Style/OneLineConditional`
52
71
  return if node.single_line?
@@ -269,7 +269,11 @@ module RuboCop
269
269
  end
270
270
 
271
271
  add_offense(cond) do |corrector|
272
+ next if part_of_ignored_node?(node)
273
+
272
274
  corrector.replace(node, new_node)
275
+
276
+ ignore_node(node)
273
277
  end
274
278
  end
275
279
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
@@ -66,7 +66,7 @@ module RuboCop
66
66
 
67
67
  def special_keyword?(node)
68
68
  # handle strings like __FILE__
69
- (node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
69
+ (node.str_type? && !node.loc?(:begin)) || node.source_range.is?('__LINE__')
70
70
  end
71
71
 
72
72
  def array_in_regexp?(node)
@@ -45,6 +45,10 @@ module RuboCop
45
45
  end
46
46
  end
47
47
  end
48
+ alias on_ivasgn on_lvasgn
49
+ alias on_cvasgn on_lvasgn
50
+ alias on_gvasgn on_lvasgn
51
+ alias on_casgn on_lvasgn
48
52
  alias on_or_asgn on_lvasgn
49
53
  alias on_op_asgn on_lvasgn
50
54
  end
@@ -112,22 +112,36 @@ module RuboCop
112
112
 
113
113
  def each_line_range(cop, line_ranges)
114
114
  line_ranges.each_with_index do |line_range, line_range_index|
115
- next if ignore_offense?(line_range)
116
- next if expected_final_disable?(cop, line_range)
115
+ next if should_skip_line_range?(cop, line_range)
117
116
 
118
117
  comment = processed_source.comment_at_line(line_range.begin)
119
- redundant = if all_disabled?(comment)
120
- find_redundant_all(line_range, line_ranges[line_range_index + 1])
121
- elsif department_disabled?(cop, comment)
122
- find_redundant_department(cop, line_range)
123
- else
124
- find_redundant_cop(cop, line_range)
125
- end
118
+ next if skip_directive?(comment)
126
119
 
120
+ next_range = line_ranges[line_range_index + 1]
121
+ redundant = find_redundant_directive(cop, comment, line_range, next_range)
127
122
  yield comment, redundant if redundant
128
123
  end
129
124
  end
130
125
 
126
+ def should_skip_line_range?(cop, line_range)
127
+ ignore_offense?(line_range) || expected_final_disable?(cop, line_range)
128
+ end
129
+
130
+ def skip_directive?(comment)
131
+ directive = DirectiveComment.new(comment)
132
+ directive.push? || directive.pop?
133
+ end
134
+
135
+ def find_redundant_directive(cop, comment, line_range, next_range)
136
+ if all_disabled?(comment)
137
+ find_redundant_all(line_range, next_range)
138
+ elsif department_disabled?(cop, comment)
139
+ find_redundant_department(cop, line_range)
140
+ else
141
+ find_redundant_cop(cop, line_range)
142
+ end
143
+ end
144
+
131
145
  # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
132
146
  def each_already_disabled(cop, line_ranges)
133
147
  line_ranges.each_cons(2) do |previous_range, range|
@@ -19,7 +19,8 @@ module RuboCop
19
19
  # * 2.2+ ... Add `rational` and `complex` above
20
20
  # * 2.7+ ... Add `ruby2_keywords` above
21
21
  # * 3.1+ ... Add `fiber` above
22
- # * 3.2+ ... `set`
22
+ # * 3.2+ ... Add `set` above
23
+ # * 4.0+ ... Add `pathname` above
23
24
  #
24
25
  # This cop target those features.
25
26
  #
@@ -69,7 +70,8 @@ module RuboCop
69
70
  (target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
70
71
  (target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
71
72
  (target_ruby_version >= 3.1 && feature_name == 'fiber') ||
72
- (target_ruby_version >= 3.2 && feature_name == 'set')
73
+ (target_ruby_version >= 3.2 && feature_name == 'set') ||
74
+ (target_ruby_version >= 4.0 && feature_name == 'pathname')
73
75
  end
74
76
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
75
77
  end
@@ -144,7 +144,9 @@ module RuboCop
144
144
  expression = node.parent.source_range if node.parent.array_type?
145
145
  [expression, variable.source]
146
146
  elsif !variable.array_type?
147
- [expression, "[#{variable.source}]"]
147
+ replacement = variable.source
148
+ replacement = "[#{replacement}]" if wrap_in_brackets?(node)
149
+ [expression, replacement]
148
150
  elsif redundant_brackets?(node)
149
151
  [expression, remove_brackets(variable)]
150
152
  else
@@ -176,6 +178,10 @@ module RuboCop
176
178
  grandparent&.resbody_type?
177
179
  end
178
180
 
181
+ def wrap_in_brackets?(node)
182
+ node.parent.array_type? && !node.parent.bracketed?
183
+ end
184
+
179
185
  def remove_brackets(array)
180
186
  array_start = array.loc.begin.source
181
187
  elements = *array
@@ -23,7 +23,15 @@ module RuboCop
23
23
  # # good (method calls possibly can return different results)
24
24
  # hash[foo] = hash[foo]
25
25
  #
26
- # @example AllowRBSInlineAnnotation:true
26
+ # @example AllowRBSInlineAnnotation: false (default)
27
+ # # bad
28
+ # foo = foo #: Integer
29
+ # foo, bar = foo, bar #: Integer
30
+ # Foo = Foo #: Integer
31
+ # hash['foo'] = hash['foo'] #: Integer
32
+ # obj.attr = obj.attr #: Integer
33
+ #
34
+ # @example AllowRBSInlineAnnotation: true
27
35
  # # good
28
36
  # foo = foo #: Integer
29
37
  # foo, bar = foo, bar #: Integer
@@ -78,6 +78,7 @@ module RuboCop
78
78
  }
79
79
  PATTERN
80
80
 
81
+ # rubocop:disable Metrics/MethodLength
81
82
  def flow_expression?(node)
82
83
  return report_on_flow_command?(node) if flow_command?(node)
83
84
 
@@ -89,12 +90,14 @@ module RuboCop
89
90
  check_if(node)
90
91
  when :case, :case_match
91
92
  check_case(node)
92
- when :def
93
+ when :def, :defs
93
94
  register_redefinition(node)
95
+ false
94
96
  else
95
97
  false
96
98
  end
97
99
  end
100
+ # rubocop:enable Metrics/MethodLength
98
101
 
99
102
  def check_if(node)
100
103
  if_branch = node.if_branch
@@ -113,8 +116,7 @@ module RuboCop
113
116
  end
114
117
 
115
118
  def register_redefinition(node)
116
- @redefined << node.method_name if redefinable_flow_method? node.method_name
117
- false
119
+ @redefined << node.method_name if redefinable_flow_method?(node.method_name)
118
120
  end
119
121
 
120
122
  def instance_eval_block?(node)
@@ -52,32 +52,39 @@ module RuboCop
52
52
  scope.variables.each_value { |variable| check_for_unused_assignments(variable) }
53
53
  end
54
54
 
55
- # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
56
55
  def check_for_unused_assignments(variable)
57
56
  return if variable.should_be_unused?
58
57
 
59
58
  variable.assignments.reverse_each do |assignment|
60
- assignment_node = assignment.node
61
- next if assignment.used? || part_of_ignored_node?(assignment_node)
59
+ check_for_unused_assignment(variable, assignment)
60
+ end
61
+ end
62
62
 
63
- message = message_for_useless_assignment(assignment)
64
- range = offense_range(assignment)
63
+ def check_for_unused_assignment(variable, assignment)
64
+ assignment_node = assignment.node
65
65
 
66
- add_offense(range, message: message) do |corrector|
67
- # In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
68
- # and where changing `x ||= 1` to `x = 1` would cause `NameError`,
69
- # the autocorrect will be skipped, even if the variable is unused.
70
- if sequential_assignment?(assignment_node) || assignment_node.parent&.or_asgn_type?
71
- next
72
- end
66
+ return if ignored_assignment?(variable, assignment_node, assignment)
73
67
 
74
- autocorrect(corrector, assignment)
75
- end
68
+ message = message_for_useless_assignment(assignment)
69
+ range = offense_range(assignment)
76
70
 
77
- ignore_node(assignment_node) if chained_assignment?(assignment_node)
71
+ add_offense(range, message: message) do |corrector|
72
+ # In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
73
+ # and where changing `x ||= 1` to `x = 1` would cause `NameError`,
74
+ # the autocorrect will be skipped, even if the variable is unused.
75
+ next if sequential_assignment?(assignment_node) ||
76
+ assignment_node.parent&.or_asgn_type?
77
+
78
+ autocorrect(corrector, assignment)
78
79
  end
80
+
81
+ ignore_node(assignment_node) if chained_assignment?(assignment_node)
82
+ end
83
+
84
+ def ignored_assignment?(variable, assignment_node, assignment)
85
+ assignment.used? || part_of_ignored_node?(assignment_node) ||
86
+ variable_in_loop_condition?(assignment_node, variable)
79
87
  end
80
- # rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
81
88
 
82
89
  def message_for_useless_assignment(assignment)
83
90
  variable = assignment.variable
@@ -208,6 +215,27 @@ module RuboCop
208
215
  def remove_local_variable_assignment_part(corrector, node)
209
216
  corrector.replace(node, node.expression.source)
210
217
  end
218
+
219
+ def variable_in_loop_condition?(assignment_node, variable)
220
+ return false if assignment_node.each_ancestor(:any_def).any?
221
+
222
+ loop_node = assignment_node.each_ancestor.find do |ancestor|
223
+ ancestor.type?(*VariableForce::LOOP_TYPES)
224
+ end
225
+
226
+ return false unless loop_node.respond_to?(:condition)
227
+
228
+ condition_node = loop_node.condition
229
+ variable_name = variable.name
230
+
231
+ return true if condition_node.lvar_type? && condition_node.children.first == variable_name
232
+
233
+ condition_node.each_descendant(:lvar) do |lvar_node|
234
+ return true if lvar_node.children.first == variable_name
235
+ end
236
+
237
+ false
238
+ end
211
239
  end
212
240
  end
213
241
  end
@@ -9,6 +9,13 @@ module RuboCop
9
9
  # on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
10
10
  # appended after these methods will never evaluate.
11
11
  #
12
+ # @safety
13
+ # As shown in the examples below, there are generally two possible ways to correct the
14
+ # offense, but this cop’s autocorrection always chooses the option that preserves the
15
+ # current behavior. While this does not change how the code behaves, that option is not
16
+ # necessarily the appropriate fix in every situation. For this reason, the autocorrection
17
+ # provided by this cop is considered unsafe.
18
+ #
12
19
  # @example
13
20
  #
14
21
  # # bad
@@ -64,6 +71,8 @@ module RuboCop
64
71
  # x&.to_s or fallback
65
72
  #
66
73
  class UselessOr < Base
74
+ extend AutoCorrector
75
+
67
76
  MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
68
77
 
69
78
  TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
@@ -89,8 +98,12 @@ module RuboCop
89
98
  private
90
99
 
91
100
  def report_offense(or_node, truthy_node)
92
- add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
93
- message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
101
+ add_offense(
102
+ or_node.loc.operator.join(or_node.rhs.source_range),
103
+ message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source)
104
+ ) do |corrector|
105
+ corrector.replace(or_node, or_node.lhs.source)
106
+ end
94
107
  end
95
108
  end
96
109
  end
@@ -31,7 +31,7 @@ module RuboCop
31
31
  @checked_nodes[node] = true
32
32
 
33
33
  case node.type
34
- when :def, :class, :module, :sclass
34
+ when :def, :defs, :class, :module, :sclass
35
35
  return false
36
36
  when :send
37
37
  return non_nil_method?(node.method_name) if node.receiver == receiver
@@ -84,7 +84,10 @@ module RuboCop
84
84
  end
85
85
 
86
86
  def assignment?(node)
87
- return compound_assignment(node) if node.masgn_type? || node.shorthand_asgn?
87
+ if node.masgn_type? || node.shorthand_asgn?
88
+ compound_assignment(node)
89
+ return false
90
+ end
88
91
 
89
92
  node.for_type? ||
90
93
  (node.respond_to?(:setter_method?) && node.setter_method?) ||
@@ -101,8 +104,6 @@ module RuboCop
101
104
  child.respond_to?(:setter_method?) && !child.setter_method?
102
105
  end
103
106
  @assignment += will_be_miscounted
104
-
105
- false
106
107
  end
107
108
 
108
109
  def simple_assignment?(node)
@@ -14,6 +14,8 @@ module RuboCop
14
14
  private
15
15
 
16
16
  def too_long?(node)
17
+ return false unless max_line_length
18
+
17
19
  lines = processed_source.lines[(node.first_line - 1)...node.last_line]
18
20
  to_single_line(lines.join("\n")).length > max_line_length
19
21
  end
@@ -27,10 +29,6 @@ module RuboCop
27
29
  .gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
28
30
  end
29
31
 
30
- def max_line_length
31
- config.for_cop('Layout/LineLength')['Max']
32
- end
33
-
34
32
  def comment_within?(node)
35
33
  comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
36
34
 
@@ -59,7 +59,7 @@ module RuboCop
59
59
  return node.loc.name if node.casgn_type?
60
60
 
61
61
  if LSP.enabled?
62
- end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
62
+ end_range = node.loc?(:name) ? node.loc.name : node.loc.begin
63
63
  node.source_range.begin.join(end_range)
64
64
  else
65
65
  node.source_range
@@ -13,7 +13,7 @@ module RuboCop
13
13
 
14
14
  DefNode = Struct.new(:node) do
15
15
  def selector
16
- if node.loc.respond_to?(:selector)
16
+ if node.loc?(:selector)
17
17
  node.loc.selector
18
18
  else
19
19
  node.loc.keyword
@@ -8,8 +8,27 @@ module RuboCop
8
8
 
9
9
  private
10
10
 
11
- def ignore_cop_directives?
12
- config.for_cop('Layout/LineLength')['IgnoreCopDirectives']
11
+ def allow_rbs_inline_annotation?
12
+ config.for_cop('Layout/LineLength')['AllowRBSInlineAnnotation']
13
+ end
14
+
15
+ def rbs_inline_annotation_on_source_line?(line_index)
16
+ source_line_number = line_index + processed_source.buffer.first_line
17
+ comment = processed_source.comment_at_line(source_line_number)
18
+
19
+ return false unless comment
20
+
21
+ comment.text.start_with?(/#:|#\[.+\]|#\|/)
22
+ end
23
+
24
+ def allow_cop_directives?
25
+ # TODO: This logic for backward compatibility with deprecated `IgnoreCopDirectives` option.
26
+ # The following three lines will be removed in RuboCop 2.0.
27
+ ignore_cop_directives = config.for_cop('Layout/LineLength')['IgnoreCopDirectives']
28
+ return true if ignore_cop_directives
29
+ return false if ignore_cop_directives == false
30
+
31
+ config.for_cop('Layout/LineLength')['AllowCopDirectives']
13
32
  end
14
33
 
15
34
  def directive_on_source_line?(line_index)
@@ -73,7 +73,7 @@ module RuboCop
73
73
 
74
74
  def location(node)
75
75
  if LSP.enabled?
76
- end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
76
+ end_range = node.loc?(:name) ? node.loc.name : node.loc.begin
77
77
  node.source_range.begin.join(end_range)
78
78
  else
79
79
  node.source_range
@@ -200,7 +200,7 @@ module RuboCop
200
200
  end
201
201
 
202
202
  def grouped_expression?(node)
203
- node.begin_type? && node.loc.respond_to?(:begin) && node.loc.begin
203
+ node.begin_type? && node.loc?(:begin) && node.loc.begin
204
204
  end
205
205
 
206
206
  def inside_arg_list_parentheses?(node, ancestor)
@@ -127,7 +127,7 @@ module RuboCop
127
127
  parent ||= node
128
128
 
129
129
  if node.respond_to?(:loc) &&
130
- node.loc.respond_to?(:heredoc_end) &&
130
+ node.loc?(:heredoc_end) &&
131
131
  node.loc.heredoc_end.last_line >= parent.last_line
132
132
  return true
133
133
  end
@@ -8,8 +8,8 @@ module RuboCop
8
8
  MSG = 'Space missing after %<token>s.'
9
9
 
10
10
  def on_new_investigation
11
- each_missing_space(processed_source.tokens) do |token|
12
- add_offense(token.pos, message: format(MSG, token: kind(token))) do |corrector|
11
+ each_missing_space(processed_source.tokens) do |token, kind|
12
+ add_offense(token.pos, message: format(MSG, token: kind)) do |corrector|
13
13
  PunctuationCorrector.add_space(corrector, token)
14
14
  end
15
15
  end
@@ -19,11 +19,12 @@ module RuboCop
19
19
 
20
20
  def each_missing_space(tokens)
21
21
  tokens.each_cons(2) do |token1, token2|
22
- next unless kind(token1)
22
+ kind = kind(token1, token2)
23
+ next unless kind
23
24
  next unless space_missing?(token1, token2)
24
25
  next unless space_required_before?(token2)
25
26
 
26
- yield token1
27
+ yield token1, kind
27
28
  end
28
29
  end
29
30