rubocop 1.33.0 → 1.35.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +29 -1
  4. data/lib/rubocop/cli/command/suggest_extensions.rb +53 -15
  5. data/lib/rubocop/config_loader.rb +12 -0
  6. data/lib/rubocop/config_loader_resolver.rb +1 -5
  7. data/lib/rubocop/cop/cop.rb +1 -1
  8. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +58 -0
  9. data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
  10. data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +69 -0
  11. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +61 -0
  12. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  13. data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
  14. data/lib/rubocop/cop/layout/block_end_newline.rb +4 -1
  15. data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +5 -2
  16. data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +2 -0
  17. data/lib/rubocop/cop/layout/indentation_width.rb +2 -0
  18. data/lib/rubocop/cop/layout/line_length.rb +4 -1
  19. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  20. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
  21. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
  22. data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
  23. data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
  24. data/lib/rubocop/cop/legacy/corrections_proxy.rb +1 -1
  25. data/lib/rubocop/cop/legacy/corrector.rb +1 -1
  26. data/lib/rubocop/cop/lint/debugger.rb +15 -15
  27. data/lib/rubocop/cop/lint/empty_block.rb +1 -1
  28. data/lib/rubocop/cop/lint/empty_conditional_body.rb +5 -0
  29. data/lib/rubocop/cop/lint/erb_new_arguments.rb +9 -9
  30. data/lib/rubocop/cop/lint/next_without_accumulator.rb +25 -6
  31. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +12 -0
  32. data/lib/rubocop/cop/lint/redundant_with_index.rb +13 -10
  33. data/lib/rubocop/cop/lint/redundant_with_object.rb +12 -11
  34. data/lib/rubocop/cop/lint/shadowed_exception.rb +15 -0
  35. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +10 -1
  36. data/lib/rubocop/cop/lint/unreachable_loop.rb +7 -1
  37. data/lib/rubocop/cop/lint/useless_access_modifier.rb +6 -4
  38. data/lib/rubocop/cop/lint/void.rb +2 -0
  39. data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -1
  40. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +76 -1
  41. data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
  42. data/lib/rubocop/cop/mixin/method_complexity.rb +4 -4
  43. data/lib/rubocop/cop/mixin/range_help.rb +4 -5
  44. data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
  45. data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -2
  46. data/lib/rubocop/cop/style/class_methods_definitions.rb +2 -1
  47. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  48. data/lib/rubocop/cop/style/combinable_loops.rb +3 -1
  49. data/lib/rubocop/cop/style/double_negation.rb +2 -0
  50. data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
  51. data/lib/rubocop/cop/style/each_with_object.rb +39 -8
  52. data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
  53. data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
  54. data/lib/rubocop/cop/style/for.rb +2 -0
  55. data/lib/rubocop/cop/style/hash_each_methods.rb +3 -1
  56. data/lib/rubocop/cop/style/hash_syntax.rb +17 -0
  57. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -1
  58. data/lib/rubocop/cop/style/inverse_methods.rb +8 -6
  59. data/lib/rubocop/cop/style/magic_comment_format.rb +307 -0
  60. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +4 -1
  61. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -1
  62. data/lib/rubocop/cop/style/next.rb +2 -0
  63. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  64. data/lib/rubocop/cop/style/numeric_literals.rb +16 -1
  65. data/lib/rubocop/cop/style/object_then.rb +2 -0
  66. data/lib/rubocop/cop/style/proc.rb +4 -1
  67. data/lib/rubocop/cop/style/redundant_begin.rb +2 -0
  68. data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
  69. data/lib/rubocop/cop/style/redundant_parentheses.rb +15 -22
  70. data/lib/rubocop/cop/style/redundant_self.rb +2 -0
  71. data/lib/rubocop/cop/style/redundant_sort_by.rb +24 -8
  72. data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
  73. data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -3
  74. data/lib/rubocop/cop/style/symbol_proc.rb +5 -0
  75. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -13
  76. data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -1
  77. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
  78. data/lib/rubocop/ext/range.rb +15 -0
  79. data/lib/rubocop/feature_loader.rb +92 -0
  80. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  81. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  82. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  83. data/lib/rubocop/formatter/markdown_formatter.rb +1 -1
  84. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  85. data/lib/rubocop/server/cache.rb +4 -2
  86. data/lib/rubocop/version.rb +1 -1
  87. data/lib/rubocop.rb +4 -1
  88. metadata +13 -8
@@ -67,19 +67,6 @@ module RuboCop
67
67
  class Debugger < Base
68
68
  MSG = 'Remove debugger entry point `%<source>s`.'
69
69
 
70
- # @!method kernel?(node)
71
- def_node_matcher :kernel?, <<~PATTERN
72
- (const {nil? cbase} :Kernel)
73
- PATTERN
74
-
75
- # @!method valid_receiver?(node, arg1)
76
- def_node_matcher :valid_receiver?, <<~PATTERN
77
- {
78
- (const {nil? cbase} %1)
79
- (send {nil? #kernel?} %1)
80
- }
81
- PATTERN
82
-
83
70
  def on_send(node)
84
71
  return unless debugger_method?(node)
85
72
 
@@ -101,7 +88,7 @@ module RuboCop
101
88
 
102
89
  *receiver, method_name = v.split('.')
103
90
  {
104
- receiver: receiver.empty? ? nil : receiver.join.to_sym,
91
+ receiver: receiver.empty? ? nil : receiver.map(&:to_sym),
105
92
  method_name: method_name.to_sym
106
93
  }
107
94
  end.compact
@@ -115,10 +102,23 @@ module RuboCop
115
102
  if method[:receiver].nil?
116
103
  send_node.receiver.nil?
117
104
  else
118
- valid_receiver?(send_node.receiver, method[:receiver])
105
+ method[:receiver] == receiver_chain(send_node)
119
106
  end
120
107
  end
121
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
122
122
  end
123
123
  end
124
124
  end
@@ -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)
@@ -7,6 +7,11 @@ module RuboCop
7
7
  #
8
8
  # NOTE: empty `else` branches are handled by `Style/EmptyElse`.
9
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
+ #
10
15
  # @example
11
16
  # # bad
12
17
  # if condition
@@ -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.
@@ -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
@@ -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)
@@ -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
@@ -6,7 +6,8 @@ module RuboCop
6
6
  #
7
7
  # IMPORTANT: RuboCop core depended on this module when it supported Rails department.
8
8
  # Rails department has been extracted to RuboCop Rails gem.
9
- # This module is deprecated and will be removed by RuboCop 2.0.
9
+ #
10
+ # @deprecated This module is deprecated and will be removed by RuboCop 2.0.
10
11
  # It will not be updated to `RuboCop::Cop::Base` v1 API to maintain compatibility
11
12
  # with existing RuboCop Rails 2.8 or lower.
12
13
  #
@@ -5,7 +5,22 @@ module RuboCop
5
5
  # This module checks for Ruby 3.1's hash value omission syntax.
6
6
  module HashShorthandSyntax
7
7
  OMIT_HASH_VALUE_MSG = 'Omit the hash value.'
8
- EXPLICIT_HASH_VALUE_MSG = 'Explicit the hash value.'
8
+ EXPLICIT_HASH_VALUE_MSG = 'Include the hash value.'
9
+ DO_NOT_MIX_MSG_PREFIX = 'Do not mix explicit and implicit hash values.'
10
+ DO_NOT_MIX_OMIT_VALUE_MSG = "#{DO_NOT_MIX_MSG_PREFIX} #{OMIT_HASH_VALUE_MSG}"
11
+ DO_NOT_MIX_EXPLICIT_VALUE_MSG = "#{DO_NOT_MIX_MSG_PREFIX} #{EXPLICIT_HASH_VALUE_MSG}"
12
+
13
+ def on_hash_for_mixed_shorthand(hash_node)
14
+ return if ignore_mixed_hash_shorthand_syntax?(hash_node)
15
+
16
+ hash_value_type_breakdown = breakdown_value_types_of_hash(hash_node)
17
+
18
+ if hash_with_mixed_shorthand_syntax?(hash_value_type_breakdown)
19
+ mixed_shorthand_syntax_check(hash_value_type_breakdown)
20
+ else
21
+ no_mixed_shorthand_syntax_check(hash_value_type_breakdown)
22
+ end
23
+ end
9
24
 
10
25
  def on_pair(node)
11
26
  return if ignore_hash_shorthand_syntax?(node)
@@ -36,8 +51,14 @@ module RuboCop
36
51
  end
37
52
  end
38
53
 
54
+ def ignore_mixed_hash_shorthand_syntax?(hash_node)
55
+ target_ruby_version <= 3.0 || enforced_shorthand_syntax != 'consistent' ||
56
+ !hash_node.hash_type?
57
+ end
58
+
39
59
  def ignore_hash_shorthand_syntax?(pair_node)
40
60
  target_ruby_version <= 3.0 || enforced_shorthand_syntax == 'either' ||
61
+ enforced_shorthand_syntax == 'consistent' ||
41
62
  !pair_node.parent.hash_type?
42
63
  end
43
64
 
@@ -81,6 +102,60 @@ module RuboCop
81
102
 
82
103
  ancestor.respond_to?(:parenthesized?) && !ancestor.parenthesized? && !!right_sibling
83
104
  end
105
+
106
+ def breakdown_value_types_of_hash(hash_node)
107
+ hash_node.pairs.group_by do |pair_node|
108
+ if pair_node.value_omission?
109
+ :value_omitted
110
+ elsif require_hash_value?(pair_node.key.source, pair_node)
111
+ :value_needed
112
+ else
113
+ :value_omittable
114
+ end
115
+ end
116
+ end
117
+
118
+ def hash_with_mixed_shorthand_syntax?(hash_value_type_breakdown)
119
+ hash_value_type_breakdown.keys.size > 1
120
+ end
121
+
122
+ def hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
123
+ hash_value_type_breakdown[:value_needed]&.any?
124
+ end
125
+
126
+ def each_omitted_value_pair(hash_value_type_breakdown, &block)
127
+ hash_value_type_breakdown[:value_omitted]&.each(&block)
128
+ end
129
+
130
+ def each_omittable_value_pair(hash_value_type_breakdown, &block)
131
+ hash_value_type_breakdown[:value_omittable]&.each(&block)
132
+ end
133
+
134
+ def mixed_shorthand_syntax_check(hash_value_type_breakdown)
135
+ if hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
136
+ each_omitted_value_pair(hash_value_type_breakdown) do |pair_node|
137
+ hash_key_source = pair_node.key.source
138
+ replacement = "#{hash_key_source}: #{hash_key_source}"
139
+ register_offense(pair_node, DO_NOT_MIX_EXPLICIT_VALUE_MSG, replacement)
140
+ end
141
+ else
142
+ each_omittable_value_pair(hash_value_type_breakdown) do |pair_node|
143
+ hash_key_source = pair_node.key.source
144
+ replacement = "#{hash_key_source}:"
145
+ register_offense(pair_node, DO_NOT_MIX_OMIT_VALUE_MSG, replacement)
146
+ end
147
+ end
148
+ end
149
+
150
+ def no_mixed_shorthand_syntax_check(hash_value_type_breakdown)
151
+ return if hash_with_values_that_cant_be_omitted?(hash_value_type_breakdown)
152
+
153
+ each_omittable_value_pair(hash_value_type_breakdown) do |pair_node|
154
+ hash_key_source = pair_node.key.source
155
+ replacement = "#{hash_key_source}:"
156
+ register_offense(pair_node, OMIT_HASH_VALUE_MSG, replacement)
157
+ end
158
+ end
84
159
  end
85
160
  end
86
161
  end
@@ -14,7 +14,7 @@ module RuboCop
14
14
  {(array ...) (send _ :each_with_index) (send _ :with_index _ ?) (send _ :zip ...)}
15
15
  PATTERN
16
16
 
17
- def on_block(node)
17
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
18
18
  on_bad_each_with_object(node) do |*match|
19
19
  handle_possible_offense(node, match, 'each_with_object')
20
20
  end
@@ -29,14 +29,14 @@ module RuboCop
29
29
  end
30
30
  end
31
31
 
32
+ alias on_numblock on_block
33
+
32
34
  private
33
35
 
34
36
  # @!method define_method?(node)
35
37
  def_node_matcher :define_method?, <<~PATTERN
36
- (block
37
- (send nil? :define_method ({sym str} $_))
38
- args
39
- _)
38
+ ({block numblock}
39
+ (send nil? :define_method ({sym str} $_)) _ _)
40
40
  PATTERN
41
41
 
42
42
  def check_complexity(node, method_name)
@@ -54,11 +54,11 @@ module RuboCop
54
54
  NOT_GIVEN = Module.new
55
55
  def range_with_surrounding_space(range_positional = NOT_GIVEN, # rubocop:disable Metrics/ParameterLists
56
56
  range: NOT_GIVEN, side: :both, newlines: true,
57
- whitespace: false, continuations: false)
57
+ whitespace: false, continuations: false,
58
+ buffer: @processed_source.buffer)
58
59
 
59
60
  range = range_positional unless range_positional == NOT_GIVEN
60
61
 
61
- buffer = @processed_source.buffer
62
62
  src = buffer.source
63
63
 
64
64
  go_left, go_right = directions(side)
@@ -70,9 +70,8 @@ module RuboCop
70
70
  Parser::Source::Range.new(buffer, begin_pos, end_pos)
71
71
  end
72
72
 
73
- def range_by_whole_lines(range, include_final_newline: false)
74
- buffer = @processed_source.buffer
75
-
73
+ def range_by_whole_lines(range, include_final_newline: false,
74
+ buffer: @processed_source.buffer)
76
75
  last_line = buffer.source_line(range.last_line)
77
76
  end_offset = last_line.length - range.last_column
78
77
  end_offset += 1 if include_final_newline
@@ -38,7 +38,7 @@ module RuboCop
38
38
  class BlockParameterName < Base
39
39
  include UncommunicativeName
40
40
 
41
- def on_block(node)
41
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
42
42
  return unless node.arguments?
43
43
 
44
44
  check(node, node.arguments)
@@ -73,11 +73,11 @@ module RuboCop
73
73
  {
74
74
  (send _ _
75
75
  (splat (lvar %1))
76
- (block-pass (lvar %2)))
76
+ (block-pass {(lvar %2) nil?}))
77
77
  (send _ _
78
78
  (splat (lvar %1))
79
79
  (hash (kwsplat (lvar %3)))
80
- (block-pass (lvar %2)))
80
+ (block-pass {(lvar %2) nil?}))
81
81
  }
82
82
  PATTERN
83
83
 
@@ -70,7 +70,7 @@ module RuboCop
70
70
 
71
71
  def on_sclass(node)
72
72
  return unless def_self_style?
73
- return unless node.identifier.source == 'self'
73
+ return unless node.identifier.self_type?
74
74
  return unless all_methods_public?(node)
75
75
 
76
76
  add_offense(node, message: MSG_SCLASS) do |corrector|
@@ -80,6 +80,7 @@ module RuboCop
80
80
 
81
81
  def on_defs(node)
82
82
  return if def_self_style?
83
+ return unless node.receiver.self_type?
83
84
 
84
85
  message = format(MSG, preferred: 'class << self')
85
86
  add_offense(node, message: message)
@@ -48,6 +48,8 @@ module RuboCop
48
48
  check_method_node(node.send_node)
49
49
  end
50
50
 
51
+ alias on_numblock on_block
52
+
51
53
  def on_send(node)
52
54
  return unless implicit_block?(node)
53
55
 
@@ -66,6 +66,8 @@ module RuboCop
66
66
  add_offense(node) if same_collection_looping?(node, node.left_sibling)
67
67
  end
68
68
 
69
+ alias on_numblock on_block
70
+
69
71
  def on_for(node)
70
72
  return unless node.parent&.begin_type?
71
73
 
@@ -82,7 +84,7 @@ module RuboCop
82
84
  end
83
85
 
84
86
  def same_collection_looping?(node, sibling)
85
- sibling&.block_type? &&
87
+ (sibling&.block_type? || sibling&.numblock_type?) &&
86
88
  sibling.send_node.method?(node.method_name) &&
87
89
  sibling.receiver == node.receiver &&
88
90
  sibling.send_node.arguments == node.send_node.arguments
@@ -93,6 +93,8 @@ module RuboCop
93
93
 
94
94
  if conditional_node
95
95
  double_negative_condition_return_value?(node, last_child, conditional_node)
96
+ elsif last_child.pair_type? || last_child.hash_type? || last_child.parent.array_type?
97
+ false
96
98
  else
97
99
  last_child.last_line <= node.last_line
98
100
  end
@@ -27,7 +27,7 @@ module RuboCop
27
27
 
28
28
  MSG = 'Use `Integer#times` for a simple loop which iterates a fixed number of times.'
29
29
 
30
- def on_block(node)
30
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
31
31
  return unless offending_each_range(node)
32
32
 
33
33
  send_node = node.send_node