rubocop 1.4.1 → 1.6.0

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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +54 -11
  4. data/config/obsoletion.yml +196 -0
  5. data/lib/rubocop.rb +14 -0
  6. data/lib/rubocop/cli.rb +5 -1
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +80 -0
  8. data/lib/rubocop/config_loader.rb +1 -1
  9. data/lib/rubocop/config_loader_resolver.rb +5 -1
  10. data/lib/rubocop/config_obsoletion.rb +65 -247
  11. data/lib/rubocop/config_obsoletion/changed_enforced_styles.rb +33 -0
  12. data/lib/rubocop/config_obsoletion/changed_parameter.rb +21 -0
  13. data/lib/rubocop/config_obsoletion/cop_rule.rb +34 -0
  14. data/lib/rubocop/config_obsoletion/extracted_cop.rb +44 -0
  15. data/lib/rubocop/config_obsoletion/parameter_rule.rb +44 -0
  16. data/lib/rubocop/config_obsoletion/removed_cop.rb +41 -0
  17. data/lib/rubocop/config_obsoletion/renamed_cop.rb +34 -0
  18. data/lib/rubocop/config_obsoletion/rule.rb +41 -0
  19. data/lib/rubocop/config_obsoletion/split_cop.rb +27 -0
  20. data/lib/rubocop/config_validator.rb +18 -4
  21. data/lib/rubocop/cop/autocorrect_logic.rb +21 -6
  22. data/lib/rubocop/cop/base.rb +17 -15
  23. data/lib/rubocop/cop/cop.rb +2 -2
  24. data/lib/rubocop/cop/correctors/string_literal_corrector.rb +6 -8
  25. data/lib/rubocop/cop/generator.rb +1 -1
  26. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +3 -3
  27. data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +6 -1
  28. data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
  29. data/lib/rubocop/cop/layout/end_of_line.rb +5 -5
  30. data/lib/rubocop/cop/layout/first_argument_indentation.rb +7 -2
  31. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +12 -0
  32. data/lib/rubocop/cop/layout/line_length.rb +6 -16
  33. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +7 -3
  34. data/lib/rubocop/cop/lint/interpolation_check.rb +7 -2
  35. data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +1 -1
  36. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -0
  37. data/lib/rubocop/cop/lint/unexpected_block_arity.rb +85 -0
  38. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +7 -2
  39. data/lib/rubocop/cop/metrics/abc_size.rb +25 -1
  40. data/lib/rubocop/cop/metrics/block_length.rb +13 -7
  41. data/lib/rubocop/cop/metrics/method_length.rb +7 -2
  42. data/lib/rubocop/cop/metrics/parameter_lists.rb +64 -1
  43. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +20 -10
  44. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +146 -0
  45. data/lib/rubocop/cop/metrics/utils/repeated_csend_discount.rb +6 -1
  46. data/lib/rubocop/cop/migration/department_name.rb +1 -1
  47. data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -2
  48. data/lib/rubocop/cop/mixin/enforce_superclass.rb +9 -1
  49. data/lib/rubocop/cop/mixin/ignored_methods.rb +36 -3
  50. data/lib/rubocop/cop/mixin/method_complexity.rb +6 -0
  51. data/lib/rubocop/cop/mixin/string_help.rb +4 -1
  52. data/lib/rubocop/cop/naming/accessor_method_name.rb +15 -1
  53. data/lib/rubocop/cop/naming/variable_number.rb +3 -1
  54. data/lib/rubocop/cop/style/and_or.rb +10 -0
  55. data/lib/rubocop/cop/style/character_literal.rb +10 -11
  56. data/lib/rubocop/cop/style/class_and_module_children.rb +8 -3
  57. data/lib/rubocop/cop/style/float_division.rb +44 -1
  58. data/lib/rubocop/cop/style/format_string.rb +8 -3
  59. data/lib/rubocop/cop/style/if_unless_modifier.rb +4 -0
  60. data/lib/rubocop/cop/style/if_with_semicolon.rb +39 -4
  61. data/lib/rubocop/cop/style/ip_addresses.rb +1 -1
  62. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -2
  63. data/lib/rubocop/cop/style/numeric_literals.rb +14 -11
  64. data/lib/rubocop/cop/style/perl_backrefs.rb +86 -9
  65. data/lib/rubocop/cop/style/redundant_argument.rb +17 -2
  66. data/lib/rubocop/cop/style/redundant_condition.rb +2 -1
  67. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +24 -8
  68. data/lib/rubocop/cop/style/single_line_block_params.rb +30 -7
  69. data/lib/rubocop/cop/style/sole_nested_conditional.rb +65 -3
  70. data/lib/rubocop/cop/style/special_global_vars.rb +1 -13
  71. data/lib/rubocop/cop/style/string_concatenation.rb +26 -1
  72. data/lib/rubocop/cop/style/string_literals.rb +14 -8
  73. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +4 -3
  74. data/lib/rubocop/cop/style/symbol_proc.rb +5 -3
  75. data/lib/rubocop/core_ext/hash.rb +20 -0
  76. data/lib/rubocop/ext/regexp_node.rb +29 -12
  77. data/lib/rubocop/ext/regexp_parser.rb +20 -9
  78. data/lib/rubocop/formatter/emacs_style_formatter.rb +2 -0
  79. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -0
  80. data/lib/rubocop/formatter/tap_formatter.rb +2 -0
  81. data/lib/rubocop/lockfile.rb +40 -0
  82. data/lib/rubocop/version.rb +1 -1
  83. metadata +32 -5
@@ -27,7 +27,7 @@ module RuboCop
27
27
  def add_offense(node_or_range, location: :expression, message: nil, severity: nil, &block)
28
28
  @v0_argument = node_or_range
29
29
  range = find_location(node_or_range, location)
30
- if block.nil? && !autocorrect?
30
+ if block.nil? && !support_autocorrect?
31
31
  super(range, message: message, severity: severity)
32
32
  else
33
33
  super(range, message: message, severity: severity) do |corrector|
@@ -136,7 +136,7 @@ module RuboCop
136
136
  end
137
137
 
138
138
  def correction_lambda
139
- return unless correction_strategy == :attempt_correction && support_autocorrect?
139
+ return unless support_autocorrect?
140
140
 
141
141
  dedup_on_node(@v0_argument) do
142
142
  autocorrect(@v0_argument)
@@ -7,16 +7,14 @@ module RuboCop
7
7
  extend Util
8
8
 
9
9
  class << self
10
- def correct(node, style)
10
+ def correct(corrector, node, style)
11
11
  return if node.dstr_type?
12
12
 
13
- lambda do |corrector|
14
- str = node.str_content
15
- if style == :single_quotes
16
- corrector.replace(node, to_string_literal(str))
17
- else
18
- corrector.replace(node, str.inspect)
19
- end
13
+ str = node.str_content
14
+ if style == :single_quotes
15
+ corrector.replace(node, to_string_literal(str))
16
+ else
17
+ corrector.replace(node, str.inspect)
20
18
  end
21
19
  end
22
20
  end
@@ -139,7 +139,7 @@ module RuboCop
139
139
  badge: badge,
140
140
  version_added: version_added)
141
141
 
142
- injector.inject do
142
+ injector.inject do # rubocop:disable Lint/UnexpectedBlockArity
143
143
  output.puts(format(CONFIGURATION_ADDED_MESSAGE,
144
144
  configuration_file_path: config_file_path))
145
145
  end
@@ -3,15 +3,15 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # This cop checks whether method definitions are
7
- # separated by one empty line.
6
+ # This cop checks whether class/module/method definitions are
7
+ # separated by one or more empty lines.
8
8
  #
9
9
  # `NumberOfEmptyLines` can be an integer (default is 1) or
10
10
  # an array (e.g. [1, 2]) to specify a minimum and maximum
11
11
  # number of empty lines permitted.
12
12
  #
13
13
  # `AllowAdjacentOneLineDefs` configures whether adjacent
14
- # one-line method definitions are considered an offense.
14
+ # one-line definitions are considered an offense.
15
15
  #
16
16
  # @example EmptyLineBetweenMethodDefs: true (default)
17
17
  # # checks for empty lines between method definitions.
@@ -45,7 +45,8 @@ module RuboCop
45
45
  MSG = 'Empty line detected around arguments.'
46
46
 
47
47
  def on_send(node)
48
- return if node.single_line? || node.arguments.empty?
48
+ return if node.single_line? || node.arguments.empty? ||
49
+ receiver_and_method_call_on_different_lines?(node)
49
50
 
50
51
  extra_lines(node) do |range|
51
52
  add_offense(range) do |corrector|
@@ -57,6 +58,10 @@ module RuboCop
57
58
 
58
59
  private
59
60
 
61
+ def receiver_and_method_call_on_different_lines?(node)
62
+ node.receiver && node.receiver.loc.last_line != node.loc.selector&.line
63
+ end
64
+
60
65
  def empty_lines(node)
61
66
  lines = processed_lines(node)
62
67
  lines.select! { |code, _| code.empty? }
@@ -84,7 +84,7 @@ module RuboCop
84
84
  private
85
85
 
86
86
  def next_line_empty?(line)
87
- processed_source[line].blank?
87
+ processed_source[line].nil? || processed_source[line].blank?
88
88
  end
89
89
 
90
90
  def require_empty_line?(node)
@@ -37,14 +37,14 @@ module RuboCop
37
37
  # # good
38
38
  # puts 'Hello' # Return character is CR+LF on all platfoms.
39
39
  #
40
- class EndOfLine < Cop
40
+ class EndOfLine < Base
41
41
  include ConfigurableEnforcedStyle
42
42
  include RangeHelp
43
43
 
44
44
  MSG_DETECTED = 'Carriage return character detected.'
45
45
  MSG_MISSING = 'Carriage return character missing.'
46
46
 
47
- def investigate(processed_source)
47
+ def on_new_investigation
48
48
  last_line = last_line(processed_source)
49
49
 
50
50
  processed_source.raw_source.each_line.with_index do |line, index|
@@ -54,9 +54,9 @@ module RuboCop
54
54
  next unless msg
55
55
  next if unimportant_missing_cr?(index, last_line, line)
56
56
 
57
- range =
58
- source_range(processed_source.buffer, index + 1, 0, line.length)
59
- add_offense(nil, location: range, message: msg)
57
+ range = source_range(processed_source.buffer, index + 1, 0, line.length)
58
+
59
+ add_offense(range, message: msg)
60
60
  # Usually there will be carriage return characters on all or none
61
61
  # of the lines in a file, so we report only one offense.
62
62
  break
@@ -207,8 +207,13 @@ module RuboCop
207
207
  PATTERN
208
208
 
209
209
  def base_range(send_node, arg_node)
210
- range_between(send_node.source_range.begin_pos,
211
- arg_node.source_range.begin_pos)
210
+ parent = send_node.parent
211
+ start_node = if parent && (parent.splat_type? || parent.kwsplat_type?)
212
+ send_node.parent
213
+ else
214
+ send_node
215
+ end
216
+ range_between(start_node.source_range.begin_pos, arg_node.source_range.begin_pos)
212
217
  end
213
218
 
214
219
  # Returns the column of the given range. For single line ranges, this
@@ -69,6 +69,7 @@ module RuboCop
69
69
  return unless outermost_send
70
70
  return unless outermost_send.loc.end
71
71
  return unless heredoc_arg.first_line != outermost_send.loc.end.line
72
+ return if subsequent_closing_parentheses_in_same_line?(outermost_send)
72
73
 
73
74
  add_offense(outermost_send.loc.end) do |corrector|
74
75
  autocorrect(corrector, outermost_send)
@@ -160,6 +161,17 @@ module RuboCop
160
161
 
161
162
  # Closing parenthesis helpers.
162
163
 
164
+ def subsequent_closing_parentheses_in_same_line?(outermost_send)
165
+ last_arg_of_outer_send = outermost_send.last_argument
166
+ return false unless last_arg_of_outer_send&.loc.respond_to?(:end) &&
167
+ (end_of_last_arg_of_outer_send = last_arg_of_outer_send.loc.end)
168
+
169
+ end_of_outer_send = outermost_send.loc.end
170
+
171
+ end_of_outer_send.line == end_of_last_arg_of_outer_send.line &&
172
+ end_of_outer_send.column == end_of_last_arg_of_outer_send.column + 1
173
+ end
174
+
163
175
  def fix_closing_parenthesis(node, corrector)
164
176
  remove_incorrect_closing_paren(node, corrector)
165
177
  add_correct_closing_paren(node, corrector)
@@ -58,12 +58,13 @@ module RuboCop
58
58
  # bar: "0000000000",
59
59
  # baz: "0000000000",
60
60
  # }
61
- class LineLength < Cop
61
+ class LineLength < Base
62
62
  include CheckLineBreakable
63
63
  include ConfigurableMax
64
64
  include IgnoredPattern
65
65
  include RangeHelp
66
66
  include LineLengthHelp
67
+ extend AutoCorrector
67
68
 
68
69
  MSG = 'Line is too long. [%<length>d/%<max>d]'
69
70
 
@@ -78,28 +79,16 @@ module RuboCop
78
79
  alias on_hash on_potential_breakable_node
79
80
  alias on_send on_potential_breakable_node
80
81
 
81
- def investigate(processed_source)
82
+ def on_new_investigation
82
83
  check_for_breakable_semicolons(processed_source)
83
84
  end
84
85
 
85
- def investigate_post_walk(processed_source)
86
+ def on_investigation_end
86
87
  processed_source.lines.each_with_index do |line, line_index|
87
88
  check_line(line, line_index)
88
89
  end
89
90
  end
90
91
 
91
- def correctable?
92
- super && !breakable_range.nil?
93
- end
94
-
95
- def autocorrect(range)
96
- return if range.nil?
97
-
98
- lambda do |corrector|
99
- corrector.insert_before(range, "\n")
100
- end
101
- end
102
-
103
92
  private
104
93
 
105
94
  attr_accessor :breakable_range
@@ -203,8 +192,9 @@ module RuboCop
203
192
 
204
193
  self.breakable_range = breakable_range_by_line_index[line_index]
205
194
 
206
- add_offense(breakable_range, location: loc, message: message) do
195
+ add_offense(loc, message: message) do |corrector|
207
196
  self.max = line_length(line)
197
+ corrector.insert_before(breakable_range, "\n") unless breakable_range.nil?
208
198
  end
209
199
  end
210
200
 
@@ -77,7 +77,7 @@ module RuboCop
77
77
 
78
78
  @base = alignment_base(node, rhs, given_style)
79
79
  correct_column = if @base
80
- @base.column + extra_indentation(given_style)
80
+ @base.column + extra_indentation(given_style, node.parent)
81
81
  else
82
82
  indentation(lhs) + correct_indentation(node)
83
83
  end
@@ -85,9 +85,13 @@ module RuboCop
85
85
  rhs if @column_delta.nonzero?
86
86
  end
87
87
 
88
- def extra_indentation(given_style)
88
+ def extra_indentation(given_style, parent)
89
89
  if given_style == :indented_relative_to_receiver
90
- configured_indentation_width
90
+ if parent && (parent.splat_type? || parent.kwsplat_type?)
91
+ configured_indentation_width - parent.loc.operator.length
92
+ else
93
+ configured_indentation_width
94
+ end
91
95
  else
92
96
  0
93
97
  end
@@ -23,10 +23,11 @@ module RuboCop
23
23
  'Use double quoted strings if you need interpolation.'
24
24
 
25
25
  def on_str(node)
26
- parent = node.parent
27
- return if parent && (parent.dstr_type? || parent.regexp_type?)
26
+ return unless node
27
+ return if string_or_regex?(node.parent)
28
28
  return unless /(?<!\\)#\{.*\}/.match?(node.source)
29
29
  return if heredoc?(node)
30
+ return unless node.loc.begin && node.loc.end
30
31
 
31
32
  add_offense(node) do |corrector|
32
33
  autocorrect(corrector, node)
@@ -35,6 +36,10 @@ module RuboCop
35
36
 
36
37
  private
37
38
 
39
+ def string_or_regex?(node)
40
+ node&.dstr_type? || node&.regexp_type?
41
+ end
42
+
38
43
  def autocorrect(corrector, node)
39
44
  starting_token, ending_token = if node.source.include?('"')
40
45
  ['%{', '}']
@@ -40,7 +40,7 @@ module RuboCop
40
40
  # do_something
41
41
  # end
42
42
  #
43
- class NoReturnInBeginEndBlocks < Cop
43
+ class NoReturnInBeginEndBlocks < Base
44
44
  MSG = 'Do not `return` in `begin..end` blocks in assignment contexts.'
45
45
 
46
46
  def on_lvasgn(node)
@@ -8,6 +8,14 @@ module RuboCop
8
8
  # given by `ruby -cw` prior to Ruby 2.6:
9
9
  # "shadowing outer local variable - foo".
10
10
  #
11
+ # NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
12
+ # because `Ractor` should not access outer variables.
13
+ # eg. following syle is encouraged:
14
+ #
15
+ # worker_id, pipe = env
16
+ # Ractor.new(worker_id, pipe) do |worker_id, pipe|
17
+ # end
18
+ #
11
19
  # @example
12
20
  #
13
21
  # # bad
@@ -34,12 +42,17 @@ module RuboCop
34
42
  class ShadowingOuterLocalVariable < Base
35
43
  MSG = 'Shadowing outer local variable - `%<variable>s`.'
36
44
 
45
+ def_node_matcher :ractor_block?, <<~PATTERN
46
+ (block (send (const nil? :Ractor) :new ...) ...)
47
+ PATTERN
48
+
37
49
  def self.joining_forces
38
50
  VariableForce
39
51
  end
40
52
 
41
53
  def before_declaring_variable(variable, variable_table)
42
54
  return if variable.should_be_unused?
55
+ return if ractor_block?(variable.scope.node)
43
56
 
44
57
  outer_local_variable = variable_table.find_variable(variable.name)
45
58
  return unless outer_local_variable
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for a block that is known to need more positional
7
+ # block arguments than are given (by default this is configured for
8
+ # `Enumerable` methods needing 2 arguments). Optional arguments are allowed,
9
+ # although they don't generally make sense as the default value will
10
+ # be used. Blocks that have no receiver, or take splatted arguments
11
+ # (ie. `*args`) are always accepted.
12
+ #
13
+ # Keyword arguments (including `**kwargs`) do not get counted towards
14
+ # this, as they are not used by the methods in question.
15
+ #
16
+ # NOTE: This cop matches for method names only and hence cannot tell apart
17
+ # methods with same name in different classes.
18
+ #
19
+ # Method names and their expected arity can be configured like this:
20
+ #
21
+ # Methods:
22
+ # inject: 2
23
+ # reduce: 2
24
+ #
25
+ # @example
26
+ # # bad
27
+ # values.reduce {}
28
+ # values.min { |a| a }
29
+ # values.sort { |a; b| a + b }
30
+ #
31
+ # # good
32
+ # values.reduce { |memo, obj| memo << obj }
33
+ # values.min { |a, b| a <=> b }
34
+ # values.sort { |*x| x[0] <=> x[1] }
35
+ #
36
+ class UnexpectedBlockArity < Base
37
+ MSG = '`%<method>s` expects at least %<expected>i positional arguments, got %<actual>i.'
38
+
39
+ def on_block(node)
40
+ return if acceptable?(node)
41
+
42
+ expected = expected_arity(node.method_name)
43
+ actual = arg_count(node)
44
+ return if actual >= expected
45
+
46
+ message = format(MSG, method: node.method_name, expected: expected, actual: actual)
47
+ add_offense(node, message: message)
48
+ end
49
+
50
+ alias on_numblock on_block
51
+
52
+ private
53
+
54
+ def methods
55
+ cop_config.fetch('Methods', [])
56
+ end
57
+
58
+ def acceptable?(node)
59
+ !(included_method?(node.method_name) && node.receiver)
60
+ end
61
+
62
+ def included_method?(name)
63
+ methods.key?(name.to_s)
64
+ end
65
+
66
+ def expected_arity(method)
67
+ cop_config['Methods'][method.to_s]
68
+ end
69
+
70
+ def arg_count(node)
71
+ return node.children[1] if node.numblock_type? # the maximum numbered param for the block
72
+
73
+ # Only `arg`, `optarg` and `mlhs` (destructuring) count as arguments that
74
+ # can be used. Keyword arguments are not used for these methods so are
75
+ # ignored.
76
+ node.arguments.count do |arg|
77
+ return Float::INFINITY if arg.restarg_type?
78
+
79
+ arg.arg_type? || arg.optarg_type? || arg.mlhs_type?
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -67,7 +67,10 @@ module RuboCop
67
67
  MSG_INDEX = 'Do not return an element of the accumulator in `%<method>s`.'
68
68
 
69
69
  def_node_matcher :reduce_with_block?, <<~PATTERN
70
- (block (send _recv {:reduce :inject} ...) (args arg+) ...)
70
+ {
71
+ (block (send _recv {:reduce :inject} ...) args ...)
72
+ (numblock (send _recv {:reduce :inject} ...) ...)
73
+ }
71
74
  PATTERN
72
75
 
73
76
  def_node_matcher :accumulator_index?, <<~PATTERN
@@ -106,9 +109,11 @@ module RuboCop
106
109
 
107
110
  def on_block(node)
108
111
  return unless reduce_with_block?(node)
112
+ return unless node.argument_list.length >= 2
109
113
 
110
114
  check_return_values(node)
111
115
  end
116
+ alias on_numblock on_block
112
117
 
113
118
  private
114
119
 
@@ -146,7 +151,7 @@ module RuboCop
146
151
  end
147
152
 
148
153
  def block_arg_name(node, index)
149
- node.arguments[index].node_parts[0]
154
+ node.argument_list[index].name
150
155
  end
151
156
 
152
157
  # Look for an index of the accumulator being returned, except where the index
@@ -7,6 +7,27 @@ module RuboCop
7
7
  # configured maximum. The ABC size is based on assignments, branches
8
8
  # (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric
9
9
  # and https://en.wikipedia.org/wiki/ABC_Software_Metric.
10
+ #
11
+ # You can have repeated "attributes" calls count as a single "branch".
12
+ # For this purpose, attributes are any method with no argument; no attempt
13
+ # is meant to distinguish actual `attr_reader` from other methods.
14
+ #
15
+ # @example CountRepeatedAttributes: false (default is true)
16
+ #
17
+ # # `model` and `current_user`, refenced 3 times each,
18
+ # # are each counted as only 1 branch each if
19
+ # # `CountRepeatedAttributes` is set to 'false'
20
+ #
21
+ # def search
22
+ # @posts = model.active.visible_by(current_user)
23
+ # .search(params[:q])
24
+ # @posts = model.some_process(@posts, current_user)
25
+ # @posts = model.another_process(@posts, current_user)
26
+ #
27
+ # render 'pages/search/page'
28
+ # end
29
+ #
30
+ # This cop also takes into account `IgnoredMethods` (defaults to `[]`)
10
31
  class AbcSize < Base
11
32
  include MethodComplexity
12
33
 
@@ -16,7 +37,10 @@ module RuboCop
16
37
  private
17
38
 
18
39
  def complexity(node)
19
- Utils::AbcSizeCalculator.calculate(node)
40
+ Utils::AbcSizeCalculator.calculate(
41
+ node,
42
+ discount_repeated_attributes: !cop_config['CountRepeatedAttributes']
43
+ )
20
44
  end
21
45
  end
22
46
  end