rubocop 1.66.1 → 1.67.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 +15 -6
- data/config/internal_affairs.yml +11 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +3 -3
- data/lib/rubocop/config_validator.rb +2 -1
- data/lib/rubocop/cop/base.rb +6 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
- data/lib/rubocop/cop/cop.rb +8 -0
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
- data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
- data/lib/rubocop/cop/internal_affairs.rb +16 -0
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -5
- data/lib/rubocop/cop/layout/leading_comment_space.rb +28 -1
- data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
- data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
- data/lib/rubocop/cop/lint/ensure_return.rb +0 -3
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +1 -1
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +10 -4
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +5 -14
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +25 -2
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +105 -41
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
- data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
- data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
- data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +12 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +46 -6
- data/lib/rubocop/cop/style/block_delimiters.rb +14 -1
- data/lib/rubocop/cop/style/collection_compact.rb +10 -10
- data/lib/rubocop/cop/style/combinable_loops.rb +7 -0
- data/lib/rubocop/cop/style/commented_keyword.rb +7 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +1 -1
- data/lib/rubocop/cop/style/hash_each_methods.rb +6 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -3
- data/lib/rubocop/cop/style/lambda.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +53 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +12 -7
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +4 -0
- data/lib/rubocop/cop/style/operator_method_call.rb +25 -6
- data/lib/rubocop/cop/style/redundant_begin.rb +4 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +3 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/require_order.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +13 -1
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
- data/lib/rubocop/cop/style/safe_navigation.rb +92 -50
- data/lib/rubocop/cop/style/select_by_regexp.rb +9 -6
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/team.rb +8 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +73 -34
- data/lib/rubocop/file_finder.rb +9 -4
- data/lib/rubocop/lsp/runtime.rb +2 -0
- data/lib/rubocop/lsp/server.rb +0 -1
- data/lib/rubocop/rspec/expect_offense.rb +1 -0
- data/lib/rubocop/runner.rb +3 -0
- data/lib/rubocop/server/cache.rb +6 -1
- data/lib/rubocop/server/core.rb +1 -0
- data/lib/rubocop/target_ruby.rb +12 -12
- data/lib/rubocop/version.rb +3 -1
- data/lib/rubocop/yaml_duplication_checker.rb +20 -27
- data/lib/rubocop.rb +2 -0
- metadata +10 -8
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
FOR_METHOD = ' Or, if they were intended to be separate method ' \
|
29
29
|
'arguments, separate them with a comma.'
|
30
30
|
|
31
|
-
# rubocop:disable Metrics/AbcSize
|
31
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
32
32
|
def on_dstr(node)
|
33
33
|
each_bad_cons(node) do |lhs_node, rhs_node|
|
34
34
|
range = lhs_node.source_range.join(rhs_node.source_range)
|
@@ -40,13 +40,19 @@ module RuboCop
|
|
40
40
|
end
|
41
41
|
|
42
42
|
add_offense(range, message: message) do |corrector|
|
43
|
-
|
43
|
+
if lhs_node.value == ''
|
44
|
+
corrector.remove(lhs_node)
|
45
|
+
elsif rhs_node.value == ''
|
46
|
+
corrector.remove(rhs_node)
|
47
|
+
else
|
48
|
+
range = lhs_node.source_range.end.join(rhs_node.source_range.begin)
|
44
49
|
|
45
|
-
|
50
|
+
corrector.replace(range, ' + ')
|
51
|
+
end
|
46
52
|
end
|
47
53
|
end
|
48
54
|
end
|
49
|
-
# rubocop:enable Metrics/AbcSize
|
55
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
50
56
|
|
51
57
|
private
|
52
58
|
|
@@ -29,25 +29,16 @@ module RuboCop
|
|
29
29
|
|
30
30
|
MSG = '`it` calls without arguments will refer to the first block param in Ruby 3.4; ' \
|
31
31
|
'use `it()` or `self.it`.'
|
32
|
+
RESTRICT_ON_SEND = %i[it].freeze
|
32
33
|
|
33
|
-
def
|
34
|
-
return unless (
|
35
|
-
return unless
|
34
|
+
def on_send(node)
|
35
|
+
return unless (block_node = node.each_ancestor(:block).first)
|
36
|
+
return unless block_node.arguments.empty_and_without_delimiters?
|
36
37
|
|
37
|
-
if
|
38
|
-
add_offense(body)
|
39
|
-
else
|
40
|
-
body.each_descendant(:send).each do |send_node|
|
41
|
-
next unless deprecated_it_method?(send_node)
|
42
|
-
|
43
|
-
add_offense(send_node)
|
44
|
-
end
|
45
|
-
end
|
38
|
+
add_offense(node) if deprecated_it_method?(node)
|
46
39
|
end
|
47
40
|
|
48
41
|
def deprecated_it_method?(node)
|
49
|
-
return false unless node.method?(:it)
|
50
|
-
|
51
42
|
!node.receiver && node.arguments.empty? && !node.parenthesized? && !node.block_literal?
|
52
43
|
end
|
53
44
|
end
|
@@ -30,6 +30,8 @@ module RuboCop
|
|
30
30
|
# interpolation should not be removed if the expanded value
|
31
31
|
# contains a space character.
|
32
32
|
expanded_value = autocorrected_value(final_node)
|
33
|
+
expanded_value = handle_special_regexp_chars(begin_node, expanded_value)
|
34
|
+
|
33
35
|
return if in_array_percent_literal?(begin_node) && /\s|\A\z/.match?(expanded_value)
|
34
36
|
|
35
37
|
add_offense(final_node) do |corrector|
|
@@ -77,6 +79,27 @@ module RuboCop
|
|
77
79
|
end
|
78
80
|
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity
|
79
81
|
|
82
|
+
def handle_special_regexp_chars(begin_node, value)
|
83
|
+
parent_node = begin_node.parent
|
84
|
+
|
85
|
+
return value unless parent_node.regexp_type? && parent_node.slash_literal? && value['/']
|
86
|
+
|
87
|
+
# When a literal string containing a forward slash preceded by backslashes
|
88
|
+
# is interpolated inside a regexp, the number of resultant backslashes in the
|
89
|
+
# compiled Regexp is `(2(n+1) / 4)+1`, where `n` is the number of backslashes
|
90
|
+
# inside the interpolation.
|
91
|
+
# ie. 0-2 backslashes is compiled to 1, 3-6 is compiled to 3, etc.
|
92
|
+
# This maintains that same behavior in order to ensure the Regexp behavior
|
93
|
+
# does not change upon removing the interpolation.
|
94
|
+
value.gsub(%r{(\\*)/}) do
|
95
|
+
backslashes = Regexp.last_match[1]
|
96
|
+
backslash_count = backslashes.length
|
97
|
+
needed_backslashes = (2 * ((backslash_count + 1) / 4)) + 1
|
98
|
+
|
99
|
+
"#{'\\' * needed_backslashes}/"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
80
103
|
def autocorrected_value_for_string(node)
|
81
104
|
if node.source.start_with?("'", '%q')
|
82
105
|
node.children.last.inspect[1..-2]
|
@@ -150,7 +173,7 @@ module RuboCop
|
|
150
173
|
|
151
174
|
def ends_heredoc_line?(node)
|
152
175
|
grandparent = node.parent.parent
|
153
|
-
return false unless grandparent&.dstr_type? && grandparent
|
176
|
+
return false unless grandparent&.dstr_type? && grandparent.heredoc?
|
154
177
|
|
155
178
|
line = processed_source.lines[node.last_line - 1]
|
156
179
|
line.size == node.loc.last_column + 1
|
@@ -161,7 +184,7 @@ module RuboCop
|
|
161
184
|
return false unless parent.dstr_type? || parent.dsym_type?
|
162
185
|
|
163
186
|
grandparent = parent.parent
|
164
|
-
grandparent&.array_type? && grandparent
|
187
|
+
grandparent&.array_type? && grandparent.percent_literal?
|
165
188
|
end
|
166
189
|
end
|
167
190
|
end
|
@@ -37,9 +37,7 @@ module RuboCop
|
|
37
37
|
private
|
38
38
|
|
39
39
|
def valid_context?(node)
|
40
|
-
unless node.arguments.one? &&
|
41
|
-
return true
|
42
|
-
end
|
40
|
+
return true unless node.arguments.one? && node.first_argument.parenthesized_call?
|
43
41
|
return true if first_argument_block_type?(node.first_argument)
|
44
42
|
|
45
43
|
node.operator_method? || node.setter_method? || chained_calls?(node) ||
|
@@ -51,11 +49,12 @@ module RuboCop
|
|
51
49
|
end
|
52
50
|
|
53
51
|
def valid_first_argument?(first_arg)
|
54
|
-
first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg)
|
52
|
+
first_arg.operator_keyword? || first_arg.hash_type? || ternary_expression?(first_arg) ||
|
53
|
+
compound_range?(first_arg)
|
55
54
|
end
|
56
55
|
|
57
|
-
def
|
58
|
-
|
56
|
+
def compound_range?(first_arg)
|
57
|
+
first_arg.range_type? && first_arg.parenthesized_call?
|
59
58
|
end
|
60
59
|
|
61
60
|
def chained_calls?(node)
|
@@ -131,7 +131,7 @@ module RuboCop
|
|
131
131
|
private
|
132
132
|
|
133
133
|
def assume_receiver_instance_exists?(receiver)
|
134
|
-
return true if receiver.const_type? && !receiver.
|
134
|
+
return true if receiver.const_type? && !receiver.short_name.match?(SNAKE_CASE)
|
135
135
|
|
136
136
|
receiver.literal? && !receiver.nil_type?
|
137
137
|
end
|
@@ -3,88 +3,152 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Check to make sure that if safe navigation is used
|
7
|
-
#
|
8
|
-
# method calls on
|
6
|
+
# Check to make sure that if safe navigation is used in an `&&` or `||` condition,
|
7
|
+
# consistent and appropriate safe navigation, without excess or deficiency,
|
8
|
+
# is used for all method calls on the same object.
|
9
9
|
#
|
10
10
|
# @example
|
11
11
|
# # bad
|
12
|
-
# foo&.bar && foo
|
12
|
+
# foo&.bar && foo&.baz
|
13
13
|
#
|
14
|
-
# #
|
15
|
-
# foo
|
14
|
+
# # good
|
15
|
+
# foo&.bar && foo.baz
|
16
16
|
#
|
17
17
|
# # bad
|
18
|
-
# foo
|
18
|
+
# foo.bar && foo&.baz
|
19
19
|
#
|
20
20
|
# # good
|
21
21
|
# foo.bar && foo.baz
|
22
22
|
#
|
23
|
+
# # bad
|
24
|
+
# foo&.bar || foo.baz
|
25
|
+
#
|
23
26
|
# # good
|
24
27
|
# foo&.bar || foo&.baz
|
25
28
|
#
|
29
|
+
# # bad
|
30
|
+
# foo.bar || foo&.baz
|
31
|
+
#
|
26
32
|
# # good
|
33
|
+
# foo.bar || foo.baz
|
34
|
+
#
|
35
|
+
# # bad
|
27
36
|
# foo&.bar && (foobar.baz || foo&.baz)
|
28
37
|
#
|
38
|
+
# # good
|
39
|
+
# foo&.bar && (foobar.baz || foo.baz)
|
40
|
+
#
|
29
41
|
class SafeNavigationConsistency < Base
|
30
|
-
include IgnoredNode
|
31
42
|
include NilMethods
|
32
43
|
extend AutoCorrector
|
33
44
|
|
34
|
-
|
45
|
+
USE_DOT_MSG = 'Use `.` instead of unnecessary `&.`.'
|
46
|
+
USE_SAFE_NAVIGATION_MSG = 'Use `&.` for consistency with safe navigation.'
|
47
|
+
|
48
|
+
def on_and(node)
|
49
|
+
all_operands = collect_operands(node, [])
|
50
|
+
operand_groups = all_operands.group_by { |operand| receiver_name_as_key(operand, +'') }
|
51
|
+
|
52
|
+
operand_groups.each_value do |grouped_operands|
|
53
|
+
next unless (dot_op, begin_of_rest_operands = find_consistent_parts(grouped_operands))
|
35
54
|
|
36
|
-
|
37
|
-
|
55
|
+
rest_operands = grouped_operands[begin_of_rest_operands..]
|
56
|
+
rest_operands.each do |operand|
|
57
|
+
next if already_appropriate_call?(operand, dot_op)
|
38
58
|
|
39
|
-
|
59
|
+
register_offense(operand, dot_op)
|
60
|
+
end
|
61
|
+
end
|
40
62
|
end
|
63
|
+
alias on_or on_and
|
41
64
|
|
42
|
-
|
43
|
-
ancestor = top_conditional_ancestor(node)
|
44
|
-
conditions = ancestor.conditions
|
45
|
-
safe_nav_receiver = node.receiver
|
65
|
+
private
|
46
66
|
|
47
|
-
|
48
|
-
|
67
|
+
def collect_operands(node, operand_nodes)
|
68
|
+
operand_nodes(node.lhs, operand_nodes)
|
69
|
+
operand_nodes(node.rhs, operand_nodes)
|
49
70
|
|
50
|
-
|
51
|
-
|
71
|
+
operand_nodes
|
72
|
+
end
|
52
73
|
|
53
|
-
|
74
|
+
def receiver_name_as_key(method, fully_receivers)
|
75
|
+
if method.parent.call_type?
|
76
|
+
receiver(method.parent, fully_receivers)
|
77
|
+
else
|
78
|
+
fully_receivers << method.receiver&.source.to_s
|
79
|
+
end
|
80
|
+
end
|
54
81
|
|
55
|
-
|
82
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
83
|
+
def find_consistent_parts(grouped_operands)
|
84
|
+
csend_in_and, csend_in_or, send_in_and, send_in_or = most_left_indices(grouped_operands)
|
85
|
+
|
86
|
+
if csend_in_and
|
87
|
+
['.', (send_in_and ? [send_in_and, csend_in_and].min : csend_in_and) + 1]
|
88
|
+
elsif send_in_or && csend_in_or
|
89
|
+
send_in_or < csend_in_or ? ['.', send_in_or + 1] : ['&.', csend_in_or + 1]
|
90
|
+
elsif send_in_and && csend_in_or && send_in_and < csend_in_or
|
91
|
+
['.', csend_in_or]
|
56
92
|
end
|
57
93
|
end
|
94
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
58
95
|
|
59
|
-
|
96
|
+
def already_appropriate_call?(operand, dot_op)
|
97
|
+
(operand.safe_navigation? && dot_op == '&.') || (operand.dot? && dot_op == '.')
|
98
|
+
end
|
99
|
+
|
100
|
+
def register_offense(operand, dot_operator)
|
101
|
+
offense_range = operand.operator_method? ? operand : operand.loc.dot
|
102
|
+
message = dot_operator == '.' ? USE_DOT_MSG : USE_SAFE_NAVIGATION_MSG
|
60
103
|
|
61
|
-
|
62
|
-
|
104
|
+
add_offense(offense_range, message: message) do |corrector|
|
105
|
+
next if operand.operator_method?
|
63
106
|
|
64
|
-
|
107
|
+
corrector.replace(operand.loc.dot, dot_operator)
|
108
|
+
end
|
65
109
|
end
|
66
110
|
|
67
|
-
def
|
68
|
-
|
111
|
+
def operand_nodes(operand, operand_nodes)
|
112
|
+
if operand.operator_keyword?
|
113
|
+
collect_operands(operand, operand_nodes)
|
114
|
+
elsif operand.call_type?
|
115
|
+
operand_nodes << operand
|
116
|
+
end
|
69
117
|
end
|
70
118
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
119
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
120
|
+
def most_left_indices(grouped_operands)
|
121
|
+
indices = { csend_in_and: nil, csend_in_or: nil, send_in_and: nil, send_in_or: nil }
|
122
|
+
|
123
|
+
grouped_operands.each_with_index do |operand, index|
|
124
|
+
indices[:csend_in_and] ||= index if operand_in_and?(operand) && operand.csend_type?
|
125
|
+
indices[:csend_in_or] ||= index if operand_in_or?(operand) && operand.csend_type?
|
126
|
+
indices[:send_in_and] ||= index if operand_in_and?(operand) && !nilable?(operand)
|
127
|
+
indices[:send_in_or] ||= index if operand_in_or?(operand) && !nilable?(operand)
|
77
128
|
end
|
78
129
|
|
79
|
-
|
130
|
+
indices.values
|
80
131
|
end
|
132
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
81
133
|
|
82
|
-
def
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
134
|
+
def operand_in_and?(node)
|
135
|
+
return true if node.parent.and_type?
|
136
|
+
|
137
|
+
parent = node.parent.parent while node.parent.begin_type?
|
138
|
+
|
139
|
+
parent&.and_type?
|
140
|
+
end
|
141
|
+
|
142
|
+
def operand_in_or?(node)
|
143
|
+
return true if node.parent.or_type?
|
144
|
+
|
145
|
+
parent = node.parent.parent while node.parent.begin_type?
|
146
|
+
|
147
|
+
parent&.or_type?
|
148
|
+
end
|
149
|
+
|
150
|
+
def nilable?(node)
|
151
|
+
node.csend_type? || nil_methods.include?(node.method_name)
|
88
152
|
end
|
89
153
|
end
|
90
154
|
end
|
@@ -3,29 +3,47 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Identifies places where `URI.regexp` is obsolete and should
|
7
|
-
#
|
6
|
+
# Identifies places where `URI.regexp` is obsolete and should not be used.
|
7
|
+
#
|
8
|
+
# For Ruby 3.3 or lower, use `URI::DEFAULT_PARSER.make_regexp`.
|
9
|
+
# For Ruby 3.4 or higher, use `URI::RFC2396_PARSER.make_regexp`.
|
10
|
+
#
|
11
|
+
# NOTE: If you need to support both Ruby 3.3 and lower as well as Ruby 3.4 and higher,
|
12
|
+
# consider manually changing the code as follows:
|
13
|
+
#
|
14
|
+
# [source,ruby]
|
15
|
+
# ----
|
16
|
+
# defined?(URI::RFC2396_PARSER) ? URI::RFC2396_PARSER : URI::DEFAULT_PARSER
|
17
|
+
# ----
|
8
18
|
#
|
9
19
|
# @example
|
10
20
|
# # bad
|
11
21
|
# URI.regexp('http://example.com')
|
12
22
|
#
|
13
|
-
# # good
|
23
|
+
# # good - Ruby 3.3 or lower
|
14
24
|
# URI::DEFAULT_PARSER.make_regexp('http://example.com')
|
15
25
|
#
|
26
|
+
# # good - Ruby 3.4 or higher
|
27
|
+
# URI::RFC2396_PARSER.make_regexp('http://example.com')
|
28
|
+
#
|
16
29
|
class UriRegexp < Base
|
17
30
|
extend AutoCorrector
|
18
31
|
|
19
32
|
MSG = '`%<current>s` is obsolete and should not be used. Instead, use `%<preferred>s`.'
|
20
|
-
URI_CONSTANTS = ['URI', '::URI'].freeze
|
21
33
|
RESTRICT_ON_SEND = %i[regexp].freeze
|
22
34
|
|
35
|
+
# @!method uri_constant?(node)
|
36
|
+
def_node_matcher :uri_constant?, <<~PATTERN
|
37
|
+
(const {cbase nil?} :URI)
|
38
|
+
PATTERN
|
39
|
+
|
23
40
|
def on_send(node)
|
24
|
-
return unless node.receiver
|
25
|
-
return unless URI_CONSTANTS.include?(node.receiver.source)
|
41
|
+
return unless uri_constant?(node.receiver)
|
26
42
|
|
43
|
+
parser = target_ruby_version >= 3.4 ? 'RFC2396_PARSER' : 'DEFAULT_PARSER'
|
27
44
|
argument = node.first_argument ? "(#{node.first_argument.source})" : ''
|
28
|
-
|
45
|
+
|
46
|
+
preferred_method = "#{node.receiver.source}::#{parser}.make_regexp#{argument}"
|
29
47
|
message = format(MSG, current: node.source, preferred: preferred_method)
|
30
48
|
|
31
49
|
add_offense(node.loc.selector, message: message) do |corrector|
|
@@ -15,7 +15,7 @@ module RuboCop
|
|
15
15
|
parent = node.parent
|
16
16
|
|
17
17
|
parent&.send_type? && parent.arguments.include?(node) &&
|
18
|
-
!parent.parenthesized? && parent
|
18
|
+
!parent.parenthesized? && parent.block_literal?
|
19
19
|
end
|
20
20
|
|
21
21
|
# Override to determine values that are invalid in a percent array
|
@@ -5,7 +5,6 @@ module RuboCop
|
|
5
5
|
# Common functionality for modifier cops.
|
6
6
|
module StatementModifier
|
7
7
|
include LineLengthHelp
|
8
|
-
include RangeHelp
|
9
8
|
|
10
9
|
private
|
11
10
|
|
@@ -65,7 +64,9 @@ module RuboCop
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def method_source(if_body)
|
68
|
-
|
67
|
+
end_range = if_body.implicit_call? ? if_body.loc.dot.end : if_body.loc.selector
|
68
|
+
|
69
|
+
if_body.source_range.begin.join(end_range).source
|
69
70
|
end
|
70
71
|
|
71
72
|
def first_line_comment(node)
|
@@ -116,9 +116,9 @@ module RuboCop
|
|
116
116
|
add_offense(range, message: create_message(word)) do |corrector|
|
117
117
|
suggestions = find_flagged_term(word)['Suggestions']
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
119
|
+
if (preferred_term = preferred_sole_term(suggestions))
|
120
|
+
corrector.replace(range, preferred_term)
|
121
|
+
end
|
122
122
|
end
|
123
123
|
end
|
124
124
|
end
|
@@ -157,6 +157,15 @@ module RuboCop
|
|
157
157
|
set_regexes(flagged_term_strings, allowed_strings)
|
158
158
|
end
|
159
159
|
|
160
|
+
def preferred_sole_term(suggestions)
|
161
|
+
case suggestions
|
162
|
+
when Array
|
163
|
+
suggestions.one? && preferred_sole_term(suggestions.first)
|
164
|
+
when String
|
165
|
+
suggestions
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
160
169
|
def extract_regexp(term, term_definition)
|
161
170
|
return term_definition['Regex'] if term_definition['Regex']
|
162
171
|
return /(?:\b|(?<=[\W_]))#{term}(?:\b|(?=[\W_]))/ if term_definition['WholeWord']
|
data/lib/rubocop/cop/offense.rb
CHANGED
@@ -97,8 +97,8 @@ module RuboCop
|
|
97
97
|
# @!attribute [r] correctable?
|
98
98
|
#
|
99
99
|
# @return [Boolean]
|
100
|
-
# whether this offense can be automatically corrected via
|
101
|
-
#
|
100
|
+
# whether this offense can be automatically corrected via autocorrect.
|
101
|
+
# This includes todo comments, for example when requested with `--disable-uncorrectable`.
|
102
102
|
def correctable?
|
103
103
|
@status != :unsupported
|
104
104
|
end
|
@@ -68,6 +68,8 @@ module RuboCop
|
|
68
68
|
# class Foo
|
69
69
|
#
|
70
70
|
# private :bar, :baz
|
71
|
+
# private *%i[qux quux]
|
72
|
+
# private *METHOD_NAMES
|
71
73
|
#
|
72
74
|
# end
|
73
75
|
#
|
@@ -76,6 +78,8 @@ module RuboCop
|
|
76
78
|
# class Foo
|
77
79
|
#
|
78
80
|
# private :bar, :baz
|
81
|
+
# private *%i[qux quux]
|
82
|
+
# private *METHOD_NAMES
|
79
83
|
#
|
80
84
|
# end
|
81
85
|
#
|
@@ -128,7 +132,9 @@ module RuboCop
|
|
128
132
|
|
129
133
|
# @!method access_modifier_with_symbol?(node)
|
130
134
|
def_node_matcher :access_modifier_with_symbol?, <<~PATTERN
|
131
|
-
(send nil? {:private :protected :public :module_function}
|
135
|
+
(send nil? {:private :protected :public :module_function}
|
136
|
+
{(sym _) (splat {#percent_symbol_array? const})}
|
137
|
+
)
|
132
138
|
PATTERN
|
133
139
|
|
134
140
|
# @!method access_modifier_with_attr?(node)
|
@@ -170,6 +176,10 @@ module RuboCop
|
|
170
176
|
end
|
171
177
|
end
|
172
178
|
|
179
|
+
def percent_symbol_array?(node)
|
180
|
+
node.array_type? && node.percent_literal?(:symbol)
|
181
|
+
end
|
182
|
+
|
173
183
|
def allow_modifiers_on_symbols?(node)
|
174
184
|
cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
|
175
185
|
end
|
@@ -218,7 +228,7 @@ module RuboCop
|
|
218
228
|
|
219
229
|
def find_corresponding_def_node(node)
|
220
230
|
if access_modifier_with_symbol?(node)
|
221
|
-
method_name = node.first_argument.value
|
231
|
+
method_name = node.first_argument.respond_to?(:value) && node.first_argument.value
|
222
232
|
node.parent.each_child_node(:def).find do |child|
|
223
233
|
child.method?(method_name)
|
224
234
|
end
|
@@ -10,6 +10,9 @@ module RuboCop
|
|
10
10
|
# NOTE: If there is a method call before the accessor method it is always allowed
|
11
11
|
# as it might be intended like Sorbet.
|
12
12
|
#
|
13
|
+
# NOTE: If there is a RBS::Inline annotation comment just after the accessor method
|
14
|
+
# it is always allowed.
|
15
|
+
#
|
13
16
|
# @example EnforcedStyle: grouped (default)
|
14
17
|
# # bad
|
15
18
|
# class Foo
|
@@ -92,7 +95,7 @@ module RuboCop
|
|
92
95
|
comment_line?(processed_source[node.first_line - 2])
|
93
96
|
end
|
94
97
|
|
95
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
98
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
96
99
|
def groupable_accessor?(node)
|
97
100
|
return true unless (previous_expression = node.left_siblings.last)
|
98
101
|
|
@@ -105,11 +108,16 @@ module RuboCop
|
|
105
108
|
|
106
109
|
return true unless previous_expression.send_type?
|
107
110
|
|
111
|
+
# Accessors with RBS::Inline annotations shouldn't be groupable.
|
112
|
+
return false if processed_source.comments.any? do |c|
|
113
|
+
same_line?(c, previous_expression) && c.text.start_with?('#:')
|
114
|
+
end
|
115
|
+
|
108
116
|
previous_expression.attribute_accessor? ||
|
109
117
|
previous_expression.access_modifier? ||
|
110
118
|
node.first_line - previous_expression.last_line > 1 # there is a space between nodes
|
111
119
|
end
|
112
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
120
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
113
121
|
|
114
122
|
def class_send_elements(class_node)
|
115
123
|
class_def = class_node.body
|