rubocop 1.79.1 → 1.80.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/exe/rubocop +1 -8
- data/lib/rubocop/cli.rb +5 -0
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +3 -1
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -0
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -2
- data/lib/rubocop/cop/lint/self_assignment.rb +5 -4
- data/lib/rubocop/cop/naming/method_name.rb +1 -1
- data/lib/rubocop/cop/style/array_intersect.rb +45 -11
- data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -3
- data/lib/rubocop/cop/style/map_to_set.rb +1 -3
- data/lib/rubocop/cop/style/redundant_begin.rb +32 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +7 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +14 -1
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +12 -6
- data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -5
- data/lib/rubocop/lsp/routes.rb +31 -2
- data/lib/rubocop/result_cache.rb +13 -11
- data/lib/rubocop/target_finder.rb +9 -9
- data/lib/rubocop/version.rb +1 -1
- metadata +5 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 496ab84015431ed6854f23f7a0e5ca4df59bc01056024b8895c59900c885530d
|
4
|
+
data.tar.gz: '09bc286e311ba0b4e2cb9cbc9b4c4ed33b7154311e27be5c9604f30cde4c54d7'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b647e72a501941d047a93c9d761840664ce140ae11a9d5326855d6a9755cab4d065dcbf37db926396ab078cf18a44378ab89ed4a40745dd35bf3cec9fbdb4ce
|
7
|
+
data.tar.gz: 5f26cbc1e08e4fb9fa03b2cef099543864dfa741fb73e5e7062186f810a7f0f816bbe3dae981e8dba2c3758318fcbf015f7dbf140e472fbc8b5dd2f9fde1c9bf
|
data/README.md
CHANGED
@@ -51,7 +51,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
51
51
|
in your `Gemfile`:
|
52
52
|
|
53
53
|
```rb
|
54
|
-
gem 'rubocop', '~> 1.
|
54
|
+
gem 'rubocop', '~> 1.80', require: false
|
55
55
|
```
|
56
56
|
|
57
57
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
data/exe/rubocop
CHANGED
@@ -12,13 +12,6 @@ if RuboCop::Server.running?
|
|
12
12
|
exit_status = RuboCop::Server::ClientCommand::Exec.new.run
|
13
13
|
else
|
14
14
|
require 'rubocop'
|
15
|
-
|
16
|
-
cli = RuboCop::CLI.new
|
17
|
-
|
18
|
-
time_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
19
|
-
exit_status = cli.run
|
20
|
-
elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - time_start
|
21
|
-
|
22
|
-
puts "Finished in #{elapsed_time} seconds" if cli.options[:debug] || cli.options[:display_time]
|
15
|
+
exit_status = RuboCop::CLI.new.run
|
23
16
|
end
|
24
17
|
exit exit_status
|
data/lib/rubocop/cli.rb
CHANGED
@@ -37,6 +37,8 @@ module RuboCop
|
|
37
37
|
#
|
38
38
|
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
39
39
|
def run(args = ARGV)
|
40
|
+
time_start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
41
|
+
|
40
42
|
@options, paths = Options.new.parse(args)
|
41
43
|
@env = Environment.new(@options, @config_store, paths)
|
42
44
|
|
@@ -72,6 +74,9 @@ module RuboCop
|
|
72
74
|
warn e.message
|
73
75
|
warn e.backtrace
|
74
76
|
STATUS_ERROR
|
77
|
+
ensure
|
78
|
+
elapsed_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) - time_start
|
79
|
+
puts "Finished in #{elapsed_time} seconds" if @options[:debug] || @options[:display_time]
|
75
80
|
end
|
76
81
|
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize
|
77
82
|
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
class ForToEachCorrector
|
7
7
|
extend NodePattern::Macros
|
8
8
|
|
9
|
-
CORRECTION = '%<collection>s
|
9
|
+
CORRECTION = '%<collection>s%<dot>seach do |%<argument>s|'
|
10
10
|
|
11
11
|
def initialize(for_node)
|
12
12
|
@for_node = for_node
|
@@ -25,7 +25,12 @@ module RuboCop
|
|
25
25
|
attr_reader :for_node, :variable_node, :collection_node
|
26
26
|
|
27
27
|
def correction
|
28
|
-
format(
|
28
|
+
format(
|
29
|
+
CORRECTION,
|
30
|
+
collection: collection_source,
|
31
|
+
dot: collection_node.csend_type? ? '&.' : '.',
|
32
|
+
argument: variable_node.source
|
33
|
+
)
|
29
34
|
end
|
30
35
|
|
31
36
|
def collection_source
|
@@ -38,7 +38,7 @@ module RuboCop
|
|
38
38
|
RESTRICT_ON_SEND = MODULE_INCLUSION_METHODS
|
39
39
|
|
40
40
|
def on_send(node)
|
41
|
-
return if node.receiver
|
41
|
+
return if node.receiver || node.arguments.empty?
|
42
42
|
return if node.parent&.type?(:send, :any_block)
|
43
43
|
|
44
44
|
return if next_line_empty_or_enable_directive_comment?(node.last_line)
|
@@ -83,6 +83,8 @@ module RuboCop
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def allowed_method?(node)
|
86
|
+
node = node.body if node.respond_to?(:modifier_form?) && node.modifier_form?
|
87
|
+
|
86
88
|
return false unless node.send_type?
|
87
89
|
|
88
90
|
MODULE_INCLUSION_METHODS.include?(node.method_name)
|
@@ -62,40 +62,19 @@ module RuboCop
|
|
62
62
|
node.receiver && node.receiver.loc.last_line != node.loc.selector&.line
|
63
63
|
end
|
64
64
|
|
65
|
-
def
|
66
|
-
|
67
|
-
|
68
|
-
lines.map { |_, line| line }
|
69
|
-
end
|
70
|
-
|
71
|
-
def extra_lines(node)
|
72
|
-
empty_lines(node).each do |line|
|
73
|
-
range = source_range(processed_source.buffer, line, 0)
|
74
|
-
yield(range)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def processed_lines(node)
|
79
|
-
line_numbers(node).each_with_object([]) do |num, array|
|
80
|
-
array << [processed_source.lines[num - 1], num]
|
65
|
+
def extra_lines(node, &block)
|
66
|
+
node.arguments.each do |arg|
|
67
|
+
empty_range_for_starting_point(arg.source_range.begin, &block)
|
81
68
|
end
|
82
|
-
end
|
83
69
|
|
84
|
-
|
85
|
-
inner_lines = []
|
86
|
-
line_nums = node.arguments.each_with_object([]) do |arg_node, lines|
|
87
|
-
lines << outer_lines(arg_node)
|
88
|
-
inner_lines << inner_lines(arg_node) if arg_node.multiline?
|
89
|
-
end
|
90
|
-
line_nums.flatten.uniq - inner_lines.flatten - outer_lines(node)
|
70
|
+
empty_range_for_starting_point(node.loc.end.begin, &block) if node.loc.end
|
91
71
|
end
|
92
72
|
|
93
|
-
def
|
94
|
-
|
95
|
-
|
73
|
+
def empty_range_for_starting_point(start)
|
74
|
+
range = range_with_surrounding_space(start, whitespace: true, side: :left)
|
75
|
+
return unless range.last_line - range.first_line > 1
|
96
76
|
|
97
|
-
|
98
|
-
[node.first_line - 1, node.last_line + 1]
|
77
|
+
yield range.source_buffer.line_range(range.last_line - 1).adjust(end_pos: 1)
|
99
78
|
end
|
100
79
|
end
|
101
80
|
end
|
@@ -10,6 +10,8 @@ module RuboCop
|
|
10
10
|
# condition, an explicit `return` statement, etc. In other contexts, the second operand should
|
11
11
|
# be indented regardless of enforced style.
|
12
12
|
#
|
13
|
+
# In both styles, operators should be aligned when an assignment begins on the next line.
|
14
|
+
#
|
13
15
|
# @example EnforcedStyle: aligned (default)
|
14
16
|
# # bad
|
15
17
|
# if a +
|
@@ -24,8 +24,6 @@ module RuboCop
|
|
24
24
|
|
25
25
|
MSG_REPEATED_ELEMENT = 'Duplicate element inside regexp character class'
|
26
26
|
|
27
|
-
OCTAL_DIGITS_AFTER_ESCAPE = 2
|
28
|
-
|
29
27
|
def on_regexp(node)
|
30
28
|
each_repeated_character_class_element_loc(node) do |loc|
|
31
29
|
add_offense(loc, message: MSG_REPEATED_ELEMENT) do |corrector|
|
@@ -40,9 +38,9 @@ module RuboCop
|
|
40
38
|
|
41
39
|
seen = Set.new
|
42
40
|
group_expressions(node, expr.expressions) do |group|
|
43
|
-
group_source = group.
|
41
|
+
group_source = group.to_s
|
44
42
|
|
45
|
-
yield
|
43
|
+
yield group.expression if seen.include?(group_source)
|
46
44
|
|
47
45
|
seen << group_source
|
48
46
|
end
|
@@ -52,40 +50,13 @@ module RuboCop
|
|
52
50
|
private
|
53
51
|
|
54
52
|
def group_expressions(node, expressions)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
until expressions.empty?
|
59
|
-
# With we may need to compose a group of multiple expressions.
|
60
|
-
group = [expressions.shift]
|
61
|
-
next if within_interpolation?(node, group.first)
|
62
|
-
|
63
|
-
# With regexp_parser < 2.7 escaped octal sequences may be up to 3
|
64
|
-
# separate expressions ("\\0", "0", "1").
|
65
|
-
pop_octal_digits(group, expressions) if escaped_octal?(group.first.to_s)
|
66
|
-
|
67
|
-
yield(group)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def pop_octal_digits(current_child, expressions)
|
72
|
-
OCTAL_DIGITS_AFTER_ESCAPE.times do
|
73
|
-
next_child = expressions.first
|
74
|
-
break unless octal?(next_child.to_s)
|
53
|
+
expressions.each do |expression|
|
54
|
+
next if within_interpolation?(node, expression)
|
75
55
|
|
76
|
-
|
56
|
+
yield(expression)
|
77
57
|
end
|
78
58
|
end
|
79
59
|
|
80
|
-
def source_range(children)
|
81
|
-
return children.first.expression if children.size == 1
|
82
|
-
|
83
|
-
range_between(
|
84
|
-
children.first.expression.begin_pos,
|
85
|
-
children.last.expression.begin_pos + children.last.to_s.length
|
86
|
-
)
|
87
|
-
end
|
88
|
-
|
89
60
|
def skip_expression?(expr)
|
90
61
|
expr.type != :set || expr.token == :intersection
|
91
62
|
end
|
@@ -99,14 +70,6 @@ module RuboCop
|
|
99
70
|
interpolation_locs(node).any? { |il| il.overlaps?(parse_tree_child_loc) }
|
100
71
|
end
|
101
72
|
|
102
|
-
def escaped_octal?(string)
|
103
|
-
string.length == 2 && string[0] == '\\' && octal?(string[1])
|
104
|
-
end
|
105
|
-
|
106
|
-
def octal?(char)
|
107
|
-
('0'..'7').cover?(char)
|
108
|
-
end
|
109
|
-
|
110
73
|
def interpolation_locs(node)
|
111
74
|
@interpolation_locs ||= {}
|
112
75
|
|
@@ -52,10 +52,9 @@ module RuboCop
|
|
52
52
|
each_missing_enable do |cop, line_range|
|
53
53
|
next if acceptable_range?(cop, line_range)
|
54
54
|
|
55
|
-
range = source_range(processed_source.buffer, line_range.min, 0..0)
|
56
55
|
comment = processed_source.comment_at_line(line_range.begin)
|
57
56
|
|
58
|
-
add_offense(
|
57
|
+
add_offense(comment, message: message(cop, comment))
|
59
58
|
end
|
60
59
|
end
|
61
60
|
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.receiver)
|
46
46
|
|
47
47
|
if node.method?(:[]=)
|
48
|
-
handle_key_assignment(node)
|
48
|
+
handle_key_assignment(node)
|
49
49
|
elsif node.assignment_method?
|
50
50
|
handle_attribute_assignment(node) if node.arguments.size == 1
|
51
51
|
end
|
@@ -105,12 +105,13 @@ module RuboCop
|
|
105
105
|
end
|
106
106
|
|
107
107
|
def handle_key_assignment(node)
|
108
|
-
value_node = node.
|
108
|
+
value_node = node.last_argument
|
109
|
+
node_arguments = node.arguments[0...-1]
|
109
110
|
|
110
111
|
if value_node.send_type? && value_node.method?(:[]) &&
|
111
112
|
node.receiver == value_node.receiver &&
|
112
|
-
|
113
|
-
|
113
|
+
node_arguments.none?(&:call_type?) &&
|
114
|
+
node_arguments == value_node.arguments
|
114
115
|
add_offense(node)
|
115
116
|
end
|
116
117
|
end
|
@@ -10,6 +10,8 @@ module RuboCop
|
|
10
10
|
# * `(array1 & array2).any?`
|
11
11
|
# * `(array1.intersection(array2)).any?`
|
12
12
|
# * `array1.any? { |elem| array2.member?(elem) }`
|
13
|
+
# * `(array1 & array2).count > 0`
|
14
|
+
# * `(array1 & array2).size > 0`
|
13
15
|
#
|
14
16
|
# can be replaced with `array1.intersect?(array2)`.
|
15
17
|
#
|
@@ -51,6 +53,19 @@ module RuboCop
|
|
51
53
|
# array1.intersect?(array2)
|
52
54
|
# !array1.intersect?(array2)
|
53
55
|
#
|
56
|
+
# # bad
|
57
|
+
# (array1 & array2).count > 0
|
58
|
+
# (array1 & array2).count.positive?
|
59
|
+
# (array1 & array2).count != 0
|
60
|
+
#
|
61
|
+
# (array1 & array2).count == 0
|
62
|
+
# (array1 & array2).count.zero?
|
63
|
+
#
|
64
|
+
# # good
|
65
|
+
# array1.intersect?(array2)
|
66
|
+
#
|
67
|
+
# !array1.intersect?(array2)
|
68
|
+
#
|
54
69
|
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
55
70
|
# # good
|
56
71
|
# (array1 & array2).present?
|
@@ -73,9 +88,11 @@ module RuboCop
|
|
73
88
|
PREDICATES = %i[any? empty? none?].to_set.freeze
|
74
89
|
ACTIVE_SUPPORT_PREDICATES = (PREDICATES + %i[present? blank?]).freeze
|
75
90
|
|
91
|
+
ARRAY_SIZE_METHODS = %i[count length size].to_set.freeze
|
92
|
+
|
76
93
|
# @!method bad_intersection_check?(node, predicates)
|
77
94
|
def_node_matcher :bad_intersection_check?, <<~PATTERN
|
78
|
-
(call
|
95
|
+
$(call
|
79
96
|
{
|
80
97
|
(begin (send $_ :& $_))
|
81
98
|
(call $_ :intersection $_)
|
@@ -84,6 +101,20 @@ module RuboCop
|
|
84
101
|
)
|
85
102
|
PATTERN
|
86
103
|
|
104
|
+
# @!method intersection_size_check?(node, predicates)
|
105
|
+
def_node_matcher :intersection_size_check?, <<~PATTERN
|
106
|
+
(call
|
107
|
+
$(call
|
108
|
+
{
|
109
|
+
(begin (send $_ :& $_))
|
110
|
+
(call $_ :intersection $_)
|
111
|
+
}
|
112
|
+
%ARRAY_SIZE_METHODS
|
113
|
+
)
|
114
|
+
{$:> (int 0) | $:positive? | $:!= (int 0) | $:== (int 0) | $:zero?}
|
115
|
+
)
|
116
|
+
PATTERN
|
117
|
+
|
87
118
|
# @!method any_none_block_intersection(node)
|
88
119
|
def_node_matcher :any_none_block_intersection, <<~PATTERN
|
89
120
|
{
|
@@ -104,15 +135,15 @@ module RuboCop
|
|
104
135
|
PATTERN
|
105
136
|
|
106
137
|
MSG = 'Use `%<replacement>s` instead of `%<existing>s`.'
|
107
|
-
STRAIGHT_METHODS = %i[present? any?].freeze
|
108
|
-
NEGATED_METHODS = %i[blank? empty? none?].freeze
|
138
|
+
STRAIGHT_METHODS = %i[present? any? > positive? !=].freeze
|
139
|
+
NEGATED_METHODS = %i[blank? empty? none? == zero?].freeze
|
109
140
|
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
110
141
|
|
111
142
|
def on_send(node)
|
112
143
|
return if node.block_literal?
|
113
|
-
return unless (receiver, argument, method_name = bad_intersection?(node))
|
144
|
+
return unless (dot_node, receiver, argument, method_name = bad_intersection?(node))
|
114
145
|
|
115
|
-
dot =
|
146
|
+
dot = dot_node.loc.dot.source
|
116
147
|
bang = straight?(method_name) ? '' : '!'
|
117
148
|
replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
|
118
149
|
|
@@ -135,13 +166,16 @@ module RuboCop
|
|
135
166
|
private
|
136
167
|
|
137
168
|
def bad_intersection?(node)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
PREDICATES
|
142
|
-
end
|
169
|
+
bad_intersection_check?(node, bad_intersection_predicates) ||
|
170
|
+
intersection_size_check?(node)
|
171
|
+
end
|
143
172
|
|
144
|
-
|
173
|
+
def bad_intersection_predicates
|
174
|
+
if active_support_extensions_enabled?
|
175
|
+
ACTIVE_SUPPORT_PREDICATES
|
176
|
+
else
|
177
|
+
PREDICATES
|
178
|
+
end
|
145
179
|
end
|
146
180
|
|
147
181
|
def straight?(method_name)
|
@@ -70,18 +70,25 @@ module RuboCop
|
|
70
70
|
(send _ :& _))
|
71
71
|
PATTERN
|
72
72
|
|
73
|
+
# rubocop:disable Metrics/AbcSize
|
73
74
|
def on_send(node)
|
74
75
|
return unless node.receiver&.begin_type?
|
75
76
|
return unless (preferred_method = preferred_method(node))
|
76
77
|
|
77
78
|
bit_operation = node.receiver.children.first
|
78
79
|
lhs, _operator, rhs = *bit_operation
|
79
|
-
|
80
|
+
|
81
|
+
preferred = if preferred_method == 'allbits?' && lhs.source == node.first_argument.source
|
82
|
+
"#{rhs.source}.allbits?(#{lhs.source})"
|
83
|
+
else
|
84
|
+
"#{lhs.source}.#{preferred_method}(#{rhs.source})"
|
85
|
+
end
|
80
86
|
|
81
87
|
add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
|
82
88
|
corrector.replace(node, preferred)
|
83
89
|
end
|
84
90
|
end
|
91
|
+
# rubocop:enable Metrics/AbcSize
|
85
92
|
|
86
93
|
private
|
87
94
|
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def autocorrect(corrector, node)
|
71
|
-
if node.
|
71
|
+
if node.post_condition_loop?
|
72
72
|
replace_begin_end_with_modifier(corrector, node)
|
73
73
|
elsif node.modifier_form?
|
74
74
|
replace_source(corrector, node.source_range, modifier_replacement(node))
|
@@ -56,12 +56,10 @@ module RuboCop
|
|
56
56
|
|
57
57
|
def on_send(node)
|
58
58
|
return unless (to_h_node, map_node = map_to_h(node))
|
59
|
+
return if to_h_node.block_literal?
|
59
60
|
|
60
61
|
message = format(MSG, method: map_node.loc.selector.source, dot: to_h_node.loc.dot.source)
|
61
62
|
add_offense(map_node.loc.selector, message: message) do |corrector|
|
62
|
-
# If the `to_h` call already has a block, do not autocorrect.
|
63
|
-
next if to_h_node.block_literal?
|
64
|
-
|
65
63
|
autocorrect(corrector, to_h_node, map_node)
|
66
64
|
end
|
67
65
|
end
|
@@ -40,12 +40,10 @@ module RuboCop
|
|
40
40
|
|
41
41
|
def on_send(node)
|
42
42
|
return unless (to_set_node, map_node = map_to_set?(node))
|
43
|
+
return if to_set_node.block_literal?
|
43
44
|
|
44
45
|
message = format(MSG, method: map_node.loc.selector.source)
|
45
46
|
add_offense(map_node.loc.selector, message: message) do |corrector|
|
46
|
-
# If the `to_set` call already has a block, do not autocorrect.
|
47
|
-
next if to_set_node.block_literal?
|
48
|
-
|
49
47
|
autocorrect(corrector, to_set_node, map_node)
|
50
48
|
end
|
51
49
|
end
|
@@ -85,6 +85,29 @@ module RuboCop
|
|
85
85
|
end
|
86
86
|
alias on_defs on_def
|
87
87
|
|
88
|
+
def on_if(node)
|
89
|
+
return if node.modifier_form?
|
90
|
+
|
91
|
+
inspect_branches(node)
|
92
|
+
end
|
93
|
+
|
94
|
+
def on_case(node)
|
95
|
+
inspect_branches(node)
|
96
|
+
end
|
97
|
+
alias on_case_match on_case
|
98
|
+
|
99
|
+
def on_while(node)
|
100
|
+
return if node.modifier_form?
|
101
|
+
|
102
|
+
body = node.body
|
103
|
+
|
104
|
+
return unless body&.kwbegin_type?
|
105
|
+
return if body.rescue_node || body.ensure_node
|
106
|
+
|
107
|
+
register_offense(body)
|
108
|
+
end
|
109
|
+
alias on_until on_while
|
110
|
+
|
88
111
|
def on_block(node)
|
89
112
|
return if target_ruby_version < 2.5
|
90
113
|
return if node.send_node.lambda_literal?
|
@@ -199,6 +222,15 @@ module RuboCop
|
|
199
222
|
def valid_begin_assignment?(node)
|
200
223
|
node.parent&.assignment? && !node.children.one?
|
201
224
|
end
|
225
|
+
|
226
|
+
def inspect_branches(node)
|
227
|
+
node.branches.each do |branch|
|
228
|
+
next unless branch&.kwbegin_type?
|
229
|
+
next if branch.rescue_node || branch.ensure_node
|
230
|
+
|
231
|
+
register_offense(branch)
|
232
|
+
end
|
233
|
+
end
|
202
234
|
end
|
203
235
|
end
|
204
236
|
end
|
@@ -247,7 +247,7 @@ module RuboCop
|
|
247
247
|
"#{if_branch.receiver.source} #{if_branch.method_name} (#{argument_source}"
|
248
248
|
elsif if_branch.true_type?
|
249
249
|
condition = if_branch.parent.condition
|
250
|
-
return condition.source if condition.arguments.empty?
|
250
|
+
return condition.source if condition.arguments.empty? || condition.parenthesized?
|
251
251
|
|
252
252
|
wrap_arguments_with_parens(condition)
|
253
253
|
else
|
@@ -149,7 +149,7 @@ module RuboCop
|
|
149
149
|
return offense(begin_node, message)
|
150
150
|
end
|
151
151
|
|
152
|
-
check_send(begin_node, node) if node
|
152
|
+
check_send(begin_node, node) if call_node?(node)
|
153
153
|
end
|
154
154
|
|
155
155
|
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
@@ -219,7 +219,13 @@ module RuboCop
|
|
219
219
|
!!config.for_enabled_cop('Style/ParenthesesAroundCondition')['AllowInMultilineConditions']
|
220
220
|
end
|
221
221
|
|
222
|
+
def call_node?(node)
|
223
|
+
node.call_type? || (node.any_block_type? && node.braces? && !node.lambda_or_proc?)
|
224
|
+
end
|
225
|
+
|
222
226
|
def check_send(begin_node, node)
|
227
|
+
node = node.send_node if node.any_block_type?
|
228
|
+
|
223
229
|
return check_unary(begin_node, node) if node.unary_operation?
|
224
230
|
|
225
231
|
return unless method_call_with_redundant_parentheses?(node)
|
@@ -142,6 +142,7 @@ module RuboCop
|
|
142
142
|
# @!method strip_begin(node)
|
143
143
|
def_node_matcher :strip_begin, '{ (begin $!begin) $!(begin) }'
|
144
144
|
|
145
|
+
# rubocop:disable Metrics/AbcSize
|
145
146
|
def on_if(node)
|
146
147
|
return if allowed_if_condition?(node)
|
147
148
|
|
@@ -155,9 +156,11 @@ module RuboCop
|
|
155
156
|
removal_ranges = [begin_range(node, body), end_range(node, body)]
|
156
157
|
|
157
158
|
report_offense(node, method_chain, method_call, *removal_ranges) do |corrector|
|
159
|
+
corrector.replace(receiver, checked_variable.source) if checked_variable.csend_type?
|
158
160
|
corrector.insert_before(method_call.loc.dot, '&') unless method_call.safe_navigation?
|
159
161
|
end
|
160
162
|
end
|
163
|
+
# rubocop:enable Metrics/AbcSize
|
161
164
|
|
162
165
|
def on_and(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
163
166
|
collect_and_clauses(node).each do |(lhs, lhs_operator_range), (rhs, _rhs_operator_range)|
|
@@ -259,6 +262,8 @@ module RuboCop
|
|
259
262
|
end
|
260
263
|
|
261
264
|
def dotless_operator_call?(method_call)
|
265
|
+
method_call = method_call.parent while method_call.parent.send_type?
|
266
|
+
|
262
267
|
return false if method_call.loc.dot
|
263
268
|
|
264
269
|
method_call.method?(:[]) || method_call.method?(:[]=) || method_call.operator_method?
|
@@ -333,8 +338,16 @@ module RuboCop
|
|
333
338
|
|
334
339
|
def matching_call_nodes?(left, right)
|
335
340
|
return false unless left && right.respond_to?(:call_type?)
|
341
|
+
return false unless left.call_type? && right.call_type?
|
342
|
+
|
343
|
+
# Compare receiver and method name, but ignore the difference between
|
344
|
+
# safe navigation method call (`&.`) and dot method call (`.`).
|
345
|
+
left_receiver, left_method, *left_args = left.children
|
346
|
+
right_receiver, right_method, *right_args = right.children
|
336
347
|
|
337
|
-
|
348
|
+
left_method == right_method &&
|
349
|
+
matching_nodes?(left_receiver, right_receiver) &&
|
350
|
+
left_args == right_args
|
338
351
|
end
|
339
352
|
|
340
353
|
def chain_length(method_chain, method)
|
@@ -81,7 +81,7 @@ module RuboCop
|
|
81
81
|
|
82
82
|
content = *sym
|
83
83
|
content = content.map { |c| c.is_a?(AST::Node) ? c.source : c }.join
|
84
|
-
content_without_delimiter_pairs = content.gsub(/(\[[^\s\[\]]*\])|(\([^\s
|
84
|
+
content_without_delimiter_pairs = content.gsub(/(\[[^\s\[\]]*\])|(\([^\s()]*\))/, '')
|
85
85
|
|
86
86
|
content.include?(' ') || DELIMITERS.any? do |delimiter|
|
87
87
|
content_without_delimiter_pairs.include?(delimiter)
|
@@ -71,6 +71,8 @@ module RuboCop
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
BRANCH_NODES = %i[if case case_match rescue].freeze
|
75
|
+
|
74
76
|
def variable_table
|
75
77
|
@variable_table ||= VariableTable.new(self)
|
76
78
|
end
|
@@ -236,11 +238,16 @@ module RuboCop
|
|
236
238
|
end
|
237
239
|
|
238
240
|
def process_loop(node)
|
239
|
-
if
|
241
|
+
if node.post_condition_loop?
|
240
242
|
# See the comment at the end of file for this behavior.
|
241
243
|
condition_node, body_node = *node
|
242
244
|
process_node(body_node)
|
243
245
|
process_node(condition_node)
|
246
|
+
elsif node.for_type?
|
247
|
+
# In `for item in items` the rightmost expression is evaluated first.
|
248
|
+
process_node(node.collection)
|
249
|
+
process_node(node.variable)
|
250
|
+
process_node(node.body) if node.body
|
244
251
|
else
|
245
252
|
process_children(node)
|
246
253
|
end
|
@@ -353,16 +360,15 @@ module RuboCop
|
|
353
360
|
end
|
354
361
|
end
|
355
362
|
|
356
|
-
def reference_assignments(loop_assignments,
|
363
|
+
def reference_assignments(loop_assignments, loop_node)
|
357
364
|
# If inside a branching statement, mark all as referenced.
|
358
365
|
# Otherwise, mark only the last assignment as referenced.
|
359
366
|
# Note that `rescue` must be considered as branching because of
|
360
367
|
# the `retry` keyword.
|
361
|
-
|
362
|
-
|
363
|
-
else
|
364
|
-
loop_assignments.last&.reference!(node)
|
368
|
+
loop_assignments.each do |assignment|
|
369
|
+
assignment.reference!(loop_node) if assignment.node.each_ancestor(*BRANCH_NODES).any?
|
365
370
|
end
|
371
|
+
loop_assignments.last&.reference!(loop_node)
|
366
372
|
end
|
367
373
|
|
368
374
|
def scanned_node?(node)
|
@@ -4,7 +4,7 @@ module RuboCop
|
|
4
4
|
module Formatter
|
5
5
|
# This formatter displays a YAML configuration file where all cops that
|
6
6
|
# detected any offenses are configured to not detect the offense.
|
7
|
-
class DisabledConfigFormatter < BaseFormatter
|
7
|
+
class DisabledConfigFormatter < BaseFormatter # rubocop:disable Metrics/ClassLength
|
8
8
|
include PathUtil
|
9
9
|
|
10
10
|
HEADING = <<~COMMENTS
|
@@ -17,6 +17,22 @@ module RuboCop
|
|
17
17
|
# versions of RuboCop, may require this file to be generated again.
|
18
18
|
COMMENTS
|
19
19
|
|
20
|
+
EXCLUDED_CONFIG_KEYS = %w[
|
21
|
+
AutoCorrect
|
22
|
+
Description
|
23
|
+
Enabled
|
24
|
+
Exclude
|
25
|
+
Include
|
26
|
+
Reference
|
27
|
+
References
|
28
|
+
Safe
|
29
|
+
SafeAutoCorrect
|
30
|
+
StyleGuide
|
31
|
+
VersionAdded
|
32
|
+
VersionChanged
|
33
|
+
VersionRemoved
|
34
|
+
].freeze
|
35
|
+
|
20
36
|
@config_to_allow_offenses = {}
|
21
37
|
@detected_styles = {}
|
22
38
|
|
@@ -163,10 +179,7 @@ module RuboCop
|
|
163
179
|
end
|
164
180
|
|
165
181
|
def cop_config_params(default_cfg, cfg)
|
166
|
-
default_cfg.keys -
|
167
|
-
%w[Description StyleGuide Reference References Enabled Exclude Safe
|
168
|
-
SafeAutoCorrect VersionAdded VersionChanged VersionRemoved] -
|
169
|
-
cfg.keys
|
182
|
+
default_cfg.keys - EXCLUDED_CONFIG_KEYS - cfg.keys
|
170
183
|
end
|
171
184
|
|
172
185
|
def output_cop_param_comments(output_buffer, params, default_cfg)
|
data/lib/rubocop/lsp/routes.rb
CHANGED
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
capabilities: LanguageServer::Protocol::Interface::ServerCapabilities.new(
|
52
52
|
document_formatting_provider: true,
|
53
53
|
text_document_sync: LanguageServer::Protocol::Interface::TextDocumentSyncOptions.new(
|
54
|
-
change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::
|
54
|
+
change: LanguageServer::Protocol::Constant::TextDocumentSyncKind::INCREMENTAL,
|
55
55
|
open_close: true
|
56
56
|
)
|
57
57
|
)
|
@@ -76,7 +76,12 @@ module RuboCop
|
|
76
76
|
|
77
77
|
handle 'textDocument/didChange' do |request|
|
78
78
|
params = request[:params]
|
79
|
-
|
79
|
+
file_uri = params[:textDocument][:uri]
|
80
|
+
text = @text_cache[file_uri]
|
81
|
+
params[:contentChanges].each do |content|
|
82
|
+
text = change_text(text, content[:text], content[:range])
|
83
|
+
end
|
84
|
+
result = diagnostic(file_uri, text)
|
80
85
|
@server.write(result)
|
81
86
|
end
|
82
87
|
|
@@ -219,6 +224,30 @@ module RuboCop
|
|
219
224
|
}
|
220
225
|
end
|
221
226
|
|
227
|
+
def change_text(orig_text, text, range)
|
228
|
+
return text unless range
|
229
|
+
|
230
|
+
start_pos = text_pos(orig_text, range[:start])
|
231
|
+
end_pos = text_pos(orig_text, range[:end])
|
232
|
+
text_bin = orig_text.b
|
233
|
+
text_bin[start_pos...end_pos] = text.b
|
234
|
+
text_bin.force_encoding(orig_text.encoding)
|
235
|
+
end
|
236
|
+
|
237
|
+
def text_pos(text, range)
|
238
|
+
line = range[:line]
|
239
|
+
char = range[:character]
|
240
|
+
pos = 0
|
241
|
+
text.each_line.with_index do |l, i|
|
242
|
+
if i == line
|
243
|
+
pos += l.encode('utf-16be').b[0, char * 2].encode('utf-8', 'utf-16be').bytesize
|
244
|
+
return pos
|
245
|
+
end
|
246
|
+
pos += l.bytesize
|
247
|
+
end
|
248
|
+
pos
|
249
|
+
end
|
250
|
+
|
222
251
|
def convert_file_uri_to_path(uri)
|
223
252
|
URI.decode_www_form_component(uri.delete_prefix('file://'))
|
224
253
|
end
|
data/lib/rubocop/result_cache.rb
CHANGED
@@ -198,20 +198,22 @@ module RuboCop
|
|
198
198
|
end
|
199
199
|
|
200
200
|
def rubocop_extra_features
|
201
|
-
|
202
|
-
|
201
|
+
@rubocop_extra_features ||= begin
|
202
|
+
lib_root = File.join(File.dirname(__FILE__), '..')
|
203
|
+
exe_root = File.join(lib_root, '..', 'exe')
|
203
204
|
|
204
|
-
|
205
|
-
|
206
|
-
|
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)
|
207
208
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
209
|
+
# These are all the files we have `require`d plus everything in the
|
210
|
+
# exe directory. A change to any of them could affect the cop output
|
211
|
+
# so we include them in the cache hash.
|
212
|
+
source_files = $LOADED_FEATURES + Find.find(exe_root).to_a
|
213
|
+
source_files -= ResultCache.rubocop_required_features # Rely on gem versions
|
213
214
|
|
214
|
-
|
215
|
+
source_files
|
216
|
+
end
|
215
217
|
end
|
216
218
|
|
217
219
|
# Return a hash of the options given at invocation, minus the ones that have
|
@@ -42,14 +42,12 @@ module RuboCop
|
|
42
42
|
# Support Windows: Backslashes from command-line -> forward slashes
|
43
43
|
base_dir = base_dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) if File::ALT_SEPARATOR
|
44
44
|
all_files = find_files(base_dir, File::FNM_DOTMATCH)
|
45
|
-
# use file.include? for performance optimization
|
46
|
-
hidden_files = all_files.select { |file| file.include?(HIDDEN_PATH_SUBSTRING) }.sort
|
47
45
|
base_dir_config = @config_store.for(base_dir)
|
48
46
|
|
49
|
-
target_files = if
|
47
|
+
target_files = if hidden_path?(base_dir)
|
50
48
|
all_files.select { |file| ruby_file?(file) }
|
51
49
|
else
|
52
|
-
all_files.select { |file| to_inspect?(file,
|
50
|
+
all_files.select { |file| to_inspect?(file, base_dir_config) }
|
53
51
|
end
|
54
52
|
|
55
53
|
target_files.sort_by!(&order)
|
@@ -74,18 +72,20 @@ module RuboCop
|
|
74
72
|
|
75
73
|
private
|
76
74
|
|
77
|
-
def to_inspect?(file,
|
75
|
+
def to_inspect?(file, base_dir_config)
|
78
76
|
return false if base_dir_config.file_to_exclude?(file)
|
79
|
-
return true if !
|
80
|
-
file <=> hidden_file
|
81
|
-
end && ruby_file?(file)
|
77
|
+
return true if !hidden_path?(file) && ruby_file?(file)
|
82
78
|
|
83
79
|
base_dir_config.file_to_include?(file)
|
84
80
|
end
|
85
81
|
|
82
|
+
def hidden_path?(path)
|
83
|
+
path.include?(HIDDEN_PATH_SUBSTRING)
|
84
|
+
end
|
85
|
+
|
86
86
|
def wanted_dir_patterns(base_dir, exclude_pattern, flags)
|
87
87
|
# Escape glob characters in base_dir to avoid unwanted behavior.
|
88
|
-
base_dir = base_dir.gsub(/[
|
88
|
+
base_dir = base_dir.gsub(/[\\{}\[\]*?]/) do |reserved_glob_character|
|
89
89
|
"\\#{reserved_glob_character}"
|
90
90
|
end
|
91
91
|
|
data/lib/rubocop/version.rb
CHANGED
metadata
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.80.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
8
8
|
- Jonas Arvidsson
|
9
9
|
- Yuji Nakayama
|
10
|
-
autorequire:
|
11
10
|
bindir: exe
|
12
11
|
cert_chain: []
|
13
|
-
date: 2025-
|
12
|
+
date: 2025-08-22 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: json
|
@@ -1091,12 +1090,11 @@ licenses:
|
|
1091
1090
|
- MIT
|
1092
1091
|
metadata:
|
1093
1092
|
homepage_uri: https://rubocop.org/
|
1094
|
-
changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.
|
1093
|
+
changelog_uri: https://github.com/rubocop/rubocop/releases/tag/v1.80.0
|
1095
1094
|
source_code_uri: https://github.com/rubocop/rubocop/
|
1096
|
-
documentation_uri: https://docs.rubocop.org/rubocop/1.
|
1095
|
+
documentation_uri: https://docs.rubocop.org/rubocop/1.80/
|
1097
1096
|
bug_tracker_uri: https://github.com/rubocop/rubocop/issues
|
1098
1097
|
rubygems_mfa_required: 'true'
|
1099
|
-
post_install_message:
|
1100
1098
|
rdoc_options: []
|
1101
1099
|
require_paths:
|
1102
1100
|
- lib
|
@@ -1111,8 +1109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
1111
1109
|
- !ruby/object:Gem::Version
|
1112
1110
|
version: '0'
|
1113
1111
|
requirements: []
|
1114
|
-
rubygems_version: 3.
|
1115
|
-
signing_key:
|
1112
|
+
rubygems_version: 3.6.2
|
1116
1113
|
specification_version: 4
|
1117
1114
|
summary: Automatic Ruby code style checking tool.
|
1118
1115
|
test_files: []
|