rubocop 1.35.1 → 1.37.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 +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
|