rubocop 1.35.1 → 1.37.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 +32 -1
- data/lib/rubocop/arguments_env.rb +17 -0
- data/lib/rubocop/arguments_file.rb +17 -0
- data/lib/rubocop/cli/command/execute_runner.rb +7 -7
- data/lib/rubocop/cop/generator.rb +1 -2
- data/lib/rubocop/cop/layout/block_alignment.rb +14 -12
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -2
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +13 -9
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +25 -9
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +28 -3
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -2
- data/lib/rubocop/cop/lint/duplicate_magic_comment.rb +73 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +11 -1
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +25 -6
- data/lib/rubocop/cop/lint/duplicate_require.rb +1 -1
- data/lib/rubocop/cop/lint/empty_class.rb +3 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +46 -4
- data/lib/rubocop/cop/lint/nested_method_definition.rb +50 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +4 -5
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +12 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +7 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +29 -9
- data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -2
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -11
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +17 -2
- data/lib/rubocop/cop/lint/unreachable_loop.rb +2 -2
- data/lib/rubocop/cop/lint/unused_method_argument.rb +4 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_methods.rb +10 -5
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +13 -5
- data/lib/rubocop/cop/mixin/comments_help.rb +12 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +4 -0
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +6 -3
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +9 -5
- data/lib/rubocop/cop/mixin/rescue_node.rb +3 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +6 -5
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +97 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +7 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/case_equality.rb +40 -10
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
- data/lib/rubocop/cop/style/collection_compact.rb +6 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +40 -5
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/endless_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +4 -0
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +7 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +39 -0
- data/lib/rubocop/cop/style/perl_backrefs.rb +22 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +1 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -2
- data/lib/rubocop/cop/style/redundant_initialize.rb +3 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +8 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +173 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -1
- data/lib/rubocop/cop/style/static_class.rb +32 -1
- data/lib/rubocop/cop/style/symbol_array.rb +2 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +6 -5
- data/lib/rubocop/cop/style/word_array.rb +2 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +8 -2
- data/lib/rubocop/options.rb +13 -13
- data/lib/rubocop/rspec/shared_contexts.rb +13 -1
- data/lib/rubocop/runner.rb +4 -0
- data/lib/rubocop/server/cache.rb +5 -1
- data/lib/rubocop/server/cli.rb +9 -2
- data/lib/rubocop/server/client_command/exec.rb +5 -0
- data/lib/rubocop/server/core.rb +2 -1
- data/lib/rubocop/server/socket_reader.rb +5 -1
- data/lib/rubocop/server.rb +1 -1
- data/lib/rubocop/version.rb +8 -2
- data/lib/rubocop.rb +3 -0
- metadata +10 -5
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Naming
|
6
|
-
#
|
6
|
+
# Recommends the use of inclusive language instead of problematic terms.
|
7
7
|
# The cop can check the following locations for offenses:
|
8
8
|
# - identifiers
|
9
9
|
# - constants
|
@@ -9,6 +9,11 @@ module RuboCop
|
|
9
9
|
# Applications of visibility methods to symbols can be controlled
|
10
10
|
# using AllowModifiersOnSymbols config.
|
11
11
|
#
|
12
|
+
# @safety
|
13
|
+
# Autocorrection is not safe, because the visibility of dynamically
|
14
|
+
# defined methods can vary depending on the state determined by
|
15
|
+
# the group access modifier.
|
16
|
+
#
|
12
17
|
# @example EnforcedStyle: group (default)
|
13
18
|
# # bad
|
14
19
|
# class Foo
|
@@ -63,7 +68,10 @@ module RuboCop
|
|
63
68
|
#
|
64
69
|
# end
|
65
70
|
class AccessModifierDeclarations < Base
|
71
|
+
extend AutoCorrector
|
72
|
+
|
66
73
|
include ConfigurableEnforcedStyle
|
74
|
+
include RangeHelp
|
67
75
|
|
68
76
|
GROUP_STYLE_MESSAGE = [
|
69
77
|
'`%<access_modifier>s` should not be',
|
@@ -88,7 +96,10 @@ module RuboCop
|
|
88
96
|
return if allow_modifiers_on_symbols?(node)
|
89
97
|
|
90
98
|
if offense?(node)
|
91
|
-
add_offense(node.loc.selector)
|
99
|
+
add_offense(node.loc.selector) do |corrector|
|
100
|
+
autocorrect(corrector, node)
|
101
|
+
end
|
102
|
+
opposite_style_detected
|
92
103
|
else
|
93
104
|
correct_style_detected
|
94
105
|
end
|
@@ -96,6 +107,23 @@ module RuboCop
|
|
96
107
|
|
97
108
|
private
|
98
109
|
|
110
|
+
def autocorrect(corrector, node)
|
111
|
+
case style
|
112
|
+
when :group
|
113
|
+
def_node = find_corresponding_def_node(node)
|
114
|
+
return unless def_node
|
115
|
+
|
116
|
+
remove_node(corrector, def_node)
|
117
|
+
remove_node(corrector, node)
|
118
|
+
insert_def(corrector, node, def_node.source)
|
119
|
+
when :inline
|
120
|
+
remove_node(corrector, node)
|
121
|
+
select_grouped_def_nodes(node).each do |grouped_def_node|
|
122
|
+
insert_inline_modifier(corrector, grouped_def_node, node.method_name)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
99
127
|
def allow_modifiers_on_symbols?(node)
|
100
128
|
cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
|
101
129
|
end
|
@@ -130,6 +158,74 @@ module RuboCop
|
|
130
158
|
format(INLINE_STYLE_MESSAGE, access_modifier: access_modifier)
|
131
159
|
end
|
132
160
|
end
|
161
|
+
|
162
|
+
def find_corresponding_def_node(node)
|
163
|
+
if access_modifier_with_symbol?(node)
|
164
|
+
method_name = node.arguments.first.value
|
165
|
+
node.parent.each_child_node(:def).find do |child|
|
166
|
+
child.method?(method_name)
|
167
|
+
end
|
168
|
+
else
|
169
|
+
node.arguments.first
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def find_argument_less_modifier_node(node)
|
174
|
+
node.parent.each_child_node(:send).find do |child|
|
175
|
+
child.method?(node.method_name) && child.arguments.empty?
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def select_grouped_def_nodes(node)
|
180
|
+
node.right_siblings.take_while do |sibling|
|
181
|
+
!(sibling.send_type? && sibling.bare_access_modifier_declaration?)
|
182
|
+
end.select(&:def_type?)
|
183
|
+
end
|
184
|
+
|
185
|
+
def insert_def(corrector, node, source)
|
186
|
+
source = [*processed_source.ast_with_comments[node].map(&:text), source].join("\n")
|
187
|
+
argument_less_modifier_node = find_argument_less_modifier_node(node)
|
188
|
+
if argument_less_modifier_node
|
189
|
+
corrector.insert_after(argument_less_modifier_node, "\n\n#{source}")
|
190
|
+
else
|
191
|
+
corrector.insert_before(
|
192
|
+
node.each_ancestor(:block, :class, :module).first.location.end,
|
193
|
+
"#{node.method_name}\n\n#{source}\n"
|
194
|
+
)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def insert_inline_modifier(corrector, node, modifier_name)
|
199
|
+
corrector.insert_before(node, "#{modifier_name} ")
|
200
|
+
end
|
201
|
+
|
202
|
+
def remove_node(corrector, node)
|
203
|
+
corrector.remove(
|
204
|
+
range_by_whole_lines(
|
205
|
+
range_with_comments(node),
|
206
|
+
include_final_newline: true
|
207
|
+
)
|
208
|
+
)
|
209
|
+
end
|
210
|
+
|
211
|
+
def range_with_comments(node)
|
212
|
+
ranges = [
|
213
|
+
node,
|
214
|
+
*processed_source.ast_with_comments[node]
|
215
|
+
].map do |element|
|
216
|
+
element.location.expression
|
217
|
+
end
|
218
|
+
ranges.reduce do |result, range|
|
219
|
+
add_range(result, range)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def add_range(range1, range2)
|
224
|
+
range1.with(
|
225
|
+
begin_pos: [range1.begin_pos, range2.begin_pos].min,
|
226
|
+
end_pos: [range1.end_pos, range2.end_pos].max
|
227
|
+
)
|
228
|
+
end
|
133
229
|
end
|
134
230
|
end
|
135
231
|
end
|
@@ -135,12 +135,16 @@ module RuboCop
|
|
135
135
|
end
|
136
136
|
|
137
137
|
def separate_accessors(node)
|
138
|
-
node.arguments.
|
139
|
-
|
138
|
+
node.arguments.flat_map do |arg|
|
139
|
+
lines = [
|
140
|
+
*processed_source.ast_with_comments[arg].map(&:text),
|
140
141
|
"#{node.method_name} #{arg.source}"
|
142
|
+
]
|
143
|
+
if arg == node.arguments.first
|
144
|
+
lines
|
141
145
|
else
|
142
146
|
indent = ' ' * node.loc.column
|
143
|
-
"#{indent}#{
|
147
|
+
lines.map { |line| "#{indent}#{line}" }
|
144
148
|
end
|
145
149
|
end.join("\n")
|
146
150
|
end
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
|
9
9
|
# the case equality operator is a constant.
|
10
|
+
|
11
|
+
# If `AllowOnSelfClass` option is enabled, the cop will ignore violations when the receiver of
|
12
|
+
# the case equality operator is `self.class`. Note intermediate variables are not accepted.
|
10
13
|
#
|
11
14
|
# @example
|
12
15
|
# # bad
|
@@ -26,6 +29,14 @@ module RuboCop
|
|
26
29
|
# # good
|
27
30
|
# Array === something
|
28
31
|
#
|
32
|
+
# @example AllowOnSelfClass: false (default)
|
33
|
+
# # bad
|
34
|
+
# self.class === something
|
35
|
+
#
|
36
|
+
# @example AllowOnSelfClass: true
|
37
|
+
# # good
|
38
|
+
# self.class === something
|
39
|
+
#
|
29
40
|
class CaseEquality < Base
|
30
41
|
extend AutoCorrector
|
31
42
|
|
@@ -33,7 +44,10 @@ module RuboCop
|
|
33
44
|
RESTRICT_ON_SEND = %i[===].freeze
|
34
45
|
|
35
46
|
# @!method case_equality?(node)
|
36
|
-
def_node_matcher :case_equality?, '(send $#
|
47
|
+
def_node_matcher :case_equality?, '(send $#offending_receiver? :=== $_)'
|
48
|
+
|
49
|
+
# @!method self_class?(node)
|
50
|
+
def_node_matcher :self_class?, '(send (self) :class)'
|
37
51
|
|
38
52
|
def on_send(node)
|
39
53
|
case_equality?(node) do |lhs, rhs|
|
@@ -48,12 +62,11 @@ module RuboCop
|
|
48
62
|
|
49
63
|
private
|
50
64
|
|
51
|
-
def
|
52
|
-
if cop_config.fetch('AllowOnConstant', false)
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
end
|
65
|
+
def offending_receiver?(node)
|
66
|
+
return false if node&.const_type? && cop_config.fetch('AllowOnConstant', false)
|
67
|
+
return false if self_class?(node) && cop_config.fetch('AllowOnSelfClass', false)
|
68
|
+
|
69
|
+
true
|
57
70
|
end
|
58
71
|
|
59
72
|
def replacement(lhs, rhs)
|
@@ -66,12 +79,29 @@ module RuboCop
|
|
66
79
|
#
|
67
80
|
# So here is noop.
|
68
81
|
when :begin
|
69
|
-
|
70
|
-
"#{lhs.source}.include?(#{rhs.source})" if child&.range_type?
|
82
|
+
begin_replacement(lhs, rhs)
|
71
83
|
when :const
|
72
|
-
|
84
|
+
const_replacement(lhs, rhs)
|
85
|
+
when :send
|
86
|
+
send_replacement(lhs, rhs)
|
73
87
|
end
|
74
88
|
end
|
89
|
+
|
90
|
+
def begin_replacement(lhs, rhs)
|
91
|
+
return unless lhs.children.first&.range_type?
|
92
|
+
|
93
|
+
"#{lhs.source}.include?(#{rhs.source})"
|
94
|
+
end
|
95
|
+
|
96
|
+
def const_replacement(lhs, rhs)
|
97
|
+
"#{rhs.source}.is_a?(#{lhs.source})"
|
98
|
+
end
|
99
|
+
|
100
|
+
def send_replacement(lhs, rhs)
|
101
|
+
return unless self_class?(lhs)
|
102
|
+
|
103
|
+
"#{rhs.source}.is_a?(#{lhs.source})"
|
104
|
+
end
|
75
105
|
end
|
76
106
|
end
|
77
107
|
end
|
@@ -36,8 +36,8 @@ module RuboCop
|
|
36
36
|
extend AutoCorrector
|
37
37
|
|
38
38
|
MSG = 'Use `%<good>s` instead of `%<bad>s`.'
|
39
|
-
|
40
39
|
RESTRICT_ON_SEND = %i[reject reject! select select!].freeze
|
40
|
+
TO_ENUM_METHODS = %i[to_enum lazy].freeze
|
41
41
|
|
42
42
|
# @!method reject_method_with_block_pass?(node)
|
43
43
|
def_node_matcher :reject_method_with_block_pass?, <<~PATTERN
|
@@ -69,6 +69,7 @@ module RuboCop
|
|
69
69
|
|
70
70
|
def on_send(node)
|
71
71
|
return unless (range = offense_range(node))
|
72
|
+
return if target_ruby_version <= 3.0 && to_enum_method?(node)
|
72
73
|
|
73
74
|
good = good_method_name(node)
|
74
75
|
message = format(MSG, good: good, bad: range.source)
|
@@ -94,6 +95,10 @@ module RuboCop
|
|
94
95
|
end
|
95
96
|
end
|
96
97
|
|
98
|
+
def to_enum_method?(node)
|
99
|
+
TO_ENUM_METHODS.include?(node.children.first.method_name)
|
100
|
+
end
|
101
|
+
|
97
102
|
def good_method_name(node)
|
98
103
|
if node.bang_method?
|
99
104
|
'compact!'
|
@@ -28,14 +28,14 @@ module RuboCop
|
|
28
28
|
MSG = 'Use `Integer#times` for a simple loop which iterates a fixed number of times.'
|
29
29
|
|
30
30
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
31
|
-
return unless
|
31
|
+
return unless offending?(node)
|
32
32
|
|
33
33
|
send_node = node.send_node
|
34
34
|
|
35
35
|
range = send_node.receiver.source_range.join(send_node.loc.selector)
|
36
36
|
|
37
37
|
add_offense(range) do |corrector|
|
38
|
-
range_type, min, max =
|
38
|
+
range_type, min, max = each_range(node)
|
39
39
|
|
40
40
|
max += 1 if range_type == :irange
|
41
41
|
|
@@ -45,9 +45,44 @@ module RuboCop
|
|
45
45
|
|
46
46
|
private
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
48
|
+
def offending?(node)
|
49
|
+
each_range_with_zero_origin?(node) || each_range_without_block_argument?(node)
|
50
|
+
end
|
51
|
+
|
52
|
+
# @!method each_range(node)
|
53
|
+
def_node_matcher :each_range, <<~PATTERN
|
54
|
+
(block
|
55
|
+
(send
|
56
|
+
(begin
|
57
|
+
(${irange erange}
|
58
|
+
(int $_) (int $_)))
|
59
|
+
:each)
|
60
|
+
(args ...)
|
61
|
+
...)
|
62
|
+
PATTERN
|
63
|
+
|
64
|
+
# @!method each_range_with_zero_origin?(node)
|
65
|
+
def_node_matcher :each_range_with_zero_origin?, <<~PATTERN
|
66
|
+
(block
|
67
|
+
(send
|
68
|
+
(begin
|
69
|
+
({irange erange}
|
70
|
+
(int 0) (int _)))
|
71
|
+
:each)
|
72
|
+
(args ...)
|
73
|
+
...)
|
74
|
+
PATTERN
|
75
|
+
|
76
|
+
# @!method each_range_without_block_argument?(node)
|
77
|
+
def_node_matcher :each_range_without_block_argument?, <<~PATTERN
|
78
|
+
(block
|
79
|
+
(send
|
80
|
+
(begin
|
81
|
+
({irange erange}
|
82
|
+
(int _) (int _)))
|
83
|
+
:each)
|
84
|
+
(args)
|
85
|
+
...)
|
51
86
|
PATTERN
|
52
87
|
end
|
53
88
|
end
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
52
52
|
MSG_EXPANDED = 'Put the `end` of empty method definitions on the next line.'
|
53
53
|
|
54
54
|
def on_def(node)
|
55
|
-
return if node.body ||
|
55
|
+
return if node.body || processed_source.contains_comment?(node.source_range)
|
56
56
|
return if correct_style?(node)
|
57
57
|
|
58
58
|
add_offense(node) do |corrector|
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
# * always - forces use of the 3.1 syntax (e.g. {foo:})
|
29
29
|
# * never - forces use of explicit hash literal value
|
30
30
|
# * either - accepts both shorthand and explicit use of hash literal value
|
31
|
-
# * consistent - like "
|
31
|
+
# * consistent - like "either", but will avoid mixing styles in a single hash
|
32
32
|
#
|
33
33
|
# @example EnforcedStyle: ruby19 (default)
|
34
34
|
# # bad
|
@@ -20,8 +20,8 @@ module RuboCop
|
|
20
20
|
return if require_parentheses_for_hash_value_omission?(node)
|
21
21
|
return if syntax_like_method_call?(node)
|
22
22
|
return if super_call_without_arguments?(node)
|
23
|
-
return if allowed_camel_case_method_call?(node)
|
24
23
|
return if legitimate_call_with_parentheses?(node)
|
24
|
+
return if allowed_camel_case_method_call?(node)
|
25
25
|
return if allowed_string_interpolation_method_call?(node)
|
26
26
|
|
27
27
|
add_offense(offense_range(node), message: OMIT_MSG) do |corrector|
|
@@ -97,7 +97,8 @@ module RuboCop
|
|
97
97
|
call_in_optional_arguments?(node) ||
|
98
98
|
call_in_single_line_inheritance?(node) ||
|
99
99
|
allowed_multiline_call_with_parentheses?(node) ||
|
100
|
-
allowed_chained_call_with_parentheses?(node)
|
100
|
+
allowed_chained_call_with_parentheses?(node) ||
|
101
|
+
assignment_in_condition?(node)
|
101
102
|
end
|
102
103
|
|
103
104
|
def call_in_literals?(node)
|
@@ -202,6 +203,16 @@ module RuboCop
|
|
202
203
|
def inside_string_interpolation?(node)
|
203
204
|
node.ancestors.drop_while { |a| !a.begin_type? }.any?(&:dstr_type?)
|
204
205
|
end
|
206
|
+
|
207
|
+
def assignment_in_condition?(node)
|
208
|
+
parent = node.parent
|
209
|
+
return false unless parent
|
210
|
+
|
211
|
+
grandparent = parent.parent
|
212
|
+
return false unless grandparent
|
213
|
+
|
214
|
+
parent.assignment? && (grandparent.conditional? || grandparent.when_type?)
|
215
|
+
end
|
205
216
|
end
|
206
217
|
# rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
|
207
218
|
end
|
@@ -49,7 +49,8 @@ module RuboCop
|
|
49
49
|
def on_if(node)
|
50
50
|
return unless if_else?(node)
|
51
51
|
|
52
|
-
condition = node.condition
|
52
|
+
condition = unwrap_begin_nodes(node.condition)
|
53
|
+
|
53
54
|
return if double_negation?(condition) || !negated_condition?(condition)
|
54
55
|
|
55
56
|
type = node.ternary? ? 'ternary' : 'if-else'
|
@@ -71,6 +72,11 @@ module RuboCop
|
|
71
72
|
!node.elsif? && else_branch && (!else_branch.if_type? || !else_branch.elsif?)
|
72
73
|
end
|
73
74
|
|
75
|
+
def unwrap_begin_nodes(node)
|
76
|
+
node = node.children.first while node.begin_type? || node.kwbegin_type?
|
77
|
+
node
|
78
|
+
end
|
79
|
+
|
74
80
|
def negated_condition?(node)
|
75
81
|
node.send_type? &&
|
76
82
|
(node.negation_method? || NEGATED_EQUALITY_METHODS.include?(node.method_name))
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for redundant dot before operator method call.
|
7
|
+
# The target operator methods are `|`, `^`, `&`, `<=>`, `==`, `===`, `=~`, `>`, `>=`, `<`,
|
8
|
+
# `<=`, `<<`, `>>`, `+`, `-`, `*`, `/`, `%`, `**`, `~`, `!`, `!=`, and `!~`.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
#
|
12
|
+
# # bad
|
13
|
+
# foo.+ bar
|
14
|
+
# foo.& bar
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# foo + bar
|
18
|
+
# foo & bar
|
19
|
+
#
|
20
|
+
class OperatorMethodCall < Base
|
21
|
+
extend AutoCorrector
|
22
|
+
|
23
|
+
MSG = 'Redundant dot detected.'
|
24
|
+
RESTRICT_ON_SEND = %i[| ^ & <=> == === =~ > >= < <= << >> + - * / % ** ~ ! != !~].freeze
|
25
|
+
|
26
|
+
def on_send(node)
|
27
|
+
return unless (dot = node.loc.dot)
|
28
|
+
|
29
|
+
_lhs, _op, rhs = *node
|
30
|
+
return if rhs.children.first
|
31
|
+
|
32
|
+
add_offense(dot) do |corrector|
|
33
|
+
corrector.replace(dot, ' ')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -83,10 +83,31 @@ module RuboCop
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
# @private
|
87
|
+
# @param [RuboCop::AST::Node] node
|
88
|
+
# @return [String, nil]
|
89
|
+
def preferred_expression_to_node_with_constant_prefix(node)
|
90
|
+
expression = preferred_expression_to(node)
|
91
|
+
return unless expression
|
92
|
+
|
93
|
+
"#{constant_prefix(node)}#{expression}"
|
94
|
+
end
|
95
|
+
|
96
|
+
# @private
|
97
|
+
# @param [RuboCop::AST::Node] node
|
98
|
+
# @return [String]
|
99
|
+
def constant_prefix(node)
|
100
|
+
if node.each_ancestor(:class, :module).any?
|
101
|
+
'::'
|
102
|
+
else
|
103
|
+
''
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
86
107
|
# @private
|
87
108
|
# @param [RuboCop::AST::Node] node
|
88
109
|
def on_back_ref_or_gvar_or_nth_ref(node)
|
89
|
-
preferred_expression =
|
110
|
+
preferred_expression = preferred_expression_to_node_with_constant_prefix(node)
|
90
111
|
return unless preferred_expression
|
91
112
|
|
92
113
|
add_offense(
|
@@ -145,11 +145,14 @@ module RuboCop
|
|
145
145
|
|
146
146
|
return false unless if_branch && else_branch
|
147
147
|
|
148
|
-
if_branch
|
149
|
-
else_branch.send_type? && else_branch.arguments.count == 1 &&
|
148
|
+
single_argument_method?(if_branch) && single_argument_method?(else_branch) &&
|
150
149
|
same_method?(if_branch, else_branch)
|
151
150
|
end
|
152
151
|
|
152
|
+
def single_argument_method?(node)
|
153
|
+
node.send_type? && !node.method?(:[]) && node.arguments.one?
|
154
|
+
end
|
155
|
+
|
153
156
|
def same_method?(if_branch, else_branch)
|
154
157
|
if_branch.method?(else_branch.method_name) && if_branch.receiver == else_branch.receiver
|
155
158
|
end
|
@@ -140,7 +140,9 @@ module RuboCop
|
|
140
140
|
end
|
141
141
|
|
142
142
|
def allow_comments?(node)
|
143
|
-
cop_config['AllowComments']
|
143
|
+
return false unless cop_config['AllowComments']
|
144
|
+
|
145
|
+
contains_comments?(node) && !comments_contain_disables?(node, name)
|
144
146
|
end
|
145
147
|
|
146
148
|
def same_args?(super_node, args)
|
@@ -29,6 +29,9 @@ module RuboCop
|
|
29
29
|
# @!method rescue?(node)
|
30
30
|
def_node_matcher :rescue?, '{^resbody ^^resbody}'
|
31
31
|
|
32
|
+
# @!method allowed_pin_operator?(node)
|
33
|
+
def_node_matcher :allowed_pin_operator?, '^(pin (begin !{lvar ivar cvar gvar}))'
|
34
|
+
|
32
35
|
# @!method arg_in_call_with_block?(node)
|
33
36
|
def_node_matcher :arg_in_call_with_block?, '^^(block (send _ _ equal?(%0) ...) ...)'
|
34
37
|
|
@@ -44,6 +47,7 @@ module RuboCop
|
|
44
47
|
empty_parentheses?(node) ||
|
45
48
|
first_arg_begins_with_hash_literal?(node) ||
|
46
49
|
rescue?(node) ||
|
50
|
+
allowed_pin_operator?(node) ||
|
47
51
|
allowed_expression?(node)
|
48
52
|
end
|
49
53
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
|
75
75
|
non_redundant =
|
76
76
|
whitespace_in_free_space_mode?(node, class_elem) ||
|
77
|
-
backslash_b?(class_elem) ||
|
77
|
+
backslash_b?(class_elem) || backslash_zero?(class_elem) ||
|
78
78
|
requires_escape_outside_char_class?(class_elem)
|
79
79
|
|
80
80
|
!non_redundant
|
@@ -104,6 +104,13 @@ module RuboCop
|
|
104
104
|
elem == '\b'
|
105
105
|
end
|
106
106
|
|
107
|
+
def backslash_zero?(elem)
|
108
|
+
# See https://github.com/rubocop/rubocop/issues/11067 for details - in short "\0" != "0" -
|
109
|
+
# the former means an Unicode code point `"\u0000"`, the latter a number character `"0"`.
|
110
|
+
# Similarly "\032" means "\u001A". Other numbers starting with "\0" can also be mentioned.
|
111
|
+
elem == '\0'
|
112
|
+
end
|
113
|
+
|
107
114
|
def requires_escape_outside_char_class?(elem)
|
108
115
|
REQUIRES_ESCAPE_OUTSIDE_CHAR_CLASS_CHARS.include?(elem)
|
109
116
|
end
|