rubocop 1.76.2 → 1.78.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 +23 -1
- data/lib/rubocop/cli.rb +12 -1
- data/lib/rubocop/config_loader.rb +1 -38
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
- data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +26 -5
- data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
- data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
- data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -3
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +25 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +8 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/method_name.rb +87 -12
- data/lib/rubocop/cop/naming/predicate_method.rb +64 -6
- data/lib/rubocop/cop/naming/predicate_prefix.rb +2 -2
- data/lib/rubocop/cop/security/eval.rb +2 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/exponential_notation.rb +2 -2
- data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
- data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +11 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -1
- data/lib/rubocop/cop/style/redundant_self.rb +3 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +4 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/lsp/diagnostic.rb +4 -4
- 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
- data/lib/ruby_lsp/rubocop/addon.rb +2 -2
- metadata +7 -4
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Prefer `Enumerable` predicate methods over expressions with `count`.
|
7
|
+
#
|
8
|
+
# The cop checks calls to `count` without arguments, or with a
|
9
|
+
# block. It doesn't register offenses for `count` with a positional
|
10
|
+
# argument because its behavior differs from predicate methods (`count`
|
11
|
+
# matches the argument using `==`, while `any?`, `none?` and `one?` use
|
12
|
+
# `===`).
|
13
|
+
#
|
14
|
+
# NOTE: This cop doesn't check `length` and `size` methods because they
|
15
|
+
# would yield false positives. For example, `String` implements `length`
|
16
|
+
# and `size`, but it doesn't include `Enumerable`.
|
17
|
+
#
|
18
|
+
# @safety
|
19
|
+
# The cop is unsafe because receiver might not include `Enumerable`, or
|
20
|
+
# it has nonstandard implementation of `count` or any replacement
|
21
|
+
# methods.
|
22
|
+
#
|
23
|
+
# It's also unsafe because for collections with falsey values, expressions
|
24
|
+
# with `count` without a block return a different result than methods `any?`,
|
25
|
+
# `none?` and `one?`:
|
26
|
+
#
|
27
|
+
# [source,ruby]
|
28
|
+
# ----
|
29
|
+
# [nil, false].count.positive?
|
30
|
+
# [nil].count == 1
|
31
|
+
# # => true
|
32
|
+
#
|
33
|
+
# [nil, false].any?
|
34
|
+
# [nil].one?
|
35
|
+
# # => false
|
36
|
+
#
|
37
|
+
# [nil].count == 0
|
38
|
+
# # => false
|
39
|
+
#
|
40
|
+
# [nil].none?
|
41
|
+
# # => true
|
42
|
+
# ----
|
43
|
+
#
|
44
|
+
# Autocorrection is unsafe when replacement methods don't iterate over
|
45
|
+
# every element in collection and the given block runs side effects:
|
46
|
+
#
|
47
|
+
# [source,ruby]
|
48
|
+
# ----
|
49
|
+
# x.count(&:method_with_side_effects).positive?
|
50
|
+
# # calls `method_with_side_effects` on every element
|
51
|
+
#
|
52
|
+
# x.any?(&:method_with_side_effects)
|
53
|
+
# # calls `method_with_side_effects` until first element returns a truthy value
|
54
|
+
# ----
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
#
|
58
|
+
# # bad
|
59
|
+
# x.count.positive?
|
60
|
+
# x.count > 0
|
61
|
+
# x.count != 0
|
62
|
+
#
|
63
|
+
# x.count(&:foo?).positive?
|
64
|
+
# x.count { |item| item.foo? }.positive?
|
65
|
+
#
|
66
|
+
# # good
|
67
|
+
# x.any?
|
68
|
+
#
|
69
|
+
# x.any?(&:foo?)
|
70
|
+
# x.any? { |item| item.foo? }
|
71
|
+
#
|
72
|
+
# # bad
|
73
|
+
# x.count.zero?
|
74
|
+
# x.count == 0
|
75
|
+
#
|
76
|
+
# # good
|
77
|
+
# x.none?
|
78
|
+
#
|
79
|
+
# # bad
|
80
|
+
# x.count == 1
|
81
|
+
# x.one?
|
82
|
+
#
|
83
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
84
|
+
#
|
85
|
+
# # good
|
86
|
+
# x.count > 1
|
87
|
+
#
|
88
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
89
|
+
#
|
90
|
+
# # bad
|
91
|
+
# x.count > 1
|
92
|
+
#
|
93
|
+
# # good
|
94
|
+
# x.many?
|
95
|
+
#
|
96
|
+
class CollectionQuerying < Base
|
97
|
+
include RangeHelp
|
98
|
+
extend AutoCorrector
|
99
|
+
|
100
|
+
MSG = 'Use `%<prefer>s` instead.'
|
101
|
+
|
102
|
+
RESTRICT_ON_SEND = %i[positive? > != zero? ==].freeze
|
103
|
+
|
104
|
+
REPLACEMENTS = {
|
105
|
+
[:positive?, nil] => :any?,
|
106
|
+
[:>, 0] => :any?,
|
107
|
+
[:!=, 0] => :any?,
|
108
|
+
[:zero?, nil] => :none?,
|
109
|
+
[:==, 0] => :none?,
|
110
|
+
[:==, 1] => :one?,
|
111
|
+
[:>, 1] => :many?
|
112
|
+
}.freeze
|
113
|
+
|
114
|
+
# @!method count_predicate(node)
|
115
|
+
def_node_matcher :count_predicate, <<~PATTERN
|
116
|
+
(send
|
117
|
+
{
|
118
|
+
(any_block $(call !nil? :count) _ _)
|
119
|
+
$(call !nil? :count (block-pass _)?)
|
120
|
+
}
|
121
|
+
{
|
122
|
+
:positive? |
|
123
|
+
:> (int 0) |
|
124
|
+
:!= (int 0) |
|
125
|
+
:zero? |
|
126
|
+
:== (int 0) |
|
127
|
+
:== (int 1) |
|
128
|
+
:> (int 1)
|
129
|
+
})
|
130
|
+
PATTERN
|
131
|
+
|
132
|
+
def on_send(node)
|
133
|
+
return unless (count_node = count_predicate(node))
|
134
|
+
|
135
|
+
replacement_method = replacement_method(node)
|
136
|
+
|
137
|
+
return unless replacement_supported?(replacement_method)
|
138
|
+
|
139
|
+
offense_range = count_node.loc.selector.join(node.source_range.end)
|
140
|
+
add_offense(offense_range,
|
141
|
+
message: format(MSG, prefer: replacement_method)) do |corrector|
|
142
|
+
corrector.replace(count_node.loc.selector, replacement_method)
|
143
|
+
corrector.remove(removal_range(node))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def replacement_method(node)
|
150
|
+
REPLACEMENTS.fetch([node.method_name, node.first_argument&.value])
|
151
|
+
end
|
152
|
+
|
153
|
+
def replacement_supported?(method_name)
|
154
|
+
return true if active_support_extensions_enabled?
|
155
|
+
|
156
|
+
method_name != :many?
|
157
|
+
end
|
158
|
+
|
159
|
+
def removal_range(node)
|
160
|
+
range = (node.loc.dot || node.loc.selector).join(node.source_range.end)
|
161
|
+
|
162
|
+
range_with_surrounding_space(range, side: :left)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -87,7 +87,7 @@ module RuboCop
|
|
87
87
|
true
|
88
88
|
end
|
89
89
|
|
90
|
-
def integral(node)
|
90
|
+
def integral?(node)
|
91
91
|
mantissa, = node.source.split('e')
|
92
92
|
/^-?[1-9](\d*[1-9])?$/.match?(mantissa)
|
93
93
|
end
|
@@ -101,7 +101,7 @@ module RuboCop
|
|
101
101
|
when :engineering
|
102
102
|
!engineering?(node)
|
103
103
|
when :integral
|
104
|
-
!integral(node)
|
104
|
+
!integral?(node)
|
105
105
|
else
|
106
106
|
false
|
107
107
|
end
|
@@ -9,7 +9,20 @@ module RuboCop
|
|
9
9
|
# On the other hand, `ENV.fetch` raises `KeyError` or returns the explicitly
|
10
10
|
# specified default value.
|
11
11
|
#
|
12
|
-
# @example
|
12
|
+
# @example DefaultToNil: true (default)
|
13
|
+
# # bad
|
14
|
+
# ENV['X']
|
15
|
+
# x = ENV['X']
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# ENV.fetch('X', nil)
|
19
|
+
# x = ENV.fetch('X', nil)
|
20
|
+
#
|
21
|
+
# # also good
|
22
|
+
# !ENV['X']
|
23
|
+
# ENV['X'].some_method # (e.g. `.nil?`)
|
24
|
+
#
|
25
|
+
# @example DefaultToNil: false
|
13
26
|
# # bad
|
14
27
|
# ENV['X']
|
15
28
|
# x = ENV['X']
|
@@ -25,7 +38,8 @@ module RuboCop
|
|
25
38
|
class FetchEnvVar < Base
|
26
39
|
extend AutoCorrector
|
27
40
|
|
28
|
-
|
41
|
+
MSG_WITH_NIL = 'Use `ENV.fetch(%<key>s, nil)` instead of `ENV[%<key>s]`.'
|
42
|
+
MSG_WITHOUT_NIL = 'Use `ENV.fetch(%<key>s)` instead of `ENV[%<key>s]`.'
|
29
43
|
RESTRICT_ON_SEND = [:[]].freeze
|
30
44
|
|
31
45
|
# @!method env_with_bracket?(node)
|
@@ -37,7 +51,7 @@ module RuboCop
|
|
37
51
|
env_with_bracket?(node) do |name_node|
|
38
52
|
break unless offensive?(node)
|
39
53
|
|
40
|
-
message = format(
|
54
|
+
message = format(offense_message, key: name_node.source)
|
41
55
|
add_offense(node, message: message) do |corrector|
|
42
56
|
corrector.replace(node, new_code(name_node))
|
43
57
|
end
|
@@ -46,6 +60,14 @@ module RuboCop
|
|
46
60
|
|
47
61
|
private
|
48
62
|
|
63
|
+
def default_to_nil?
|
64
|
+
cop_config.fetch('DefaultToNil', true)
|
65
|
+
end
|
66
|
+
|
67
|
+
def offense_message
|
68
|
+
default_to_nil? ? MSG_WITH_NIL : MSG_WITHOUT_NIL
|
69
|
+
end
|
70
|
+
|
49
71
|
def allowed_var?(node)
|
50
72
|
env_key_node = node.children.last
|
51
73
|
env_key_node.str_type? && cop_config['AllowedVars'].include?(env_key_node.value)
|
@@ -53,12 +75,12 @@ module RuboCop
|
|
53
75
|
|
54
76
|
def used_as_flag?(node)
|
55
77
|
return false if node.root?
|
56
|
-
return true if used_if_condition_in_body(node)
|
78
|
+
return true if used_if_condition_in_body?(node)
|
57
79
|
|
58
80
|
node.parent.send_type? && (node.parent.prefix_bang? || node.parent.comparison_method?)
|
59
81
|
end
|
60
82
|
|
61
|
-
def used_if_condition_in_body(node)
|
83
|
+
def used_if_condition_in_body?(node)
|
62
84
|
if_node = node.ancestors.find(&:if_type?)
|
63
85
|
|
64
86
|
return false unless (condition = if_node&.condition)
|
@@ -125,7 +147,11 @@ module RuboCop
|
|
125
147
|
end
|
126
148
|
|
127
149
|
def new_code(name_node)
|
128
|
-
|
150
|
+
if default_to_nil?
|
151
|
+
"ENV.fetch(#{name_node.source}, nil)"
|
152
|
+
else
|
153
|
+
"ENV.fetch(#{name_node.source})"
|
154
|
+
end
|
129
155
|
end
|
130
156
|
end
|
131
157
|
end
|
@@ -44,17 +44,17 @@ 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)
|
54
54
|
def_node_matcher :hash_from_array?, '(send (const {nil? cbase} :Hash) :[] ...)'
|
55
55
|
|
56
56
|
def on_send(node)
|
57
|
-
return
|
57
|
+
return if part_of_ignored_node?(node) || !hash_from_array?(node)
|
58
58
|
|
59
59
|
# There are several cases:
|
60
60
|
# If there is one argument:
|
@@ -63,7 +63,8 @@ module RuboCop
|
|
63
63
|
# If there is 0 or 2+ arguments:
|
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
|
-
node.arguments.
|
66
|
+
node.arguments.one? ? single_argument(node) : multi_argument(node)
|
67
|
+
ignore_node(node)
|
67
68
|
end
|
68
69
|
|
69
70
|
private
|
@@ -111,7 +112,12 @@ module RuboCop
|
|
111
112
|
end
|
112
113
|
|
113
114
|
def requires_parens?(node)
|
114
|
-
|
115
|
+
if node.call_type?
|
116
|
+
return false if node.method?(:[])
|
117
|
+
return true if node.arguments.any? && !node.parenthesized?
|
118
|
+
end
|
119
|
+
|
120
|
+
node.operator_keyword?
|
115
121
|
end
|
116
122
|
|
117
123
|
def multi_argument(node)
|
@@ -122,7 +128,9 @@ module RuboCop
|
|
122
128
|
corrector.replace(node, args_to_hash(node.arguments))
|
123
129
|
|
124
130
|
parent = node.parent
|
125
|
-
|
131
|
+
if parent&.send_type? && !parent.method?(:to_h) && !parent.parenthesized?
|
132
|
+
add_parentheses(parent, corrector)
|
133
|
+
end
|
126
134
|
end
|
127
135
|
end
|
128
136
|
end
|
@@ -223,8 +223,17 @@ module RuboCop
|
|
223
223
|
|
224
224
|
def too_long_line_based_on_allow_uri?(line)
|
225
225
|
if allow_uri?
|
226
|
-
uri_range =
|
227
|
-
return false if uri_range &&
|
226
|
+
uri_range = find_excessive_range(line, :uri)
|
227
|
+
return false if uri_range && allowed_position?(line, uri_range)
|
228
|
+
end
|
229
|
+
|
230
|
+
true
|
231
|
+
end
|
232
|
+
|
233
|
+
def too_long_line_based_on_allow_qualified_name?(line)
|
234
|
+
if allow_qualified_name?
|
235
|
+
namespace_range = find_excessive_range(line, :namespace)
|
236
|
+
return false if namespace_range && allowed_position?(line, namespace_range)
|
228
237
|
end
|
229
238
|
|
230
239
|
true
|
@@ -109,7 +109,7 @@ module RuboCop
|
|
109
109
|
private
|
110
110
|
|
111
111
|
def find_block_variables(node, block_argument_name)
|
112
|
-
node.each_descendant(:lvar).select do |descendant|
|
112
|
+
node.body.each_descendant(:lvar).select do |descendant|
|
113
113
|
descendant.source == block_argument_name
|
114
114
|
end
|
115
115
|
end
|
@@ -251,7 +251,7 @@ module RuboCop
|
|
251
251
|
return false unless (last_argument = node.last_argument)
|
252
252
|
return true if last_argument.forwarded_restarg_type?
|
253
253
|
|
254
|
-
last_argument.hash_type? && last_argument.children.
|
254
|
+
last_argument.hash_type? && last_argument.children.any?(&:forwarded_kwrestarg_type?)
|
255
255
|
end
|
256
256
|
end
|
257
257
|
# rubocop:enable Metrics/ModuleLength, Metrics/CyclomaticComplexity
|
@@ -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
|
@@ -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?) ||
|
@@ -255,7 +255,10 @@ module RuboCop
|
|
255
255
|
end
|
256
256
|
|
257
257
|
def disallowed_one_line_pattern_matching?(begin_node, node)
|
258
|
-
|
258
|
+
if (parent = begin_node.parent)
|
259
|
+
return false if parent.any_def_type? && parent.endless?
|
260
|
+
return false if parent.assignment?
|
261
|
+
end
|
259
262
|
|
260
263
|
node.any_match_pattern_type? && node.each_ancestor.none?(&:operator_keyword?)
|
261
264
|
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?
|
@@ -115,8 +115,9 @@ module RuboCop
|
|
115
115
|
end
|
116
116
|
|
117
117
|
def correct_node(corrector, node)
|
118
|
-
corrector.replace(node.loc.keyword, 'if') if node.unless?
|
118
|
+
corrector.replace(node.loc.keyword, 'if') if node.unless? && !part_of_ignored_node?(node)
|
119
119
|
corrector.replace(node.condition, chainable_condition(node))
|
120
|
+
ignore_node(node)
|
120
121
|
end
|
121
122
|
|
122
123
|
def correct_for_guard_condition_style(corrector, node, if_branch)
|
@@ -270,7 +270,7 @@ module RuboCop
|
|
270
270
|
end
|
271
271
|
|
272
272
|
def allow_if_method_has_argument?(send_node)
|
273
|
-
!!cop_config.fetch('AllowMethodsWithArguments', false) &&
|
273
|
+
!!cop_config.fetch('AllowMethodsWithArguments', false) && send_node.arguments.any?
|
274
274
|
end
|
275
275
|
|
276
276
|
def allow_comments?
|
@@ -79,7 +79,7 @@ module RuboCop
|
|
79
79
|
LanguageServer::Protocol::Interface::CodeDescription.new(href: doc_url)
|
80
80
|
end
|
81
81
|
|
82
|
-
# rubocop:disable
|
82
|
+
# rubocop:disable Metrics/MethodLength
|
83
83
|
def autocorrect_action
|
84
84
|
LanguageServer::Protocol::Interface::CodeAction.new(
|
85
85
|
title: "Autocorrect #{@offense.cop_name}",
|
@@ -98,7 +98,7 @@ module RuboCop
|
|
98
98
|
is_preferred: true
|
99
99
|
)
|
100
100
|
end
|
101
|
-
# rubocop:enable
|
101
|
+
# rubocop:enable Metrics/MethodLength
|
102
102
|
|
103
103
|
# rubocop:disable Metrics/MethodLength
|
104
104
|
def offense_replacements
|
@@ -120,7 +120,7 @@ module RuboCop
|
|
120
120
|
end
|
121
121
|
# rubocop:enable Metrics/MethodLength
|
122
122
|
|
123
|
-
# rubocop:disable
|
123
|
+
# rubocop:disable Metrics/MethodLength
|
124
124
|
def disable_line_action
|
125
125
|
LanguageServer::Protocol::Interface::CodeAction.new(
|
126
126
|
title: "Disable #{@offense.cop_name} for this line",
|
@@ -138,7 +138,7 @@ module RuboCop
|
|
138
138
|
)
|
139
139
|
)
|
140
140
|
end
|
141
|
-
# rubocop:enable
|
141
|
+
# rubocop:enable Metrics/MethodLength
|
142
142
|
|
143
143
|
def line_disable_comment
|
144
144
|
new_text = if @offense.source_line.include?(' # rubocop:disable ')
|
@@ -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
|
data/lib/rubocop/server/cache.rb
CHANGED
@@ -46,12 +46,14 @@ module RuboCop
|
|
46
46
|
end
|
47
47
|
|
48
48
|
# rubocop:disable Metrics/AbcSize
|
49
|
-
def restart_key
|
49
|
+
def restart_key(args_config_file_path: nil)
|
50
50
|
lockfile_path = LOCKFILE_NAMES.map do |lockfile_name|
|
51
51
|
Pathname(project_dir).join(lockfile_name)
|
52
52
|
end.find(&:exist?)
|
53
53
|
version_data = lockfile_path&.read || RuboCop::Version::STRING
|
54
|
-
config_data = Pathname(
|
54
|
+
config_data = Pathname(
|
55
|
+
args_config_file_path || ConfigFinder.find_config_path(Dir.pwd)
|
56
|
+
).read
|
55
57
|
yaml = load_erb_templated_yaml(config_data)
|
56
58
|
|
57
59
|
inherit_from_data = inherit_from_data(yaml)
|
@@ -38,6 +38,16 @@ module RuboCop
|
|
38
38
|
warn 'RuboCop server is not running.' unless running
|
39
39
|
end
|
40
40
|
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
def args_config_file_path
|
44
|
+
first_args_config_key_index = ARGV.index { |value| ['-c', '--config'].include?(value) }
|
45
|
+
|
46
|
+
return if first_args_config_key_index.nil?
|
47
|
+
|
48
|
+
ARGV[first_args_config_key_index + 1]
|
49
|
+
end
|
50
|
+
end
|
41
51
|
end
|
42
52
|
end
|
43
53
|
end
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
exit 0
|
35
35
|
end
|
36
36
|
|
37
|
-
|
37
|
+
write_version_file
|
38
38
|
|
39
39
|
host = ENV.fetch('RUBOCOP_SERVER_HOST', '127.0.0.1')
|
40
40
|
port = ENV.fetch('RUBOCOP_SERVER_PORT', 0)
|
@@ -42,6 +42,16 @@ module RuboCop
|
|
42
42
|
Server::Core.new.start(host, port, detach: @detach)
|
43
43
|
end
|
44
44
|
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def write_version_file
|
49
|
+
Cache.write_version_file(
|
50
|
+
Cache.restart_key(
|
51
|
+
args_config_file_path: self.class.args_config_file_path
|
52
|
+
)
|
53
|
+
)
|
54
|
+
end
|
45
55
|
end
|
46
56
|
end
|
47
57
|
end
|