rubocop 1.66.1 → 1.68.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +55 -6
- data/config/internal_affairs.yml +11 -0
- data/lib/rubocop/cached_data.rb +12 -4
- data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
- data/lib/rubocop/cli/command/execute_runner.rb +1 -1
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli/command/version.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +3 -3
- data/lib/rubocop/config_validator.rb +2 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +22 -2
- 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/alignment_corrector.rb +1 -12
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
- 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 +56 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
- 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_branch.rb +39 -4
- 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/non_atomic_file_operation.rb +7 -0
- 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_chain.rb +9 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +107 -41
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
- data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -0
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +3 -1
- 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/block_forwarding.rb +1 -1
- 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 +4 -5
- 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/ambiguous_endless_method_definition.rb +79 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +46 -6
- data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +31 -3
- data/lib/rubocop/cop/style/collection_compact.rb +10 -10
- data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
- 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/endless_method.rb +1 -14
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/guard_clause.rb +15 -2
- 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/keyword_arguments_merging.rb +67 -0
- data/lib/rubocop/cop/style/lambda.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +59 -8
- 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/multiple_comparison.rb +28 -39
- 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 +23 -5
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -11
- 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 +104 -50
- data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
- 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 +26 -5
- 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/cop/variable_force/assignment.rb +18 -3
- data/lib/rubocop/cop/variable_force/branch.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +5 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cops_documentation_generator.rb +81 -40
- data/lib/rubocop/file_finder.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- 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 +17 -6
- data/lib/rubocop/server/cache.rb +6 -1
- data/lib/rubocop/server/core.rb +1 -0
- data/lib/rubocop/target_ruby.rb +13 -13
- data/lib/rubocop/version.rb +28 -7
- data/lib/rubocop/yaml_duplication_checker.rb +20 -27
- data/lib/rubocop.rb +10 -0
- metadata +13 -4
@@ -3,13 +3,12 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Layout
|
6
|
-
# Checks for indentation that doesn't use the specified number
|
7
|
-
#
|
6
|
+
# Checks for indentation that doesn't use the specified number of spaces.
|
7
|
+
# The indentation width can be configured using the `Width` setting. The default width is 2.
|
8
8
|
#
|
9
|
-
# See also the IndentationConsistency cop which is the companion to this
|
10
|
-
# one.
|
9
|
+
# See also the `Layout/IndentationConsistency` cop which is the companion to this one.
|
11
10
|
#
|
12
|
-
# @example
|
11
|
+
# @example Width: 2 (default)
|
13
12
|
# # bad
|
14
13
|
# class A
|
15
14
|
# def test
|
@@ -49,18 +49,57 @@ module RuboCop
|
|
49
49
|
# #ruby=2.7.0
|
50
50
|
# #ruby-gemset=myproject
|
51
51
|
#
|
52
|
+
# @example AllowRBSInlineAnnotation: false (default)
|
53
|
+
#
|
54
|
+
# # bad
|
55
|
+
#
|
56
|
+
# include Enumerable #[Integer]
|
57
|
+
#
|
58
|
+
# attr_reader :name #: String
|
59
|
+
# attr_reader :age #: Integer?
|
60
|
+
#
|
61
|
+
# @example AllowRBSInlineAnnotation: true
|
62
|
+
#
|
63
|
+
# # good
|
64
|
+
#
|
65
|
+
# include Enumerable #[Integer]
|
66
|
+
#
|
67
|
+
# attr_reader :name #: String
|
68
|
+
# attr_reader :age #: Integer?
|
69
|
+
#
|
70
|
+
# @example AllowSteepAnnotation: false (default)
|
71
|
+
#
|
72
|
+
# # bad
|
73
|
+
# [1, 2, 3].each_with_object([]) do |n, list| #$ Array[Integer]
|
74
|
+
# list << n
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# name = 'John' #: String
|
78
|
+
#
|
79
|
+
# @example AllowSteepAnnotation: true
|
80
|
+
#
|
81
|
+
# # good
|
82
|
+
#
|
83
|
+
# [1, 2, 3].each_with_object([]) do |n, list| #$ Array[Integer]
|
84
|
+
# list << n
|
85
|
+
# end
|
86
|
+
#
|
87
|
+
# name = 'John' #: String
|
88
|
+
#
|
52
89
|
class LeadingCommentSpace < Base
|
53
90
|
include RangeHelp
|
54
91
|
extend AutoCorrector
|
55
92
|
|
56
93
|
MSG = 'Missing space after `#`.'
|
57
94
|
|
58
|
-
def on_new_investigation
|
95
|
+
def on_new_investigation # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
59
96
|
processed_source.comments.each do |comment|
|
60
97
|
next unless /\A(?!#\+\+|#--)(#+[^#\s=])/.match?(comment.text)
|
61
98
|
next if comment.loc.line == 1 && allowed_on_first_line?(comment)
|
62
99
|
next if doxygen_comment_style?(comment)
|
63
100
|
next if gemfile_ruby_comment?(comment)
|
101
|
+
next if rbs_inline_annotation?(comment)
|
102
|
+
next if steep_annotation?(comment)
|
64
103
|
|
65
104
|
add_offense(comment) do |corrector|
|
66
105
|
expr = comment.source_range
|
@@ -115,6 +154,22 @@ module RuboCop
|
|
115
154
|
def gemfile_ruby_comment?(comment)
|
116
155
|
allow_gemfile_ruby_comment? && ruby_comment_in_gemfile?(comment)
|
117
156
|
end
|
157
|
+
|
158
|
+
def allow_rbs_inline_annotation?
|
159
|
+
cop_config['AllowRBSInlineAnnotation']
|
160
|
+
end
|
161
|
+
|
162
|
+
def rbs_inline_annotation?(comment)
|
163
|
+
allow_rbs_inline_annotation? && comment.text.start_with?(/#:|#\[.+\]/)
|
164
|
+
end
|
165
|
+
|
166
|
+
def allow_steep_annotation?
|
167
|
+
cop_config['AllowSteepAnnotation']
|
168
|
+
end
|
169
|
+
|
170
|
+
def steep_annotation?(comment)
|
171
|
+
allow_steep_annotation? && comment.text.start_with?(/#[$:]/)
|
172
|
+
end
|
118
173
|
end
|
119
174
|
end
|
120
175
|
end
|
@@ -33,12 +33,12 @@ module RuboCop
|
|
33
33
|
private
|
34
34
|
|
35
35
|
def offense_range(node, begin_pos)
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
return if dot_before_brackets?(node, receiver_end_pos, selector_begin_pos)
|
36
|
+
receiver_end_pos = node.receiver.source_range.end_pos
|
37
|
+
selector_begin_pos = node.loc.selector.begin_pos
|
38
|
+
return if receiver_end_pos >= selector_begin_pos
|
39
|
+
return if dot_before_brackets?(node, receiver_end_pos, selector_begin_pos)
|
41
40
|
|
41
|
+
if reference_variable_with_brackets?(node)
|
42
42
|
range_between(receiver_end_pos, selector_begin_pos)
|
43
43
|
elsif node.method?(:[]=)
|
44
44
|
offense_range_for_assignment(node, begin_pos)
|
@@ -57,6 +57,7 @@ module RuboCop
|
|
57
57
|
# # good
|
58
58
|
# (a.foo)..(b.bar)
|
59
59
|
class AmbiguousRange < Base
|
60
|
+
include RationalLiteral
|
60
61
|
extend AutoCorrector
|
61
62
|
|
62
63
|
MSG = 'Wrap complex range boundaries with parentheses to avoid ambiguity.'
|
@@ -79,12 +80,14 @@ module RuboCop
|
|
79
80
|
yield range.end if range.end
|
80
81
|
end
|
81
82
|
|
83
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
82
84
|
def acceptable?(node)
|
83
85
|
node.begin_type? ||
|
84
|
-
node.literal? ||
|
86
|
+
node.literal? || rational_literal?(node) ||
|
85
87
|
node.variable? || node.const_type? || node.self_type? ||
|
86
88
|
(node.call_type? && acceptable_call?(node))
|
87
89
|
end
|
90
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
88
91
|
|
89
92
|
def acceptable_call?(node)
|
90
93
|
return true if node.unary_operation?
|
@@ -17,8 +17,7 @@ module RuboCop
|
|
17
17
|
class BigDecimalNew < Base
|
18
18
|
extend AutoCorrector
|
19
19
|
|
20
|
-
MSG = '
|
21
|
-
'Use `%<double_colon>sBigDecimal()` instead.'
|
20
|
+
MSG = '`BigDecimal.new()` is deprecated. Use `BigDecimal()` instead.'
|
22
21
|
RESTRICT_ON_SEND = %i[new].freeze
|
23
22
|
|
24
23
|
# @!method big_decimal_new(node)
|
@@ -28,13 +27,11 @@ module RuboCop
|
|
28
27
|
PATTERN
|
29
28
|
|
30
29
|
def on_send(node)
|
31
|
-
big_decimal_new(node) do |
|
32
|
-
|
33
|
-
message = format(MSG, double_colon: double_colon)
|
34
|
-
|
35
|
-
add_offense(node.loc.selector, message: message) do |corrector|
|
30
|
+
big_decimal_new(node) do |cbase|
|
31
|
+
add_offense(node.loc.selector) do |corrector|
|
36
32
|
corrector.remove(node.loc.selector)
|
37
33
|
corrector.remove(node.loc.dot)
|
34
|
+
corrector.remove(cbase) if cbase
|
38
35
|
end
|
39
36
|
end
|
40
37
|
end
|
@@ -36,7 +36,7 @@ module RuboCop
|
|
36
36
|
return unless boolean_symbol?(node)
|
37
37
|
|
38
38
|
parent = node.parent
|
39
|
-
return if parent&.array_type? && parent
|
39
|
+
return if parent&.array_type? && parent.percent_literal?(:symbol)
|
40
40
|
|
41
41
|
add_offense(node, message: format(MSG, boolean: node.value)) do |corrector|
|
42
42
|
autocorrect(corrector, node)
|
@@ -15,6 +15,9 @@ module RuboCop
|
|
15
15
|
# With `IgnoreConstantBranches: true`, branches are not registered
|
16
16
|
# as offenses if they return a constant value.
|
17
17
|
#
|
18
|
+
# With `IgnoreDuplicateElseBranch: true`, in conditionals with multiple branches,
|
19
|
+
# duplicate 'else' branches are not registered as offenses.
|
20
|
+
#
|
18
21
|
# @example
|
19
22
|
# # bad
|
20
23
|
# if foo
|
@@ -83,21 +86,37 @@ module RuboCop
|
|
83
86
|
# else MEDIUM_SIZE
|
84
87
|
# end
|
85
88
|
#
|
89
|
+
# @example IgnoreDuplicateElseBranch: true
|
90
|
+
# # good
|
91
|
+
# if foo
|
92
|
+
# do_foo
|
93
|
+
# elsif bar
|
94
|
+
# do_bar
|
95
|
+
# else
|
96
|
+
# do_foo
|
97
|
+
# end
|
98
|
+
#
|
86
99
|
class DuplicateBranch < Base
|
87
100
|
MSG = 'Duplicate branch body detected.'
|
88
101
|
|
89
102
|
def on_branching_statement(node)
|
90
|
-
branches(node)
|
91
|
-
|
103
|
+
branches = branches(node)
|
104
|
+
branches.each_with_object(Set.new) do |branch, previous|
|
105
|
+
next unless consider_branch?(branches, branch)
|
92
106
|
|
93
107
|
add_offense(offense_range(branch)) unless previous.add?(branch)
|
94
108
|
end
|
95
109
|
end
|
96
|
-
alias on_if on_branching_statement
|
97
110
|
alias on_case on_branching_statement
|
98
111
|
alias on_case_match on_branching_statement
|
99
112
|
alias on_rescue on_branching_statement
|
100
113
|
|
114
|
+
def on_if(node)
|
115
|
+
# Ignore 'elsif' nodes, because we don't want to check them separately whether
|
116
|
+
# the 'else' branch is duplicated. We want to check only on the outermost conditional.
|
117
|
+
on_branching_statement(node) unless node.elsif?
|
118
|
+
end
|
119
|
+
|
101
120
|
private
|
102
121
|
|
103
122
|
def offense_range(duplicate_branch)
|
@@ -118,10 +137,14 @@ module RuboCop
|
|
118
137
|
node.branches.compact
|
119
138
|
end
|
120
139
|
|
121
|
-
def consider_branch?(branch)
|
140
|
+
def consider_branch?(branches, branch)
|
122
141
|
return false if ignore_literal_branches? && literal_branch?(branch)
|
123
142
|
return false if ignore_constant_branches? && const_branch?(branch)
|
124
143
|
|
144
|
+
if ignore_duplicate_else_branches? && duplicate_else_branch?(branches, branch)
|
145
|
+
return false
|
146
|
+
end
|
147
|
+
|
125
148
|
true
|
126
149
|
end
|
127
150
|
|
@@ -133,6 +156,10 @@ module RuboCop
|
|
133
156
|
cop_config.fetch('IgnoreConstantBranches', false)
|
134
157
|
end
|
135
158
|
|
159
|
+
def ignore_duplicate_else_branches?
|
160
|
+
cop_config.fetch('IgnoreDuplicateElseBranch', false)
|
161
|
+
end
|
162
|
+
|
136
163
|
def literal_branch?(branch) # rubocop:disable Metrics/CyclomaticComplexity
|
137
164
|
return false if !branch.literal? || branch.xstr_type?
|
138
165
|
return true if branch.basic_literal?
|
@@ -147,6 +174,14 @@ module RuboCop
|
|
147
174
|
def const_branch?(branch)
|
148
175
|
branch.const_type?
|
149
176
|
end
|
177
|
+
|
178
|
+
def duplicate_else_branch?(branches, branch)
|
179
|
+
return false unless (parent = branch.parent)
|
180
|
+
|
181
|
+
branches.size > 2 &&
|
182
|
+
branch.equal?(branches.last) &&
|
183
|
+
parent.respond_to?(:else?) && parent.else?
|
184
|
+
end
|
150
185
|
end
|
151
186
|
end
|
152
187
|
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for duplicate literal, constant, or variable elements in Set.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# Set[:foo, :bar, :foo]
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# Set[:foo, :bar]
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# Set.new([:foo, :bar, :foo])
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# Set.new([:foo, :bar])
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# [:foo, :bar, :foo].to_set
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# [:foo, :bar].to_set
|
27
|
+
#
|
28
|
+
class DuplicateSetElement < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
31
|
+
MSG = 'Remove the duplicate element in Set.'
|
32
|
+
RESTRICT_ON_SEND = %i[\[\] new to_set].freeze
|
33
|
+
|
34
|
+
# @!method set_init_elements(node)
|
35
|
+
def_node_matcher :set_init_elements, <<~PATTERN
|
36
|
+
{
|
37
|
+
(send (const {nil? cbase} :Set) :[] $...)
|
38
|
+
(send (const {nil? cbase} :Set) :new (array $...))
|
39
|
+
(call (array $...) :to_set)
|
40
|
+
}
|
41
|
+
PATTERN
|
42
|
+
|
43
|
+
def on_send(node)
|
44
|
+
return unless (set_elements = set_init_elements(node))
|
45
|
+
|
46
|
+
seen_elements = Set[]
|
47
|
+
|
48
|
+
set_elements.each_with_index do |set_element, index|
|
49
|
+
# NOTE: Skip due to the possibility of corner cases where Set elements
|
50
|
+
# may have changing return values if they are not literals, constants, or variables.
|
51
|
+
next if !set_element.literal? && !set_element.const_type? && !set_element.variable?
|
52
|
+
|
53
|
+
if seen_elements.include?(set_element)
|
54
|
+
register_offense(set_element, set_elements[index - 1])
|
55
|
+
else
|
56
|
+
seen_elements << set_element
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
alias on_csend on_send
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def register_offense(current_element, prev_element)
|
65
|
+
add_offense(current_element) do |corrector|
|
66
|
+
range = prev_element.source_range.end.join(current_element.source_range.end)
|
67
|
+
|
68
|
+
corrector.remove(range)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -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
|
@@ -134,6 +134,7 @@ module RuboCop
|
|
134
134
|
|
135
135
|
corrector.replace(node.child_nodes.first.loc.name, 'FileUtils')
|
136
136
|
corrector.replace(node.loc.selector, replacement_method(node))
|
137
|
+
corrector.insert_before(node.last_argument, 'mode: ') if require_mode_keyword?(node)
|
137
138
|
end
|
138
139
|
|
139
140
|
def replacement_method(node)
|
@@ -152,6 +153,12 @@ module RuboCop
|
|
152
153
|
force_method_name?(node) || force_option?(node)
|
153
154
|
end
|
154
155
|
|
156
|
+
def require_mode_keyword?(node)
|
157
|
+
return false unless node.receiver.const_name == 'Dir'
|
158
|
+
|
159
|
+
replacement_method(node) == 'mkdir_p' && node.arguments.length == 2
|
160
|
+
end
|
161
|
+
|
155
162
|
def force_option?(node)
|
156
163
|
node.arguments.any? { |arg| force?(arg) }
|
157
164
|
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
|
@@ -38,6 +38,8 @@ module RuboCop
|
|
38
38
|
PATTERN
|
39
39
|
|
40
40
|
def on_send(node)
|
41
|
+
return unless require_safe_navigation?(node)
|
42
|
+
|
41
43
|
bad_method?(node) do |safe_nav, method|
|
42
44
|
return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
|
43
45
|
|
@@ -52,6 +54,13 @@ module RuboCop
|
|
52
54
|
|
53
55
|
private
|
54
56
|
|
57
|
+
def require_safe_navigation?(node)
|
58
|
+
parent = node.parent
|
59
|
+
return true unless parent&.and_type?
|
60
|
+
|
61
|
+
parent.rhs != node || parent.lhs.receiver != parent.rhs.receiver
|
62
|
+
end
|
63
|
+
|
55
64
|
# @param [Parser::Source::Range] offense_range
|
56
65
|
# @param [RuboCop::AST::SendNode] send_node
|
57
66
|
# @return [String]
|