rubocop 1.54.2 → 1.55.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 +3 -1
- data/config/default.yml +8 -2
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
- data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +8 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
- data/lib/rubocop/cop/mixin/string_help.rb +2 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +226 -53
- data/lib/rubocop/cop/style/combinable_loops.rb +1 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +6 -1
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +19 -7
- data/lib/rubocop/cop/style/symbol_array.rb +22 -3
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +9 -3
- data/lib/rubocop/lsp/runtime.rb +12 -1
- data/lib/rubocop/lsp/server.rb +4 -2
- data/lib/rubocop/result_cache.rb +4 -0
- data/lib/rubocop/target_finder.rb +6 -2
- data/lib/rubocop/version.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7bfd5d73e8097398116fc389fa55f96eca51b61c95a5e9e4654d7eeebaeef985
|
4
|
+
data.tar.gz: a2cf8206a9896953e85516ebdc00f673a5852eb9613e877fee6b43058f7ef080
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 454b6be8363e0a91226348e2543587d5e6c3503bdaa9b2c0287f1a1e347f9a315c8f8337c5762e59f83f7406a797645ebef7e16a896694da29cb751a658e5579
|
7
|
+
data.tar.gz: 388fe4a1934bf7659148ce32a2837f5ff0822babc1e17abd1a2c4f8138e6a839a7c4f304202e7e712763dbc23fadee4c92412554cbe699a8f81810e602d62f49
|
data/README.md
CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
53
53
|
in your `Gemfile`:
|
54
54
|
|
55
55
|
```rb
|
56
|
-
gem 'rubocop', '~> 1.
|
56
|
+
gem 'rubocop', '~> 1.55', require: false
|
57
57
|
```
|
58
58
|
|
59
59
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
@@ -67,6 +67,8 @@ $ cd my/cool/ruby/project
|
|
67
67
|
$ rubocop
|
68
68
|
```
|
69
69
|
|
70
|
+
You can also use this magic in your favorite editor with RuboCop's [built-in LSP](https://docs.rubocop.org/rubocop/usage/lsp.html).
|
71
|
+
|
70
72
|
## Documentation
|
71
73
|
|
72
74
|
You can read a lot more about RuboCop in its [official docs](https://docs.rubocop.org).
|
data/config/default.yml
CHANGED
@@ -3072,6 +3072,7 @@ Style/ArgumentsForwarding:
|
|
3072
3072
|
StyleGuide: '#arguments-forwarding'
|
3073
3073
|
Enabled: pending
|
3074
3074
|
AllowOnlyRestArgument: true
|
3075
|
+
UseAnonymousForwarding: true
|
3075
3076
|
VersionAdded: '1.1'
|
3076
3077
|
|
3077
3078
|
Style/ArrayCoercion:
|
@@ -3916,8 +3917,9 @@ Style/HashConversion:
|
|
3916
3917
|
Description: 'Avoid Hash[] in favor of ary.to_h or literal hashes.'
|
3917
3918
|
StyleGuide: '#avoid-hash-constructor'
|
3918
3919
|
Enabled: pending
|
3920
|
+
SafeAutoCorrect: false
|
3919
3921
|
VersionAdded: '1.10'
|
3920
|
-
VersionChanged: '1.
|
3922
|
+
VersionChanged: '1.55'
|
3921
3923
|
AllowSplatArgument: true
|
3922
3924
|
|
3923
3925
|
Style/HashEachMethods:
|
@@ -4810,12 +4812,16 @@ Style/RedundantArgument:
|
|
4810
4812
|
Enabled: pending
|
4811
4813
|
Safe: false
|
4812
4814
|
VersionAdded: '1.4'
|
4813
|
-
VersionChanged: '1.
|
4815
|
+
VersionChanged: '1.55'
|
4814
4816
|
Methods:
|
4815
4817
|
# Array#join
|
4816
4818
|
join: ''
|
4817
4819
|
# Array#sum
|
4818
4820
|
sum: 0
|
4821
|
+
# Kernel.#exit
|
4822
|
+
exit: true
|
4823
|
+
# Kernel.#exit!
|
4824
|
+
exit!: false
|
4819
4825
|
# String#split
|
4820
4826
|
split: ' '
|
4821
4827
|
# String#chomp
|
data/config/obsoletion.yml
CHANGED
@@ -224,6 +224,11 @@ changed_parameters:
|
|
224
224
|
- AllowedMethods
|
225
225
|
- AllowedPatterns
|
226
226
|
severity: warning
|
227
|
+
- cops: Style/ArgumentsForwarding
|
228
|
+
parameters: AllowOnlyRestArgument
|
229
|
+
reason: "`AllowOnlyRestArgument` has no effect with TargetRubyVersion >= 3.2."
|
230
|
+
severity: warning
|
231
|
+
minimum_ruby_version: 3.2
|
227
232
|
|
228
233
|
# Enforced styles that have been removed or replaced
|
229
234
|
changed_enforced_styles:
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def violated?
|
22
|
-
config[cop]&.key?(parameter)
|
22
|
+
applies_to_current_ruby_version? && config[cop]&.key?(parameter)
|
23
23
|
end
|
24
24
|
|
25
25
|
def warning?
|
@@ -28,6 +28,14 @@ module RuboCop
|
|
28
28
|
|
29
29
|
private
|
30
30
|
|
31
|
+
def applies_to_current_ruby_version?
|
32
|
+
minimum_ruby_version = metadata['minimum_ruby_version']
|
33
|
+
|
34
|
+
return true unless minimum_ruby_version
|
35
|
+
|
36
|
+
config.target_ruby_version >= minimum_ruby_version
|
37
|
+
end
|
38
|
+
|
31
39
|
def alternative
|
32
40
|
metadata['alternative']
|
33
41
|
end
|
@@ -48,6 +48,10 @@ module RuboCop
|
|
48
48
|
|
49
49
|
MSG = 'Redundant line break detected.'
|
50
50
|
|
51
|
+
def on_lvasgn(node)
|
52
|
+
super unless end_with_percent_blank_string?(processed_source)
|
53
|
+
end
|
54
|
+
|
51
55
|
def on_send(node)
|
52
56
|
# Include "the whole expression".
|
53
57
|
node = node.parent while node.parent&.send_type? ||
|
@@ -61,6 +65,10 @@ module RuboCop
|
|
61
65
|
|
62
66
|
private
|
63
67
|
|
68
|
+
def end_with_percent_blank_string?(processed_source)
|
69
|
+
processed_source.buffer.source.end_with?("%\n\n")
|
70
|
+
end
|
71
|
+
|
64
72
|
def check_assignment(node, _rhs)
|
65
73
|
return unless offense?(node)
|
66
74
|
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
|
69
69
|
def same_conditions_node_different_branch?(variable, outer_local_variable)
|
70
70
|
variable_node = variable_node(variable)
|
71
|
-
return false unless variable_node
|
71
|
+
return false unless node_or_its_ascendant_conditional?(variable_node)
|
72
72
|
|
73
73
|
outer_local_variable_node =
|
74
74
|
find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
|
@@ -96,6 +96,12 @@ module RuboCop
|
|
96
96
|
|
97
97
|
find_conditional_node_from_ascendant(parent)
|
98
98
|
end
|
99
|
+
|
100
|
+
def node_or_its_ascendant_conditional?(node)
|
101
|
+
return true if node.conditional?
|
102
|
+
|
103
|
+
!!find_conditional_node_from_ascendant(node)
|
104
|
+
end
|
99
105
|
end
|
100
106
|
end
|
101
107
|
end
|
@@ -30,8 +30,8 @@ module RuboCop
|
|
30
30
|
private
|
31
31
|
|
32
32
|
def inside_interpolation?(node)
|
33
|
-
# A :begin node inside a :dstr node is an interpolation.
|
34
|
-
node.ancestors.drop_while { |a| !a.begin_type? }.any?
|
33
|
+
# A :begin node inside a :dstr or :dsym node is an interpolation.
|
34
|
+
node.ancestors.drop_while { |a| !a.begin_type? }.any? { |a| a.dstr_type? || a.dsym_type? }
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
@@ -8,6 +8,12 @@ module RuboCop
|
|
8
8
|
# This cop identifies places where `do_something(*args, &block)`
|
9
9
|
# can be replaced by `do_something(...)`.
|
10
10
|
#
|
11
|
+
# In Ruby 3.2, anonymous args/kwargs forwarding has been added.
|
12
|
+
#
|
13
|
+
# This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
|
14
|
+
# replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
|
15
|
+
# by setting UseAnonymousForwarding: false.
|
16
|
+
#
|
11
17
|
# @example
|
12
18
|
# # bad
|
13
19
|
# def foo(*args, &block)
|
@@ -24,7 +30,27 @@ module RuboCop
|
|
24
30
|
# bar(...)
|
25
31
|
# end
|
26
32
|
#
|
27
|
-
# @example
|
33
|
+
# @example UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2)
|
34
|
+
# # bad
|
35
|
+
# def foo(*args, **kwargs)
|
36
|
+
# args_only(*args)
|
37
|
+
# kwargs_only(**kwargs)
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# def foo(*, **)
|
42
|
+
# args_only(*)
|
43
|
+
# kwargs_only(**)
|
44
|
+
# end
|
45
|
+
#
|
46
|
+
# @example UseAnonymousForwarding: false (only relevant for Ruby >= 3.2)
|
47
|
+
# # good
|
48
|
+
# def foo(*args, **kwargs)
|
49
|
+
# args_only(*args)
|
50
|
+
# kwargs_only(**kwargs)
|
51
|
+
# end
|
52
|
+
#
|
53
|
+
# @example AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2)
|
28
54
|
# # good
|
29
55
|
# def foo(*args)
|
30
56
|
# bar(*args)
|
@@ -34,7 +60,7 @@ module RuboCop
|
|
34
60
|
# bar(**kwargs)
|
35
61
|
# end
|
36
62
|
#
|
37
|
-
# @example AllowOnlyRestArgument: false
|
63
|
+
# @example AllowOnlyRestArgument: false (only relevant for Ruby < 3.2)
|
38
64
|
# # bad
|
39
65
|
# # The following code can replace the arguments with `...`,
|
40
66
|
# # but it will change the behavior. Because `...` forwards block also.
|
@@ -53,77 +79,133 @@ module RuboCop
|
|
53
79
|
|
54
80
|
minimum_target_ruby_version 2.7
|
55
81
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
PATTERN
|
62
|
-
|
63
|
-
# @!method only_rest_arguments?(node, name)
|
64
|
-
def_node_matcher :only_rest_arguments?, <<~PATTERN
|
65
|
-
{
|
66
|
-
(send _ _ (splat (lvar %1)))
|
67
|
-
(send _ _ (hash (kwsplat (lvar %1))))
|
68
|
-
}
|
69
|
-
PATTERN
|
70
|
-
|
71
|
-
# @!method forwarding_method_arguments?(node, rest_name, block_name, kwargs_name)
|
72
|
-
def_node_matcher :forwarding_method_arguments?, <<~PATTERN
|
73
|
-
{
|
74
|
-
(send _ _
|
75
|
-
(splat (lvar %1))
|
76
|
-
(block-pass {(lvar %2) nil?}))
|
77
|
-
(send _ _
|
78
|
-
(splat (lvar %1))
|
79
|
-
(hash (kwsplat (lvar %3)))
|
80
|
-
(block-pass {(lvar %2) nil?}))
|
81
|
-
}
|
82
|
-
PATTERN
|
82
|
+
FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
|
83
|
+
|
84
|
+
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
85
|
+
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
86
|
+
KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
|
83
87
|
|
84
88
|
def on_def(node)
|
85
89
|
return unless node.body
|
86
|
-
return unless (rest_args_name, args = use_rest_arguments?(node.arguments))
|
87
|
-
return if args.any?(&:default?)
|
88
90
|
|
89
|
-
node.
|
90
|
-
|
91
|
+
forwardable_args = extract_forwardable_args(node.arguments)
|
92
|
+
|
93
|
+
send_classifications = classify_send_nodes(
|
94
|
+
node,
|
95
|
+
node.each_descendant(:send).to_a,
|
96
|
+
non_splat_or_block_pass_lvar_references(node.body),
|
97
|
+
forwardable_args
|
98
|
+
)
|
91
99
|
|
92
|
-
|
93
|
-
all_lvars_as_forwarding_method_arguments?(node, send_node)
|
100
|
+
return if send_classifications.empty?
|
94
101
|
|
95
|
-
|
96
|
-
|
102
|
+
if only_forwards_all?(send_classifications)
|
103
|
+
add_forward_all_offenses(node, send_classifications)
|
104
|
+
elsif target_ruby_version >= 3.2
|
105
|
+
add_post_ruby_32_offenses(node, send_classifications, forwardable_args)
|
97
106
|
end
|
98
107
|
end
|
108
|
+
|
99
109
|
alias on_defs on_def
|
100
110
|
|
101
111
|
private
|
102
112
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
113
|
+
def extract_forwardable_args(args)
|
114
|
+
[args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
|
115
|
+
end
|
116
|
+
|
117
|
+
def only_forwards_all?(send_classifications)
|
118
|
+
send_classifications.each_value.all? { |c, _, _| c == :all }
|
119
|
+
end
|
120
|
+
|
121
|
+
def add_forward_all_offenses(node, send_classifications)
|
122
|
+
send_classifications.each_key do |send_node|
|
123
|
+
register_forward_all_offense_on_forwarding_method(send_node)
|
124
|
+
end
|
125
|
+
|
126
|
+
register_forward_all_offense_on_method_def(node)
|
127
|
+
end
|
128
|
+
|
129
|
+
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
130
|
+
return unless use_anonymous_forwarding?
|
131
|
+
|
132
|
+
rest_arg, kwrest_arg, _block_arg = *forwardable_args
|
133
|
+
|
134
|
+
send_classifications.each do |send_node, (_c, forward_rest, forward_kwrest)|
|
135
|
+
if forward_rest
|
136
|
+
register_forward_args_offense(def_node.arguments, rest_arg)
|
137
|
+
register_forward_args_offense(send_node, forward_rest)
|
138
|
+
end
|
106
139
|
|
107
|
-
|
140
|
+
if forward_kwrest
|
141
|
+
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
142
|
+
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
143
|
+
end
|
144
|
+
end
|
108
145
|
end
|
109
146
|
|
110
|
-
def
|
111
|
-
|
147
|
+
def non_splat_or_block_pass_lvar_references(body)
|
148
|
+
body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
|
149
|
+
parent = lvar.parent
|
150
|
+
|
151
|
+
next if lvar.lvar_type? && FORWARDING_LVAR_TYPES.include?(parent.type)
|
112
152
|
|
113
|
-
|
153
|
+
lvar.children.first
|
154
|
+
end.uniq
|
114
155
|
end
|
115
156
|
|
116
|
-
def
|
117
|
-
|
157
|
+
def classify_send_nodes(def_node, send_nodes, referenced_lvars, forwardable_args)
|
158
|
+
send_nodes.to_h do |send_node|
|
159
|
+
classification_and_forwards = classification_and_forwards(
|
160
|
+
def_node,
|
161
|
+
send_node,
|
162
|
+
referenced_lvars,
|
163
|
+
forwardable_args
|
164
|
+
)
|
165
|
+
|
166
|
+
[send_node, classification_and_forwards]
|
167
|
+
end.compact
|
168
|
+
end
|
118
169
|
|
119
|
-
|
120
|
-
|
170
|
+
def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
|
171
|
+
classifier = SendNodeClassifier.new(
|
172
|
+
def_node,
|
173
|
+
send_node,
|
174
|
+
referenced_lvars,
|
175
|
+
forwardable_args,
|
176
|
+
target_ruby_version: target_ruby_version,
|
177
|
+
allow_only_rest_arguments: allow_only_rest_arguments?
|
178
|
+
)
|
121
179
|
|
122
|
-
|
180
|
+
classification = classifier.classification
|
181
|
+
|
182
|
+
return unless classification
|
183
|
+
|
184
|
+
[classification, classifier.forwarded_rest_arg, classifier.forwarded_kwrest_arg]
|
123
185
|
end
|
124
186
|
|
125
|
-
def
|
126
|
-
add_offense(
|
187
|
+
def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
|
188
|
+
add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
|
189
|
+
unless parentheses?(def_arguments_or_send)
|
190
|
+
add_parentheses(def_arguments_or_send, corrector)
|
191
|
+
end
|
192
|
+
|
193
|
+
corrector.replace(rest_arg_or_splat, '*')
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def register_forward_kwargs_offense(add_parens, def_arguments_or_send, kwrest_arg_or_splat)
|
198
|
+
add_offense(kwrest_arg_or_splat, message: KWARGS_MSG) do |corrector|
|
199
|
+
if add_parens && !parentheses?(def_arguments_or_send)
|
200
|
+
add_parentheses(def_arguments_or_send, corrector)
|
201
|
+
end
|
202
|
+
|
203
|
+
corrector.replace(kwrest_arg_or_splat, '**')
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
def register_forward_all_offense_on_forwarding_method(forwarding_method)
|
208
|
+
add_offense(arguments_range(forwarding_method), message: FORWARDING_MSG) do |corrector|
|
127
209
|
begin_pos = forwarding_method.loc.selector&.end_pos || forwarding_method.loc.dot.end_pos
|
128
210
|
range = range_between(begin_pos, forwarding_method.source_range.end_pos)
|
129
211
|
|
@@ -131,8 +213,8 @@ module RuboCop
|
|
131
213
|
end
|
132
214
|
end
|
133
215
|
|
134
|
-
def
|
135
|
-
add_offense(arguments_range(method_definition)) do |corrector|
|
216
|
+
def register_forward_all_offense_on_method_def(method_definition)
|
217
|
+
add_offense(arguments_range(method_definition), message: FORWARDING_MSG) do |corrector|
|
136
218
|
arguments_range = range_with_surrounding_space(
|
137
219
|
method_definition.arguments.source_range, side: :left
|
138
220
|
)
|
@@ -149,6 +231,97 @@ module RuboCop
|
|
149
231
|
def allow_only_rest_arguments?
|
150
232
|
cop_config.fetch('AllowOnlyRestArgument', true)
|
151
233
|
end
|
234
|
+
|
235
|
+
def use_anonymous_forwarding?
|
236
|
+
cop_config.fetch('UseAnonymousForwarding', false)
|
237
|
+
end
|
238
|
+
|
239
|
+
# Classifies send nodes for possible rest/kwrest/all (including block) forwarding.
|
240
|
+
class SendNodeClassifier
|
241
|
+
extend NodePattern::Macros
|
242
|
+
|
243
|
+
# @!method find_forwarded_rest_arg(node, rest_name)
|
244
|
+
def_node_search :find_forwarded_rest_arg, '(splat (lvar %1))'
|
245
|
+
|
246
|
+
# @!method find_forwarded_kwrest_arg(node, kwrest_name)
|
247
|
+
def_node_search :find_forwarded_kwrest_arg, '(kwsplat (lvar %1))'
|
248
|
+
|
249
|
+
# @!method find_forwarded_block_arg(node, block_name)
|
250
|
+
def_node_search :find_forwarded_block_arg, '(block_pass {(lvar %1) nil?})'
|
251
|
+
|
252
|
+
def initialize(def_node, send_node, referenced_lvars, forwardable_args, **config)
|
253
|
+
@def_node = def_node
|
254
|
+
@send_node = send_node
|
255
|
+
@referenced_lvars = referenced_lvars
|
256
|
+
@rest_arg, @kwrest_arg, @block_arg = *forwardable_args
|
257
|
+
@rest_arg_name, @kwrest_arg_name, @block_arg_name =
|
258
|
+
*forwardable_args.map { |a| a&.name }
|
259
|
+
@config = config
|
260
|
+
end
|
261
|
+
|
262
|
+
def forwarded_rest_arg
|
263
|
+
return nil if referenced_rest_arg?
|
264
|
+
|
265
|
+
find_forwarded_rest_arg(@send_node, @rest_arg_name).first
|
266
|
+
end
|
267
|
+
|
268
|
+
def forwarded_kwrest_arg
|
269
|
+
return nil if referenced_kwrest_arg?
|
270
|
+
|
271
|
+
find_forwarded_kwrest_arg(@send_node, @kwrest_arg_name).first
|
272
|
+
end
|
273
|
+
|
274
|
+
def forwarded_block_arg
|
275
|
+
return nil if referenced_block_arg?
|
276
|
+
|
277
|
+
find_forwarded_block_arg(@send_node, @block_arg_name).first
|
278
|
+
end
|
279
|
+
|
280
|
+
def classification
|
281
|
+
return nil unless forwarded_rest_arg || forwarded_kwrest_arg
|
282
|
+
|
283
|
+
if referenced_none? && (forwarded_exactly_all? || pre_ruby_32_allow_forward_all?)
|
284
|
+
:all
|
285
|
+
elsif target_ruby_version >= 3.2
|
286
|
+
:rest_or_kwrest
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
private
|
291
|
+
|
292
|
+
def referenced_rest_arg?
|
293
|
+
@referenced_lvars.include?(@rest_arg_name)
|
294
|
+
end
|
295
|
+
|
296
|
+
def referenced_kwrest_arg?
|
297
|
+
@referenced_lvars.include?(@kwrest_arg_name)
|
298
|
+
end
|
299
|
+
|
300
|
+
def referenced_block_arg?
|
301
|
+
@referenced_lvars.include?(@block_arg_name)
|
302
|
+
end
|
303
|
+
|
304
|
+
def referenced_none?
|
305
|
+
!(referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?)
|
306
|
+
end
|
307
|
+
|
308
|
+
def forwarded_exactly_all?
|
309
|
+
@send_node.arguments.size == 3 &&
|
310
|
+
forwarded_rest_arg &&
|
311
|
+
forwarded_kwrest_arg &&
|
312
|
+
forwarded_block_arg
|
313
|
+
end
|
314
|
+
|
315
|
+
def target_ruby_version
|
316
|
+
@config.fetch(:target_ruby_version)
|
317
|
+
end
|
318
|
+
|
319
|
+
def pre_ruby_32_allow_forward_all?
|
320
|
+
target_ruby_version < 3.2 &&
|
321
|
+
@def_node.arguments.none?(&:default?) &&
|
322
|
+
(@block_arg ? forwarded_block_arg : !@config.fetch(:allow_only_rest_arguments))
|
323
|
+
end
|
324
|
+
end
|
152
325
|
end
|
153
326
|
end
|
154
327
|
end
|
@@ -67,6 +67,7 @@ module RuboCop
|
|
67
67
|
return unless node.parent&.begin_type?
|
68
68
|
return unless collection_looping_method?(node)
|
69
69
|
return unless same_collection_looping_block?(node, node.left_sibling)
|
70
|
+
return unless node.body && node.left_sibling.body
|
70
71
|
|
71
72
|
add_offense(node) do |corrector|
|
72
73
|
combine_with_left_sibling(corrector, node)
|
@@ -10,6 +10,16 @@ module RuboCop
|
|
10
10
|
# `Hash[*ary]` can be replaced with `ary.each_slice(2).to_h` but it will be complicated.
|
11
11
|
# So, `AllowSplatArgument` option is true by default to allow splat argument for simple code.
|
12
12
|
#
|
13
|
+
# @safety
|
14
|
+
# This cop's autocorrection is unsafe because `ArgumentError` occurs
|
15
|
+
# if the number of elements is odd:
|
16
|
+
#
|
17
|
+
# [source,ruby]
|
18
|
+
# ----
|
19
|
+
# Hash[[[1, 2], [3]]] #=> {1=>2, 3=>nil}
|
20
|
+
# [[1, 2], [5]].to_h #=> wrong array length at 1 (expected 2, was 1) (ArgumentError)
|
21
|
+
# ----
|
22
|
+
#
|
13
23
|
# @example
|
14
24
|
# # bad
|
15
25
|
# Hash[ary]
|
@@ -124,9 +124,10 @@ module RuboCop
|
|
124
124
|
node.parent&.class_type? && node.parent&.single_line?
|
125
125
|
end
|
126
126
|
|
127
|
-
def call_with_ambiguous_arguments?(node)
|
127
|
+
def call_with_ambiguous_arguments?(node) # rubocop:disable Metrics/PerceivedComplexity
|
128
128
|
call_with_braced_block?(node) ||
|
129
129
|
call_as_argument_or_chain?(node) ||
|
130
|
+
call_in_match_pattern?(node) ||
|
130
131
|
hash_literal_in_arguments?(node) ||
|
131
132
|
node.descendants.any? do |n|
|
132
133
|
n.forwarded_args_type? || ambiguous_literal?(n) || logical_operator?(n) ||
|
@@ -144,6 +145,10 @@ module RuboCop
|
|
144
145
|
node.parent.csend_type? || node.parent.super_type? || node.parent.yield_type?)
|
145
146
|
end
|
146
147
|
|
148
|
+
def call_in_match_pattern?(node)
|
149
|
+
node.parent&.match_pattern_type?
|
150
|
+
end
|
151
|
+
|
147
152
|
def hash_literal_in_arguments?(node)
|
148
153
|
node.arguments.any? do |n|
|
149
154
|
hash_literal?(n) ||
|
@@ -35,6 +35,8 @@ module RuboCop
|
|
35
35
|
# array.join('')
|
36
36
|
# [1, 2, 3].join("")
|
37
37
|
# array.sum(0)
|
38
|
+
# exit(true)
|
39
|
+
# exit!(false)
|
38
40
|
# string.split(" ")
|
39
41
|
# "first\nsecond".split(" ")
|
40
42
|
# string.chomp("\n")
|
@@ -45,6 +47,8 @@ module RuboCop
|
|
45
47
|
# array.join
|
46
48
|
# [1, 2, 3].join
|
47
49
|
# array.sum
|
50
|
+
# exit
|
51
|
+
# exit!
|
48
52
|
# string.split
|
49
53
|
# "first second".split
|
50
54
|
# string.chomp
|
@@ -55,9 +59,10 @@ module RuboCop
|
|
55
59
|
extend AutoCorrector
|
56
60
|
|
57
61
|
MSG = 'Argument %<arg>s is redundant because it is implied by default.'
|
62
|
+
NO_RECEIVER_METHODS = %i[exit exit!].freeze
|
58
63
|
|
59
64
|
def on_send(node)
|
60
|
-
return if node.receiver.nil?
|
65
|
+
return if !NO_RECEIVER_METHODS.include?(node.method_name) && node.receiver.nil?
|
61
66
|
return if node.arguments.count != 1
|
62
67
|
return unless redundant_argument?(node)
|
63
68
|
|
@@ -52,7 +52,7 @@ module RuboCop
|
|
52
52
|
include AllowedMethods
|
53
53
|
include AllowedPattern
|
54
54
|
|
55
|
-
MSG = '
|
55
|
+
MSG = 'Return `false` instead of `nil` in predicate methods.'
|
56
56
|
|
57
57
|
# @!method return_nil?(node)
|
58
58
|
def_node_matcher :return_nil?, <<~PATTERN
|
@@ -65,16 +65,28 @@ module RuboCop
|
|
65
65
|
return unless (body = node.body)
|
66
66
|
|
67
67
|
body.each_descendant(:return) do |return_node|
|
68
|
-
|
68
|
+
register_offense(return_node, 'return false') if return_nil?(return_node)
|
69
|
+
end
|
69
70
|
|
70
|
-
|
71
|
+
return unless (nil_node = nil_node_at_the_end_of_method_body(body))
|
71
72
|
|
72
|
-
|
73
|
-
corrector.replace(return_node, 'return false')
|
74
|
-
end
|
75
|
-
end
|
73
|
+
register_offense(nil_node, 'false')
|
76
74
|
end
|
77
75
|
alias on_defs on_def
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def nil_node_at_the_end_of_method_body(body)
|
80
|
+
return unless (last_child = body.children.last)
|
81
|
+
|
82
|
+
last_child if last_child.is_a?(AST::Node) && last_child.nil_type?
|
83
|
+
end
|
84
|
+
|
85
|
+
def register_offense(offense_node, replacement)
|
86
|
+
add_offense(offense_node) do |corrector|
|
87
|
+
corrector.replace(offense_node, replacement)
|
88
|
+
end
|
89
|
+
end
|
78
90
|
end
|
79
91
|
end
|
80
92
|
end
|
@@ -22,6 +22,15 @@ module RuboCop
|
|
22
22
|
# # bad
|
23
23
|
# [:foo, :bar, :baz]
|
24
24
|
#
|
25
|
+
# # bad (contains spaces)
|
26
|
+
# %i[foo\ bar baz\ quux]
|
27
|
+
#
|
28
|
+
# # bad (contains [] with spaces)
|
29
|
+
# %i[foo \[ \]]
|
30
|
+
#
|
31
|
+
# # bad (contains () with spaces)
|
32
|
+
# %i(foo \( \))
|
33
|
+
#
|
25
34
|
# @example EnforcedStyle: brackets
|
26
35
|
# # good
|
27
36
|
# [:foo, :bar, :baz]
|
@@ -40,6 +49,7 @@ module RuboCop
|
|
40
49
|
|
41
50
|
PERCENT_MSG = 'Use `%i` or `%I` for an array of symbols.'
|
42
51
|
ARRAY_MSG = 'Use %<prefer>s for an array of symbols.'
|
52
|
+
DELIMITERS = ['[', ']', '(', ')'].freeze
|
43
53
|
|
44
54
|
class << self
|
45
55
|
attr_accessor :largest_brackets
|
@@ -47,7 +57,7 @@ module RuboCop
|
|
47
57
|
|
48
58
|
def on_array(node)
|
49
59
|
if bracketed_array_of?(:sym, node)
|
50
|
-
return if
|
60
|
+
return if complex_content?(node)
|
51
61
|
|
52
62
|
check_bracketed_array(node, 'i')
|
53
63
|
elsif node.percent_literal?(:symbol)
|
@@ -57,13 +67,22 @@ module RuboCop
|
|
57
67
|
|
58
68
|
private
|
59
69
|
|
60
|
-
def
|
70
|
+
def complex_content?(node)
|
61
71
|
node.children.any? do |sym|
|
62
72
|
content, = *sym
|
63
|
-
content.to_s
|
73
|
+
content = content.to_s
|
74
|
+
content_without_delimiter_pairs = content.gsub(/(\[\])|(\(\))/, '')
|
75
|
+
|
76
|
+
content.include?(' ') || DELIMITERS.any? do |delimiter|
|
77
|
+
content_without_delimiter_pairs.include?(delimiter)
|
78
|
+
end
|
64
79
|
end
|
65
80
|
end
|
66
81
|
|
82
|
+
def invalid_percent_array_contents?(node)
|
83
|
+
complex_content?(node)
|
84
|
+
end
|
85
|
+
|
67
86
|
def build_bracketed_array(node)
|
68
87
|
return '[]' if node.children.empty?
|
69
88
|
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
63
63
|
|
64
64
|
def classname_attribute_value(file)
|
65
65
|
@classname_attribute_value_cache ||= Hash.new do |hash, key|
|
66
|
-
hash[key] = key.
|
66
|
+
hash[key] = key.delete_suffix('.rb').gsub("#{Dir.pwd}/", '').tr('/', '.')
|
67
67
|
end
|
68
68
|
@classname_attribute_value_cache[file]
|
69
69
|
end
|
data/lib/rubocop/lsp/routes.rb
CHANGED
@@ -36,7 +36,9 @@ module RuboCop
|
|
36
36
|
end
|
37
37
|
|
38
38
|
handle 'initialize' do |request|
|
39
|
-
|
39
|
+
initialization_options = extract_initialization_options_from(request)
|
40
|
+
|
41
|
+
@server.configure(initialization_options)
|
40
42
|
|
41
43
|
@server.write(
|
42
44
|
id: request[:id],
|
@@ -164,10 +166,14 @@ module RuboCop
|
|
164
166
|
|
165
167
|
private
|
166
168
|
|
167
|
-
def
|
169
|
+
def extract_initialization_options_from(request)
|
168
170
|
safe_autocorrect = request.dig(:params, :initializationOptions, :safeAutocorrect)
|
169
171
|
|
170
|
-
|
172
|
+
{
|
173
|
+
safe_autocorrect: safe_autocorrect.nil? || safe_autocorrect == true,
|
174
|
+
lint_mode: request.dig(:params, :initializationOptions, :lintMode) == true,
|
175
|
+
layout_mode: request.dig(:params, :initializationOptions, :layoutMode) == true
|
176
|
+
}
|
171
177
|
end
|
172
178
|
|
173
179
|
def format_file(file_uri)
|
data/lib/rubocop/lsp/runtime.rb
CHANGED
@@ -14,12 +14,14 @@ module RuboCop
|
|
14
14
|
# Runtime for Language Server Protocol of RuboCop.
|
15
15
|
# @api private
|
16
16
|
class Runtime
|
17
|
-
attr_writer :safe_autocorrect
|
17
|
+
attr_writer :safe_autocorrect, :lint_mode, :layout_mode
|
18
18
|
|
19
19
|
def initialize(config_store)
|
20
20
|
@config_store = config_store
|
21
21
|
@logged_paths = []
|
22
22
|
@safe_autocorrect = true
|
23
|
+
@lint_mode = false
|
24
|
+
@layout_mode = false
|
23
25
|
end
|
24
26
|
|
25
27
|
# This abuses the `--stdin` option of rubocop and reads the formatted text
|
@@ -37,6 +39,7 @@ module RuboCop
|
|
37
39
|
formatting_options = {
|
38
40
|
stdin: text, force_exclusion: true, autocorrect: true, safe_autocorrect: @safe_autocorrect
|
39
41
|
}
|
42
|
+
formatting_options[:only] = config_only_options if @lint_mode || @layout_mode
|
40
43
|
|
41
44
|
redirect_stdout { run_rubocop(formatting_options, path) }
|
42
45
|
|
@@ -47,6 +50,7 @@ module RuboCop
|
|
47
50
|
diagnostic_options = {
|
48
51
|
stdin: text, force_exclusion: true, formatters: ['json'], format: 'json'
|
49
52
|
}
|
53
|
+
diagnostic_options[:only] = config_only_options if @lint_mode || @layout_mode
|
50
54
|
|
51
55
|
json = redirect_stdout { run_rubocop(diagnostic_options, path) }
|
52
56
|
results = JSON.parse(json, symbolize_names: true)
|
@@ -64,6 +68,13 @@ module RuboCop
|
|
64
68
|
|
65
69
|
private
|
66
70
|
|
71
|
+
def config_only_options
|
72
|
+
only_options = []
|
73
|
+
only_options << 'Lint' if @lint_mode
|
74
|
+
only_options << 'Layout' if @layout_mode
|
75
|
+
only_options
|
76
|
+
end
|
77
|
+
|
67
78
|
def redirect_stdout(&block)
|
68
79
|
stdout = StringIO.new
|
69
80
|
|
data/lib/rubocop/lsp/server.rb
CHANGED
@@ -53,8 +53,10 @@ module RuboCop
|
|
53
53
|
@runtime.offenses(path, text)
|
54
54
|
end
|
55
55
|
|
56
|
-
def configure(
|
57
|
-
@runtime.safe_autocorrect = safe_autocorrect
|
56
|
+
def configure(options)
|
57
|
+
@runtime.safe_autocorrect = options[:safe_autocorrect]
|
58
|
+
@runtime.lint_mode = options[:lint_mode]
|
59
|
+
@runtime.layout_mode = options[:layout_mode]
|
58
60
|
end
|
59
61
|
|
60
62
|
def stop(&block)
|
data/lib/rubocop/result_cache.rb
CHANGED
@@ -202,6 +202,10 @@ module RuboCop
|
|
202
202
|
lib_root = File.join(File.dirname(__FILE__), '..')
|
203
203
|
exe_root = File.join(lib_root, '..', 'exe')
|
204
204
|
|
205
|
+
# Make sure to use an absolute path to prevent errors on Windows
|
206
|
+
# when traversing the relative paths with symlinks.
|
207
|
+
exe_root = File.absolute_path(exe_root)
|
208
|
+
|
205
209
|
# These are all the files we have `require`d plus everything in the
|
206
210
|
# exe directory. A change to any of them could affect the cop output
|
207
211
|
# so we include them in the cache hash.
|
@@ -94,8 +94,12 @@ module RuboCop
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def wanted_dir_patterns(base_dir, exclude_pattern, flags)
|
97
|
-
base_dir
|
98
|
-
|
97
|
+
# Escape glob characters in base_dir to avoid unwanted behavior.
|
98
|
+
base_dir = base_dir.gsub(/[\\\{\}\[\]\*\?]/) do |reserved_glob_character|
|
99
|
+
"\\#{reserved_glob_character}"
|
100
|
+
end
|
101
|
+
|
102
|
+
dirs = Dir.glob(File.join(base_dir, '*/'), flags)
|
99
103
|
.reject do |dir|
|
100
104
|
next true if dir.end_with?('/./', '/../')
|
101
105
|
next true if File.fnmatch?(exclude_pattern, dir, flags)
|
data/lib/rubocop/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.55.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2023-07-
|
13
|
+
date: 2023-07-25 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: json
|
@@ -134,7 +134,7 @@ dependencies:
|
|
134
134
|
requirements:
|
135
135
|
- - ">="
|
136
136
|
- !ruby/object:Gem::Version
|
137
|
-
version: 1.28.
|
137
|
+
version: 1.28.1
|
138
138
|
- - "<"
|
139
139
|
- !ruby/object:Gem::Version
|
140
140
|
version: '2.0'
|
@@ -144,7 +144,7 @@ dependencies:
|
|
144
144
|
requirements:
|
145
145
|
- - ">="
|
146
146
|
- !ruby/object:Gem::Version
|
147
|
-
version: 1.28.
|
147
|
+
version: 1.28.1
|
148
148
|
- - "<"
|
149
149
|
- !ruby/object:Gem::Version
|
150
150
|
version: '2.0'
|
@@ -1023,7 +1023,7 @@ metadata:
|
|
1023
1023
|
homepage_uri: https://rubocop.org/
|
1024
1024
|
changelog_uri: https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md
|
1025
1025
|
source_code_uri: https://github.com/rubocop/rubocop/
|
1026
|
-
documentation_uri: https://docs.rubocop.org/rubocop/1.
|
1026
|
+
documentation_uri: https://docs.rubocop.org/rubocop/1.55/
|
1027
1027
|
bug_tracker_uri: https://github.com/rubocop/rubocop/issues
|
1028
1028
|
rubygems_mfa_required: 'true'
|
1029
1029
|
post_install_message:
|