rubocop 1.18.2 → 1.19.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 (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +23 -6
  4. data/lib/rubocop.rb +4 -0
  5. data/lib/rubocop/cli.rb +18 -0
  6. data/lib/rubocop/config_loader.rb +1 -1
  7. data/lib/rubocop/config_loader_resolver.rb +22 -7
  8. data/lib/rubocop/config_validator.rb +18 -5
  9. data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
  10. data/lib/rubocop/cop/correctors/require_library_corrector.rb +23 -0
  11. data/lib/rubocop/cop/documentation.rb +1 -1
  12. data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
  13. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  14. data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +34 -0
  15. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +71 -0
  16. data/lib/rubocop/cop/layout/class_structure.rb +5 -1
  17. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -0
  18. data/lib/rubocop/cop/layout/end_alignment.rb +10 -2
  19. data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
  20. data/lib/rubocop/cop/layout/hash_alignment.rb +22 -18
  21. data/lib/rubocop/cop/layout/heredoc_indentation.rb +0 -7
  22. data/lib/rubocop/cop/layout/indentation_style.rb +2 -2
  23. data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
  24. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +36 -22
  25. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +22 -9
  26. data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
  27. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  28. data/lib/rubocop/cop/layout/space_inside_parens.rb +5 -5
  29. data/lib/rubocop/cop/layout/trailing_whitespace.rb +24 -1
  30. data/lib/rubocop/cop/lint/ambiguous_range.rb +105 -0
  31. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +5 -2
  32. data/lib/rubocop/cop/lint/duplicate_branch.rb +2 -1
  33. data/lib/rubocop/cop/lint/duplicate_methods.rb +8 -5
  34. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -1
  35. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  36. data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
  37. data/lib/rubocop/cop/mixin/hash_transform_method.rb +6 -1
  38. data/lib/rubocop/cop/mixin/heredoc.rb +7 -0
  39. data/lib/rubocop/cop/mixin/percent_array.rb +13 -7
  40. data/lib/rubocop/cop/mixin/require_library.rb +59 -0
  41. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  42. data/lib/rubocop/cop/naming/inclusive_language.rb +18 -1
  43. data/lib/rubocop/cop/style/block_delimiters.rb +31 -0
  44. data/lib/rubocop/cop/style/commented_keyword.rb +2 -1
  45. data/lib/rubocop/cop/style/conditional_assignment.rb +19 -5
  46. data/lib/rubocop/cop/style/double_cop_disable_directive.rb +1 -7
  47. data/lib/rubocop/cop/style/double_negation.rb +12 -1
  48. data/lib/rubocop/cop/style/encoding.rb +26 -15
  49. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  50. data/lib/rubocop/cop/style/explicit_block_argument.rb +32 -7
  51. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +8 -2
  52. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
  53. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  54. data/lib/rubocop/cop/style/hash_transform_keys.rb +0 -3
  55. data/lib/rubocop/cop/style/identical_conditional_branches.rb +30 -5
  56. data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -1
  57. data/lib/rubocop/cop/style/missing_else.rb +7 -0
  58. data/lib/rubocop/cop/style/mutable_constant.rb +6 -8
  59. data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
  60. data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +83 -0
  61. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  62. data/lib/rubocop/cop/style/semicolon.rb +32 -24
  63. data/lib/rubocop/cop/style/single_line_block_params.rb +3 -1
  64. data/lib/rubocop/cop/style/single_line_methods.rb +25 -15
  65. data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
  66. data/lib/rubocop/cop/style/special_global_vars.rb +21 -0
  67. data/lib/rubocop/cop/style/symbol_array.rb +3 -3
  68. data/lib/rubocop/cop/style/word_array.rb +23 -5
  69. data/lib/rubocop/cop/util.rb +7 -2
  70. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -1
  71. data/lib/rubocop/magic_comment.rb +44 -15
  72. data/lib/rubocop/options.rb +1 -1
  73. data/lib/rubocop/version.rb +1 -1
  74. metadata +15 -9
@@ -289,12 +289,16 @@ module RuboCop
289
289
  (node.first_line - 1).downto(1) do |annotation_line|
290
290
  break unless (comment = processed_source.comment_at_line(annotation_line))
291
291
 
292
- first_comment = comment
292
+ first_comment = comment if whole_line_comment_at_line?(annotation_line)
293
293
  end
294
294
 
295
295
  start_line_position(first_comment || node)
296
296
  end
297
297
 
298
+ def whole_line_comment_at_line?(line)
299
+ /\A\s*#/.match?(processed_source.lines[line - 1])
300
+ end
301
+
298
302
  def start_line_position(node)
299
303
  buffer.line_range(node.loc.line).begin_pos - 1
300
304
  end
@@ -38,12 +38,14 @@ module RuboCop
38
38
  class EmptyLineAfterGuardClause < Base
39
39
  include RangeHelp
40
40
  extend AutoCorrector
41
+ extend Util
41
42
 
42
43
  MSG = 'Add empty line after guard clause.'
43
44
  END_OF_HEREDOC_LINE = 1
44
45
 
45
46
  def on_if(node)
46
47
  return if correct_style?(node)
48
+ return if multiple_statements_on_line?(node)
47
49
 
48
50
  if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
49
51
  return if next_line_empty_or_enable_directive_comment?(heredoc_line(node, heredoc_node))
@@ -166,6 +168,13 @@ module RuboCop
166
168
  node
167
169
  end
168
170
  end
171
+
172
+ def multiple_statements_on_line?(node)
173
+ parent = node.parent
174
+ return false unless parent
175
+
176
+ parent.begin_type? && parent.single_line?
177
+ end
169
178
  end
170
179
  end
171
180
  end
@@ -165,9 +165,11 @@ module RuboCop
165
165
  end
166
166
 
167
167
  def alignment_node_for_variable_style(node)
168
- return node.parent if node.case_type? && node.argument?
168
+ return node.parent if node.case_type? && node.argument? &&
169
+ node.loc.line == node.parent.loc.line
170
+
171
+ assignment = assignment_or_operator_method(node)
169
172
 
170
- assignment = node.ancestors.find(&:assignment_or_similar?)
171
173
  if assignment && !line_break_before_keyword?(assignment.source_range, node)
172
174
  assignment
173
175
  else
@@ -177,6 +179,12 @@ module RuboCop
177
179
  node
178
180
  end
179
181
  end
182
+
183
+ def assignment_or_operator_method(node)
184
+ node.ancestors.find do |ancestor|
185
+ ancestor.assignment_or_similar? || ancestor.send_type? && ancestor.operator_method?
186
+ end
187
+ end
180
188
  end
181
189
  end
182
190
  end
@@ -154,7 +154,7 @@ module RuboCop
154
154
 
155
155
  def on_send(node)
156
156
  return if style != :consistent && enforce_first_argument_with_fixed_indentation?
157
- return if !node.arguments? || bare_operator?(node)
157
+ return if !node.arguments? || bare_operator?(node) || node.setter_method?
158
158
 
159
159
  indent = base_indentation(node) + configured_indentation_width
160
160
 
@@ -213,18 +213,22 @@ module RuboCop
213
213
  check_pairs(node)
214
214
  end
215
215
 
216
- attr_accessor :offences_by, :column_deltas
216
+ attr_accessor :offenses_by, :column_deltas
217
217
 
218
218
  private
219
219
 
220
220
  def autocorrect_incompatible_with_other_cops?(node)
221
- enforce_first_argument_with_fixed_indentation? &&
222
- node.pairs.any? &&
223
- node.parent&.call_type? && node.parent.loc.selector.line == node.pairs.first.loc.line
221
+ return false unless enforce_first_argument_with_fixed_indentation? &&
222
+ node.pairs.any? &&
223
+ node.parent&.call_type?
224
+
225
+ parent_loc = node.parent.loc
226
+ selector = parent_loc.selector || parent_loc.expression
227
+ selector.line == node.pairs.first.loc.line
224
228
  end
225
229
 
226
230
  def reset!
227
- self.offences_by = {}
231
+ self.offenses_by = {}
228
232
  self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
229
233
  end
230
234
 
@@ -248,33 +252,33 @@ module RuboCop
248
252
  end
249
253
  end
250
254
 
251
- add_offences
255
+ add_offenses
252
256
  end
253
257
 
254
- def add_offences
255
- kwsplat_offences = offences_by.delete(KeywordSplatAlignment)
256
- register_offences_with_format(kwsplat_offences, KeywordSplatAlignment)
258
+ def add_offenses
259
+ kwsplat_offenses = offenses_by.delete(KeywordSplatAlignment)
260
+ register_offenses_with_format(kwsplat_offenses, KeywordSplatAlignment)
257
261
 
258
- format, offences = offences_by.min_by { |_, v| v.length }
259
- register_offences_with_format(offences, format)
262
+ format, offenses = offenses_by.min_by { |_, v| v.length }
263
+ register_offenses_with_format(offenses, format)
260
264
  end
261
265
 
262
- def register_offences_with_format(offences, format)
263
- (offences || []).each do |offence|
264
- add_offense(offence, message: MESSAGES[format]) do |corrector|
265
- delta = column_deltas[alignment_for(offence).first.class][offence]
266
+ def register_offenses_with_format(offenses, format)
267
+ (offenses || []).each do |offense|
268
+ add_offense(offense, message: MESSAGES[format]) do |corrector|
269
+ delta = column_deltas[alignment_for(offense).first.class][offense]
266
270
 
267
- correct_node(corrector, offence, delta) unless delta.nil?
271
+ correct_node(corrector, offense, delta) unless delta.nil?
268
272
  end
269
273
  end
270
274
  end
271
275
 
272
276
  def check_delta(delta, node:, alignment:)
273
- offences_by[alignment.class] ||= []
277
+ offenses_by[alignment.class] ||= []
274
278
  return if good_alignment? delta
275
279
 
276
280
  column_deltas[alignment.class][node] = delta
277
- offences_by[alignment.class].push(node)
281
+ offenses_by[alignment.class].push(node)
278
282
  end
279
283
 
280
284
  def ignore_hash_argument?(node)
@@ -143,13 +143,6 @@ module RuboCop
143
143
  indent_level(base_line)
144
144
  end
145
145
 
146
- def indent_level(str)
147
- indentations = str.lines
148
- .map { |line| line[/^\s*/] }
149
- .reject { |line| line.end_with?("\n") }
150
- indentations.empty? ? 0 : indentations.min_by(&:size).size
151
- end
152
-
153
146
  # Returns '~', '-' or nil
154
147
  def heredoc_indent_type(node)
155
148
  node.source[/^<<([~-])/, 1]
@@ -43,7 +43,7 @@ module RuboCop
43
43
  str_ranges = string_literal_ranges(processed_source.ast)
44
44
 
45
45
  processed_source.lines.each.with_index(1) do |line, lineno|
46
- next unless (range = find_offence(line, lineno))
46
+ next unless (range = find_offense(line, lineno))
47
47
  next if in_string_literal?(str_ranges, range)
48
48
 
49
49
  add_offense(range) { |corrector| autocorrect(corrector, range) }
@@ -60,7 +60,7 @@ module RuboCop
60
60
  end
61
61
  end
62
62
 
63
- def find_offence(line, lineno)
63
+ def find_offense(line, lineno)
64
64
  match = if style == :spaces
65
65
  line.match(/\A\s*\t+/)
66
66
  else
@@ -57,7 +57,7 @@ module RuboCop
57
57
 
58
58
  def on_new_investigation
59
59
  processed_source.comments.each do |comment|
60
- next unless /\A#+[^#\s=:+-]/.match?(comment.text)
60
+ next unless /\A#+[^#\s=+-]/.match?(comment.text)
61
61
  next if comment.loc.line == 1 && allowed_on_first_line?(comment)
62
62
  next if doxygen_comment_style?(comment)
63
63
  next if gemfile_ruby_comment?(comment)
@@ -11,8 +11,7 @@ module RuboCop
11
11
  # concatenated string parts shall be indented regardless of `EnforcedStyle` configuration.
12
12
  #
13
13
  # If `EnforcedStyle: indented` is set, it's the second line that shall be indented one step
14
- # more than the first line. Lines 3 and forward shall be aligned with line 2. Here too there
15
- # are exceptions. Values in a hash literal are always aligned.
14
+ # more than the first line. Lines 3 and forward shall be aligned with line 2.
16
15
  #
17
16
  # @example
18
17
  # # bad
@@ -34,29 +33,44 @@ module RuboCop
34
33
  # 'z'
35
34
  # end
36
35
  #
37
- # my_hash = {
38
- # first: 'a message' \
39
- # 'in two parts'
40
- # }
41
- #
42
36
  # @example EnforcedStyle: aligned (default)
43
37
  # # bad
44
38
  # puts 'x' \
45
39
  # 'y'
46
40
  #
41
+ # my_hash = {
42
+ # first: 'a message' \
43
+ # 'in two parts'
44
+ # }
45
+ #
47
46
  # # good
48
47
  # puts 'x' \
49
48
  # 'y'
50
49
  #
50
+ # my_hash = {
51
+ # first: 'a message' \
52
+ # 'in two parts'
53
+ # }
54
+ #
51
55
  # @example EnforcedStyle: indented
52
56
  # # bad
53
57
  # result = 'x' \
54
58
  # 'y'
55
59
  #
60
+ # my_hash = {
61
+ # first: 'a message' \
62
+ # 'in two parts'
63
+ # }
64
+ #
56
65
  # # good
57
66
  # result = 'x' \
58
67
  # 'y'
59
68
  #
69
+ # my_hash = {
70
+ # first: 'a message' \
71
+ # 'in two parts'
72
+ # }
73
+ #
60
74
  class LineEndStringConcatenationIndentation < Base
61
75
  include ConfigurableEnforcedStyle
62
76
  include Alignment
@@ -70,7 +84,7 @@ module RuboCop
70
84
  return unless strings_concatenated_with_backslash?(node)
71
85
 
72
86
  children = node.children
73
- if style == :aligned && !always_indented?(node) || always_aligned?(node)
87
+ if style == :aligned && !always_indented?(node)
74
88
  check_aligned(children, 1)
75
89
  else
76
90
  check_indented(children)
@@ -85,24 +99,15 @@ module RuboCop
85
99
  private
86
100
 
87
101
  def strings_concatenated_with_backslash?(dstr_node)
88
- !dstr_node.heredoc? &&
89
- !single_string_literal?(dstr_node) &&
90
- dstr_node.children.length > 1 &&
91
- dstr_node.children.all? { |c| c.str_type? || c.dstr_type? }
92
- end
93
-
94
- def single_string_literal?(dstr_node)
95
- dstr_node.loc.respond_to?(:begin) && dstr_node.loc.begin
102
+ dstr_node.multiline? &&
103
+ dstr_node.children.all? { |c| c.str_type? || c.dstr_type? } &&
104
+ dstr_node.children.none?(&:multiline?)
96
105
  end
97
106
 
98
107
  def always_indented?(dstr_node)
99
108
  PARENT_TYPES_FOR_INDENTED.include?(dstr_node.parent&.type)
100
109
  end
101
110
 
102
- def always_aligned?(dstr_node)
103
- dstr_node.parent&.pair_type?
104
- end
105
-
106
111
  def check_aligned(children, start_index)
107
112
  base_column = children[start_index - 1].loc.column
108
113
  children[start_index..-1].each do |child|
@@ -113,11 +118,20 @@ module RuboCop
113
118
  end
114
119
 
115
120
  def check_indented(children)
116
- base_column = children[0].source_range.source_line =~ /\S/
117
- @column_delta = base_column + configured_indentation_width - children[1].loc.column
121
+ @column_delta = base_column(children[0]) + configured_indentation_width -
122
+ children[1].loc.column
118
123
  add_offense_and_correction(children[1], MSG_INDENT) if @column_delta != 0
119
124
  end
120
125
 
126
+ def base_column(child)
127
+ grandparent = child.parent.parent
128
+ if grandparent&.type == :pair
129
+ grandparent.loc.column
130
+ else
131
+ child.source_range.source_line =~ /\S/
132
+ end
133
+ end
134
+
121
135
  def add_offense_and_correction(node, message)
122
136
  add_offense(node, message: message) { |corrector| autocorrect(corrector, node) }
123
137
  end
@@ -29,8 +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 def defs class module].freeze
33
- RUBY_2_5_ANCESTOR_TYPES = (ANCESTOR_TYPES + %i[block]).freeze
32
+ ANCESTOR_TYPES = %i[kwbegin def defs class module block].freeze
34
33
  ANCESTOR_TYPES_WITH_ACCESS_MODIFIERS = %i[def defs].freeze
35
34
  ALTERNATIVE_ACCESS_MODIFIERS = %i[public_class_method private_class_method].freeze
36
35
 
@@ -118,6 +117,8 @@ module RuboCop
118
117
  ancestor_node = ancestor_node(node)
119
118
 
120
119
  return ancestor_node if ancestor_node.nil? || ancestor_node.kwbegin_type?
120
+ return if ancestor_node.respond_to?(:send_node) &&
121
+ aligned_with_line_break_method?(ancestor_node, node)
121
122
 
122
123
  assignment_node = assignment_node(ancestor_node)
123
124
  return assignment_node if same_line?(ancestor_node, assignment_node)
@@ -129,14 +130,26 @@ module RuboCop
129
130
  end
130
131
 
131
132
  def ancestor_node(node)
132
- ancestor_types =
133
- if target_ruby_version >= 2.5
134
- RUBY_2_5_ANCESTOR_TYPES
135
- else
136
- ANCESTOR_TYPES
137
- end
133
+ node.each_ancestor(*ANCESTOR_TYPES).first
134
+ end
135
+
136
+ def aligned_with_line_break_method?(ancestor_node, node)
137
+ send_node_loc = ancestor_node.send_node.loc
138
+ do_keyword_line = ancestor_node.loc.begin.line
139
+ rescue_keyword_column = node.loc.keyword.column
140
+ selector = send_node_loc.respond_to?(:selector) ? send_node_loc.selector : send_node_loc
141
+
142
+ if aligned_with_leading_dot?(do_keyword_line, send_node_loc, rescue_keyword_column)
143
+ return true
144
+ end
145
+
146
+ do_keyword_line == selector.line && rescue_keyword_column == selector.column
147
+ end
148
+
149
+ def aligned_with_leading_dot?(do_keyword_line, send_node_loc, rescue_keyword_column)
150
+ return false unless send_node_loc.respond_to?(:dot) && (dot = send_node_loc.dot)
138
151
 
139
- node.each_ancestor(*ancestor_types).first
152
+ do_keyword_line == dot.line && rescue_keyword_column == dot.column
140
153
  end
141
154
 
142
155
  def assignment_node(node)
@@ -63,6 +63,10 @@ module RuboCop
63
63
  [Style::SelfAssignment]
64
64
  end
65
65
 
66
+ def on_sclass(node)
67
+ check_operator(:sclass, node.loc.operator, node.source_range)
68
+ end
69
+
66
70
  def on_pair(node)
67
71
  return unless node.hash_rocket?
68
72
 
@@ -104,6 +108,14 @@ module RuboCop
104
108
  check_operator(:assignment, node.loc.operator, rhs.source_range)
105
109
  end
106
110
 
111
+ def on_casgn(node)
112
+ _, _, right, = *node
113
+
114
+ return unless right
115
+
116
+ check_operator(:assignment, node.loc.operator, right.source_range)
117
+ end
118
+
107
119
  def on_binary(node)
108
120
  _, rhs, = *node
109
121
 
@@ -130,7 +142,6 @@ module RuboCop
130
142
  alias on_and on_binary
131
143
  alias on_lvasgn on_assignment
132
144
  alias on_masgn on_assignment
133
- alias on_casgn on_special_asgn
134
145
  alias on_ivasgn on_assignment
135
146
  alias on_cvasgn on_assignment
136
147
  alias on_gvasgn on_assignment
@@ -18,7 +18,7 @@ module RuboCop
18
18
  MSG = 'Put a space before an end-of-line comment.'
19
19
 
20
20
  def on_new_investigation
21
- processed_source.tokens.each_cons(2) do |token1, token2|
21
+ processed_source.sorted_tokens.each_cons(2) do |token1, token2|
22
22
  next unless token2.comment?
23
23
  next unless token1.line == token2.line
24
24
  next unless token1.pos.end == token2.pos.begin
@@ -43,12 +43,12 @@ module RuboCop
43
43
  MSG_SPACE = 'No space inside parentheses detected.'
44
44
 
45
45
  def on_new_investigation
46
- @processed_source = processed_source
46
+ tokens = processed_source.sorted_tokens
47
47
 
48
48
  if style == :space
49
- process_with_space_style(processed_source)
49
+ process_with_space_style(tokens)
50
50
  else
51
- each_extraneous_space(processed_source.tokens) do |range|
51
+ each_extraneous_space(tokens) do |range|
52
52
  add_offense(range) do |corrector|
53
53
  corrector.remove(range)
54
54
  end
@@ -58,8 +58,8 @@ module RuboCop
58
58
 
59
59
  private
60
60
 
61
- def process_with_space_style(processed_source)
62
- processed_source.tokens.each_cons(2) do |token1, token2|
61
+ def process_with_space_style(tokens)
62
+ tokens.each_cons(2) do |token1, token2|
63
63
  each_extraneous_space_in_empty_parens(token1, token2) do |range|
64
64
  add_offense(range) do |corrector|
65
65
  corrector.remove(range)