rubocop 1.57.2 → 1.60.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +4 -4
  4. data/config/default.yml +46 -3
  5. data/lib/rubocop/config.rb +0 -2
  6. data/lib/rubocop/config_loader.rb +0 -1
  7. data/lib/rubocop/config_obsoletion.rb +11 -8
  8. data/lib/rubocop/config_validator.rb +0 -2
  9. data/lib/rubocop/cop/base.rb +6 -0
  10. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  11. data/lib/rubocop/cop/exclude_limit.rb +1 -1
  12. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  13. data/lib/rubocop/cop/internal_affairs/example_description.rb +4 -4
  14. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  15. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  16. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  17. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  18. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  19. data/lib/rubocop/cop/layout/end_alignment.rb +5 -1
  20. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  21. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
  22. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  23. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  24. data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
  25. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
  26. data/lib/rubocop/cop/layout/redundant_line_break.rb +7 -2
  27. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  28. data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
  29. data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
  30. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  31. data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
  32. data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
  33. data/lib/rubocop/cop/lint/debugger.rb +2 -1
  34. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  35. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
  36. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  37. data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
  38. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
  39. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
  40. data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
  41. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  42. data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
  43. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +43 -0
  44. data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
  45. data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
  46. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
  47. data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
  48. data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
  49. data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
  50. data/lib/rubocop/cop/lint/syntax.rb +6 -3
  51. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  52. data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
  53. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  54. data/lib/rubocop/cop/lint/useless_times.rb +1 -1
  55. data/lib/rubocop/cop/lint/void.rb +14 -1
  56. data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
  57. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  58. data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
  59. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  60. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  61. data/lib/rubocop/cop/naming/block_forwarding.rb +12 -4
  62. data/lib/rubocop/cop/naming/constant_name.rb +1 -2
  63. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  64. data/lib/rubocop/cop/security/open.rb +2 -2
  65. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  66. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  67. data/lib/rubocop/cop/style/arguments_forwarding.rb +127 -17
  68. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  69. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  70. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  71. data/lib/rubocop/cop/style/case_like_if.rb +4 -4
  72. data/lib/rubocop/cop/style/class_check.rb +1 -0
  73. data/lib/rubocop/cop/style/collection_compact.rb +18 -8
  74. data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
  75. data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
  76. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
  77. data/lib/rubocop/cop/style/date_time.rb +5 -4
  78. data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
  79. data/lib/rubocop/cop/style/each_with_object.rb +2 -2
  80. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  81. data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
  82. data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
  83. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  84. data/lib/rubocop/cop/style/hash_each_methods.rb +105 -11
  85. data/lib/rubocop/cop/style/hash_except.rb +2 -1
  86. data/lib/rubocop/cop/style/identical_conditional_branches.rb +4 -1
  87. data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
  88. data/lib/rubocop/cop/style/invertible_unless_condition.rb +39 -2
  89. data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +3 -2
  90. data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
  91. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
  92. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
  93. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
  94. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  95. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  96. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -3
  97. data/lib/rubocop/cop/style/next.rb +1 -1
  98. data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
  99. data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
  100. data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
  101. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
  102. data/lib/rubocop/cop/style/redundant_argument.rb +3 -2
  103. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +3 -3
  104. data/lib/rubocop/cop/style/redundant_each.rb +7 -4
  105. data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
  106. data/lib/rubocop/cop/style/redundant_line_continuation.rb +10 -1
  107. data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -10
  108. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  109. data/lib/rubocop/cop/style/redundant_self.rb +17 -2
  110. data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
  111. data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
  112. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  113. data/lib/rubocop/cop/style/sample.rb +2 -1
  114. data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
  115. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  116. data/lib/rubocop/cop/style/semicolon.rb +8 -0
  117. data/lib/rubocop/cop/style/single_argument_dig.rb +5 -2
  118. data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
  119. data/lib/rubocop/cop/style/string_chars.rb +1 -0
  120. data/lib/rubocop/cop/style/strip.rb +7 -4
  121. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  122. data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
  123. data/lib/rubocop/cop/style/unpack_first.rb +11 -14
  124. data/lib/rubocop/cops_documentation_generator.rb +11 -1
  125. data/lib/rubocop/ext/regexp_node.rb +9 -4
  126. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  127. data/lib/rubocop/formatter/html_formatter.rb +1 -2
  128. data/lib/rubocop/formatter/json_formatter.rb +0 -1
  129. data/lib/rubocop/formatter.rb +1 -1
  130. data/lib/rubocop/lsp/routes.rb +1 -1
  131. data/lib/rubocop/options.rb +0 -8
  132. data/lib/rubocop/result_cache.rb +0 -1
  133. data/lib/rubocop/rspec/shared_contexts.rb +6 -0
  134. data/lib/rubocop/rspec/support.rb +1 -0
  135. data/lib/rubocop/runner.rb +1 -1
  136. data/lib/rubocop/server/cache.rb +1 -2
  137. data/lib/rubocop/server/client_command/exec.rb +0 -1
  138. data/lib/rubocop/server/server_command/exec.rb +0 -1
  139. data/lib/rubocop/version.rb +1 -1
  140. data/lib/rubocop.rb +4 -0
  141. metadata +15 -10
  142. /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -12,7 +12,16 @@ module RuboCop
12
12
  #
13
13
  # This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
14
14
  # replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
15
- # by setting UseAnonymousForwarding: false.
15
+ # by setting `UseAnonymousForwarding: false`.
16
+ #
17
+ # And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
18
+ # and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
19
+ # that are sufficient for anonymizing meaningless naming.
20
+ #
21
+ # Meaningless names that are commonly used can be anonymized by default:
22
+ # e.g., `*args`, `**options`, `&block`, and so on.
23
+ #
24
+ # Names not on this list are likely to be meaningful and are allowed by default.
16
25
  #
17
26
  # @example
18
27
  # # bad
@@ -72,6 +81,38 @@ module RuboCop
72
81
  # bar(**kwargs)
73
82
  # end
74
83
  #
84
+ # @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
85
+ # # bad
86
+ # def foo(*args)
87
+ # bar(*args)
88
+ # end
89
+ #
90
+ # # good
91
+ # def foo(*)
92
+ # bar(*)
93
+ # end
94
+ #
95
+ # @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
96
+ # # bad
97
+ # def foo(**kwargs)
98
+ # bar(**kwargs)
99
+ # end
100
+ #
101
+ # # good
102
+ # def foo(**)
103
+ # bar(**)
104
+ # end
105
+ #
106
+ # @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
107
+ # # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`.
108
+ # def foo(&block)
109
+ # bar(&block)
110
+ # end
111
+ #
112
+ # # good
113
+ # def foo(&)
114
+ # bar(&)
115
+ # end
75
116
  class ArgumentsForwarding < Base
76
117
  include RangeHelp
77
118
  extend AutoCorrector
@@ -85,17 +126,21 @@ module RuboCop
85
126
  FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
86
127
  ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
87
128
  KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
129
+ BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
130
+
131
+ def self.autocorrect_incompatible_with
132
+ [Naming::BlockForwarding]
133
+ end
88
134
 
89
135
  def on_def(node)
90
136
  return unless node.body
91
137
 
92
- forwardable_args = extract_forwardable_args(node.arguments)
138
+ restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
139
+ forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
140
+ send_nodes = node.each_descendant(:send).to_a
93
141
 
94
142
  send_classifications = classify_send_nodes(
95
- node,
96
- node.each_descendant(:send).to_a,
97
- non_splat_or_block_pass_lvar_references(node.body),
98
- forwardable_args
143
+ node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
99
144
  )
100
145
 
101
146
  return if send_classifications.empty?
@@ -115,31 +160,54 @@ module RuboCop
115
160
  [args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
116
161
  end
117
162
 
163
+ def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
164
+ restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
165
+ kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
166
+ blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
167
+
168
+ [restarg_node, kwrestarg_node, blockarg_node]
169
+ end
170
+
118
171
  def only_forwards_all?(send_classifications)
119
172
  send_classifications.all? { |_, c, _, _| c == :all }
120
173
  end
121
174
 
175
+ # rubocop:disable Metrics/MethodLength
122
176
  def add_forward_all_offenses(node, send_classifications, forwardable_args)
123
- send_classifications.each do |send_node, _c, forward_rest, _forward_kwrest|
124
- register_forward_all_offense(send_node, send_node, forward_rest)
177
+ _rest_arg, _kwrest_arg, block_arg = *forwardable_args
178
+ registered_block_arg_offense = false
179
+
180
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
181
+ if !forward_rest && !forward_kwrest
182
+ register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
183
+ register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
184
+
185
+ registered_block_arg_offense = true
186
+ break
187
+ else
188
+ register_forward_all_offense(send_node, send_node, forward_rest)
189
+ end
125
190
  end
126
191
 
192
+ return if registered_block_arg_offense
193
+
127
194
  rest_arg, _kwrest_arg, _block_arg = *forwardable_args
128
195
  register_forward_all_offense(node, node.arguments, rest_arg)
129
196
  end
197
+ # rubocop:enable Metrics/MethodLength
130
198
 
131
199
  def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
132
200
  return unless use_anonymous_forwarding?
133
201
 
134
202
  rest_arg, kwrest_arg, _block_arg = *forwardable_args
135
203
 
136
- send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
137
- if forward_rest
204
+ send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, _forward_block_arg| # rubocop:disable Layout/LineLength
205
+ if outside_block?(forward_rest)
138
206
  register_forward_args_offense(def_node.arguments, rest_arg)
139
207
  register_forward_args_offense(send_node, forward_rest)
140
208
  end
141
209
 
142
- if forward_kwrest
210
+ if outside_block?(forward_kwrest)
143
211
  register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
144
212
  register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
145
213
  end
@@ -173,10 +241,7 @@ module RuboCop
173
241
 
174
242
  def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
175
243
  classifier = SendNodeClassifier.new(
176
- def_node,
177
- send_node,
178
- referenced_lvars,
179
- forwardable_args,
244
+ def_node, send_node, referenced_lvars, forwardable_args,
180
245
  target_ruby_version: target_ruby_version,
181
246
  allow_only_rest_arguments: allow_only_rest_arguments?
182
247
  )
@@ -185,7 +250,28 @@ module RuboCop
185
250
 
186
251
  return unless classification
187
252
 
188
- [classification, classifier.forwarded_rest_arg, classifier.forwarded_kwrest_arg]
253
+ [
254
+ classification,
255
+ classifier.forwarded_rest_arg,
256
+ classifier.forwarded_kwrest_arg,
257
+ classifier.forwarded_block_arg
258
+ ]
259
+ end
260
+
261
+ def redundant_named_arg(arg, config_name, keyword)
262
+ return nil unless arg
263
+
264
+ redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
265
+ "#{keyword}#{redundant_arg_name}"
266
+ end << keyword
267
+
268
+ redundant_arg_names.include?(arg.source) ? arg : nil
269
+ end
270
+
271
+ def outside_block?(node)
272
+ return false unless node
273
+
274
+ node.each_ancestor(:block, :numblock).none?
189
275
  end
190
276
 
191
277
  def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
@@ -204,6 +290,16 @@ module RuboCop
204
290
  end
205
291
  end
206
292
 
293
+ def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
294
+ return if target_ruby_version <= 3.0 || block_arg.source == '&' || explicit_block_name?
295
+
296
+ add_offense(block_arg, message: BLOCK_MSG) do |corrector|
297
+ add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
298
+
299
+ corrector.replace(block_arg, '&')
300
+ end
301
+ end
302
+
207
303
  def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
208
304
  arg_range = arguments_range(def_or_send, rest_or_splat)
209
305
 
@@ -278,7 +374,7 @@ module RuboCop
278
374
  end
279
375
 
280
376
  def classification
281
- return nil unless forwarded_rest_arg || forwarded_kwrest_arg
377
+ return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
282
378
 
283
379
  if can_forward_all?
284
380
  :all
@@ -362,9 +458,23 @@ module RuboCop
362
458
  def no_additional_args?
363
459
  forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
364
460
 
461
+ return false if missing_rest_arg_or_kwrest_arg?
462
+
365
463
  @def_node.arguments.size == forwardable_count &&
366
464
  @send_node.arguments.size == forwardable_count
367
465
  end
466
+
467
+ def missing_rest_arg_or_kwrest_arg?
468
+ (@rest_arg_name && !forwarded_rest_arg) ||
469
+ (@kwrest_arg_name && !forwarded_kwrest_arg)
470
+ end
471
+ end
472
+
473
+ def explicit_block_name?
474
+ block_forwarding_config = config.for_cop('Naming/BlockForwarding')
475
+ return false unless block_forwarding_config['Enabled']
476
+
477
+ block_forwarding_config['EnforcedStyle'] == 'explicit'
368
478
  end
369
479
  end
370
480
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
7
+ # them to use `arr.first` and `arr.last` instead.
8
+ #
9
+ # The cop is disabled by default due to safety concerns.
10
+ #
11
+ # @safety
12
+ # This cop is unsafe because `[0]` or `[-1]` can be called on a Hash,
13
+ # which returns a value for `0` or `-1` key, but changing these to use
14
+ # `.first` or `.last` will return first/last tuple instead. Also, String
15
+ # does not implement `first`/`last` methods.
16
+ #
17
+ # @example
18
+ # # bad
19
+ # arr[0]
20
+ # arr[-1]
21
+ #
22
+ # # good
23
+ # arr.first
24
+ # arr.last
25
+ # arr[0] = 2
26
+ # arr[0][-2]
27
+ #
28
+ class ArrayFirstLast < Base
29
+ extend AutoCorrector
30
+
31
+ MSG = 'Use `%<preferred>s`.'
32
+ RESTRICT_ON_SEND = %i[[]].freeze
33
+
34
+ # rubocop:disable Metrics/AbcSize
35
+ def on_send(node)
36
+ return unless node.arguments.size == 1 && node.first_argument.int_type?
37
+
38
+ value = node.first_argument.value
39
+ return unless [0, -1].include?(value)
40
+
41
+ node = innermost_braces_node(node)
42
+ return if node.parent && brace_method?(node.parent)
43
+
44
+ preferred = (value.zero? ? 'first' : 'last')
45
+ add_offense(node.loc.selector, message: format(MSG, preferred: preferred)) do |corrector|
46
+ corrector.replace(node.loc.selector, ".#{preferred}")
47
+ end
48
+ end
49
+ # rubocop:enable Metrics/AbcSize
50
+
51
+ private
52
+
53
+ def innermost_braces_node(node)
54
+ node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
55
+ node
56
+ end
57
+
58
+ def brace_method?(node)
59
+ node.send_type? && (node.method?(:[]) || node.method?(:[]=))
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -16,31 +16,38 @@ module RuboCop
16
16
  # File.open('file') do |f|
17
17
  # # ...
18
18
  # end
19
+ #
20
+ # # bad
21
+ # f = Tempfile.open('temp')
22
+ #
23
+ # # good
24
+ # Tempfile.open('temp') do |f|
25
+ # # ...
26
+ # end
19
27
  class AutoResourceCleanup < Base
20
- MSG = 'Use the block version of `%<class>s.%<method>s`.'
21
-
22
- TARGET_METHODS = { File: :open }.freeze
28
+ MSG = 'Use the block version of `%<current>s`.'
29
+ RESTRICT_ON_SEND = %i[open].freeze
23
30
 
24
- RESTRICT_ON_SEND = TARGET_METHODS.values.freeze
31
+ # @!method file_open_method?(node)
32
+ def_node_matcher :file_open_method?, <<~PATTERN
33
+ (send (const {nil? cbase} {:File :Tempfile}) :open ...)
34
+ PATTERN
25
35
 
26
36
  def on_send(node)
27
- TARGET_METHODS.each do |target_class, target_method|
28
- next if node.method_name != target_method
37
+ return if !file_open_method?(node) || cleanup?(node)
29
38
 
30
- target_receiver = s(:const, nil, target_class)
31
- next if node.receiver != target_receiver
39
+ current = node.receiver.source_range.begin.join(node.selector.end).source
32
40
 
33
- next if cleanup?(node)
34
-
35
- add_offense(node, message: format(MSG, class: target_class, method: target_method))
36
- end
41
+ add_offense(node, message: format(MSG, current: current))
37
42
  end
38
43
 
39
44
  private
40
45
 
41
46
  def cleanup?(node)
42
- parent = node.parent
43
- node.block_argument? || (parent && (parent.block_type? || !parent.lvasgn_type?))
47
+ return true if node.block_argument?
48
+ return false unless (parent = node.parent)
49
+
50
+ parent.block_type? || !parent.lvasgn_type?
44
51
  end
45
52
  end
46
53
  end
@@ -33,7 +33,7 @@ module RuboCop
33
33
  def on_class(class_node)
34
34
  @macros_to_rewrite[class_node] = Set.new
35
35
 
36
- find_macros(class_node.body).each do |_visibility, macros|
36
+ find_macros(class_node.body).each_value do |macros|
37
37
  bisected = find_bisection(macros)
38
38
  next unless bisected.any?
39
39
 
@@ -74,7 +74,7 @@ module RuboCop
74
74
  def find_macros(class_def)
75
75
  # Find all the macros (`attr_reader`, `attr_writer`, etc.) in the class body
76
76
  # and turn them into `Macro` objects so that they can be processed.
77
- return [] if !class_def || class_def.def_type?
77
+ return {} if !class_def || class_def.def_type?
78
78
 
79
79
  send_nodes =
80
80
  if class_def.send_type?
@@ -125,7 +125,7 @@ module RuboCop
125
125
  when :==, :eql?, :equal?
126
126
  find_target_in_equality_node(node)
127
127
  when :===
128
- node.arguments.first
128
+ node.first_argument
129
129
  when :include?, :cover?
130
130
  find_target_in_include_or_cover_node(node)
131
131
  when :match, :match?, :=~
@@ -134,7 +134,7 @@ module RuboCop
134
134
  end
135
135
 
136
136
  def find_target_in_equality_node(node)
137
- argument = node.arguments.first
137
+ argument = node.first_argument
138
138
  receiver = node.receiver
139
139
  return unless argument && receiver
140
140
 
@@ -152,7 +152,7 @@ module RuboCop
152
152
  end
153
153
 
154
154
  def find_target_in_match_node(node)
155
- argument = node.arguments.first
155
+ argument = node.first_argument
156
156
  receiver = node.receiver
157
157
  return unless receiver
158
158
 
@@ -185,7 +185,7 @@ module RuboCop
185
185
  def condition_from_send_node(node, target)
186
186
  case node.method_name
187
187
  when :is_a?
188
- node.arguments.first if node.receiver == target
188
+ node.first_argument if node.receiver == target
189
189
  when :==, :eql?, :equal?
190
190
  condition_from_equality_node(node, target)
191
191
  when :=~, :match, :match?
@@ -40,6 +40,7 @@ module RuboCop
40
40
  corrector.replace(node.loc.selector, replacement)
41
41
  end
42
42
  end
43
+ alias on_csend on_send
43
44
 
44
45
  def message(node)
45
46
  if node.method?(:is_a?)
@@ -23,6 +23,8 @@ module RuboCop
23
23
  # array.reject { |e| e.nil? }
24
24
  # array.delete_if { |e| e.nil? }
25
25
  # array.select { |e| !e.nil? }
26
+ # array.grep_v(nil)
27
+ # array.grep_v(NilClass)
26
28
  #
27
29
  # # good
28
30
  # array.compact
@@ -46,14 +48,14 @@ module RuboCop
46
48
  extend TargetRubyVersion
47
49
 
48
50
  MSG = 'Use `%<good>s` instead of `%<bad>s`.'
49
- RESTRICT_ON_SEND = %i[reject delete_if reject! select select!].freeze
51
+ RESTRICT_ON_SEND = %i[reject delete_if reject! select select! grep_v].freeze
50
52
  TO_ENUM_METHODS = %i[to_enum lazy].freeze
51
53
 
52
54
  minimum_target_ruby_version 2.4
53
55
 
54
56
  # @!method reject_method_with_block_pass?(node)
55
57
  def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
56
- (send !nil? {:reject :delete_if :reject!}
58
+ (call !nil? {:reject :delete_if :reject!}
57
59
  (block_pass
58
60
  (sym :nil?)))
59
61
  PATTERN
@@ -61,24 +63,29 @@ module RuboCop
61
63
  # @!method reject_method?(node)
62
64
  def_node_matcher :reject_method?, <<~PATTERN
63
65
  (block
64
- (send
66
+ (call
65
67
  !nil? {:reject :delete_if :reject!})
66
68
  $(args ...)
67
- (send
69
+ (call
68
70
  $(lvar _) :nil?))
69
71
  PATTERN
70
72
 
71
73
  # @!method select_method?(node)
72
74
  def_node_matcher :select_method?, <<~PATTERN
73
75
  (block
74
- (send
76
+ (call
75
77
  !nil? {:select :select!})
76
78
  $(args ...)
77
- (send
78
- (send
79
+ (call
80
+ (call
79
81
  $(lvar _) :nil?) :!))
80
82
  PATTERN
81
83
 
84
+ # @!method grep_v_with_nil?(node)
85
+ def_node_matcher :grep_v_with_nil?, <<~PATTERN
86
+ (send _ :grep_v {(nil) (const {nil? cbase} :NilClass)})
87
+ PATTERN
88
+
82
89
  def on_send(node)
83
90
  return unless (range = offense_range(node))
84
91
  return if allowed_receiver?(node.receiver)
@@ -91,11 +98,13 @@ module RuboCop
91
98
 
92
99
  add_offense(range, message: message) { |corrector| corrector.replace(range, good) }
93
100
  end
101
+ alias on_csend on_send
94
102
 
95
103
  private
96
104
 
105
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
97
106
  def offense_range(node)
98
- if reject_method_with_block_pass?(node)
107
+ if reject_method_with_block_pass?(node) || grep_v_with_nil?(node)
99
108
  range(node, node)
100
109
  else
101
110
  block_node = node.parent
@@ -109,6 +118,7 @@ module RuboCop
109
118
  range(node, block_node)
110
119
  end
111
120
  end
121
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
112
122
 
113
123
  def to_enum_method?(node)
114
124
  return false unless node.receiver.send_type?
@@ -59,8 +59,6 @@ module RuboCop
59
59
  class CombinableLoops < Base
60
60
  extend AutoCorrector
61
61
 
62
- include RangeHelp
63
-
64
62
  MSG = 'Combine this loop with the previous loop.'
65
63
 
66
64
  def on_block(node)
@@ -105,11 +103,19 @@ module RuboCop
105
103
  end
106
104
 
107
105
  def combine_with_left_sibling(corrector, node)
108
- corrector.replace(
109
- node.left_sibling.body,
110
- "#{node.left_sibling.body.source}\n#{node.body.source}"
111
- )
112
- corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
106
+ corrector.remove(node.left_sibling.body.source_range.end.join(node.left_sibling.loc.end))
107
+ corrector.remove(node.source_range.begin.join(node.body.source_range.begin))
108
+
109
+ correct_end_of_block(corrector, node)
110
+ end
111
+
112
+ def correct_end_of_block(corrector, node)
113
+ return unless node.left_sibling.respond_to?(:braces?)
114
+ return if node.right_sibling&.block_type? || node.right_sibling&.numblock_type?
115
+
116
+ end_of_block = node.left_sibling.braces? ? '}' : ' end'
117
+ corrector.remove(node.loc.end)
118
+ corrector.insert_before(node.source_range.end, end_of_block)
113
119
  end
114
120
  end
115
121
  end
@@ -63,6 +63,7 @@ module RuboCop
63
63
  end
64
64
  end
65
65
  # rubocop:enable Metrics
66
+ alias on_csend on_send
66
67
 
67
68
  private
68
69
 
@@ -233,7 +233,7 @@ module RuboCop
233
233
  PATTERN
234
234
 
235
235
  ASSIGNMENT_TYPES.each do |type|
236
- define_method "on_#{type}" do |node|
236
+ define_method :"on_#{type}" do |node|
237
237
  return if part_of_ignored_node?(node)
238
238
  return if node.parent&.shorthand_asgn?
239
239
 
@@ -534,7 +534,7 @@ module RuboCop
534
534
  end
535
535
 
536
536
  def element_assignment?(node)
537
- node.send_type? && node.method_name != :[]=
537
+ node.send_type? && !node.method?(:[]=)
538
538
  end
539
539
 
540
540
  def extract_branches(node)
@@ -49,12 +49,12 @@ module RuboCop
49
49
  class DateTime < Base
50
50
  extend AutoCorrector
51
51
 
52
- CLASS_MSG = 'Prefer Time over DateTime.'
53
- COERCION_MSG = 'Do not use #to_datetime.'
52
+ CLASS_MSG = 'Prefer `Time` over `DateTime`.'
53
+ COERCION_MSG = 'Do not use `#to_datetime`.'
54
54
 
55
55
  # @!method date_time?(node)
56
56
  def_node_matcher :date_time?, <<~PATTERN
57
- (send (const {nil? (cbase)} :DateTime) ...)
57
+ (call (const {nil? (cbase)} :DateTime) ...)
58
58
  PATTERN
59
59
 
60
60
  # @!method historic_date?(node)
@@ -64,7 +64,7 @@ module RuboCop
64
64
 
65
65
  # @!method to_datetime?(node)
66
66
  def_node_matcher :to_datetime?, <<~PATTERN
67
- (send _ :to_datetime)
67
+ (call _ :to_datetime)
68
68
  PATTERN
69
69
 
70
70
  def on_send(node)
@@ -75,6 +75,7 @@ module RuboCop
75
75
 
76
76
  add_offense(node, message: message) { |corrector| autocorrect(corrector, node) }
77
77
  end
78
+ alias on_csend on_send
78
79
 
79
80
  private
80
81
 
@@ -32,27 +32,27 @@ module RuboCop
32
32
 
33
33
  send_node = node.send_node
34
34
 
35
- range = send_node.receiver.source_range.join(send_node.loc.selector)
36
-
37
- add_offense(range) do |corrector|
35
+ add_offense(send_node) do |corrector|
38
36
  range_type, min, max = each_range(node)
39
37
 
40
38
  max += 1 if range_type == :irange
41
39
 
42
- corrector.replace(node.send_node, "#{max - min}.times")
40
+ corrector.replace(send_node, "#{max - min}.times")
43
41
  end
44
42
  end
45
43
 
46
44
  private
47
45
 
48
46
  def offending?(node)
47
+ return false unless node.arguments.empty?
48
+
49
49
  each_range_with_zero_origin?(node) || each_range_without_block_argument?(node)
50
50
  end
51
51
 
52
52
  # @!method each_range(node)
53
53
  def_node_matcher :each_range, <<~PATTERN
54
54
  (block
55
- (send
55
+ (call
56
56
  (begin
57
57
  (${irange erange}
58
58
  (int $_) (int $_)))
@@ -64,7 +64,7 @@ module RuboCop
64
64
  # @!method each_range_with_zero_origin?(node)
65
65
  def_node_matcher :each_range_with_zero_origin?, <<~PATTERN
66
66
  (block
67
- (send
67
+ (call
68
68
  (begin
69
69
  ({irange erange}
70
70
  (int 0) (int _)))
@@ -76,7 +76,7 @@ module RuboCop
76
76
  # @!method each_range_without_block_argument?(node)
77
77
  def_node_matcher :each_range_without_block_argument?, <<~PATTERN
78
78
  (block
79
- (send
79
+ (call
80
80
  (begin
81
81
  ({irange erange}
82
82
  (int _) (int _)))
@@ -58,12 +58,12 @@ module RuboCop
58
58
 
59
59
  # @!method each_with_object_block_candidate?(node)
60
60
  def_node_matcher :each_with_object_block_candidate?, <<~PATTERN
61
- (block $(send _ {:inject :reduce} _) $_ $_)
61
+ (block $(call _ {:inject :reduce} _) $_ $_)
62
62
  PATTERN
63
63
 
64
64
  # @!method each_with_object_numblock_candidate?(node)
65
65
  def_node_matcher :each_with_object_numblock_candidate?, <<~PATTERN
66
- (numblock $(send _ {:inject :reduce} _) 2 $_)
66
+ (numblock $(call _ {:inject :reduce} _) 2 $_)
67
67
  PATTERN
68
68
 
69
69
  def autocorrect_block(corrector, node, return_value)
@@ -83,7 +83,7 @@ module RuboCop
83
83
  parent = node.parent
84
84
  return false unless parent && %i[send super zsuper].include?(parent.type)
85
85
 
86
- node.equal?(parent.arguments.first) && !parentheses?(node.parent)
86
+ node.equal?(parent.first_argument) && !parentheses?(node.parent)
87
87
  end
88
88
 
89
89
  def replacement_range(node)