rubocop 1.32.0 → 1.35.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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +73 -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 → auto_generate_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.rb +1 -1
  10. data/lib/rubocop/config_finder.rb +68 -0
  11. data/lib/rubocop/config_loader.rb +12 -40
  12. data/lib/rubocop/config_loader_resolver.rb +1 -5
  13. data/lib/rubocop/config_obsoletion/changed_parameter.rb +5 -0
  14. data/lib/rubocop/config_obsoletion/parameter_rule.rb +4 -0
  15. data/lib/rubocop/config_obsoletion.rb +7 -2
  16. data/lib/rubocop/cop/cop.rb +1 -1
  17. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +58 -0
  18. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  19. data/lib/rubocop/cop/generator/require_file_injector.rb +2 -2
  20. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +69 -0
  21. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +62 -0
  22. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  23. data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
  24. data/lib/rubocop/cop/layout/block_end_newline.rb +35 -5
  25. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +5 -2
  26. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +2 -0
  27. data/lib/rubocop/cop/layout/end_of_line.rb +4 -4
  28. data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
  29. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
  30. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
  31. data/lib/rubocop/cop/layout/indentation_width.rb +2 -0
  32. data/lib/rubocop/cop/layout/line_length.rb +4 -1
  33. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  34. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  35. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  36. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  37. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  38. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  39. data/lib/rubocop/cop/legacy/corrections_proxy.rb +1 -1
  40. data/lib/rubocop/cop/legacy/corrector.rb +1 -1
  41. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +21 -8
  42. data/lib/rubocop/cop/lint/debugger.rb +26 -16
  43. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  44. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  45. data/lib/rubocop/cop/lint/empty_conditional_body.rb +65 -1
  46. data/lib/rubocop/cop/lint/erb_new_arguments.rb +9 -9
  47. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +4 -0
  48. data/lib/rubocop/cop/lint/next_without_accumulator.rb +25 -6
  49. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +6 -6
  50. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +12 -0
  51. data/lib/rubocop/cop/lint/number_conversion.rb +24 -8
  52. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +9 -3
  53. data/lib/rubocop/cop/lint/redundant_with_index.rb +13 -10
  54. data/lib/rubocop/cop/lint/redundant_with_object.rb +12 -11
  55. data/lib/rubocop/cop/lint/shadowed_exception.rb +15 -0
  56. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +10 -1
  57. data/lib/rubocop/cop/lint/unreachable_loop.rb +7 -1
  58. data/lib/rubocop/cop/lint/useless_access_modifier.rb +6 -4
  59. data/lib/rubocop/cop/lint/void.rb +2 -0
  60. data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
  61. data/lib/rubocop/cop/metrics/block_length.rb +6 -7
  62. data/lib/rubocop/cop/metrics/method_length.rb +8 -8
  63. data/lib/rubocop/cop/mixin/allowed_methods.rb +15 -1
  64. data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -1
  65. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  66. data/lib/rubocop/cop/mixin/comments_help.rb +5 -1
  67. data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -1
  68. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +76 -1
  69. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  70. data/lib/rubocop/cop/mixin/method_complexity.rb +8 -13
  71. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  72. data/lib/rubocop/cop/mixin/range_help.rb +4 -5
  73. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  74. data/lib/rubocop/cop/naming/constant_name.rb +2 -2
  75. data/lib/rubocop/cop/naming/predicate_name.rb +24 -3
  76. data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -2
  77. data/lib/rubocop/cop/style/block_delimiters.rb +26 -7
  78. data/lib/rubocop/cop/style/class_and_module_children.rb +4 -4
  79. data/lib/rubocop/cop/style/class_equality_comparison.rb +32 -7
  80. data/lib/rubocop/cop/style/class_methods_definitions.rb +2 -1
  81. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  82. data/lib/rubocop/cop/style/combinable_loops.rb +3 -1
  83. data/lib/rubocop/cop/style/double_negation.rb +2 -0
  84. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  85. data/lib/rubocop/cop/style/each_with_object.rb +39 -8
  86. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  87. data/lib/rubocop/cop/style/empty_heredoc.rb +15 -1
  88. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  89. data/lib/rubocop/cop/style/for.rb +2 -0
  90. data/lib/rubocop/cop/style/format_string_token.rb +21 -8
  91. data/lib/rubocop/cop/style/guard_clause.rb +27 -16
  92. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -1
  93. data/lib/rubocop/cop/style/hash_except.rb +0 -4
  94. data/lib/rubocop/cop/style/hash_syntax.rb +17 -0
  95. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -1
  96. data/lib/rubocop/cop/style/inverse_methods.rb +8 -6
  97. data/lib/rubocop/cop/style/magic_comment_format.rb +307 -0
  98. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
  99. data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -1
  100. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -7
  101. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -6
  102. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +4 -1
  103. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -1
  104. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  105. data/lib/rubocop/cop/style/next.rb +3 -5
  106. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  107. data/lib/rubocop/cop/style/numeric_literals.rb +16 -1
  108. data/lib/rubocop/cop/style/numeric_predicate.rb +28 -8
  109. data/lib/rubocop/cop/style/object_then.rb +2 -0
  110. data/lib/rubocop/cop/style/proc.rb +4 -1
  111. data/lib/rubocop/cop/style/redundant_begin.rb +2 -0
  112. data/lib/rubocop/cop/style/redundant_condition.rb +19 -4
  113. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  114. data/lib/rubocop/cop/style/redundant_parentheses.rb +15 -22
  115. data/lib/rubocop/cop/style/redundant_self.rb +2 -0
  116. data/lib/rubocop/cop/style/redundant_sort.rb +21 -6
  117. data/lib/rubocop/cop/style/redundant_sort_by.rb +24 -8
  118. data/lib/rubocop/cop/style/safe_navigation.rb +4 -2
  119. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  120. data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -5
  121. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  122. data/lib/rubocop/cop/style/symbol_proc.rb +34 -9
  123. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -13
  124. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -1
  125. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  126. data/lib/rubocop/cop/style/word_array.rb +1 -1
  127. data/lib/rubocop/cop/util.rb +1 -1
  128. data/lib/rubocop/ext/range.rb +15 -0
  129. data/lib/rubocop/feature_loader.rb +94 -0
  130. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  131. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  132. data/lib/rubocop/formatter/html_formatter.rb +3 -3
  133. data/lib/rubocop/formatter/markdown_formatter.rb +1 -1
  134. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  135. data/lib/rubocop/result_cache.rb +22 -20
  136. data/lib/rubocop/server/cache.rb +36 -1
  137. data/lib/rubocop/server/cli.rb +19 -2
  138. data/lib/rubocop/version.rb +1 -1
  139. data/lib/rubocop.rb +5 -3
  140. metadata +15 -9
  141. data/lib/rubocop/cop/mixin/ignored_methods.rb +0 -52
@@ -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
@@ -66,7 +66,7 @@ module RuboCop
66
66
  private
67
67
 
68
68
  def delimiter
69
- CLASS_METHOD_DELIMETER
69
+ CLASS_METHOD_DELIMITER
70
70
  end
71
71
  end
72
72
 
@@ -89,7 +89,7 @@ module RuboCop
89
89
  private
90
90
 
91
91
  def delimiter
92
- instance_method? ? INSTANCE_METHOD_DELIMETER : CLASS_METHOD_DELIMETER
92
+ instance_method? ? INSTANCE_METHOD_DELIMITER : CLASS_METHOD_DELIMITER
93
93
  end
94
94
 
95
95
  def instance_method?
@@ -126,8 +126,8 @@ module RuboCop
126
126
 
127
127
  RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.keys.map(&:method).freeze
128
128
 
129
- CLASS_METHOD_DELIMETER = '.'
130
- INSTANCE_METHOD_DELIMETER = '#'
129
+ CLASS_METHOD_DELIMITER = '.'
130
+ INSTANCE_METHOD_DELIMITER = '#'
131
131
 
132
132
  def on_send(node)
133
133
  check(node) do |deprecated|
@@ -63,7 +63,7 @@ module RuboCop
63
63
  class EmptyBlock < Base
64
64
  MSG = 'Empty block detected.'
65
65
 
66
- def on_block(node)
66
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
67
67
  return if node.body
68
68
  return if allow_empty_lambdas? && lambda_or_proc?(node)
69
69
  return if cop_config['AllowComments'] && allow_comment?(node)
@@ -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
@@ -6,18 +6,18 @@ module RuboCop
6
6
  #
7
7
  # This cop emulates the following Ruby warnings in Ruby 2.6.
8
8
  #
9
+ # [source,console]
10
+ # ----
9
11
  # % cat example.rb
10
12
  # ERB.new('hi', nil, '-', '@output_buffer')
11
13
  # % ruby -rerb example.rb
12
- # example.rb:1: warning: Passing safe_level with the 2nd argument of
13
- # ERB.new is deprecated. Do not use it, and specify other arguments as
14
- # keyword arguments.
15
- # example.rb:1: warning: Passing trim_mode with the 3rd argument of
16
- # ERB.new is deprecated. Use keyword argument like
17
- # ERB.new(str, trim_mode:...) instead.
18
- # example.rb:1: warning: Passing eoutvar with the 4th argument of ERB.new
19
- # is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...)
20
- # instead.
14
+ # example.rb:1: warning: Passing safe_level with the 2nd argument of ERB.new is
15
+ # deprecated. Do not use it, and specify other arguments as keyword arguments.
16
+ # example.rb:1: warning: Passing trim_mode with the 3rd argument of ERB.new is
17
+ # deprecated. Use keyword argument like ERB.new(str, trim_mode:...) instead.
18
+ # example.rb:1: warning: Passing eoutvar with the 4th argument of ERB.new is
19
+ # deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.
20
+ # ----
21
21
  #
22
22
  # Now non-keyword arguments other than first one are softly deprecated
23
23
  # and will be removed when Ruby 2.5 becomes EOL.
@@ -58,6 +58,7 @@ module RuboCop
58
58
  (node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
59
59
  end
60
60
 
61
+ # rubocop:disable Metrics/MethodLength
61
62
  def autocorrected_value(node)
62
63
  case node.type
63
64
  when :int
@@ -70,10 +71,13 @@ module RuboCop
70
71
  autocorrected_value_for_symbol(node)
71
72
  when :array
72
73
  autocorrected_value_for_array(node)
74
+ when :nil
75
+ ''
73
76
  else
74
77
  node.source.gsub('"', '\"')
75
78
  end
76
79
  end
80
+ # rubocop:enable Metrics/MethodLength
77
81
 
78
82
  def autocorrected_value_for_string(node)
79
83
  if node.source.start_with?("'", '%q')
@@ -25,13 +25,8 @@ module RuboCop
25
25
  class NextWithoutAccumulator < Base
26
26
  MSG = 'Use `next` with an accumulator argument in a `reduce`.'
27
27
 
28
- # @!method on_body_of_reduce(node)
29
- def_node_matcher :on_body_of_reduce, <<~PATTERN
30
- (block (send _recv {:reduce :inject} !sym) _blockargs $(begin ...))
31
- PATTERN
32
-
33
28
  def on_block(node)
34
- on_body_of_reduce(node) do |body|
29
+ on_block_body_of_reduce(node) do |body|
35
30
  void_next = body.each_node(:next).find do |n|
36
31
  n.children.empty? && parent_block_node(n) == node
37
32
  end
@@ -40,11 +35,35 @@ module RuboCop
40
35
  end
41
36
  end
42
37
 
38
+ def on_numblock(node)
39
+ on_numblock_body_of_reduce(node) do |body|
40
+ void_next = body.each_node(:next).find do |n|
41
+ n.children.empty? && parent_numblock_node(n) == node
42
+ end
43
+
44
+ add_offense(void_next) if void_next
45
+ end
46
+ end
47
+
43
48
  private
44
49
 
50
+ # @!method on_block_body_of_reduce(node)
51
+ def_node_matcher :on_block_body_of_reduce, <<~PATTERN
52
+ (block (send _recv {:reduce :inject} !sym) _blockargs $(begin ...))
53
+ PATTERN
54
+
55
+ # @!method on_numblock_body_of_reduce(node)
56
+ def_node_matcher :on_numblock_body_of_reduce, <<~PATTERN
57
+ (numblock (send _recv {:reduce :inject} !sym) _argscount $(begin ...))
58
+ PATTERN
59
+
45
60
  def parent_block_node(node)
46
61
  node.each_ancestor(:block).first
47
62
  end
63
+
64
+ def parent_numblock_node(node)
65
+ node.each_ancestor(:numblock).first
66
+ end
48
67
  end
49
68
  end
50
69
  end
@@ -99,19 +99,19 @@ module RuboCop
99
99
  end
100
100
 
101
101
  def register_offense(node, exist_node)
102
- unless force_method?(node)
103
- add_offense(node,
104
- message: format(MSG_CHANGE_FORCE_METHOD,
105
- method_name: replacement_method(node)))
106
- end
102
+ add_offense(node, message: message_change_force_method(node)) unless force_method?(node)
107
103
 
108
104
  range = range_between(node.parent.loc.keyword.begin_pos,
109
105
  exist_node.loc.expression.end_pos)
110
106
  add_offense(range, message: message_remove_file_exist_check(exist_node)) do |corrector|
111
- autocorrect(corrector, node, range)
107
+ autocorrect(corrector, node, range) unless node.parent.elsif?
112
108
  end
113
109
  end
114
110
 
111
+ def message_change_force_method(node)
112
+ format(MSG_CHANGE_FORCE_METHOD, method_name: replacement_method(node))
113
+ end
114
+
115
115
  def message_remove_file_exist_check(node)
116
116
  receiver, method_name = receiver_and_method_name(node)
117
117
  format(MSG_REMOVE_FILE_EXIST_CHECK, receiver: receiver, method_name: method_name)
@@ -74,6 +74,18 @@ module RuboCop
74
74
  end
75
75
  end
76
76
 
77
+ def on_numblock(node)
78
+ return if target_ruby_version >= 3.0
79
+ return unless node.body
80
+ return unless unsorted_dir_loop?(node.send_node)
81
+
82
+ node.argument_list
83
+ .filter { |argument| var_is_required?(node.body, argument.name) }
84
+ .each do
85
+ add_offense(node.send_node) { |corrector| correct_block(corrector, node.send_node) }
86
+ end
87
+ end
88
+
77
89
  def on_block_pass(node)
78
90
  return if target_ruby_version >= 3.0
79
91
  return unless method_require?(node)
@@ -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,11 @@ module RuboCop
7
7
  # `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods
8
8
  # are checked by default. These are customizable with `AllowedMethods` option.
9
9
  #
10
+ # The `AllowedMethods` option specifies nil-safe methods,
11
+ # in other words, it is a method that is allowed to skip safe navigation.
12
+ # Note that the `AllowedMethod` option is not an option that specifies methods
13
+ # for which to suppress (allow) this cop's check.
14
+ #
10
15
  # In the example below, the safe navigation operator (`&.`) is unnecessary
11
16
  # because `NilClass` has methods like `respond_to?` and `is_a?`.
12
17
  #
@@ -35,12 +40,13 @@ module RuboCop
35
40
  # # good - without `&.` this will always return `true`
36
41
  # foo&.respond_to?(:to_a)
37
42
  #
38
- # @example AllowedMethods: [foo?]
43
+ # @example AllowedMethods: [nil_safe_method]
39
44
  # # bad
40
- # do_something if attrs&.foo?(:[])
45
+ # do_something if attrs&.nil_safe_method(:[])
41
46
  #
42
47
  # # good
43
- # do_something if attrs&.bar?(:[])
48
+ # do_something if attrs.nil_safe_method(:[])
49
+ # do_something if attrs&.not_nil_safe_method(:[])
44
50
  #
45
51
  class RedundantSafeNavigation < Base
46
52
  include AllowedMethods
@@ -33,16 +33,6 @@ module RuboCop
33
33
  MSG_EACH_WITH_INDEX = 'Use `each` instead of `each_with_index`.'
34
34
  MSG_WITH_INDEX = 'Remove redundant `with_index`.'
35
35
 
36
- # @!method redundant_with_index?(node)
37
- def_node_matcher :redundant_with_index?, <<~PATTERN
38
- (block
39
- $(send
40
- _ {:each_with_index :with_index} ...)
41
- (args
42
- (arg _))
43
- ...)
44
- PATTERN
45
-
46
36
  def on_block(node)
47
37
  return unless (send = redundant_with_index?(node))
48
38
 
@@ -58,8 +48,21 @@ module RuboCop
58
48
  end
59
49
  end
60
50
 
51
+ alias on_numblock on_block
52
+
61
53
  private
62
54
 
55
+ # @!method redundant_with_index?(node)
56
+ def_node_matcher :redundant_with_index?, <<~PATTERN
57
+ {
58
+ (block
59
+ $(send _ {:each_with_index :with_index} ...)
60
+ (args (arg _)) ...)
61
+ (numblock
62
+ $(send _ {:each_with_index :with_index} ...) 1 ...)
63
+ }
64
+ PATTERN
65
+
63
66
  def message(node)
64
67
  if node.method?(:each_with_index)
65
68
  MSG_EACH_WITH_INDEX
@@ -31,19 +31,8 @@ module RuboCop
31
31
  extend AutoCorrector
32
32
 
33
33
  MSG_EACH_WITH_OBJECT = 'Use `each` instead of `each_with_object`.'
34
-
35
34
  MSG_WITH_OBJECT = 'Remove redundant `with_object`.'
36
35
 
37
- # @!method redundant_with_object?(node)
38
- def_node_matcher :redundant_with_object?, <<~PATTERN
39
- (block
40
- $(send _ {:each_with_object :with_object}
41
- _)
42
- (args
43
- (arg _))
44
- ...)
45
- PATTERN
46
-
47
36
  def on_block(node)
48
37
  return unless (send = redundant_with_object?(node))
49
38
 
@@ -59,8 +48,20 @@ module RuboCop
59
48
  end
60
49
  end
61
50
 
51
+ alias on_numblock on_block
52
+
62
53
  private
63
54
 
55
+ # @!method redundant_with_object?(node)
56
+ def_node_matcher :redundant_with_object?, <<~PATTERN
57
+ {
58
+ (block
59
+ $(send _ {:each_with_object :with_object} _) (args (arg _)) ...)
60
+ (numblock
61
+ $(send _ {:each_with_object :with_object} _) 1 ...)
62
+ }
63
+ PATTERN
64
+
64
65
  def message(node)
65
66
  if node.method?(:each_with_object)
66
67
  MSG_EACH_WITH_OBJECT
@@ -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,19 @@ 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)
72
+ return true unless outer_local_variable_node
71
73
 
72
74
  outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
73
75
  end
76
+
77
+ def find_conditional_node_from_ascendant(node)
78
+ return unless (parent = node.parent)
79
+ return parent if parent.conditional?
80
+
81
+ find_conditional_node_from_ascendant(parent)
82
+ end
74
83
  end
75
84
  end
76
85
  end
@@ -101,10 +101,14 @@ module RuboCop
101
101
  check(node) if loop_method?(node)
102
102
  end
103
103
 
104
+ def on_numblock(node)
105
+ check(node) if loop_method?(node)
106
+ end
107
+
104
108
  private
105
109
 
106
110
  def loop_method?(node)
107
- return false unless node.block_type?
111
+ return false unless node.block_type? || node.numblock_type?
108
112
 
109
113
  send_node = node.send_node
110
114
  return false if matches_allowed_pattern?(send_node.source)
@@ -179,6 +183,8 @@ module RuboCop
179
183
 
180
184
  def preceded_by_continue_statement?(break_statement)
181
185
  break_statement.left_siblings.any? do |sibling|
186
+ # Numblocks have the arguments count as a number in the AST.
187
+ next if sibling.is_a?(Integer)
182
188
  next if sibling.loop_keyword? || loop_method?(sibling)
183
189
 
184
190
  sibling.each_descendant(*CONTINUE_KEYWORDS).any?
@@ -142,6 +142,8 @@ module RuboCop
142
142
  check_node(node.body)
143
143
  end
144
144
 
145
+ alias on_numblock on_block
146
+
145
147
  private
146
148
 
147
149
  def autocorrect(corrector, node)
@@ -157,17 +159,17 @@ module RuboCop
157
159
 
158
160
  # @!method dynamic_method_definition?(node)
159
161
  def_node_matcher :dynamic_method_definition?, <<~PATTERN
160
- {(send nil? :define_method ...) (block (send nil? :define_method ...) ...)}
162
+ {(send nil? :define_method ...) ({block numblock} (send nil? :define_method ...) ...)}
161
163
  PATTERN
162
164
 
163
165
  # @!method class_or_instance_eval?(node)
164
166
  def_node_matcher :class_or_instance_eval?, <<~PATTERN
165
- (block (send _ {:class_eval :instance_eval}) ...)
167
+ ({block numblock} (send _ {:class_eval :instance_eval}) ...)
166
168
  PATTERN
167
169
 
168
170
  # @!method class_or_module_or_struct_new_call?(node)
169
171
  def_node_matcher :class_or_module_or_struct_new_call?, <<~PATTERN
170
- (block (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...)
172
+ ({block numblock} (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...)
171
173
  PATTERN
172
174
 
173
175
  def check_node(node)
@@ -277,7 +279,7 @@ module RuboCop
277
279
  matcher_name = "#{m}_block?".to_sym
278
280
  unless respond_to?(matcher_name)
279
281
  self.class.def_node_matcher matcher_name, <<~PATTERN
280
- (block (send {nil? const} {:#{m}} ...) ...)
282
+ ({block numblock} (send {nil? const} {:#{m}} ...) ...)
281
283
  PATTERN
282
284
  end
283
285
 
@@ -67,6 +67,8 @@ module RuboCop
67
67
  check_expression(node.body)
68
68
  end
69
69
 
70
+ alias on_numblock on_block
71
+
70
72
  def on_begin(node)
71
73
  check_begin(node)
72
74
  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