rubocop 1.66.1 → 1.67.0
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +15 -6
- data/config/internal_affairs.yml +11 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +3 -3
- data/lib/rubocop/config_validator.rb +2 -1
- data/lib/rubocop/cop/base.rb +6 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
- data/lib/rubocop/cop/cop.rb +8 -0
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
- data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
- data/lib/rubocop/cop/internal_affairs.rb +16 -0
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -5
- data/lib/rubocop/cop/layout/leading_comment_space.rb +28 -1
- data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
- data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
- data/lib/rubocop/cop/lint/ensure_return.rb +0 -3
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +10 -4
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +5 -14
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +25 -2
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +105 -41
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
- data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
- data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
- data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +12 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +46 -6
- data/lib/rubocop/cop/style/block_delimiters.rb +14 -1
- data/lib/rubocop/cop/style/collection_compact.rb +10 -10
- data/lib/rubocop/cop/style/combinable_loops.rb +7 -0
- data/lib/rubocop/cop/style/commented_keyword.rb +7 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +1 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +6 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -3
- data/lib/rubocop/cop/style/lambda.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +53 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -7
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +25 -6
- data/lib/rubocop/cop/style/redundant_begin.rb +4 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +3 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/require_order.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +13 -1
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
- data/lib/rubocop/cop/style/safe_navigation.rb +92 -50
- data/lib/rubocop/cop/style/select_by_regexp.rb +9 -6
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/team.rb +8 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +73 -34
- data/lib/rubocop/file_finder.rb +9 -4
- data/lib/rubocop/lsp/runtime.rb +2 -0
- data/lib/rubocop/lsp/server.rb +0 -1
- data/lib/rubocop/rspec/expect_offense.rb +1 -0
- data/lib/rubocop/runner.rb +3 -0
- data/lib/rubocop/server/cache.rb +6 -1
- data/lib/rubocop/server/core.rb +1 -0
- data/lib/rubocop/target_ruby.rb +12 -12
- data/lib/rubocop/version.rb +3 -1
- data/lib/rubocop/yaml_duplication_checker.rb +20 -27
- data/lib/rubocop.rb +2 -0
- 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
|
-
|
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
|
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
|
54
|
-
|
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
|
-
|
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?]
|
@@ -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.
|
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(
|
163
|
+
def find_node_for_line(last_line)
|
164
164
|
processed_source.ast.each_node do |node|
|
165
|
-
return node if
|
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
|
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
|
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
|
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)
|
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
|
-
|
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
|
80
|
-
return
|
81
|
-
return
|
82
|
-
return unless
|
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
|
-
|
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
|
-
|
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
|
134
|
-
|
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
|
140
|
-
|
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
|
-
|
189
|
+
find_method_chain(node.parent)
|
148
190
|
end
|
149
191
|
|
150
|
-
def
|
151
|
-
|
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
|
155
|
-
|
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
|
-
|
159
|
-
|
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
|
-
|
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
|
167
|
-
if
|
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(
|
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 = {
|
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(&:
|
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
|
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
|
|
data/lib/rubocop/cop/team.rb
CHANGED
@@ -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
|
-
|
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
|
data/lib/rubocop/cop/util.rb
CHANGED