rubocop 1.66.1 → 1.67.0
Sign up to get free protection for your applications and to get access to all the features.
- 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