rubocop 1.67.0 → 1.69.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 +81 -6
- data/lib/rubocop/cached_data.rb +12 -4
- data/lib/rubocop/cli/command/execute_runner.rb +1 -1
- data/lib/rubocop/cli/command/version.rb +2 -2
- data/lib/rubocop/cop/autocorrect_logic.rb +22 -2
- data/lib/rubocop/cop/base.rb +1 -1
- data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +2 -4
- data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +46 -0
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -3
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +3 -4
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +3 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +7 -7
- data/lib/rubocop/cop/layout/leading_comment_space.rb +44 -1
- data/lib/rubocop/cop/layout/line_length.rb +118 -4
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
- data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -35
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -2
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +16 -17
- data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +11 -12
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -0
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
- data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
- data/lib/rubocop/cop/lint/empty_file.rb +0 -2
- data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +14 -6
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -3
- data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
- data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +3 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -5
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +8 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +106 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +12 -7
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +9 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +5 -1
- data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +88 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
- data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
- data/lib/rubocop/cop/lint/void.rb +3 -2
- data/lib/rubocop/cop/metrics/class_length.rb +7 -7
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -2
- data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -0
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
- data/lib/rubocop/cop/mixin/dig_help.rb +27 -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/multiline_expression_indentation.rb +5 -9
- data/lib/rubocop/cop/mixin/range_help.rb +0 -1
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +6 -7
- data/lib/rubocop/cop/naming/file_name.rb +0 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -11
- data/lib/rubocop/cop/naming/variable_name.rb +3 -4
- data/lib/rubocop/cop/naming/variable_number.rb +2 -3
- data/lib/rubocop/cop/offense.rb +2 -3
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +53 -24
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
- data/lib/rubocop/cop/style/array_intersect.rb +5 -4
- data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +18 -3
- data/lib/rubocop/cop/style/case_like_if.rb +8 -11
- data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
- data/lib/rubocop/cop/style/commented_keyword.rb +11 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +19 -21
- data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
- data/lib/rubocop/cop/style/dig_chain.rb +90 -0
- data/lib/rubocop/cop/style/endless_method.rb +1 -14
- data/lib/rubocop/cop/style/file_null.rb +73 -0
- data/lib/rubocop/cop/style/file_touch.rb +75 -0
- data/lib/rubocop/cop/style/for.rb +0 -1
- data/lib/rubocop/cop/style/global_vars.rb +1 -3
- data/lib/rubocop/cop/style/guard_clause.rb +15 -2
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +0 -1
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -2
- data/lib/rubocop/cop/style/if_with_semicolon.rb +14 -5
- data/lib/rubocop/cop/style/inverse_methods.rb +0 -1
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
- data/lib/rubocop/cop/style/lambda_call.rb +0 -1
- data/lib/rubocop/cop/style/map_into_array.rb +6 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +7 -11
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
- 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/mutable_constant.rb +4 -5
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +6 -4
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
- data/lib/rubocop/cop/style/not.rb +1 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +25 -4
- data/lib/rubocop/cop/style/operator_method_call.rb +5 -6
- data/lib/rubocop/cop/style/or_assignment.rb +3 -6
- data/lib/rubocop/cop/style/parallel_assignment.rb +8 -13
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +36 -21
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +21 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +9 -11
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -0
- data/lib/rubocop/cop/style/redundant_return.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self.rb +7 -14
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +7 -5
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +2 -3
- data/lib/rubocop/cop/style/safe_navigation.rb +13 -1
- data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
- data/lib/rubocop/cop/style/self_assignment.rb +11 -17
- data/lib/rubocop/cop/style/signal_exception.rb +2 -3
- data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +13 -3
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -3
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +0 -1
- data/lib/rubocop/cop/style/swap_values.rb +4 -15
- data/lib/rubocop/cop/style/ternary_parentheses.rb +25 -4
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
- data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
- 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/cop/variable_force.rb +4 -10
- data/lib/rubocop/cops_documentation_generator.rb +20 -10
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/runner.rb +16 -8
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +27 -8
- data/lib/rubocop.rb +16 -0
- metadata +28 -12
@@ -5,17 +5,16 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# Checks for places where binary operator has identical operands.
|
7
7
|
#
|
8
|
-
# It covers
|
9
|
-
# comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, ``<=``;
|
8
|
+
# It covers comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, ``<=``;
|
10
9
|
# bitwise operators: `|`, `^`, `&`;
|
11
10
|
# boolean operators: `&&`, `||`
|
12
11
|
# and "spaceship" operator - ``<=>``.
|
13
12
|
#
|
14
13
|
# Simple arithmetic operations are allowed by this cop: `+`, `*`, `**`, `<<` and `>>`.
|
15
14
|
# Although these can be rewritten in a different way, it should not be necessary to
|
16
|
-
# do so.
|
17
|
-
#
|
18
|
-
#
|
15
|
+
# do so. Operations such as `-` or `/` where the result will always be the same
|
16
|
+
# (`x - x` will always be 0; `x / x` will always be 1) are offenses, but these
|
17
|
+
# are covered by Lint/NumericOperationWithConstantResult instead.
|
19
18
|
#
|
20
19
|
# @safety
|
21
20
|
# This cop is unsafe as it does not consider side effects when calling methods
|
@@ -30,7 +29,6 @@ module RuboCop
|
|
30
29
|
#
|
31
30
|
# @example
|
32
31
|
# # bad
|
33
|
-
# x / x
|
34
32
|
# x.top >= x.top
|
35
33
|
#
|
36
34
|
# if a.x != 0 && a.x != 0
|
@@ -47,19 +45,20 @@ module RuboCop
|
|
47
45
|
#
|
48
46
|
class BinaryOperatorWithIdenticalOperands < Base
|
49
47
|
MSG = 'Binary operator `%<op>s` has identical operands.'
|
50
|
-
|
48
|
+
MATH_OPERATORS = %i[- + * / ** << >>].to_set.freeze
|
51
49
|
|
52
50
|
def on_send(node)
|
53
51
|
return unless node.binary_operation?
|
52
|
+
return if MATH_OPERATORS.include?(node.method_name)
|
53
|
+
return unless node.receiver == node.first_argument
|
54
54
|
|
55
|
-
|
56
|
-
return if ALLOWED_MATH_OPERATORS.include?(node.method_name)
|
57
|
-
|
58
|
-
add_offense(node, message: format(MSG, op: operation)) if lhs == rhs
|
55
|
+
add_offense(node, message: format(MSG, op: node.method_name))
|
59
56
|
end
|
60
57
|
|
61
58
|
def on_and(node)
|
62
|
-
|
59
|
+
return unless node.lhs == node.rhs
|
60
|
+
|
61
|
+
add_offense(node, message: format(MSG, op: node.operator))
|
63
62
|
end
|
64
63
|
alias on_or on_and
|
65
64
|
end
|
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
PATTERN
|
52
52
|
|
53
53
|
def on_send(node)
|
54
|
-
return if node.arguments.any? { |arg| arg.variable? || arg.
|
54
|
+
return if node.arguments.any? { |arg| arg.variable? || arg.call_type? || arg.const_type? }
|
55
55
|
return if digest_const?(node.receiver)
|
56
56
|
return unless algorithm_const(node)
|
57
57
|
|
@@ -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
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
MSG = 'Do not return from an `ensure` block.'
|
44
44
|
|
45
45
|
def on_ensure(node)
|
46
|
-
node.
|
46
|
+
node.branch&.each_node(:return) { |return_node| add_offense(return_node) }
|
47
47
|
end
|
48
48
|
end
|
49
49
|
end
|
@@ -29,6 +29,9 @@ module RuboCop
|
|
29
29
|
# tolerance = 0.0001
|
30
30
|
# (x - 0.1).abs < tolerance
|
31
31
|
#
|
32
|
+
# # good - comparing against nil
|
33
|
+
# Float(x, exception: false) == nil
|
34
|
+
#
|
32
35
|
# # Or some other epsilon based type of comparison:
|
33
36
|
# # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
|
34
37
|
#
|
@@ -42,8 +45,12 @@ module RuboCop
|
|
42
45
|
RESTRICT_ON_SEND = EQUALITY_METHODS
|
43
46
|
|
44
47
|
def on_send(node)
|
45
|
-
|
46
|
-
|
48
|
+
return unless node.arguments.one?
|
49
|
+
|
50
|
+
lhs = node.receiver
|
51
|
+
rhs = node.first_argument
|
52
|
+
|
53
|
+
return if literal_safe?(lhs) || literal_safe?(rhs)
|
47
54
|
|
48
55
|
add_offense(node) if float?(lhs) || float?(rhs)
|
49
56
|
end
|
@@ -65,15 +72,16 @@ module RuboCop
|
|
65
72
|
end
|
66
73
|
end
|
67
74
|
|
68
|
-
def
|
69
|
-
|
75
|
+
def literal_safe?(node)
|
76
|
+
return false unless node
|
77
|
+
|
78
|
+
(node.numeric_type? && node.value.zero?) || node.nil_type?
|
70
79
|
end
|
71
80
|
|
72
81
|
# rubocop:disable Metrics/PerceivedComplexity
|
73
82
|
def check_send(node)
|
74
83
|
if node.arithmetic_operation?
|
75
|
-
|
76
|
-
float?(lhs) || float?(rhs)
|
84
|
+
float?(node.receiver) || float?(node.first_argument)
|
77
85
|
elsif FLOAT_RETURNING_METHODS.include?(node.method_name)
|
78
86
|
true
|
79
87
|
elsif node.receiver&.float_type?
|
@@ -18,9 +18,7 @@ module RuboCop
|
|
18
18
|
MSG = 'Float out of range.'
|
19
19
|
|
20
20
|
def on_float(node)
|
21
|
-
value
|
22
|
-
|
23
|
-
return unless value.infinite? || (value.zero? && /[1-9]/.match?(node.source))
|
21
|
+
return unless node.value.infinite? || (node.value.zero? && /[1-9]/.match?(node.source))
|
24
22
|
|
25
23
|
add_offense(node)
|
26
24
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for the deprecated use of keyword arguments as a default in `Hash.new`.
|
7
|
+
#
|
8
|
+
# This usage raises a warning in Ruby 3.3 and results in an error in Ruby 3.4.
|
9
|
+
# In Ruby 3.4, keyword arguments will instead be used to change the behavior of a hash.
|
10
|
+
# For example, the capacity option can be passed to create a hash with a certain size
|
11
|
+
# if you know it in advance, for better performance.
|
12
|
+
#
|
13
|
+
# NOTE: The following corner case may result in a false negative when upgrading from Ruby 3.3
|
14
|
+
# or earlier, but it is intentionally not detected to respect the expected usage in Ruby 3.4.
|
15
|
+
#
|
16
|
+
# [source,ruby]
|
17
|
+
# ----
|
18
|
+
# Hash.new(capacity: 42)
|
19
|
+
# ----
|
20
|
+
#
|
21
|
+
# @example
|
22
|
+
#
|
23
|
+
# # bad
|
24
|
+
# Hash.new(key: :value)
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# Hash.new({key: :value})
|
28
|
+
#
|
29
|
+
class HashNewWithKeywordArgumentsAsDefault < Base
|
30
|
+
extend AutoCorrector
|
31
|
+
|
32
|
+
MSG = 'Use a hash literal instead of keyword arguments.'
|
33
|
+
RESTRICT_ON_SEND = %i[new].freeze
|
34
|
+
|
35
|
+
# @!method hash_new(node)
|
36
|
+
def_node_matcher :hash_new, <<~PATTERN
|
37
|
+
(send (const {nil? (cbase)} :Hash) :new $[hash !braces?])
|
38
|
+
PATTERN
|
39
|
+
|
40
|
+
def on_send(node)
|
41
|
+
return unless (first_argument = hash_new(node))
|
42
|
+
|
43
|
+
if first_argument.pairs.one?
|
44
|
+
key = first_argument.pairs.first.key
|
45
|
+
return if key.respond_to?(:value) && key.value == :capacity
|
46
|
+
end
|
47
|
+
|
48
|
+
add_offense(first_argument) do |corrector|
|
49
|
+
corrector.wrap(first_argument, '{', '}')
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -24,14 +24,17 @@ module RuboCop
|
|
24
24
|
MSG = 'Interpolation in single quoted string detected. ' \
|
25
25
|
'Use double quoted strings if you need interpolation.'
|
26
26
|
|
27
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
27
28
|
def on_str(node)
|
28
29
|
return if node.parent&.regexp_type?
|
29
30
|
return unless /(?<!\\)#\{.*\}/.match?(node.source)
|
30
31
|
return if heredoc?(node)
|
31
32
|
return unless node.loc.begin && node.loc.end
|
33
|
+
return unless valid_syntax?(node)
|
32
34
|
|
33
35
|
add_offense(node) { |corrector| autocorrect(corrector, node) }
|
34
36
|
end
|
37
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
35
38
|
|
36
39
|
private
|
37
40
|
|
@@ -49,6 +52,12 @@ module RuboCop
|
|
49
52
|
def heredoc?(node)
|
50
53
|
node.loc.is_a?(Parser::Source::Map::Heredoc) || (node.parent && heredoc?(node.parent))
|
51
54
|
end
|
55
|
+
|
56
|
+
def valid_syntax?(node)
|
57
|
+
double_quoted_string = node.source.gsub(/\A'|'\z/, '"')
|
58
|
+
|
59
|
+
parse(double_quoted_string).valid_syntax?
|
60
|
+
end
|
52
61
|
end
|
53
62
|
end
|
54
63
|
end
|
@@ -26,6 +26,9 @@ module RuboCop
|
|
26
26
|
#
|
27
27
|
class ItWithoutArgumentsInBlock < Base
|
28
28
|
include NodePattern::Macros
|
29
|
+
extend TargetRubyVersion
|
30
|
+
|
31
|
+
maximum_target_ruby_version 3.3
|
29
32
|
|
30
33
|
MSG = '`it` calls without arguments will refer to the first block param in Ruby 3.4; ' \
|
31
34
|
'use `it()` or `self.it`.'
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
40
40
|
traverse_node(node.condition) do |asgn_node|
|
41
41
|
next unless asgn_node.loc.operator
|
42
42
|
|
43
|
-
rhs = asgn_node.
|
43
|
+
rhs = asgn_node.rhs
|
44
44
|
next if !all_literals?(rhs) || parallel_assignment_with_splat_operator?(rhs)
|
45
45
|
|
46
46
|
range = offense_range(asgn_node, rhs)
|
@@ -36,12 +36,9 @@ module RuboCop
|
|
36
36
|
|
37
37
|
def on_irange(node)
|
38
38
|
return unless node.children.compact.all?(&:str_type?)
|
39
|
+
return if node.begin.nil? || node.end.nil?
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
return if range_start.nil? || range_end.nil?
|
43
|
-
|
44
|
-
add_offense(node) if unsafe_range?(range_start.value, range_end.value)
|
41
|
+
add_offense(node) if unsafe_range?(node.begin.value, node.end.value)
|
45
42
|
end
|
46
43
|
alias on_erange on_irange
|
47
44
|
|
@@ -95,7 +95,7 @@ module RuboCop
|
|
95
95
|
MSG = 'Method definitions must not be nested. Use `lambda` instead.'
|
96
96
|
|
97
97
|
def on_def(node)
|
98
|
-
subject, = *node
|
98
|
+
subject, = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
99
99
|
return if node.defs_type? && subject.variable?
|
100
100
|
|
101
101
|
def_ancestor = node.each_ancestor(:def, :defs).first
|
@@ -95,7 +95,7 @@ module RuboCop
|
|
95
95
|
end
|
96
96
|
|
97
97
|
def allowable_use_with_if?(if_node)
|
98
|
-
if_node.condition.
|
98
|
+
if_node.condition.operator_keyword? || if_node.else_branch
|
99
99
|
end
|
100
100
|
|
101
101
|
def register_offense(node, exist_node)
|
@@ -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
|
@@ -33,8 +33,7 @@ module RuboCop
|
|
33
33
|
NUMBERED_PARAMETER_RANGE = (1..9).freeze
|
34
34
|
|
35
35
|
def on_lvasgn(node)
|
36
|
-
|
37
|
-
return unless /\A_(\d+)\z/ =~ lhs
|
36
|
+
return unless /\A_(\d+)\z/ =~ node.name
|
38
37
|
|
39
38
|
number = Regexp.last_match(1).to_i
|
40
39
|
template = NUMBERED_PARAMETER_RANGE.include?(number) ? NUM_PARAM_MSG : LVAR_MSG
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Certain numeric operations have a constant result, usually 0 or 1.
|
7
|
+
# Subtracting a number from itself or multiplying it by 0 will always return 0.
|
8
|
+
# Additionally, a variable modulo 0 or itself will always return 0.
|
9
|
+
# Dividing a number by itself or raising it to the power of 0 will always return 1.
|
10
|
+
# As such, they can be replaced with that result.
|
11
|
+
# These are probably leftover from debugging, or are mistakes.
|
12
|
+
# Other numeric operations that are similarly leftover from debugging or mistakes
|
13
|
+
# are handled by Lint/UselessNumericOperation.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# x - x
|
19
|
+
# x * 0
|
20
|
+
# x % 1
|
21
|
+
# x % x
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# 0
|
25
|
+
#
|
26
|
+
# # bad
|
27
|
+
# x -= x
|
28
|
+
# x *= 0
|
29
|
+
# x %= 1
|
30
|
+
# x %= x
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# x = 0
|
34
|
+
#
|
35
|
+
# # bad
|
36
|
+
# x / x
|
37
|
+
# x ** 0
|
38
|
+
#
|
39
|
+
# # good
|
40
|
+
# 1
|
41
|
+
#
|
42
|
+
# # bad
|
43
|
+
# x /= x
|
44
|
+
# x **= 0
|
45
|
+
#
|
46
|
+
# # good
|
47
|
+
# x = 1
|
48
|
+
#
|
49
|
+
class NumericOperationWithConstantResult < Base
|
50
|
+
extend AutoCorrector
|
51
|
+
MSG = 'Numeric operation with a constant result detected.'
|
52
|
+
RESTRICT_ON_SEND = %i[- * / % **].freeze
|
53
|
+
|
54
|
+
# @!method operation_with_constant_result?(node)
|
55
|
+
def_node_matcher :operation_with_constant_result?,
|
56
|
+
'(send (send nil? $_) $_ ({int | send nil?} $_))'
|
57
|
+
|
58
|
+
# @!method abbreviated_assignment_with_constant_result?(node)
|
59
|
+
def_node_matcher :abbreviated_assignment_with_constant_result?,
|
60
|
+
'(op-asgn (lvasgn $_) $_ ({int | lvar} $_))'
|
61
|
+
|
62
|
+
def on_send(node)
|
63
|
+
return unless operation_with_constant_result?(node)
|
64
|
+
|
65
|
+
variable, operation, number = operation_with_constant_result?(node)
|
66
|
+
result = constant_result?(variable, operation, number)
|
67
|
+
return unless result
|
68
|
+
|
69
|
+
add_offense(node) do |corrector|
|
70
|
+
corrector.replace(node, result.to_s)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def on_op_asgn(node)
|
75
|
+
return unless abbreviated_assignment_with_constant_result?(node)
|
76
|
+
|
77
|
+
variable, operation, number = abbreviated_assignment_with_constant_result?(node)
|
78
|
+
result = constant_result?(variable, operation, number)
|
79
|
+
return unless result
|
80
|
+
|
81
|
+
add_offense(node) do |corrector|
|
82
|
+
corrector.replace(node, "#{variable} = #{result}")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
private
|
87
|
+
|
88
|
+
# rubocop :disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
89
|
+
def constant_result?(variable, operation, number)
|
90
|
+
if number.to_s == '0'
|
91
|
+
return 0 if operation == :*
|
92
|
+
return 1 if operation == :**
|
93
|
+
elsif number.to_s == '1'
|
94
|
+
return 0 if operation == :%
|
95
|
+
elsif number == variable
|
96
|
+
return 0 if %i[- %].include?(operation)
|
97
|
+
return 1 if operation == :/
|
98
|
+
end
|
99
|
+
# If we weren't able to find any matches, return false so we can bail out.
|
100
|
+
false
|
101
|
+
end
|
102
|
+
# rubocop :enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
@@ -27,8 +27,7 @@ module RuboCop
|
|
27
27
|
MSG = 'Avoid using or-assignment with constants.'
|
28
28
|
|
29
29
|
def on_or_asgn(node)
|
30
|
-
|
31
|
-
return unless lhs&.casgn_type?
|
30
|
+
return unless node.lhs&.casgn_type?
|
32
31
|
|
33
32
|
add_offense(node.loc.operator) do |corrector|
|
34
33
|
next if node.each_ancestor(:def, :defs).any?
|
@@ -111,7 +111,7 @@ module RuboCop
|
|
111
111
|
range_between(start + begin_pos - 1, start + end_pos)
|
112
112
|
end
|
113
113
|
|
114
|
-
# If the list of cops is comma-separated, but without
|
114
|
+
# If the list of cops is comma-separated, but without an empty space after the comma,
|
115
115
|
# we should **not** remove the prepending empty space, thus begin_pos += 1
|
116
116
|
def range_with_comma_after(comment, start, begin_pos, end_pos)
|
117
117
|
begin_pos += 1 if comment.source[end_pos + 1] != ' '
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# Checks for redundant safe navigation calls.
|
7
7
|
# Use cases where a constant, named in camel case for classes and modules is `nil` are rare,
|
8
8
|
# and an offense is not detected when the receiver is a constant. The detection also applies
|
9
|
-
# to literal receivers, except for `nil`.
|
9
|
+
# to `self`, and to literal receivers, except for `nil`.
|
10
10
|
#
|
11
11
|
# For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
|
12
12
|
# and `equal?` methods are checked by default.
|
@@ -29,6 +29,9 @@ module RuboCop
|
|
29
29
|
# # bad
|
30
30
|
# CamelCaseConst&.do_something
|
31
31
|
#
|
32
|
+
# # good
|
33
|
+
# CamelCaseConst.do_something
|
34
|
+
#
|
32
35
|
# # bad
|
33
36
|
# do_something if attrs&.respond_to?(:[])
|
34
37
|
#
|
@@ -41,9 +44,6 @@ module RuboCop
|
|
41
44
|
# end
|
42
45
|
#
|
43
46
|
# # good
|
44
|
-
# CamelCaseConst.do_something
|
45
|
-
#
|
46
|
-
# # good
|
47
47
|
# while node.is_a?(BeginNode)
|
48
48
|
# node = node.parent
|
49
49
|
# end
|
@@ -67,6 +67,12 @@ module RuboCop
|
|
67
67
|
# foo.to_f
|
68
68
|
# foo.to_s
|
69
69
|
#
|
70
|
+
# # bad
|
71
|
+
# self&.foo
|
72
|
+
#
|
73
|
+
# # good
|
74
|
+
# self.foo
|
75
|
+
#
|
70
76
|
# @example AllowedMethods: [nil_safe_method]
|
71
77
|
# # bad
|
72
78
|
# do_something if attrs&.nil_safe_method(:[])
|
@@ -133,7 +139,7 @@ module RuboCop
|
|
133
139
|
def assume_receiver_instance_exists?(receiver)
|
134
140
|
return true if receiver.const_type? && !receiver.short_name.match?(SNAKE_CASE)
|
135
141
|
|
136
|
-
receiver.literal? && !receiver.nil_type?
|
142
|
+
receiver.self_type? || (receiver.literal? && !receiver.nil_type?)
|
137
143
|
end
|
138
144
|
|
139
145
|
def check?(node)
|
@@ -141,8 +147,7 @@ module RuboCop
|
|
141
147
|
return false unless parent
|
142
148
|
|
143
149
|
condition?(parent, node) ||
|
144
|
-
parent.
|
145
|
-
parent.or_type? ||
|
150
|
+
parent.operator_keyword? ||
|
146
151
|
(parent.send_type? && parent.negation_method?)
|
147
152
|
end
|
148
153
|
|