rubocop 1.16.1 → 1.18.3

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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +70 -29
  4. data/lib/rubocop.rb +2 -0
  5. data/lib/rubocop/cli/command/suggest_extensions.rb +3 -3
  6. data/lib/rubocop/config_loader.rb +1 -1
  7. data/lib/rubocop/config_loader_resolver.rb +1 -1
  8. data/lib/rubocop/config_validator.rb +5 -5
  9. data/lib/rubocop/cop/base.rb +2 -2
  10. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  11. data/lib/rubocop/cop/bundler/gem_version.rb +38 -4
  12. data/lib/rubocop/cop/corrector.rb +4 -4
  13. data/lib/rubocop/cop/generator.rb +1 -1
  14. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
  15. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  16. data/lib/rubocop/cop/layout/array_alignment.rb +2 -2
  17. data/lib/rubocop/cop/layout/block_alignment.rb +1 -1
  18. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +7 -1
  19. data/lib/rubocop/cop/layout/comment_indentation.rb +1 -1
  20. data/lib/rubocop/cop/layout/dot_position.rb +7 -1
  21. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +13 -15
  22. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
  23. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
  24. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  25. data/lib/rubocop/cop/layout/hash_alignment.rb +11 -9
  26. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  27. data/lib/rubocop/cop/layout/indentation_width.rb +8 -0
  28. data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +122 -0
  29. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +6 -6
  30. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +2 -2
  31. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +6 -6
  32. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -6
  33. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +6 -6
  34. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +3 -3
  35. data/lib/rubocop/cop/layout/parameter_alignment.rb +2 -2
  36. data/lib/rubocop/cop/layout/redundant_line_break.rb +11 -9
  37. data/lib/rubocop/cop/layout/space_around_keyword.rb +12 -0
  38. data/lib/rubocop/cop/layout/space_around_operators.rb +11 -1
  39. data/lib/rubocop/cop/lint/literal_as_condition.rb +13 -1
  40. data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +32 -17
  41. data/lib/rubocop/cop/lint/nested_percent_literal.rb +1 -1
  42. data/lib/rubocop/cop/lint/percent_string_array.rb +1 -1
  43. data/lib/rubocop/cop/lint/percent_symbol_array.rb +1 -1
  44. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +93 -65
  45. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +5 -0
  46. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  47. data/lib/rubocop/cop/lint/unused_block_argument.rb +1 -1
  48. data/lib/rubocop/cop/lint/useless_assignment.rb +1 -1
  49. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  50. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  51. data/lib/rubocop/cop/migration/department_name.rb +3 -1
  52. data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -1
  53. data/lib/rubocop/cop/naming/inclusive_language.rb +249 -0
  54. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +2 -2
  55. data/lib/rubocop/cop/style/block_delimiters.rb +15 -0
  56. data/lib/rubocop/cop/style/class_and_module_children.rb +14 -0
  57. data/lib/rubocop/cop/style/comment_annotation.rb +50 -6
  58. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +8 -2
  59. data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
  60. data/lib/rubocop/cop/style/identical_conditional_branches.rb +29 -0
  61. data/lib/rubocop/cop/style/multiple_comparison.rb +1 -1
  62. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
  63. data/lib/rubocop/cop/style/quoted_symbols.rb +2 -2
  64. data/lib/rubocop/cop/style/raise_args.rb +2 -0
  65. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +1 -1
  66. data/lib/rubocop/cop/style/regexp_literal.rb +10 -1
  67. data/lib/rubocop/cop/style/single_line_methods.rb +11 -6
  68. data/lib/rubocop/cop/style/special_global_vars.rb +3 -3
  69. data/lib/rubocop/cop/style/string_concatenation.rb +32 -5
  70. data/lib/rubocop/cop/style/string_literals.rb +2 -2
  71. data/lib/rubocop/cop/style/swap_values.rb +1 -1
  72. data/lib/rubocop/cop/style/unpack_first.rb +1 -1
  73. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  74. data/lib/rubocop/directive_comment.rb +53 -5
  75. data/lib/rubocop/options.rb +4 -4
  76. data/lib/rubocop/remote_config.rb +10 -2
  77. data/lib/rubocop/rspec/cop_helper.rb +1 -1
  78. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  79. data/lib/rubocop/version.rb +1 -1
  80. metadata +5 -3
@@ -93,18 +93,18 @@ module RuboCop
93
93
  extend AutoCorrector
94
94
 
95
95
  SAME_LINE_MESSAGE = 'Closing method call brace must be on the ' \
96
- 'same line as the last argument when opening brace is on the same ' \
97
- 'line as the first argument.'
96
+ 'same line as the last argument when opening brace is on the same ' \
97
+ 'line as the first argument.'
98
98
 
99
99
  NEW_LINE_MESSAGE = 'Closing method call brace must be on the ' \
100
- 'line after the last argument when opening brace is on a separate ' \
101
- 'line from the first argument.'
100
+ 'line after the last argument when opening brace is on a separate ' \
101
+ 'line from the first argument.'
102
102
 
103
103
  ALWAYS_NEW_LINE_MESSAGE = 'Closing method call brace must be on ' \
104
- 'the line after the last argument.'
104
+ 'the line after the last argument.'
105
105
 
106
106
  ALWAYS_SAME_LINE_MESSAGE = 'Closing method call brace must be on ' \
107
- 'the same line as the last argument.'
107
+ 'the same line as the last argument.'
108
108
 
109
109
  def on_send(node)
110
110
  check_brace_layout(node)
@@ -105,18 +105,18 @@ module RuboCop
105
105
  extend AutoCorrector
106
106
 
107
107
  SAME_LINE_MESSAGE = 'Closing method definition brace must be on the ' \
108
- 'same line as the last parameter when opening brace is on the same ' \
109
- 'line as the first parameter.'
108
+ 'same line as the last parameter when opening brace is on the same ' \
109
+ 'line as the first parameter.'
110
110
 
111
111
  NEW_LINE_MESSAGE = 'Closing method definition brace must be on the ' \
112
- 'line after the last parameter when opening brace is on a separate ' \
113
- 'line from the first parameter.'
112
+ 'line after the last parameter when opening brace is on a separate ' \
113
+ 'line from the first parameter.'
114
114
 
115
115
  ALWAYS_NEW_LINE_MESSAGE = 'Closing method definition brace must be ' \
116
- 'on the line after the last parameter.'
116
+ 'on the line after the last parameter.'
117
117
 
118
118
  ALWAYS_SAME_LINE_MESSAGE = 'Closing method definition brace must be ' \
119
- 'on the same line as the last parameter.'
119
+ 'on the same line as the last parameter.'
120
120
 
121
121
  def on_def(node)
122
122
  check_brace_layout(node.arguments)
@@ -59,9 +59,9 @@ module RuboCop
59
59
  return unless style == :aligned && cop_config['IndentationWidth']
60
60
 
61
61
  raise ValidationError, 'The `Layout/MultilineOperationIndentation`' \
62
- ' cop only accepts an `IndentationWidth` ' \
63
- 'configuration parameter when ' \
64
- '`EnforcedStyle` is `indented`.'
62
+ ' cop only accepts an `IndentationWidth` ' \
63
+ 'configuration parameter when ' \
64
+ '`EnforcedStyle` is `indented`.'
65
65
  end
66
66
 
67
67
  private
@@ -73,10 +73,10 @@ module RuboCop
73
73
  extend AutoCorrector
74
74
 
75
75
  ALIGN_PARAMS_MSG = 'Align the parameters of a method definition if ' \
76
- 'they span more than one line.'
76
+ 'they span more than one line.'
77
77
 
78
78
  FIXED_INDENT_MSG = 'Use one level of indentation for parameters ' \
79
- 'following the first line of a multi-line method definition.'
79
+ 'following the first line of a multi-line method definition.'
80
80
 
81
81
  def on_def(node)
82
82
  return if node.arguments.size < 2
@@ -42,8 +42,9 @@ module RuboCop
42
42
  # # good
43
43
  # foo(a) { |x| puts x }
44
44
  #
45
- class RedundantLineBreak < Cop
45
+ class RedundantLineBreak < Base
46
46
  include CheckAssignment
47
+ extend AutoCorrector
47
48
 
48
49
  MSG = 'Redundant line break detected.'
49
50
 
@@ -55,23 +56,24 @@ module RuboCop
55
56
 
56
57
  return unless offense?(node) && !part_of_ignored_node?(node)
57
58
 
58
- add_offense(node)
59
- ignore_node(node)
59
+ register_offense(node)
60
60
  end
61
61
 
62
+ private
63
+
62
64
  def check_assignment(node, _rhs)
63
65
  return unless offense?(node)
64
66
 
65
- add_offense(node)
66
- ignore_node(node)
67
+ register_offense(node)
67
68
  end
68
69
 
69
- def autocorrect(node)
70
- ->(corrector) { corrector.replace(node.source_range, to_single_line(node.source).strip) }
70
+ def register_offense(node)
71
+ add_offense(node) do |corrector|
72
+ corrector.replace(node.source_range, to_single_line(node.source).strip)
73
+ end
74
+ ignore_node(node)
71
75
  end
72
76
 
73
- private
74
-
75
77
  def offense?(node)
76
78
  return false if configured_to_not_be_inspected?(node)
77
79
 
@@ -81,6 +81,18 @@ module RuboCop
81
81
  check(node, %i[begin end].freeze, nil)
82
82
  end
83
83
 
84
+ # Handle one-line pattern matching syntax (`in`) with `Parser::Ruby27`.
85
+ def on_match_pattern(node)
86
+ return if target_ruby_version >= 3.0
87
+
88
+ check(node, [:operator].freeze)
89
+ end
90
+
91
+ # Handle one-line pattern matching syntax (`in`) with `Parser::Ruby30`.
92
+ def on_match_pattern_p(node)
93
+ check(node, [:operator].freeze)
94
+ end
95
+
84
96
  def on_next(node)
85
97
  check(node, [:keyword].freeze)
86
98
  end
@@ -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
 
@@ -120,6 +124,12 @@ module RuboCop
120
124
  check_operator(:special_asgn, node.loc.operator, right.source_range)
121
125
  end
122
126
 
127
+ def on_match_pattern(node)
128
+ return if target_ruby_version < 3.0
129
+
130
+ check_operator(:match_pattern, node.loc.operator, node.source_range)
131
+ end
132
+
123
133
  alias on_or on_binary
124
134
  alias on_and on_binary
125
135
  alias on_lvasgn on_assignment
@@ -192,7 +202,7 @@ module RuboCop
192
202
  elsif excess_leading_space?(type, operator, with_space) ||
193
203
  excess_trailing_space?(right_operand, with_space)
194
204
  "Operator `#{operator.source}` should be surrounded " \
195
- 'by a single space.'
205
+ 'by a single space.'
196
206
  end
197
207
  end
198
208
 
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for literals used as the conditions or as
7
7
  # operands in and/or expressions serving as the conditions of
8
- # if/while/until.
8
+ # if/while/until/case-when/case-in.
9
9
  #
10
10
  # @example
11
11
  #
@@ -67,6 +67,18 @@ module RuboCop
67
67
  end
68
68
  end
69
69
 
70
+ def on_case_match(case_match_node)
71
+ if case_match_node.condition
72
+ check_case(case_match_node)
73
+ else
74
+ case_match_node.each_in_pattern do |in_pattern_node|
75
+ next unless in_pattern_node.condition.literal?
76
+
77
+ add_offense(in_pattern_node)
78
+ end
79
+ end
80
+ end
81
+
70
82
  def on_send(node)
71
83
  return unless node.negation_method?
72
84
 
@@ -45,37 +45,52 @@ module RuboCop
45
45
  class MissingCopEnableDirective < Base
46
46
  include RangeHelp
47
47
 
48
- MSG = 'Re-enable %<cop>s cop with `# rubocop:enable` after disabling it.'
49
- MSG_BOUND = 'Re-enable %<cop>s cop within %<max_range>s lines after disabling it.'
48
+ MSG = 'Re-enable %<cop>s %<type>s with `# rubocop:enable` after disabling it.'
49
+ MSG_BOUND = 'Re-enable %<cop>s %<type>s within %<max_range>s lines after disabling it.'
50
50
 
51
- # rubocop:disable Metrics/AbcSize
52
51
  def on_new_investigation
53
- max_range = cop_config['MaximumRangeSize']
54
- processed_source.disabled_line_ranges.each do |cop, line_ranges|
55
- line_ranges.each do |line_range|
56
- # This has to remain a strict inequality to handle
57
- # the case when max_range is Float::INFINITY
58
- next if line_range.max - line_range.min < max_range + 2
52
+ each_missing_enable do |cop, line_range|
53
+ # This has to remain a strict inequality to handle
54
+ # the case when max_range is Float::INFINITY
55
+ next if line_range.max - line_range.min < max_range + 2
59
56
 
60
- range = source_range(processed_source.buffer, line_range.min, (0..0))
57
+ range = source_range(processed_source.buffer, line_range.min, (0..0))
58
+ comment = processed_source.comment_at_line(line_range.begin)
61
59
 
62
- add_offense(range, message: message(max_range: max_range, cop: cop))
63
- end
60
+ add_offense(range, message: message(cop, comment))
64
61
  end
65
62
  end
66
- # rubocop:enable Metrics/AbcSize
67
63
 
68
64
  private
69
65
 
70
- def message(max_range:, cop:)
66
+ def each_missing_enable
67
+ processed_source.disabled_line_ranges.each do |cop, line_ranges|
68
+ line_ranges.each { |line_range| yield cop, line_range }
69
+ end
70
+ end
71
+
72
+ def max_range
73
+ @max_range ||= cop_config['MaximumRangeSize']
74
+ end
75
+
76
+ def message(cop, comment, type = 'cop')
77
+ if department_enabled?(cop, comment)
78
+ type = 'department'
79
+ cop = cop.split('/').first
80
+ end
81
+
71
82
  if max_range == Float::INFINITY
72
- format(MSG, cop: cop)
83
+ format(MSG, cop: cop, type: type)
73
84
  else
74
- format(MSG_BOUND, cop: cop, max_range: max_range)
85
+ format(MSG_BOUND, cop: cop, type: type, max_range: max_range)
75
86
  end
76
87
  end
88
+
89
+ def department_enabled?(cop, comment)
90
+ DirectiveComment.new(comment).in_directive_department?(cop)
91
+ end
77
92
  end
78
93
  end
79
94
  end
80
95
  end
81
- # rubocop:enable Lint/RedundantCopDisableDirective, Layout/SpaceAroundOperators
96
+ # rubocop:enable Lint/RedundantCopDisableDirective
@@ -33,7 +33,7 @@ module RuboCop
33
33
  include PercentLiteral
34
34
 
35
35
  MSG = 'Within percent literals, nested percent literals do not ' \
36
- 'function and may be unwanted in the result.'
36
+ 'function and may be unwanted in the result.'
37
37
 
38
38
  # The array of regular expressions representing percent literals that,
39
39
  # if found within a percent literal expression, will cause a
@@ -29,7 +29,7 @@ module RuboCop
29
29
  TRAILING_QUOTE = /['"]?,?$/.freeze
30
30
 
31
31
  MSG = "Within `%w`/`%W`, quotes and ',' are unnecessary and may be " \
32
- 'unwanted in the resulting strings.'
32
+ 'unwanted in the resulting strings.'
33
33
 
34
34
  def on_array(node)
35
35
  process(node, '%w', '%W')
@@ -25,7 +25,7 @@ module RuboCop
25
25
  extend AutoCorrector
26
26
 
27
27
  MSG = "Within `%i`/`%I`, ':' and ',' are unnecessary and may be " \
28
- 'unwanted in the resulting symbols.'
28
+ 'unwanted in the resulting symbols.'
29
29
 
30
30
  def on_array(node)
31
31
  process(node, '%i', '%I')
@@ -25,11 +25,12 @@ module RuboCop
25
25
  #
26
26
  # # good
27
27
  # x += 1
28
- class RedundantCopDisableDirective < Base
28
+ class RedundantCopDisableDirective < Base # rubocop:todo Metrics/ClassLength
29
29
  include RangeHelp
30
30
  extend AutoCorrector
31
31
 
32
32
  COP_NAME = 'Lint/RedundantCopDisableDirective'
33
+ DEPARTMENT_MARKER = 'DEPARTMENT'
33
34
 
34
35
  attr_accessor :offenses_to_check
35
36
 
@@ -41,12 +42,9 @@ module RuboCop
41
42
  def on_new_investigation
42
43
  return unless offenses_to_check
43
44
 
44
- cop_disabled_line_ranges = processed_source.disabled_line_ranges
45
-
46
45
  redundant_cops = Hash.new { |h, k| h[k] = Set.new }
47
46
 
48
- each_redundant_disable(cop_disabled_line_ranges,
49
- offenses_to_check) do |comment, redundant_cop|
47
+ each_redundant_disable do |comment, redundant_cop|
50
48
  redundant_cops[comment].add(redundant_cop)
51
49
  end
52
50
 
@@ -56,6 +54,14 @@ module RuboCop
56
54
 
57
55
  private
58
56
 
57
+ def cop_disabled_line_ranges
58
+ processed_source.disabled_line_ranges
59
+ end
60
+
61
+ def disabled_ranges
62
+ cop_disabled_line_ranges[COP_NAME] || [0..0]
63
+ end
64
+
59
65
  def previous_line_blank?(range)
60
66
  processed_source.buffer.source_line(range.line - 1).blank?
61
67
  end
@@ -97,32 +103,34 @@ module RuboCop
97
103
  range_with_surrounding_space(range: range, side: :right, newlines: false)
98
104
  end
99
105
 
100
- def each_redundant_disable(cop_disabled_line_ranges, offenses,
101
- &block)
102
- disabled_ranges = cop_disabled_line_ranges[COP_NAME] || [0..0]
103
-
106
+ def each_redundant_disable(&block)
104
107
  cop_disabled_line_ranges.each do |cop, line_ranges|
105
- each_already_disabled(line_ranges, disabled_ranges) { |comment| yield comment, cop }
106
-
107
- each_line_range(line_ranges, disabled_ranges, offenses, cop, &block)
108
+ each_already_disabled(cop, line_ranges, &block)
109
+ each_line_range(cop, line_ranges, &block)
108
110
  end
109
111
  end
110
112
 
111
- def each_line_range(line_ranges, disabled_ranges, offenses,
112
- cop)
113
- line_ranges.each_with_index do |line_range, ix|
114
- comment = processed_source.comment_at_line(line_range.begin)
115
- next if ignore_offense?(disabled_ranges, line_range)
113
+ def each_line_range(cop, line_ranges)
114
+ line_ranges.each_with_index do |line_range, line_range_index|
115
+ next if ignore_offense?(line_range)
116
116
 
117
- redundant_cop = find_redundant(comment, offenses, cop, line_range, line_ranges[ix + 1])
118
- yield comment, redundant_cop if redundant_cop
117
+ comment = processed_source.comment_at_line(line_range.begin)
118
+ redundant = if all_disabled?(comment)
119
+ find_redundant_all(line_range, line_ranges[line_range_index + 1])
120
+ elsif department_disabled?(cop, comment)
121
+ find_redundant_department(cop, line_range)
122
+ else
123
+ find_redundant_cop(cop, line_range)
124
+ end
125
+
126
+ yield comment, redundant if redundant
119
127
  end
120
128
  end
121
129
 
122
- def each_already_disabled(line_ranges, disabled_ranges)
130
+ def each_already_disabled(cop, line_ranges)
123
131
  line_ranges.each_cons(2) do |previous_range, range|
124
- next if ignore_offense?(disabled_ranges, range)
125
- next if previous_range.end != range.begin
132
+ next if ignore_offense?(range)
133
+ next unless followed_ranges?(previous_range, range)
126
134
 
127
135
  # If a cop is disabled in a range that begins on the same line as
128
136
  # the end of the previous range, it means that the cop was
@@ -133,42 +141,56 @@ module RuboCop
133
141
  # Comments disabling all cops don't count since it's reasonable
134
142
  # to disable a few select cops first and then all cops further
135
143
  # down in the code.
136
- yield comment if comment && !all_disabled?(comment)
144
+ yield comment, cop if comment && !all_disabled?(comment)
137
145
  end
138
146
  end
139
147
 
140
- # rubocop:todo Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
141
- def find_redundant(comment, offenses, cop, line_range, next_line_range)
142
- if all_disabled?(comment)
143
- # If there's a disable all comment followed by a comment
144
- # specifically disabling `cop`, we don't report the `all`
145
- # comment. If the disable all comment is truly redundant, we will
146
- # detect that when examining the comments of another cop, and we
147
- # get the full line range for the disable all.
148
- if (next_line_range.nil? || line_range.last != next_line_range.first) &&
149
- offenses.none? { |o| line_range.cover?(o.line) }
150
- 'all'
151
- end
152
- else
153
- cop_offenses = offenses.select { |o| o.cop_name == cop }
154
- cop if cop_offenses.none? { |o| line_range.cover?(o.line) }
155
- end
148
+ def find_redundant_cop(cop, range)
149
+ cop_offenses = offenses_to_check.select { |offense| offense.cop_name == cop }
150
+ cop if range_with_offense?(range, cop_offenses)
151
+ end
152
+
153
+ def find_redundant_all(range, next_range)
154
+ # If there's a disable all comment followed by a comment
155
+ # specifically disabling `cop`, we don't report the `all`
156
+ # comment. If the disable all comment is truly redundant, we will
157
+ # detect that when examining the comments of another cop, and we
158
+ # get the full line range for the disable all.
159
+ has_no_next_range = next_range.nil? || !followed_ranges?(range, next_range)
160
+ 'all' if has_no_next_range && range_with_offense?(range)
161
+ end
162
+
163
+ def find_redundant_department(cop, range)
164
+ department = cop.split('/').first
165
+ offenses = offenses_to_check.select { |offense| offense.cop_name.start_with?(department) }
166
+ add_department_marker(department) if range_with_offense?(range, offenses)
167
+ end
168
+
169
+ def followed_ranges?(range, next_range)
170
+ range.end == next_range.begin
171
+ end
172
+
173
+ def range_with_offense?(range, offenses = offenses_to_check)
174
+ offenses.none? { |offense| range.cover?(offense.line) }
156
175
  end
157
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
158
176
 
159
177
  def all_disabled?(comment)
160
- /rubocop\s*:\s*(?:disable|todo)\s+all\b/.match?(comment.text)
178
+ DirectiveComment.new(comment).disabled_all?
161
179
  end
162
180
 
163
- def ignore_offense?(disabled_ranges, line_range)
181
+ def ignore_offense?(line_range)
164
182
  disabled_ranges.any? do |range|
165
183
  range.cover?(line_range.min) && range.cover?(line_range.max)
166
184
  end
167
185
  end
168
186
 
187
+ def department_disabled?(cop, comment)
188
+ directive = DirectiveComment.new(comment)
189
+ directive.in_directive_department?(cop) && !directive.overridden_by_department?(cop)
190
+ end
191
+
169
192
  def directive_count(comment)
170
- _, cops_string = DirectiveComment.new(comment).match_captures
171
- cops_string.split(/,\s*/).size
193
+ DirectiveComment.new(comment).directive_count
172
194
  end
173
195
 
174
196
  def add_offenses(redundant_cops)
@@ -183,12 +205,9 @@ module RuboCop
183
205
 
184
206
  def add_offense_for_entire_comment(comment, cops)
185
207
  location = DirectiveComment.new(comment).range
186
- cop_list = cops.sort.map { |c| describe(c) }
208
+ cop_names = cops.sort.map { |c| describe(c) }.join(', ')
187
209
 
188
- add_offense(
189
- location,
190
- message: "Unnecessary disabling of #{cop_list.join(', ')}."
191
- ) do |corrector|
210
+ add_offense(location, message: message(cop_names)) do |corrector|
192
211
  range = comment_range_with_surrounding_space(location, comment.loc.expression)
193
212
  corrector.remove(range)
194
213
  end
@@ -200,10 +219,8 @@ module RuboCop
200
219
  ranges = cop_ranges.map { |_, r| r }
201
220
 
202
221
  cop_ranges.each do |cop, range|
203
- add_offense(
204
- range,
205
- message: "Unnecessary disabling of #{describe(cop)}."
206
- ) do |corrector|
222
+ cop_name = describe(cop)
223
+ add_offense(range, message: message(cop_name)) do |corrector|
207
224
  range = directive_range_in_list(range, ranges)
208
225
  corrector.remove(range)
209
226
  end
@@ -211,6 +228,7 @@ module RuboCop
211
228
  end
212
229
 
213
230
  def cop_range(comment, cop)
231
+ cop = remove_department_marker(cop)
214
232
  matching_range(comment.loc.expression, cop) ||
215
233
  matching_range(comment.loc.expression, Badge.parse(cop).cop_name) ||
216
234
  raise("Couldn't find #{cop} in comment: #{comment.text}")
@@ -233,18 +251,16 @@ module RuboCop
233
251
  end
234
252
 
235
253
  def describe(cop)
236
- if cop == 'all'
237
- 'all cops'
238
- elsif all_cop_names.include?(cop)
239
- "`#{cop}`"
240
- else
241
- similar = NameSimilarity.find_similar_name(cop, all_cop_names)
242
- if similar
243
- "`#{cop}` (did you mean `#{similar}`?)"
244
- else
245
- "`#{cop}` (unknown cop)"
246
- end
247
- end
254
+ return 'all cops' if cop == 'all'
255
+ return "`#{remove_department_marker(cop)}` department" if department_marker?(cop)
256
+ return "`#{cop}`" if all_cop_names.include?(cop)
257
+
258
+ similar = NameSimilarity.find_similar_name(cop, all_cop_names)
259
+ similar ? "`#{cop}` (did you mean `#{similar}`?)" : "`#{cop}` (unknown cop)"
260
+ end
261
+
262
+ def message(cop_names)
263
+ "Unnecessary disabling of #{cop_names}."
248
264
  end
249
265
 
250
266
  def all_cop_names
@@ -255,6 +271,18 @@ module RuboCop
255
271
  line = range.source_buffer.source_line(range.last_line)
256
272
  (line =~ /\s*\z/) == range.last_column
257
273
  end
274
+
275
+ def department_marker?(department)
276
+ department.start_with?(DEPARTMENT_MARKER)
277
+ end
278
+
279
+ def remove_department_marker(department)
280
+ department.gsub(DEPARTMENT_MARKER, '')
281
+ end
282
+
283
+ def add_department_marker(department)
284
+ DEPARTMENT_MARKER + department
285
+ end
258
286
  end
259
287
  end
260
288
  end