rubocop 1.32.0 → 1.34.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +51 -16
  4. data/config/obsoletion.yml +23 -1
  5. data/lib/rubocop/cache_config.rb +29 -0
  6. data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
  7. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  8. data/lib/rubocop/cli/command/suggest_extensions.rb +53 -15
  9. data/lib/rubocop/config_finder.rb +68 -0
  10. data/lib/rubocop/config_loader.rb +12 -40
  11. data/lib/rubocop/config_loader_resolver.rb +1 -5
  12. data/lib/rubocop/config_obsoletion/changed_parameter.rb +5 -0
  13. data/lib/rubocop/config_obsoletion/parameter_rule.rb +4 -0
  14. data/lib/rubocop/config_obsoletion.rb +7 -2
  15. data/lib/rubocop/cop/cop.rb +1 -1
  16. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +28 -0
  17. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +61 -0
  18. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  19. data/lib/rubocop/cop/layout/block_end_newline.rb +33 -5
  20. data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
  21. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  22. data/lib/rubocop/cop/legacy/corrections_proxy.rb +1 -1
  23. data/lib/rubocop/cop/legacy/corrector.rb +1 -1
  24. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +21 -8
  25. data/lib/rubocop/cop/lint/debugger.rb +26 -16
  26. data/lib/rubocop/cop/lint/empty_conditional_body.rb +65 -1
  27. data/lib/rubocop/cop/lint/number_conversion.rb +24 -8
  28. data/lib/rubocop/cop/lint/shadowed_exception.rb +15 -0
  29. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +9 -1
  30. data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
  31. data/lib/rubocop/cop/metrics/block_length.rb +6 -7
  32. data/lib/rubocop/cop/metrics/method_length.rb +8 -8
  33. data/lib/rubocop/cop/mixin/allowed_methods.rb +15 -1
  34. data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -1
  35. data/lib/rubocop/cop/mixin/comments_help.rb +5 -1
  36. data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -1
  37. data/lib/rubocop/cop/mixin/method_complexity.rb +4 -9
  38. data/lib/rubocop/cop/mixin/range_help.rb +2 -2
  39. data/lib/rubocop/cop/naming/predicate_name.rb +24 -3
  40. data/lib/rubocop/cop/style/block_delimiters.rb +26 -7
  41. data/lib/rubocop/cop/style/class_and_module_children.rb +4 -4
  42. data/lib/rubocop/cop/style/class_equality_comparison.rb +32 -7
  43. data/lib/rubocop/cop/style/double_negation.rb +2 -0
  44. data/lib/rubocop/cop/style/empty_heredoc.rb +15 -1
  45. data/lib/rubocop/cop/style/format_string_token.rb +21 -8
  46. data/lib/rubocop/cop/style/hash_except.rb +0 -4
  47. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -1
  48. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -1
  49. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -7
  50. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -6
  51. data/lib/rubocop/cop/style/numeric_literals.rb +16 -1
  52. data/lib/rubocop/cop/style/numeric_predicate.rb +28 -8
  53. data/lib/rubocop/cop/style/redundant_condition.rb +19 -4
  54. data/lib/rubocop/cop/style/redundant_parentheses.rb +15 -22
  55. data/lib/rubocop/cop/style/redundant_sort.rb +21 -6
  56. data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -3
  57. data/lib/rubocop/cop/style/symbol_proc.rb +34 -9
  58. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -13
  59. data/lib/rubocop/ext/range.rb +15 -0
  60. data/lib/rubocop/feature_loader.rb +90 -0
  61. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  62. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  63. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  64. data/lib/rubocop/formatter/markdown_formatter.rb +1 -1
  65. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  66. data/lib/rubocop/result_cache.rb +22 -20
  67. data/lib/rubocop/server/cache.rb +33 -1
  68. data/lib/rubocop/server/cli.rb +19 -2
  69. data/lib/rubocop/version.rb +1 -1
  70. data/lib/rubocop.rb +2 -1
  71. metadata +13 -9
  72. data/lib/rubocop/cop/mixin/ignored_methods.rb +0 -52
@@ -5,9 +5,13 @@ module RuboCop
5
5
  # This autocorrects parentheses
6
6
  class ParenthesesCorrector
7
7
  class << self
8
+ include RangeHelp
9
+
8
10
  def correct(corrector, node)
9
11
  corrector.remove(node.loc.begin)
10
12
  corrector.remove(node.loc.end)
13
+ handle_orphaned_comma(corrector, node)
14
+
11
15
  return unless ternary_condition?(node) && next_char_is_question_mark?(node)
12
16
 
13
17
  corrector.insert_after(node.loc.end, ' ')
@@ -22,6 +26,30 @@ module RuboCop
22
26
  def next_char_is_question_mark?(node)
23
27
  node.loc.last_column == node.parent.loc.question.column
24
28
  end
29
+
30
+ def only_closing_paren_before_comma?(node)
31
+ source_buffer = node.source_range.source_buffer
32
+ line_range = source_buffer.line_range(node.loc.end.line)
33
+
34
+ line_range.source.start_with?(/\s*\)\s*,/)
35
+ end
36
+
37
+ # If removing parentheses leaves a comma on its own line, remove all the whitespace
38
+ # preceding it to prevent a syntax error.
39
+ def handle_orphaned_comma(corrector, node)
40
+ return unless only_closing_paren_before_comma?(node)
41
+
42
+ range = range_with_surrounding_space(
43
+ range: node.loc.end,
44
+ buffer: node.source_range.source_buffer,
45
+ side: :left,
46
+ newlines: true,
47
+ whitespace: true,
48
+ continuations: true
49
+ )
50
+
51
+ corrector.remove(range)
52
+ end
25
53
  end
26
54
  end
27
55
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Enforces the use of `node.single_line?` instead of
7
+ # comparing `first_line` and `last_line` for equality.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # node.loc.first_line == node.loc.last_line
12
+ #
13
+ # # bad
14
+ # node.loc.last_line == node.loc.first_line
15
+ #
16
+ # # bad
17
+ # node.loc.line == node.loc.last_line
18
+ #
19
+ # # bad
20
+ # node.loc.last_line == node.loc.line
21
+ #
22
+ # # bad
23
+ # node.first_line == node.last_line
24
+ #
25
+ # # good
26
+ # node.single_line?
27
+ #
28
+ class SingleLineComparison < Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'Use `%<preferred>s`.'
32
+ RESTRICT_ON_SEND = %i[==].freeze
33
+
34
+ # @!method single_line_comparison(node)
35
+ def_node_matcher :single_line_comparison, <<~PATTERN
36
+ {
37
+ (send (send $_receiver {:line :first_line}) :== (send _receiver :last_line))
38
+ (send (send $_receiver :last_line) :== (send _receiver {:line :first_line}))
39
+ }
40
+ PATTERN
41
+
42
+ def on_send(node)
43
+ return unless (receiver = single_line_comparison(node))
44
+
45
+ preferred = "#{extract_receiver(receiver)}.single_line?"
46
+
47
+ add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
48
+ corrector.replace(node, preferred)
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ def extract_receiver(node)
55
+ node = node.receiver if node.send_type? && %i[loc source_range].include?(node.method_name)
56
+ node.source
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -17,6 +17,7 @@ require_relative 'internal_affairs/redundant_let_rubocop_config_new'
17
17
  require_relative 'internal_affairs/redundant_location_argument'
18
18
  require_relative 'internal_affairs/redundant_message_argument'
19
19
  require_relative 'internal_affairs/redundant_method_dispatch_node'
20
+ require_relative 'internal_affairs/single_line_comparison'
20
21
  require_relative 'internal_affairs/style_detected_api_use'
21
22
  require_relative 'internal_affairs/undefined_config'
22
23
  require_relative 'internal_affairs/useless_message_assertion'
@@ -36,24 +36,52 @@ module RuboCop
36
36
  # If the end is on its own line, there is no offense
37
37
  return if begins_its_line?(node.loc.end)
38
38
 
39
- add_offense(node.loc.end, message: message(node)) do |corrector|
40
- corrector.replace(delimiter_range(node), "\n#{node.loc.end.source}#{offset(node)}")
41
- end
39
+ register_offense(node)
42
40
  end
43
41
 
44
42
  private
45
43
 
44
+ def register_offense(node)
45
+ add_offense(node.loc.end, message: message(node)) do |corrector|
46
+ offense_range = offense_range(node)
47
+ replacement = "\n#{offense_range.source.strip}"
48
+
49
+ if (heredoc = last_heredoc_argument(node.body))
50
+ corrector.remove(offense_range)
51
+ corrector.insert_after(heredoc.loc.heredoc_end, replacement)
52
+ else
53
+ corrector.replace(offense_range, replacement)
54
+ end
55
+ end
56
+ end
57
+
46
58
  def message(node)
47
59
  format(MSG, line: node.loc.end.line, column: node.loc.end.column + 1)
48
60
  end
49
61
 
50
- def delimiter_range(node)
62
+ def last_heredoc_argument(node)
63
+ return unless node&.call_type?
64
+ return unless (arguments = node&.arguments)
65
+
66
+ heredoc = arguments.reverse.detect { |arg| arg.str_type? && arg.heredoc? }
67
+ return heredoc if heredoc
68
+
69
+ last_heredoc_argument(node.children.first)
70
+ end
71
+
72
+ def offense_range(node)
51
73
  Parser::Source::Range.new(
52
74
  node.loc.expression.source_buffer,
53
75
  node.children.compact.last.loc.expression.end_pos,
54
- node.loc.expression.end_pos
76
+ end_of_method_chain(node).loc.expression.end_pos
55
77
  )
56
78
  end
79
+
80
+ def end_of_method_chain(node)
81
+ return node unless node.parent&.call_type?
82
+
83
+ end_of_method_chain(node.parent)
84
+ end
57
85
  end
58
86
  end
59
87
  end
@@ -153,7 +153,8 @@ module RuboCop
153
153
  MSG = 'Indent the first argument one step more than %<base>s.'
154
154
 
155
155
  def on_send(node)
156
- return if style != :consistent && enforce_first_argument_with_fixed_indentation?
156
+ return if style != :consistent && enforce_first_argument_with_fixed_indentation? &&
157
+ !enable_layout_first_method_argument_line_break?
157
158
  return if !node.arguments? || bare_operator?(node) || node.setter_method?
158
159
 
159
160
  indent = base_indentation(node) + configured_indentation_width
@@ -267,6 +268,10 @@ module RuboCop
267
268
  argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
268
269
  end
269
270
 
271
+ def enable_layout_first_method_argument_line_break?
272
+ config.for_cop('Layout/FirstMethodArgumentLineBreak')['Enabled']
273
+ end
274
+
270
275
  def argument_alignment_config
271
276
  config.for_cop('Layout/ArgumentAlignment')
272
277
  end
@@ -73,7 +73,7 @@ module RuboCop
73
73
  return if node.send_type? && node.loc.operator&.source != '='
74
74
  return unless rhs
75
75
  return unless supported_types.include?(rhs.type)
76
- return if rhs.first_line == rhs.last_line
76
+ return if rhs.single_line?
77
77
 
78
78
  check_by_enforced_style(node, rhs)
79
79
  end
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Legacy
6
6
  # Legacy support for Corrector#corrections
7
- # See https://docs.rubocop.org/rubocop/cop_api_v1_changelog.html
7
+ # See https://docs.rubocop.org/rubocop/v1_upgrade_notes.html
8
8
  class CorrectionsProxy
9
9
  def initialize(corrector)
10
10
  @corrector = corrector
@@ -4,7 +4,7 @@ module RuboCop
4
4
  module Cop
5
5
  module Legacy
6
6
  # Legacy Corrector for v0 API support.
7
- # See https://docs.rubocop.org/rubocop/cop_api_v1_changelog.html
7
+ # See https://docs.rubocop.org/rubocop/v1_upgrade_notes.html
8
8
  class Corrector < RuboCop::Cop::Corrector
9
9
  # Support legacy second argument
10
10
  def initialize(source, corr = [])
@@ -6,8 +6,8 @@ module RuboCop
6
6
  # Checks for ambiguous block association with method
7
7
  # when param passed without parentheses.
8
8
  #
9
- # This cop can customize ignored methods with `IgnoredMethods`.
10
- # By default, there are no methods to ignored.
9
+ # This cop can customize allowed methods with `AllowedMethods`.
10
+ # By default, there are no methods to allowed.
11
11
  #
12
12
  # @example
13
13
  #
@@ -30,18 +30,30 @@ module RuboCop
30
30
  # # Lambda arguments require no disambiguation
31
31
  # foo = ->(bar) { bar.baz }
32
32
  #
33
- # @example IgnoredMethods: [] (default)
33
+ # @example AllowedMethods: [] (default)
34
34
  #
35
35
  # # bad
36
36
  # expect { do_something }.to change { object.attribute }
37
37
  #
38
- # @example IgnoredMethods: [change]
38
+ # @example AllowedMethods: [change]
39
39
  #
40
40
  # # good
41
41
  # expect { do_something }.to change { object.attribute }
42
42
  #
43
+ # @example AllowedPatterns: [] (default)
44
+ #
45
+ # # bad
46
+ # expect { do_something }.to change { object.attribute }
47
+ #
48
+ # @example AllowedPatterns: [/change/]
49
+ #
50
+ # # good
51
+ # expect { do_something }.to change { object.attribute }
52
+ # expect { do_something }.to not_change { object.attribute }
53
+ #
43
54
  class AmbiguousBlockAssociation < Base
44
- include IgnoredMethods
55
+ include AllowedMethods
56
+ include AllowedPattern
45
57
 
46
58
  MSG = 'Parenthesize the param `%<param>s` to make sure that the ' \
47
59
  'block will be associated with the `%<method>s` method ' \
@@ -52,7 +64,7 @@ module RuboCop
52
64
 
53
65
  return unless ambiguous_block_association?(node)
54
66
  return if node.parenthesized? || node.last_argument.lambda? || node.last_argument.proc? ||
55
- allowed_method?(node)
67
+ allowed_method_pattern?(node)
56
68
 
57
69
  message = message(node)
58
70
 
@@ -66,9 +78,10 @@ module RuboCop
66
78
  send_node.last_argument.block_type? && !send_node.last_argument.send_node.arguments?
67
79
  end
68
80
 
69
- def allowed_method?(node)
81
+ def allowed_method_pattern?(node)
70
82
  node.assignment? || node.operator_method? || node.method?(:[]) ||
71
- ignored_method?(node.last_argument.send_node.source)
83
+ allowed_method?(node.last_argument.method_name) ||
84
+ matches_allowed_pattern?(node.last_argument.method_name)
72
85
  end
73
86
 
74
87
  def message(send_node)
@@ -15,9 +15,19 @@ module RuboCop
15
15
  # [source,yaml]
16
16
  # ----
17
17
  # Lint/Debugger:
18
- # WebConsole: ~
18
+ # DebuggerMethods:
19
+ # WebConsole: ~
19
20
  # ----
20
21
  #
22
+ # You can also add your own methods by adding a new category:
23
+ #
24
+ # [source,yaml]
25
+ # ----
26
+ # Lint/Debugger:
27
+ # DebuggerMethods:
28
+ # MyDebugger:
29
+ # MyDebugger.debug_this
30
+ # ----
21
31
  #
22
32
  # @example
23
33
  #
@@ -57,19 +67,6 @@ module RuboCop
57
67
  class Debugger < Base
58
68
  MSG = 'Remove debugger entry point `%<source>s`.'
59
69
 
60
- # @!method kernel?(node)
61
- def_node_matcher :kernel?, <<~PATTERN
62
- (const {nil? cbase} :Kernel)
63
- PATTERN
64
-
65
- # @!method valid_receiver?(node, arg1)
66
- def_node_matcher :valid_receiver?, <<~PATTERN
67
- {
68
- (const {nil? cbase} %1)
69
- (send {nil? #kernel?} %1)
70
- }
71
- PATTERN
72
-
73
70
  def on_send(node)
74
71
  return unless debugger_method?(node)
75
72
 
@@ -91,7 +88,7 @@ module RuboCop
91
88
 
92
89
  *receiver, method_name = v.split('.')
93
90
  {
94
- receiver: receiver.empty? ? nil : receiver.join.to_sym,
91
+ receiver: receiver.empty? ? nil : receiver.map(&:to_sym),
95
92
  method_name: method_name.to_sym
96
93
  }
97
94
  end.compact
@@ -105,10 +102,23 @@ module RuboCop
105
102
  if method[:receiver].nil?
106
103
  send_node.receiver.nil?
107
104
  else
108
- valid_receiver?(send_node.receiver, method[:receiver])
105
+ method[:receiver] == receiver_chain(send_node)
109
106
  end
110
107
  end
111
108
  end
109
+
110
+ def receiver_chain(send_node)
111
+ receivers = []
112
+ receiver = send_node.receiver
113
+
114
+ while receiver
115
+ name = receiver.send_type? ? receiver.method_name : receiver.const_name&.to_sym
116
+ receivers.unshift(name)
117
+ receiver = receiver.receiver
118
+ end
119
+
120
+ receivers
121
+ end
112
122
  end
113
123
  end
114
124
  end
@@ -4,6 +4,14 @@ module RuboCop
4
4
  module Cop
5
5
  module Lint
6
6
  # Checks for the presence of `if`, `elsif` and `unless` branches without a body.
7
+ #
8
+ # NOTE: empty `else` branches are handled by `Style/EmptyElse`.
9
+ #
10
+ # @safety
11
+ # Autocorrection for this cop is not safe. The conditions for empty branches that
12
+ # the autocorrection removes may have side effects, or the logic in subsequent
13
+ # branches may change due to the removal of a previous condition.
14
+ #
7
15
  # @example
8
16
  # # bad
9
17
  # if condition
@@ -53,7 +61,9 @@ module RuboCop
53
61
  # end
54
62
  #
55
63
  class EmptyConditionalBody < Base
64
+ extend AutoCorrector
56
65
  include CommentsHelp
66
+ include RangeHelp
57
67
 
58
68
  MSG = 'Avoid `%<keyword>s` branches without a body.'
59
69
 
@@ -61,7 +71,61 @@ module RuboCop
61
71
  return if node.body
62
72
  return if cop_config['AllowComments'] && contains_comments?(node)
63
73
 
64
- add_offense(node, message: format(MSG, keyword: node.keyword))
74
+ add_offense(node, message: format(MSG, keyword: node.keyword)) do |corrector|
75
+ autocorrect(corrector, node)
76
+ end
77
+ end
78
+
79
+ private
80
+
81
+ def autocorrect(corrector, node)
82
+ remove_comments(corrector, node)
83
+ remove_empty_branch(corrector, node)
84
+ correct_other_branches(corrector, node)
85
+ end
86
+
87
+ def remove_comments(corrector, node)
88
+ comments_in_range(node).each do |comment|
89
+ range = range_by_whole_lines(comment.loc.expression, include_final_newline: true)
90
+ corrector.remove(range)
91
+ end
92
+ end
93
+
94
+ def remove_empty_branch(corrector, node)
95
+ corrector.remove(deletion_range(branch_range(node)))
96
+ end
97
+
98
+ def correct_other_branches(corrector, node)
99
+ return unless (node.if? || node.unless?) && node.else_branch
100
+
101
+ if node.else_branch.if_type?
102
+ # Replace an orphaned `elsif` with `if`
103
+ corrector.replace(node.else_branch.loc.keyword, 'if')
104
+ else
105
+ # Flip orphaned `else`
106
+ corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
107
+ end
108
+ end
109
+
110
+ def branch_range(node)
111
+ if node.loc.else
112
+ node.source_range.with(end_pos: node.loc.else.begin_pos - 1)
113
+ else
114
+ node.source_range
115
+ end
116
+ end
117
+
118
+ def deletion_range(range)
119
+ # Collect a range between the start of the `if` node and the next relevant node,
120
+ # including final new line.
121
+ # Based on `RangeHelp#range_by_whole_lines` but allows the `if` to not start
122
+ # on the first column.
123
+ buffer = @processed_source.buffer
124
+
125
+ last_line = buffer.source_line(range.last_line)
126
+ end_offset = last_line.length - range.last_column + 1
127
+
128
+ range.adjust(end_pos: end_offset).intersect(buffer.source_range)
65
129
  end
66
130
  end
67
131
  end
@@ -16,8 +16,8 @@ module RuboCop
16
16
  # NOTE: Some values cannot be converted properly using one of the `Kernel`
17
17
  # method (for instance, `Time` and `DateTime` values are allowed by this
18
18
  # cop by default). Similarly, Rails' duration methods do not work well
19
- # with `Integer()` and can be ignored with `IgnoredMethods`. By default,
20
- # there are no methods to ignored.
19
+ # with `Integer()` and can be allowed with `AllowedMethods`. By default,
20
+ # there are no methods to allowed.
21
21
  #
22
22
  # @safety
23
23
  # Autocorrection is unsafe because it is not guaranteed that the
@@ -46,12 +46,22 @@ module RuboCop
46
46
  # foo.try { |i| Float(i) }
47
47
  # bar.send { |i| Complex(i) }
48
48
  #
49
- # @example IgnoredMethods: [] (default)
49
+ # @example AllowedMethods: [] (default)
50
50
  #
51
51
  # # bad
52
52
  # 10.minutes.to_i
53
53
  #
54
- # @example IgnoredMethods: [minutes]
54
+ # @example AllowedMethods: [minutes]
55
+ #
56
+ # # good
57
+ # 10.minutes.to_i
58
+ #
59
+ # @example AllowedPatterns: [] (default)
60
+ #
61
+ # # bad
62
+ # 10.minutes.to_i
63
+ #
64
+ # @example AllowedPatterns: [/min*/]
55
65
  #
56
66
  # # good
57
67
  # 10.minutes.to_i
@@ -62,7 +72,8 @@ module RuboCop
62
72
  # Time.now.to_datetime.to_i
63
73
  class NumberConversion < Base
64
74
  extend AutoCorrector
65
- include IgnoredMethods
75
+ include AllowedMethods
76
+ include AllowedPattern
66
77
 
67
78
  CONVERSION_METHOD_CLASS_MAPPING = {
68
79
  to_i: "#{Integer.name}(%<number_object>s, 10)",
@@ -97,7 +108,7 @@ module RuboCop
97
108
 
98
109
  def handle_conversion_method(node)
99
110
  to_method(node) do |receiver, to_method|
100
- next if receiver.nil? || ignore_receiver?(receiver)
111
+ next if receiver.nil? || allow_receiver?(receiver)
101
112
 
102
113
  message = format(
103
114
  MSG,
@@ -141,9 +152,10 @@ module RuboCop
141
152
  corrector.remove(node.loc.end)
142
153
  end
143
154
 
144
- def ignore_receiver?(receiver)
155
+ def allow_receiver?(receiver)
145
156
  if receiver.numeric_type? || (receiver.send_type? &&
146
- (conversion_method?(receiver.method_name) || ignored_method?(receiver.method_name)))
157
+ (conversion_method?(receiver.method_name) ||
158
+ allowed_method_name?(receiver.method_name)))
147
159
  true
148
160
  elsif (receiver = top_receiver(receiver))
149
161
  receiver.const_type? && ignored_class?(receiver.const_name)
@@ -152,6 +164,10 @@ module RuboCop
152
164
  end
153
165
  end
154
166
 
167
+ def allowed_method_name?(name)
168
+ allowed_method?(name) || matches_allowed_pattern?(name)
169
+ end
170
+
155
171
  def top_receiver(node)
156
172
  receiver = node
157
173
  receiver = receiver.receiver until receiver.receiver.nil?
@@ -7,6 +7,14 @@ module RuboCop
7
7
  # less specific exception being rescued before a more specific
8
8
  # exception is rescued.
9
9
  #
10
+ # An exception is considered shadowed if it is rescued after its
11
+ # ancestor is, or if it and its ancestor are both rescued in the
12
+ # same `rescue` statement. In both cases, the more specific rescue is
13
+ # unnecessary because it is covered by rescuing the less specific
14
+ # exception. (ie. `rescue Exception, StandardError` has the same behavior
15
+ # whether `StandardError` is included or not, because all `StandardError`s
16
+ # are rescued by `rescue Exception`).
17
+ #
10
18
  # @example
11
19
  #
12
20
  # # bad
@@ -19,6 +27,13 @@ module RuboCop
19
27
  # handle_standard_error
20
28
  # end
21
29
  #
30
+ # # bad
31
+ # begin
32
+ # something
33
+ # rescue Exception, StandardError
34
+ # handle_error
35
+ # end
36
+ #
22
37
  # # good
23
38
  #
24
39
  # begin
@@ -67,10 +67,18 @@ module RuboCop
67
67
  variable_node = variable.scope.node.parent
68
68
  return false unless variable_node.conditional?
69
69
 
70
- outer_local_variable_node = outer_local_variable.scope.node
70
+ outer_local_variable_node =
71
+ find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
71
72
 
72
73
  outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
73
74
  end
75
+
76
+ def find_conditional_node_from_ascendant(node)
77
+ return unless (parent = node.parent)
78
+ return parent if parent.conditional?
79
+
80
+ find_conditional_node_from_ascendant(parent)
81
+ end
74
82
  end
75
83
  end
76
84
  end
@@ -33,7 +33,9 @@ module RuboCop
33
33
  # render 'pages/search/page'
34
34
  # end
35
35
  #
36
- # This cop also takes into account `IgnoredMethods` (defaults to `[]`)
36
+ # This cop also takes into account `AllowedMethods` (defaults to `[]`)
37
+ # And `AllowedPatterns` (defaults to `[]`)
38
+ #
37
39
  class AbcSize < Base
38
40
  include MethodComplexity
39
41
 
@@ -14,8 +14,8 @@ module RuboCop
14
14
  #
15
15
  #
16
16
  # NOTE: The `ExcludedMethods` configuration is deprecated and only kept
17
- # for backwards compatibility. Please use `IgnoredMethods` instead.
18
- # By default, there are no methods to ignored.
17
+ # for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns`
18
+ # instead. By default, there are no methods to allowed.
19
19
  #
20
20
  # @example CountAsOne: ['array', 'heredoc']
21
21
  #
@@ -38,14 +38,13 @@ module RuboCop
38
38
  # NOTE: This cop does not apply for `Struct` definitions.
39
39
  class BlockLength < Base
40
40
  include CodeLength
41
- include IgnoredMethods
42
-
43
- ignored_methods deprecated_key: 'ExcludedMethods'
41
+ include AllowedMethods
42
+ include AllowedPattern
44
43
 
45
44
  LABEL = 'Block'
46
45
 
47
46
  def on_block(node)
48
- return if ignored_method?(node.method_name)
47
+ return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
49
48
  return if method_receiver_excluded?(node)
50
49
  return if node.class_constructor? || node.struct_constructor?
51
50
 
@@ -59,7 +58,7 @@ module RuboCop
59
58
  node_receiver = node.receiver&.source&.gsub(/\s+/, '')
60
59
  node_method = String(node.method_name)
61
60
 
62
- ignored_methods.any? do |config|
61
+ allowed_methods.any? do |config|
63
62
  next unless config.is_a?(String)
64
63
 
65
64
  receiver, method = config.split('.')
@@ -4,16 +4,17 @@ module RuboCop
4
4
  module Cop
5
5
  module Metrics
6
6
  # Checks if the length of a method exceeds some maximum value.
7
- # Comment lines can optionally be ignored.
7
+ # Comment lines can optionally be allowed.
8
8
  # The maximum allowed length is configurable.
9
9
  #
10
10
  # You can set literals you want to fold with `CountAsOne`.
11
11
  # Available are: 'array', 'hash', and 'heredoc'. Each literal
12
12
  # will be counted as one line regardless of its actual size.
13
13
  #
14
- # NOTE: The `ExcludedMethods` configuration is deprecated and only kept
15
- # for backwards compatibility. Please use `IgnoredMethods` instead.
16
- # By default, there are no methods to ignored.
14
+ # NOTE: The `ExcludedMethods` and `IgnoredMethods` configuration is
15
+ # deprecated and only kept for backwards compatibility.
16
+ # Please use `AllowedMethods` and `AllowedPatterns` instead.
17
+ # By default, there are no methods to allowed.
17
18
  #
18
19
  # @example CountAsOne: ['array', 'heredoc']
19
20
  #
@@ -35,14 +36,13 @@ module RuboCop
35
36
  #
36
37
  class MethodLength < Base
37
38
  include CodeLength
38
- include IgnoredMethods
39
-
40
- ignored_methods deprecated_key: 'ExcludedMethods'
39
+ include AllowedMethods
40
+ include AllowedPattern
41
41
 
42
42
  LABEL = 'Method'
43
43
 
44
44
  def on_def(node)
45
- return if ignored_method?(node.method_name)
45
+ return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
46
46
 
47
47
  check_code_length(node)
48
48
  end