rubocop 1.77.0 → 1.79.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 +36 -20
- data/lib/rubocop/cli.rb +12 -1
- data/lib/rubocop/config_loader.rb +1 -38
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +99 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
- data/lib/rubocop/cop/lint/literal_as_condition.rb +3 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/naming/method_name.rb +102 -13
- data/lib/rubocop/cop/naming/predicate_method.rb +27 -2
- data/lib/rubocop/cop/security/eval.rb +2 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/array_intersect.rb +51 -23
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/exponential_notation.rb +1 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +8 -9
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +3 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -0
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +30 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +16 -7
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/server/cache.rb +4 -2
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +23 -6
@@ -5,12 +5,13 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# In Ruby 3.1, `Array#intersect?` has been added.
|
7
7
|
#
|
8
|
-
# This cop identifies places where
|
9
|
-
#
|
10
|
-
# `array1.
|
8
|
+
# This cop identifies places where:
|
9
|
+
# * `(array1 & array2).any?`
|
10
|
+
# * `(array1.intersection(array2)).any?`
|
11
|
+
# * `array1.any? { |elem| array2.member?(elem) }`
|
12
|
+
# can be replaced with `array1.intersect?(array2)`.
|
11
13
|
#
|
12
|
-
#
|
13
|
-
# `(array1 & array2).any?` and is more readable.
|
14
|
+
# `array1.intersect?(array2)` is faster and more readable.
|
14
15
|
#
|
15
16
|
# In cases like the following, compatibility is not ensured,
|
16
17
|
# so it will not be detected when using block argument.
|
@@ -40,6 +41,10 @@ module RuboCop
|
|
40
41
|
# array1.intersection(array2).empty?
|
41
42
|
# array1.intersection(array2).none?
|
42
43
|
#
|
44
|
+
# # bad
|
45
|
+
# array1.any? { |elem| array2.member?(elem) }
|
46
|
+
# array1.none? { |elem| array2.member?(elem) }
|
47
|
+
#
|
43
48
|
# # good
|
44
49
|
# array1.intersect?(array2)
|
45
50
|
# !array1.intersect?(array2)
|
@@ -77,8 +82,26 @@ module RuboCop
|
|
77
82
|
)
|
78
83
|
PATTERN
|
79
84
|
|
80
|
-
|
81
|
-
|
85
|
+
# @!method any_none_block_intersection(node)
|
86
|
+
def_node_matcher :any_none_block_intersection, <<~PATTERN
|
87
|
+
{
|
88
|
+
(block
|
89
|
+
(call $_receiver ${:any? :none?})
|
90
|
+
(args (arg _key))
|
91
|
+
(send $_argument :member? (lvar _key))
|
92
|
+
)
|
93
|
+
(numblock
|
94
|
+
(call $_receiver ${:any? :none?}) 1
|
95
|
+
(send $_argument :member? (lvar :_1))
|
96
|
+
)
|
97
|
+
(itblock
|
98
|
+
(call $_receiver ${:any? :none?}) :it
|
99
|
+
(send $_argument :member? (lvar :it))
|
100
|
+
)
|
101
|
+
}
|
102
|
+
PATTERN
|
103
|
+
|
104
|
+
MSG = 'Use `%<replacement>s` instead of `%<existing>s`.'
|
82
105
|
STRAIGHT_METHODS = %i[present? any?].freeze
|
83
106
|
NEGATED_METHODS = %i[blank? empty? none?].freeze
|
84
107
|
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
@@ -88,16 +111,25 @@ module RuboCop
|
|
88
111
|
return unless (receiver, argument, method_name = bad_intersection?(node))
|
89
112
|
|
90
113
|
dot = node.loc.dot.source
|
91
|
-
|
114
|
+
bang = straight?(method_name) ? '' : '!'
|
115
|
+
replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
|
92
116
|
|
93
|
-
|
94
|
-
bang = straight?(method_name) ? '' : '!'
|
95
|
-
|
96
|
-
corrector.replace(node, "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})")
|
97
|
-
end
|
117
|
+
register_offense(node, replacement)
|
98
118
|
end
|
99
119
|
alias on_csend on_send
|
100
120
|
|
121
|
+
def on_block(node)
|
122
|
+
return unless (receiver, method_name, argument = any_none_block_intersection(node))
|
123
|
+
|
124
|
+
dot = node.send_node.loc.dot.source
|
125
|
+
bang = method_name == :any? ? '' : '!'
|
126
|
+
replacement = "#{bang}#{receiver.source}#{dot}intersect?(#{argument.source})"
|
127
|
+
|
128
|
+
register_offense(node, replacement)
|
129
|
+
end
|
130
|
+
alias on_numblock on_block
|
131
|
+
alias on_itblock on_block
|
132
|
+
|
101
133
|
private
|
102
134
|
|
103
135
|
def bad_intersection?(node)
|
@@ -114,16 +146,12 @@ module RuboCop
|
|
114
146
|
STRAIGHT_METHODS.include?(method_name.to_sym)
|
115
147
|
end
|
116
148
|
|
117
|
-
def
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
argument: argument,
|
124
|
-
dot: dot,
|
125
|
-
existing: existing
|
126
|
-
)
|
149
|
+
def register_offense(node, replacement)
|
150
|
+
message = format(MSG, replacement: replacement, existing: node.source)
|
151
|
+
|
152
|
+
add_offense(node, message: message) do |corrector|
|
153
|
+
corrector.replace(node, replacement)
|
154
|
+
end
|
127
155
|
end
|
128
156
|
end
|
129
157
|
end
|
@@ -111,7 +111,7 @@ module RuboCop
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
#
|
114
|
+
# Checks for `if` and `case` statements where each branch is used for
|
115
115
|
# both the assignment and comparison of the same variable
|
116
116
|
# when using the return of the condition can be used instead.
|
117
117
|
#
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for chained `dig` calls that can be collapsed into a single `dig`.
|
7
7
|
#
|
8
8
|
# @safety
|
9
9
|
# This cop is unsafe because it cannot be guaranteed that the receiver
|
@@ -44,10 +44,10 @@ module RuboCop
|
|
44
44
|
class HashConversion < Base
|
45
45
|
extend AutoCorrector
|
46
46
|
|
47
|
-
MSG_TO_H = 'Prefer ary.to_h to Hash[ary]
|
48
|
-
MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to Hash[arg1, arg2, ...]
|
49
|
-
MSG_LITERAL_HASH_ARG = 'Prefer literal hash to Hash[key: value, ...]
|
50
|
-
MSG_SPLAT = 'Prefer array_of_pairs.to_h to Hash[*array]
|
47
|
+
MSG_TO_H = 'Prefer `ary.to_h` to `Hash[ary]`.'
|
48
|
+
MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to `Hash[arg1, arg2, ...]`.'
|
49
|
+
MSG_LITERAL_HASH_ARG = 'Prefer literal hash to `Hash[key: value, ...]`.'
|
50
|
+
MSG_SPLAT = 'Prefer `array_of_pairs.to_h` to `Hash[*array]`.'
|
51
51
|
RESTRICT_ON_SEND = %i[[]].freeze
|
52
52
|
|
53
53
|
# @!method hash_from_array?(node)
|
@@ -64,11 +64,11 @@ module RuboCop
|
|
64
64
|
# Hash[a1, a2, a3, a4] => {a1 => a2, a3 => a4}
|
65
65
|
# ...but don't suggest correction if there is odd number of them (it is a bug)
|
66
66
|
node.arguments.one? ? single_argument(node) : multi_argument(node)
|
67
|
+
ignore_node(node)
|
67
68
|
end
|
68
69
|
|
69
70
|
private
|
70
71
|
|
71
|
-
# rubocop:disable Metrics/MethodLength
|
72
72
|
def single_argument(node)
|
73
73
|
first_argument = node.first_argument
|
74
74
|
if first_argument.hash_type?
|
@@ -83,11 +83,8 @@ module RuboCop
|
|
83
83
|
replacement = "(#{replacement})" if requires_parens?(first_argument)
|
84
84
|
corrector.replace(node, "#{replacement}.to_h")
|
85
85
|
end
|
86
|
-
|
87
|
-
ignore_node(node)
|
88
86
|
end
|
89
87
|
end
|
90
|
-
# rubocop:enable Metrics/MethodLength
|
91
88
|
|
92
89
|
def use_zip_method_without_argument?(first_argument)
|
93
90
|
return false unless first_argument&.send_type?
|
@@ -131,7 +128,9 @@ module RuboCop
|
|
131
128
|
corrector.replace(node, args_to_hash(node.arguments))
|
132
129
|
|
133
130
|
parent = node.parent
|
134
|
-
|
131
|
+
if parent&.send_type? && !parent.method?(:to_h) && !parent.parenthesized?
|
132
|
+
add_parentheses(parent, corrector)
|
133
|
+
end
|
135
134
|
end
|
136
135
|
end
|
137
136
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for usages of not (`not` or `!`) called on a method
|
7
7
|
# when an inverse of that method can be used instead.
|
8
8
|
#
|
9
9
|
# Methods that can be inverted by a not (`not` or `!`) should be defined
|
@@ -3,33 +3,90 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks for
|
6
|
+
# Checks for local variables and method parameters named `it`,
|
7
7
|
# where `it` can refer to the first anonymous parameter as of Ruby 3.4.
|
8
|
+
# Use a meaningful variable name instead.
|
8
9
|
#
|
9
|
-
# Although Ruby allows reassigning `it` in these cases, it could
|
10
|
+
# NOTE: Although Ruby allows reassigning `it` in these cases, it could
|
10
11
|
# cause confusion if `it` is used as a block parameter elsewhere.
|
11
|
-
# For consistency, this also applies to numblocks and blocks with
|
12
|
-
# parameters, even though `it` cannot be used in those cases.
|
13
12
|
#
|
14
13
|
# @example
|
15
14
|
# # bad
|
16
|
-
#
|
17
|
-
# foo { |bar| it = bar }
|
18
|
-
# foo { it = _2 }
|
15
|
+
# it = 5
|
19
16
|
#
|
20
|
-
# # good
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
17
|
+
# # good
|
18
|
+
# var = 5
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# def foo(it)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# def foo(arg)
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # bad
|
29
|
+
# def foo(it = 5)
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# def foo(arg = 5)
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# # bad
|
37
|
+
# def foo(*it)
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# def foo(*args)
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# # bad
|
45
|
+
# def foo(it:)
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# # good
|
49
|
+
# def foo(arg:)
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# # bad
|
53
|
+
# def foo(it: 5)
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# def foo(arg: 5)
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# # bad
|
61
|
+
# def foo(**it)
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# # good
|
65
|
+
# def foo(**kwargs)
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# # bad
|
69
|
+
# def foo(&it)
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# # good
|
73
|
+
# def foo(&block)
|
74
|
+
# end
|
24
75
|
class ItAssignment < Base
|
25
76
|
MSG = '`it` is the default block parameter; consider another name.'
|
26
77
|
|
27
78
|
def on_lvasgn(node)
|
28
79
|
return unless node.name == :it
|
29
|
-
return unless node.each_ancestor(:any_block).any?
|
30
80
|
|
31
81
|
add_offense(node.loc.name)
|
32
82
|
end
|
83
|
+
alias on_arg on_lvasgn
|
84
|
+
alias on_optarg on_lvasgn
|
85
|
+
alias on_restarg on_lvasgn
|
86
|
+
alias on_blockarg on_lvasgn
|
87
|
+
alias on_kwarg on_lvasgn
|
88
|
+
alias on_kwoptarg on_lvasgn
|
89
|
+
alias on_kwrestarg on_lvasgn
|
33
90
|
end
|
34
91
|
end
|
35
92
|
end
|
@@ -109,7 +109,9 @@ module RuboCop
|
|
109
109
|
private
|
110
110
|
|
111
111
|
def find_block_variables(node, block_argument_name)
|
112
|
-
node.
|
112
|
+
return [] unless node.body
|
113
|
+
|
114
|
+
node.body.each_descendant(:lvar).select do |descendant|
|
113
115
|
descendant.source == block_argument_name
|
114
116
|
end
|
115
117
|
end
|
@@ -222,11 +222,9 @@ module RuboCop
|
|
222
222
|
end
|
223
223
|
|
224
224
|
def unary_literal?(node)
|
225
|
-
|
226
|
-
return node.source.match?(/\A[+-]/) if node.complex_type?
|
225
|
+
return true if node.numeric_type? && node.sign?
|
227
226
|
|
228
|
-
|
229
|
-
(node.parent&.send_type? && node.parent.unary_operation?)
|
227
|
+
node.parent&.send_type? && node.parent.unary_operation?
|
230
228
|
end
|
231
229
|
|
232
230
|
def assigned_before?(node, target)
|
@@ -132,6 +132,22 @@ module RuboCop
|
|
132
132
|
# bar :baz
|
133
133
|
# end
|
134
134
|
#
|
135
|
+
# @example AllowedMethods: ["puts", "print"]
|
136
|
+
#
|
137
|
+
# # good
|
138
|
+
# puts "Hello world"
|
139
|
+
# print "Hello world"
|
140
|
+
# # still enforces parentheses on other methods
|
141
|
+
# array.delete(e)
|
142
|
+
#
|
143
|
+
# @example AllowedPatterns: ["^assert"]
|
144
|
+
#
|
145
|
+
# # good
|
146
|
+
# assert_equal 'test', x
|
147
|
+
# assert_match(/foo/, bar)
|
148
|
+
# # still enforces parentheses on other methods
|
149
|
+
# array.delete(e)
|
150
|
+
#
|
135
151
|
# @example AllowParenthesesInMultilineCall: false (default)
|
136
152
|
#
|
137
153
|
# # bad
|
@@ -29,6 +29,8 @@ module RuboCop
|
|
29
29
|
MSG = 'Do not use parallel assignment.'
|
30
30
|
|
31
31
|
def on_masgn(node) # rubocop:disable Metrics/AbcSize
|
32
|
+
return if part_of_ignored_node?(node)
|
33
|
+
|
32
34
|
rhs = node.rhs
|
33
35
|
rhs = rhs.body if rhs.rescue_type?
|
34
36
|
rhs_elements = Array(rhs).compact # edge case for one constant
|
@@ -41,6 +43,7 @@ module RuboCop
|
|
41
43
|
add_offense(range) do |corrector|
|
42
44
|
autocorrect(corrector, node, rhs)
|
43
45
|
end
|
46
|
+
ignore_node(node)
|
44
47
|
end
|
45
48
|
|
46
49
|
private
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
49
49
|
(block
|
50
50
|
$(call _ :fetch _)
|
51
51
|
(args)
|
52
|
-
${nil?
|
52
|
+
${nil? basic_literal? const_type?})
|
53
53
|
PATTERN
|
54
54
|
|
55
55
|
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
@@ -71,14 +71,6 @@ module RuboCop
|
|
71
71
|
|
72
72
|
private
|
73
73
|
|
74
|
-
def basic_literal?(node)
|
75
|
-
node&.basic_literal?
|
76
|
-
end
|
77
|
-
|
78
|
-
def const_type?(node)
|
79
|
-
node&.const_type?
|
80
|
-
end
|
81
|
-
|
82
74
|
def should_not_check?(send, body)
|
83
75
|
(body&.const_type? && !check_for_constant?) ||
|
84
76
|
(body&.str_type? && !check_for_string?) ||
|
@@ -169,6 +169,7 @@ module RuboCop
|
|
169
169
|
end
|
170
170
|
return 'an interpolated expression' if interpolation?(begin_node)
|
171
171
|
return 'a method argument' if argument_of_parenthesized_method_call?(begin_node, node)
|
172
|
+
return 'a one-line rescue' if !begin_node.parent&.call_type? && node.rescue_type?
|
172
173
|
|
173
174
|
return if begin_node.chained?
|
174
175
|
|
@@ -65,7 +65,7 @@ module RuboCop
|
|
65
65
|
return false if target_ruby_version < 3.0
|
66
66
|
return false if disallow_endless_method_style?
|
67
67
|
return false unless body_node
|
68
|
-
return false if body_node.parent.assignment_method? ||
|
68
|
+
return false if body_node.basic_conditional? || body_node.parent.assignment_method? ||
|
69
69
|
NOT_SUPPORTED_ENDLESS_METHOD_BODY_TYPES.include?(body_node.type)
|
70
70
|
|
71
71
|
!body_node.type?(:begin, :kwbegin)
|
@@ -86,10 +86,10 @@ module RuboCop
|
|
86
86
|
end
|
87
87
|
|
88
88
|
def correct_to_endless(corrector, node)
|
89
|
-
|
89
|
+
receiver = "#{node.receiver.source}." if node.receiver
|
90
90
|
arguments = node.arguments.any? ? node.arguments.source : '()'
|
91
91
|
body_source = method_body_source(node.body)
|
92
|
-
replacement = "def #{
|
92
|
+
replacement = "def #{receiver}#{node.method_name}#{arguments} = #{body_source}"
|
93
93
|
|
94
94
|
corrector.replace(node, replacement)
|
95
95
|
end
|
@@ -130,7 +130,10 @@ module RuboCop
|
|
130
130
|
end
|
131
131
|
|
132
132
|
def require_parentheses?(method_body)
|
133
|
-
|
133
|
+
return false unless method_body.send_type?
|
134
|
+
return false if method_body.arithmetic_operation?
|
135
|
+
|
136
|
+
!method_body.arguments.empty? && !method_body.comparison_method?
|
134
137
|
end
|
135
138
|
|
136
139
|
def disallow_endless_method_style?
|
@@ -175,6 +175,8 @@ module RuboCop
|
|
175
175
|
|
176
176
|
if parenthesize_method?(condition)
|
177
177
|
parenthesized_method_arguments(condition)
|
178
|
+
elsif condition.and_type?
|
179
|
+
parenthesized_and(condition)
|
178
180
|
else
|
179
181
|
"(#{condition.source})"
|
180
182
|
end
|
@@ -186,12 +188,19 @@ module RuboCop
|
|
186
188
|
end
|
187
189
|
|
188
190
|
def add_parentheses?(node)
|
189
|
-
return true if node.assignment? ||
|
191
|
+
return true if node.assignment? || node.or_type?
|
192
|
+
return true if assignment_in_and?(node)
|
190
193
|
return false unless node.call_type?
|
191
194
|
|
192
195
|
(node.arguments.any? && !node.parenthesized?) || node.prefix_not?
|
193
196
|
end
|
194
197
|
|
198
|
+
def assignment_in_and?(node)
|
199
|
+
return false unless node.and_type?
|
200
|
+
|
201
|
+
node.each_descendant.any?(&:assignment?)
|
202
|
+
end
|
203
|
+
|
195
204
|
def parenthesized_method_arguments(node)
|
196
205
|
method_call = node.source_range.begin.join(node.loc.selector.end).source
|
197
206
|
arguments = node.first_argument.source_range.begin.join(node.source_range.end).source
|
@@ -199,6 +208,26 @@ module RuboCop
|
|
199
208
|
"#{method_call}(#{arguments})"
|
200
209
|
end
|
201
210
|
|
211
|
+
def parenthesized_and(node)
|
212
|
+
# We only need to add parentheses around the last clause if it's an assignment,
|
213
|
+
# because other clauses will be unchanged by merging conditionals.
|
214
|
+
lhs = node.lhs.source
|
215
|
+
rhs = parenthesized_and_clause(node.rhs)
|
216
|
+
operator = range_with_surrounding_space(node.loc.operator, whitespace: true).source
|
217
|
+
|
218
|
+
"#{lhs}#{operator}#{rhs}"
|
219
|
+
end
|
220
|
+
|
221
|
+
def parenthesized_and_clause(node)
|
222
|
+
if node.and_type?
|
223
|
+
parenthesized_and(node)
|
224
|
+
elsif node.assignment?
|
225
|
+
"(#{node.source})"
|
226
|
+
else
|
227
|
+
node.source
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
202
231
|
def allow_modifier?
|
203
232
|
cop_config['AllowModifier']
|
204
233
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for parentheses around stabby lambda arguments.
|
7
7
|
# There are two different styles. Defaults to `require_parentheses`.
|
8
8
|
#
|
9
9
|
# @example EnforcedStyle: require_parentheses (default)
|
@@ -296,7 +296,7 @@ module RuboCop
|
|
296
296
|
variable_table.accessible_variables.each { |variable| variable.reference!(node) }
|
297
297
|
end
|
298
298
|
|
299
|
-
# Mark
|
299
|
+
# Mark last assignments which are referenced in the same loop
|
300
300
|
# as referenced by ignoring AST order since they would be referenced
|
301
301
|
# in next iteration.
|
302
302
|
def mark_assignments_as_referenced_in_loop(node)
|
@@ -308,13 +308,12 @@ module RuboCop
|
|
308
308
|
# would be skipped here.
|
309
309
|
next unless variable
|
310
310
|
|
311
|
-
variable.assignments.
|
312
|
-
|
313
|
-
assignment_node.equal?(assignment.node)
|
314
|
-
end
|
315
|
-
|
316
|
-
assignment.reference!(node)
|
311
|
+
loop_assignments = variable.assignments.select do |assignment|
|
312
|
+
assignment_nodes_in_loop.include?(assignment.node)
|
317
313
|
end
|
314
|
+
next unless loop_assignments.any?
|
315
|
+
|
316
|
+
reference_assignments(loop_assignments, node)
|
318
317
|
end
|
319
318
|
end
|
320
319
|
|
@@ -354,6 +353,16 @@ module RuboCop
|
|
354
353
|
end
|
355
354
|
end
|
356
355
|
|
356
|
+
def reference_assignments(loop_assignments, node)
|
357
|
+
# If inside a case statement, mark all as referenced.
|
358
|
+
# Otherwise, mark only the last assignment as referenced.
|
359
|
+
if loop_assignments.first.node.each_ancestor(:case, :case_match).any?
|
360
|
+
loop_assignments.each { |assignment| assignment.reference!(node) }
|
361
|
+
else
|
362
|
+
loop_assignments.last&.reference!(node)
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
357
366
|
def scanned_node?(node)
|
358
367
|
scanned_nodes.include?(node)
|
359
368
|
end
|
@@ -7,6 +7,7 @@ require 'yard'
|
|
7
7
|
# @api private
|
8
8
|
class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
9
9
|
include ::RuboCop::Cop::Documentation
|
10
|
+
|
10
11
|
CopData = Struct.new(
|
11
12
|
:cop, :description, :example_objects, :safety_objects, :see_objects, :config, keyword_init: true
|
12
13
|
)
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
# Reports information about pending cops that are not explicitly configured.
|
5
|
+
#
|
6
|
+
# This class is responsible for displaying warnings when new cops have been added to RuboCop
|
7
|
+
# but have not yet been enabled or disabled in the user's configuration.
|
8
|
+
# It provides a centralized way to determine whether such warnings should be shown,
|
9
|
+
# based on global flags or configuration settings.
|
10
|
+
class PendingCopsReporter
|
11
|
+
class << self
|
12
|
+
PENDING_BANNER = <<~BANNER
|
13
|
+
The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.
|
14
|
+
|
15
|
+
Please also note that you can opt-in to new cops by default by adding this to your config:
|
16
|
+
AllCops:
|
17
|
+
NewCops: enable
|
18
|
+
BANNER
|
19
|
+
|
20
|
+
attr_accessor :disable_pending_cops, :enable_pending_cops
|
21
|
+
|
22
|
+
def warn_if_needed(config)
|
23
|
+
return if possible_new_cops?(config)
|
24
|
+
|
25
|
+
pending_cops = pending_cops_only_qualified(config.pending_cops)
|
26
|
+
warn_on_pending_cops(pending_cops) unless pending_cops.empty?
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def pending_cops_only_qualified(pending_cops)
|
32
|
+
pending_cops.select { |cop| Cop::Registry.qualified_cop?(cop.name) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def possible_new_cops?(config)
|
36
|
+
disable_pending_cops || enable_pending_cops ||
|
37
|
+
config.disabled_new_cops? || config.enabled_new_cops?
|
38
|
+
end
|
39
|
+
|
40
|
+
def warn_on_pending_cops(pending_cops)
|
41
|
+
warn Rainbow(PENDING_BANNER).yellow
|
42
|
+
|
43
|
+
pending_cops.each { |cop| warn_pending_cop cop }
|
44
|
+
|
45
|
+
warn Rainbow('For more information: https://docs.rubocop.org/rubocop/versioning.html').yellow
|
46
|
+
end
|
47
|
+
|
48
|
+
def warn_pending_cop(cop)
|
49
|
+
version = cop.metadata['VersionAdded'] || 'N/A'
|
50
|
+
|
51
|
+
warn Rainbow("#{cop.name}: # new in #{version}").yellow
|
52
|
+
warn Rainbow(' Enabled: true').yellow
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|