rubocop 1.66.1 → 1.67.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +15 -6
  4. data/config/internal_affairs.yml +11 -0
  5. data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
  6. data/lib/rubocop/cli/command/lsp.rb +2 -2
  7. data/lib/rubocop/config_loader_resolver.rb +3 -3
  8. data/lib/rubocop/config_validator.rb +2 -1
  9. data/lib/rubocop/cop/base.rb +6 -2
  10. data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
  11. data/lib/rubocop/cop/cop.rb +8 -0
  12. data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
  13. data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
  14. data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
  15. data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
  16. data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
  17. data/lib/rubocop/cop/internal_affairs.rb +16 -0
  18. data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
  19. data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
  20. data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
  21. data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
  22. data/lib/rubocop/cop/layout/indentation_width.rb +4 -5
  23. data/lib/rubocop/cop/layout/leading_comment_space.rb +28 -1
  24. data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
  25. data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
  26. data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
  27. data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
  28. data/lib/rubocop/cop/lint/ensure_return.rb +0 -3
  29. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  30. data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
  31. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +10 -4
  32. data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +5 -14
  33. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +25 -2
  34. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
  35. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -1
  36. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +105 -41
  37. data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
  38. data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
  39. data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
  40. data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
  41. data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
  42. data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
  43. data/lib/rubocop/cop/offense.rb +2 -2
  44. data/lib/rubocop/cop/style/access_modifier_declarations.rb +12 -2
  45. data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
  46. data/lib/rubocop/cop/style/arguments_forwarding.rb +46 -6
  47. data/lib/rubocop/cop/style/block_delimiters.rb +14 -1
  48. data/lib/rubocop/cop/style/collection_compact.rb +10 -10
  49. data/lib/rubocop/cop/style/combinable_loops.rb +7 -0
  50. data/lib/rubocop/cop/style/commented_keyword.rb +7 -1
  51. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  52. data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
  53. data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
  54. data/lib/rubocop/cop/style/guard_clause.rb +1 -1
  55. data/lib/rubocop/cop/style/hash_each_methods.rb +6 -0
  56. data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
  57. data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
  58. data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -3
  59. data/lib/rubocop/cop/style/lambda.rb +1 -1
  60. data/lib/rubocop/cop/style/map_into_array.rb +53 -7
  61. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -7
  62. data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
  63. data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
  64. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
  65. data/lib/rubocop/cop/style/one_line_conditional.rb +4 -0
  66. data/lib/rubocop/cop/style/operator_method_call.rb +25 -6
  67. data/lib/rubocop/cop/style/redundant_begin.rb +4 -0
  68. data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
  69. data/lib/rubocop/cop/style/redundant_line_continuation.rb +3 -3
  70. data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
  71. data/lib/rubocop/cop/style/require_order.rb +1 -1
  72. data/lib/rubocop/cop/style/rescue_modifier.rb +13 -1
  73. data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
  74. data/lib/rubocop/cop/style/safe_navigation.rb +92 -50
  75. data/lib/rubocop/cop/style/select_by_regexp.rb +9 -6
  76. data/lib/rubocop/cop/style/semicolon.rb +1 -1
  77. data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
  78. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  79. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  80. data/lib/rubocop/cop/team.rb +8 -1
  81. data/lib/rubocop/cop/util.rb +1 -1
  82. data/lib/rubocop/cops_documentation_generator.rb +73 -34
  83. data/lib/rubocop/file_finder.rb +9 -4
  84. data/lib/rubocop/lsp/runtime.rb +2 -0
  85. data/lib/rubocop/lsp/server.rb +0 -1
  86. data/lib/rubocop/rspec/expect_offense.rb +1 -0
  87. data/lib/rubocop/runner.rb +3 -0
  88. data/lib/rubocop/server/cache.rb +6 -1
  89. data/lib/rubocop/server/core.rb +1 -0
  90. data/lib/rubocop/target_ruby.rb +12 -12
  91. data/lib/rubocop/version.rb +3 -1
  92. data/lib/rubocop/yaml_duplication_checker.rb +20 -27
  93. data/lib/rubocop.rb +2 -0
  94. metadata +10 -8
@@ -22,6 +22,9 @@ module RuboCop
22
22
 
23
23
  MSG = 'Redundant dot detected.'
24
24
  RESTRICT_ON_SEND = %i[| ^ & <=> == === =~ > >= < <= << >> + - * / % ** ~ ! != !~].freeze
25
+ INVALID_SYNTAX_ARG_TYPES = %i[
26
+ splat kwsplat forwarded_args forwarded_restarg forwarded_kwrestarg block_pass
27
+ ].freeze
25
28
 
26
29
  # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
27
30
  def on_send(node)
@@ -29,14 +32,16 @@ module RuboCop
29
32
  return if node.receiver.const_type? || !node.arguments.one?
30
33
 
31
34
  _lhs, _op, rhs = *node
32
- return if !rhs || method_call_with_parenthesized_arg?(rhs) || anonymous_forwarding?(rhs)
35
+ if !rhs || method_call_with_parenthesized_arg?(rhs) || invalid_syntax_argument?(rhs)
36
+ return
37
+ end
33
38
 
34
39
  add_offense(dot) do |corrector|
35
40
  wrap_in_parentheses_if_chained(corrector, node)
36
41
  corrector.replace(dot, ' ')
37
42
 
38
43
  selector = node.loc.selector
39
- corrector.insert_after(selector, ' ') if selector.end_pos == rhs.source_range.begin_pos
44
+ corrector.insert_after(selector, ' ') if insert_space_after?(node)
40
45
  end
41
46
  end
42
47
  # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
@@ -50,11 +55,10 @@ module RuboCop
50
55
  argument.children.first && argument.parent.parenthesized?
51
56
  end
52
57
 
53
- def anonymous_forwarding?(argument)
54
- return true if argument.forwarded_args_type? || argument.forwarded_restarg_type?
55
- return true if argument.hash_type? && argument.children.first&.forwarded_kwrestarg_type?
58
+ def invalid_syntax_argument?(argument)
59
+ type = argument.hash_type? ? argument.children.first&.type : argument.type
56
60
 
57
- argument.block_pass_type? && argument.source == '&'
61
+ INVALID_SYNTAX_ARG_TYPES.include?(type)
58
62
  end
59
63
 
60
64
  def wrap_in_parentheses_if_chained(corrector, node)
@@ -67,6 +71,21 @@ module RuboCop
67
71
  corrector.insert_after(operator, ' ')
68
72
  corrector.wrap(node, '(', ')')
69
73
  end
74
+
75
+ def insert_space_after?(node)
76
+ _lhs, op, rhs = *node
77
+ selector = node.loc.selector
78
+
79
+ return true if selector.end_pos == rhs.source_range.begin_pos
80
+ return false if node.parent&.call_type? # if chained, a space is already added
81
+
82
+ # For `/` operations, if the RHS starts with a `(` without space,
83
+ # add one to avoid a syntax error.
84
+ range = selector.end.join(rhs.source_range.begin)
85
+ return true if op == :/ && range.source == '('
86
+
87
+ false
88
+ end
70
89
  end
71
90
  end
72
91
  end
@@ -68,6 +68,10 @@ module RuboCop
68
68
 
69
69
  MSG = 'Redundant `begin` block detected.'
70
70
 
71
+ def self.autocorrect_incompatible_with
72
+ [Style::BlockDelimiters]
73
+ end
74
+
71
75
  # @!method offensive_kwbegins(node)
72
76
  def_node_search :offensive_kwbegins, <<~PATTERN
73
77
  [(kwbegin ...) !#allowable_kwbegin?]
@@ -94,7 +94,7 @@ module RuboCop
94
94
  end
95
95
 
96
96
  def use_hash_key_assignment?(else_branch)
97
- else_branch&.send_type? && else_branch&.method?(:[]=)
97
+ else_branch&.send_type? && else_branch.method?(:[]=)
98
98
  end
99
99
 
100
100
  def use_hash_key_access?(node)
@@ -122,7 +122,7 @@ module RuboCop
122
122
  end
123
123
 
124
124
  def redundant_line_continuation?(range)
125
- return true unless (node = find_node_for_line(range.line))
125
+ return true unless (node = find_node_for_line(range.last_line))
126
126
  return false if argument_newline?(node)
127
127
 
128
128
  source = node.parent ? node.parent.source : node.source
@@ -160,9 +160,9 @@ module RuboCop
160
160
  end
161
161
  # rubocop:enable Metrics/AbcSize
162
162
 
163
- def find_node_for_line(line)
163
+ def find_node_for_line(last_line)
164
164
  processed_source.ast.each_node do |node|
165
- return node if same_line?(node, line)
165
+ return node if node.respond_to?(:expression) && node.expression&.last_line == last_line
166
166
  end
167
167
  end
168
168
 
@@ -160,7 +160,7 @@ module RuboCop
160
160
  return if node.semantic_operator? && begin_node.parent
161
161
  return if node.multiline? && allow_in_multiline_conditions?
162
162
  return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
163
- return if begin_node.parent&.if_type? && begin_node.parent&.ternary?
163
+ return if begin_node.parent&.if_type? && begin_node.parent.ternary?
164
164
 
165
165
  'a logical expression'
166
166
  elsif node.respond_to?(:comparison_method?) && node.comparison_method?
@@ -103,7 +103,7 @@ module RuboCop
103
103
  next unless sibling.is_a?(AST::Node)
104
104
 
105
105
  sibling = sibling_node(sibling)
106
- break unless sibling&.send_type? && sibling&.method?(node.method_name)
106
+ break unless sibling&.send_type? && sibling.method?(node.method_name)
107
107
  break unless sibling.arguments? && !sibling.receiver
108
108
  break unless in_same_section?(sibling, node)
109
109
  break unless node.first_argument.str_type? && sibling.first_argument.str_type?
@@ -75,7 +75,7 @@ module RuboCop
75
75
 
76
76
  corrector.remove(range_between(operation.source_range.end_pos, node.source_range.end_pos))
77
77
  corrector.insert_before(operation, "begin\n#{node_indentation}")
78
- corrector.insert_after(operation, <<~RESCUE_CLAUSE.chop)
78
+ corrector.insert_after(heredoc_end(operation) || operation, <<~RESCUE_CLAUSE.chop)
79
79
 
80
80
  #{node_offset}rescue
81
81
  #{node_indentation}#{rescue_args.source}
@@ -92,6 +92,18 @@ module RuboCop
92
92
  end
93
93
  [node_indentation, node_offset]
94
94
  end
95
+
96
+ def heredoc_end(node)
97
+ return unless node.call_type?
98
+
99
+ heredoc = node.arguments.reverse.find do |argument|
100
+ argument.respond_to?(:heredoc?) && argument.heredoc?
101
+ end
102
+
103
+ return unless heredoc
104
+
105
+ heredoc.loc.heredoc_end
106
+ end
95
107
  end
96
108
  end
97
109
  end
@@ -3,7 +3,8 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Style
6
- # Checks if `return` or `return nil` is used in predicate method definitions.
6
+ # Checks for predicate method definitions that return `nil`.
7
+ # A predicate method should only return a boolean value.
7
8
  #
8
9
  # @safety
9
10
  # Autocorrection is marked as unsafe because the change of the return value
@@ -31,6 +32,24 @@ module RuboCop
31
32
  # do_something?
32
33
  # end
33
34
  #
35
+ # # bad
36
+ # def foo?
37
+ # if condition
38
+ # nil
39
+ # else
40
+ # true
41
+ # end
42
+ # end
43
+ #
44
+ # # good
45
+ # def foo?
46
+ # if condition
47
+ # false
48
+ # else
49
+ # true
50
+ # end
51
+ # end
52
+ #
34
53
  # @example AllowedMethods: ['foo?']
35
54
  # # good
36
55
  # def foo?
@@ -64,24 +83,25 @@ module RuboCop
64
83
  return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
65
84
  return unless (body = node.body)
66
85
 
67
- body.each_descendant(:return) do |return_node|
68
- register_offense(return_node, 'return false') if return_nil?(return_node)
69
- end
70
-
71
- return unless (nil_node = nil_node_at_the_end_of_method_body(body))
86
+ body.each_descendant(:return) { |return_node| handle_return(return_node) }
72
87
 
73
- register_offense(nil_node, 'false')
88
+ handle_implicit_return_values(body)
74
89
  end
75
90
  alias on_defs on_def
76
91
 
77
92
  private
78
93
 
79
- def nil_node_at_the_end_of_method_body(body)
80
- return body if body.nil_type?
81
- return unless body.begin_type?
82
- return unless (last_child = body.children.last)
94
+ def last_node_of_type(node, type)
95
+ return unless node
96
+ return node if node_type?(node, type)
97
+ return unless node.begin_type?
98
+ return unless (last_child = node.children.last)
99
+
100
+ last_child if last_child.is_a?(AST::Node) && node_type?(last_child, type)
101
+ end
83
102
 
84
- last_child if last_child.is_a?(AST::Node) && last_child.nil_type?
103
+ def node_type?(node, type)
104
+ node.type == type.to_sym
85
105
  end
86
106
 
87
107
  def register_offense(offense_node, replacement)
@@ -89,6 +109,28 @@ module RuboCop
89
109
  corrector.replace(offense_node, replacement)
90
110
  end
91
111
  end
112
+
113
+ def handle_implicit_return_values(node)
114
+ handle_if(last_node_of_type(node, :if))
115
+ handle_nil(last_node_of_type(node, :nil))
116
+ end
117
+
118
+ def handle_return(return_node)
119
+ register_offense(return_node, 'return false') if return_nil?(return_node)
120
+ end
121
+
122
+ def handle_nil(nil_node)
123
+ return unless nil_node
124
+
125
+ register_offense(nil_node, 'false')
126
+ end
127
+
128
+ def handle_if(if_node)
129
+ return unless if_node
130
+
131
+ handle_implicit_return_values(if_node.if_branch)
132
+ handle_implicit_return_values(if_node.else_branch)
133
+ end
92
134
  end
93
135
  end
94
136
  end
@@ -81,7 +81,7 @@ module RuboCop
81
81
  # foo.baz = bar if foo
82
82
  # foo.baz + bar if foo
83
83
  # foo.bar > 2 if foo
84
- class SafeNavigation < Base
84
+ class SafeNavigation < Base # rubocop:disable Metrics/ClassLength
85
85
  include NilMethods
86
86
  include RangeHelp
87
87
  extend AutoCorrector
@@ -124,47 +124,112 @@ module RuboCop
124
124
  # @!method not_nil_check?(node)
125
125
  def_node_matcher :not_nil_check?, '(send (send $_ :nil?) :!)'
126
126
 
127
+ # @!method and_inside_begin?(node)
128
+ def_node_matcher :and_inside_begin?, '`(begin and ...)'
129
+
130
+ # @!method strip_begin(node)
131
+ def_node_matcher :strip_begin, '{ (begin $!begin) $!(begin) }'
132
+
127
133
  def on_if(node)
128
134
  return if allowed_if_condition?(node)
129
135
 
130
- check_node(node)
136
+ checked_variable, receiver, method_chain, _method = extract_parts_from_if(node)
137
+ return unless offending_node?(node, checked_variable, method_chain, receiver)
138
+
139
+ body = extract_if_body(node)
140
+ method_call = receiver.parent
141
+
142
+ removal_ranges = [begin_range(node, body), end_range(node, body)]
143
+
144
+ report_offense(node, method_chain, method_call, *removal_ranges) do |corrector|
145
+ corrector.insert_before(method_call.loc.dot, '&') unless method_call.safe_navigation?
146
+ end
147
+ end
148
+
149
+ def on_and(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
150
+ collect_and_clauses(node).each do |(lhs, lhs_operator_range), (rhs, _rhs_operator_range)|
151
+ lhs_not_nil_check = not_nil_check?(lhs)
152
+ lhs_receiver = lhs_not_nil_check || lhs
153
+ rhs_receiver = find_matching_receiver_invocation(strip_begin(rhs), lhs_receiver)
154
+
155
+ next if !cop_config['ConvertCodeThatCanStartToReturnNil'] && lhs_not_nil_check
156
+ next unless offending_node?(node, lhs_receiver, rhs, rhs_receiver)
157
+
158
+ # Since we are evaluating every clause in potentially a complex chain of `and` nodes,
159
+ # we need to ensure that there isn't an object check happening
160
+ lhs_method_chain = find_method_chain(lhs_receiver)
161
+ next unless lhs_method_chain == lhs_receiver || lhs_not_nil_check
162
+
163
+ report_offense(
164
+ node,
165
+ rhs, rhs_receiver,
166
+ range_with_surrounding_space(range: lhs.source_range, side: :right),
167
+ range_with_surrounding_space(range: lhs_operator_range, side: :right),
168
+ offense_range: range_between(lhs.source_range.begin_pos, rhs.source_range.end_pos)
169
+ )
170
+ end
131
171
  end
132
172
 
133
- def on_and(node)
134
- check_node(node)
173
+ def report_offense(node, rhs, rhs_receiver, *removal_ranges, offense_range: node)
174
+ add_offense(offense_range) do |corrector|
175
+ removal_ranges.each { |range| corrector.remove(range) }
176
+ yield corrector if block_given?
177
+
178
+ handle_comments(corrector, node, rhs)
179
+
180
+ add_safe_nav_to_all_methods_in_chain(corrector, rhs_receiver, rhs)
181
+ end
135
182
  end
136
183
 
137
184
  private
138
185
 
139
- def check_node(node)
140
- checked_variable, receiver, method_chain, method = extract_parts(node)
141
- return if receiver != checked_variable || receiver.nil?
142
- return if use_var_only_in_unless_modifier?(node, checked_variable)
143
- return if chain_length(method_chain, method) > max_chain_length
144
- return if unsafe_method_used?(method_chain, method)
145
- return if method_chain.method?(:empty?)
186
+ def find_method_chain(node)
187
+ return node unless node&.parent&.call_type?
146
188
 
147
- add_offense(node) { |corrector| autocorrect(corrector, node) }
189
+ find_method_chain(node.parent)
148
190
  end
149
191
 
150
- def use_var_only_in_unless_modifier?(node, variable)
151
- node.if_type? && node.unless? && !method_called?(variable)
192
+ def collect_and_clauses(node)
193
+ # Collect the lhs, operator and rhs of all `and` nodes
194
+ # `and` nodes can be nested and can contain `begin` nodes
195
+ # This gives us a source-ordered list of clauses that is then used to look
196
+ # for matching receivers as well as operator locations for offense and corrections
197
+ node.each_descendant(:and)
198
+ .inject(and_parts(node)) { |nodes, and_node| concat_nodes(nodes, and_node) }
199
+ .sort_by { |a| a.is_a?(RuboCop::AST::Node) ? a.source_range.begin_pos : a.begin_pos }
200
+ .each_slice(2)
201
+ .each_cons(2)
152
202
  end
153
203
 
154
- def autocorrect(corrector, node)
155
- body = extract_body(node)
156
- method_call = method_call(node)
204
+ def concat_nodes(nodes, and_node)
205
+ return nodes if and_node.each_ancestor(:block).any?
157
206
 
158
- corrector.remove(begin_range(node, body))
159
- corrector.remove(end_range(node, body))
160
- corrector.insert_before(method_call.loc.dot, '&') unless method_call.safe_navigation?
161
- handle_comments(corrector, node, method_call)
207
+ nodes.concat(and_parts(and_node))
208
+ end
162
209
 
163
- add_safe_nav_to_all_methods_in_chain(corrector, method_call, body)
210
+ def and_parts(node)
211
+ parts = [node.loc.operator]
212
+ parts << node.rhs unless and_inside_begin?(node.rhs)
213
+ parts << node.lhs unless node.lhs.and_type? || and_inside_begin?(node.lhs)
214
+ parts
164
215
  end
165
216
 
166
- def extract_body(node)
167
- if node.if_type? && node.ternary?
217
+ def offending_node?(node, lhs_receiver, rhs, rhs_receiver) # rubocop:disable Metrics/CyclomaticComplexity
218
+ return false if lhs_receiver != rhs_receiver || rhs_receiver.nil?
219
+ return false if use_var_only_in_unless_modifier?(node, lhs_receiver)
220
+ return false if chain_length(rhs, rhs_receiver) > max_chain_length
221
+ return false if unsafe_method_used?(rhs, rhs_receiver.parent)
222
+ return false if rhs.send_type? && rhs.method?(:empty?)
223
+
224
+ true
225
+ end
226
+
227
+ def use_var_only_in_unless_modifier?(node, variable)
228
+ node.if_type? && node.unless? && !method_called?(variable)
229
+ end
230
+
231
+ def extract_if_body(node)
232
+ if node.ternary?
168
233
  node.branches.find { |branch| !branch.nil_type? }
169
234
  else
170
235
  node.node_parts[1]
@@ -201,20 +266,6 @@ module RuboCop
201
266
  node.else? || node.elsif?
202
267
  end
203
268
 
204
- def method_call(node)
205
- _checked_variable, matching_receiver, = extract_parts(node)
206
- matching_receiver.parent
207
- end
208
-
209
- def extract_parts(node)
210
- case node.type
211
- when :if
212
- extract_parts_from_if(node)
213
- when :and
214
- extract_parts_from_and(node)
215
- end
216
- end
217
-
218
269
  def extract_parts_from_if(node)
219
270
  variable, receiver =
220
271
  if node.ternary?
@@ -230,16 +281,6 @@ module RuboCop
230
281
  [checked_variable, matching_receiver, receiver, method]
231
282
  end
232
283
 
233
- def extract_parts_from_and(node)
234
- checked_variable, rhs = *node
235
- if cop_config['ConvertCodeThatCanStartToReturnNil']
236
- checked_variable = not_nil_check?(checked_variable) || checked_variable
237
- end
238
-
239
- checked_variable, matching_receiver, method = extract_common_parts(rhs, checked_variable)
240
- [checked_variable, matching_receiver, rhs, method]
241
- end
242
-
243
284
  def extract_common_parts(method_chain, checked_variable)
244
285
  matching_receiver = find_matching_receiver_invocation(method_chain, checked_variable)
245
286
 
@@ -249,7 +290,7 @@ module RuboCop
249
290
  end
250
291
 
251
292
  def find_matching_receiver_invocation(method_chain, checked_variable)
252
- return nil unless method_chain
293
+ return nil unless method_chain.respond_to?(:receiver)
253
294
 
254
295
  receiver = method_chain.receiver
255
296
 
@@ -259,7 +300,7 @@ module RuboCop
259
300
  end
260
301
 
261
302
  def chain_length(method_chain, method)
262
- method.each_ancestor(:send).inject(1) do |total, ancestor|
303
+ method.each_ancestor(:send).inject(0) do |total, ancestor|
263
304
  break total + 1 if ancestor == method_chain
264
305
 
265
306
  total + 1
@@ -310,6 +351,7 @@ module RuboCop
310
351
  start_method.each_ancestor do |ancestor|
311
352
  break unless %i[send block].include?(ancestor.type)
312
353
  next unless ancestor.send_type?
354
+ next if ancestor.safe_navigation?
313
355
 
314
356
  corrector.insert_before(ancestor.loc.dot, '&')
315
357
 
@@ -27,7 +27,7 @@ module RuboCop
27
27
  # so the correction may not be actually equivalent.
28
28
  #
29
29
  # @example
30
- # # bad (select or find_all)
30
+ # # bad (select, filter, or find_all)
31
31
  # array.select { |x| x.match? /regexp/ }
32
32
  # array.select { |x| /regexp/.match?(x) }
33
33
  # array.select { |x| x =~ /regexp/ }
@@ -47,9 +47,11 @@ module RuboCop
47
47
  include RangeHelp
48
48
 
49
49
  MSG = 'Prefer `%<replacement>s` to `%<original_method>s` with a regexp match.'
50
- RESTRICT_ON_SEND = %i[select find_all reject].freeze
51
- REPLACEMENTS = { select: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
52
- OPPOSITE_REPLACEMENTS = { select: 'grep_v', find_all: 'grep_v', reject: 'grep' }.freeze
50
+ RESTRICT_ON_SEND = %i[select filter find_all reject].freeze
51
+ REPLACEMENTS = { select: 'grep', filter: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
52
+ OPPOSITE_REPLACEMENTS = {
53
+ select: 'grep_v', filter: 'grep_v', find_all: 'grep_v', reject: 'grep'
54
+ }.freeze
53
55
  REGEXP_METHODS = %i[match? =~ !~].to_set.freeze
54
56
 
55
57
  # @!method regexp_match?(node)
@@ -84,8 +86,9 @@ module RuboCop
84
86
  }
85
87
  PATTERN
86
88
 
87
- # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
89
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
88
90
  def on_send(node)
91
+ return if target_ruby_version < 2.6 && node.method?(:filter)
89
92
  return unless (block_node = node.block_node)
90
93
  return if block_node.body&.begin_type?
91
94
  return if receiver_allowed?(block_node.receiver)
@@ -99,7 +102,7 @@ module RuboCop
99
102
 
100
103
  register_offense(node, block_node, regexp, replacement)
101
104
  end
102
- # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
105
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
103
106
  alias on_csend on_send
104
107
 
105
108
  private
@@ -141,7 +141,7 @@ module RuboCop
141
141
 
142
142
  def expressions_per_line(exprs)
143
143
  # create a map matching lines to the number of expressions on them
144
- exprs_lines = exprs.map(&:first_line)
144
+ exprs_lines = exprs.map(&:last_line)
145
145
  exprs_lines.group_by(&:itself)
146
146
  end
147
147
 
@@ -33,7 +33,7 @@ module RuboCop
33
33
  def on_class(node)
34
34
  return unless struct_constructor?(node.parent_class)
35
35
 
36
- add_offense(node.parent_class.source_range) do |corrector|
36
+ add_offense(node.parent_class) do |corrector|
37
37
  corrector.remove(range_with_surrounding_space(node.loc.keyword, newlines: false))
38
38
  corrector.replace(node.loc.operator, '=')
39
39
 
@@ -75,7 +75,7 @@ module RuboCop
75
75
 
76
76
  message = message(node)
77
77
 
78
- add_offense(node.source_range, message: message) do |corrector|
78
+ add_offense(node, message: message) do |corrector|
79
79
  autocorrect(corrector, node)
80
80
  end
81
81
  end
@@ -179,7 +179,7 @@ module RuboCop
179
179
  end
180
180
 
181
181
  def looks_like_trivial_reader?(node)
182
- !node.arguments? && node.body && node.body.ivar_type?
182
+ !node.arguments? && node.body&.ivar_type?
183
183
  end
184
184
 
185
185
  def trivial_writer?(node)
@@ -9,11 +9,17 @@ module RuboCop
9
9
  # For performance reasons, Team will first dispatch cops & forces in two groups,
10
10
  # first the ones needed for autocorrection (if any), then the rest
11
11
  # (unless autocorrections happened).
12
+ # rubocop:disable Metrics/ClassLength
12
13
  class Team
13
14
  # @return [Team]
14
15
  def self.new(cop_or_classes, config, options = {})
15
16
  # Support v0 api:
16
- return mobilize(cop_or_classes, config, options) if cop_or_classes.first.is_a?(Class)
17
+ if cop_or_classes.first.is_a?(Class)
18
+ warn Rainbow(<<~WARNING).yellow, uplevel: 1
19
+ `Team.new` with cop classes is deprecated. Use `Team.mobilize` instead.
20
+ WARNING
21
+ return mobilize(cop_or_classes, config, options)
22
+ end
17
23
 
18
24
  super
19
25
  end
@@ -279,5 +285,6 @@ module RuboCop
279
285
  end
280
286
  end
281
287
  end
288
+ # rubocop:enable Metrics/ClassLength
282
289
  end
283
290
  end
@@ -32,7 +32,7 @@ module RuboCop
32
32
  end
33
33
 
34
34
  def parentheses?(node)
35
- node.loc.respond_to?(:end) && node.loc.end && node.loc.end.is?(')')
35
+ node.loc.respond_to?(:end) && node.loc.end&.is?(')')
36
36
  end
37
37
 
38
38
  # rubocop:disable Metrics/AbcSize, Metrics/MethodLength