rubocop 1.18.4 → 1.21.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 +65 -13
- data/lib/rubocop/cli.rb +18 -0
- data/lib/rubocop/config_loader.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +21 -6
- data/lib/rubocop/cop/base.rb +2 -2
- data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +12 -11
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/require_library_corrector.rb +23 -0
- data/lib/rubocop/cop/documentation.rb +1 -1
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/inherit_deprecated_cop_class.rb +34 -0
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +71 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +9 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -2
- data/lib/rubocop/cop/layout/hash_alignment.rb +7 -3
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +0 -7
- data/lib/rubocop/cop/layout/leading_comment_space.rb +2 -2
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +33 -14
- data/lib/rubocop/cop/layout/line_length.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +22 -9
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +5 -5
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +24 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +107 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +105 -0
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +5 -2
- data/lib/rubocop/cop/lint/debugger.rb +2 -4
- data/lib/rubocop/cop/lint/duplicate_methods.rb +8 -5
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +7 -1
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -1
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +19 -1
- data/lib/rubocop/cop/mixin/heredoc.rb +7 -0
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
- data/lib/rubocop/cop/mixin/percent_array.rb +13 -7
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
- data/lib/rubocop/cop/mixin/require_library.rb +59 -0
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
- data/lib/rubocop/cop/naming/constant_name.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +27 -10
- data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
- data/lib/rubocop/cop/style/and_or.rb +4 -0
- data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +39 -6
- data/lib/rubocop/cop/style/case_equality.rb +6 -9
- data/lib/rubocop/cop/style/collection_methods.rb +2 -1
- data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
- data/lib/rubocop/cop/style/commented_keyword.rb +2 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +19 -5
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +23 -8
- data/lib/rubocop/cop/style/double_negation.rb +12 -1
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/encoding.rb +26 -15
- data/lib/rubocop/cop/style/explicit_block_argument.rb +46 -11
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +1 -1
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +11 -0
- data/lib/rubocop/cop/style/hash_except.rb +4 -3
- data/lib/rubocop/cop/style/hash_transform_keys.rb +0 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +30 -5
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +3 -2
- data/lib/rubocop/cop/style/lambda_call.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
- data/lib/rubocop/cop/style/method_def_parentheses.rb +10 -1
- data/lib/rubocop/cop/style/missing_else.rb +7 -0
- data/lib/rubocop/cop/style/mutable_constant.rb +68 -6
- data/lib/rubocop/cop/style/negated_if.rb +1 -1
- data/lib/rubocop/cop/style/negated_unless.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
- data/lib/rubocop/cop/style/not.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +25 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
- data/lib/rubocop/cop/style/redundant_freeze.rb +4 -3
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +83 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +19 -4
- data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
- data/lib/rubocop/cop/style/return_nil.rb +2 -1
- data/lib/rubocop/cop/style/semicolon.rb +32 -24
- data/lib/rubocop/cop/style/single_line_block_params.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +21 -0
- data/lib/rubocop/cop/style/static_class.rb +1 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +3 -0
- data/lib/rubocop/cop/style/symbol_array.rb +3 -3
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +23 -5
- data/lib/rubocop/cop/style/yoda_condition.rb +4 -7
- data/lib/rubocop/cop/util.rb +7 -2
- data/lib/rubocop/magic_comment.rb +44 -15
- data/lib/rubocop/options.rb +1 -1
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/runner.rb +1 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +9 -2
- metadata +14 -5
@@ -109,12 +109,13 @@ module RuboCop
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def opposite_condition?(node)
|
112
|
-
!node.unless? && node.if_branch.false_type? ||
|
112
|
+
(!node.unless? && node.if_branch.false_type?) ||
|
113
|
+
(node.unless? && node.if_branch.true_type?)
|
113
114
|
end
|
114
115
|
|
115
116
|
def require_parentheses?(condition)
|
116
117
|
condition.and_type? || condition.or_type? ||
|
117
|
-
condition.send_type? && condition.comparison_method?
|
118
|
+
(condition.send_type? && condition.comparison_method?)
|
118
119
|
end
|
119
120
|
end
|
120
121
|
end
|
@@ -93,8 +93,8 @@ module RuboCop
|
|
93
93
|
parent = node.parent&.block_type? ? node.parent.parent : node.parent
|
94
94
|
parent &&
|
95
95
|
(logical_operator?(parent) ||
|
96
|
-
parent.send_type? &&
|
97
|
-
parent.arguments.any? { |argument| logical_operator?(argument) })
|
96
|
+
(parent.send_type? &&
|
97
|
+
parent.arguments.any? { |argument| logical_operator?(argument) }))
|
98
98
|
end
|
99
99
|
|
100
100
|
def call_in_optional_arguments?(node)
|
@@ -122,14 +122,14 @@ module RuboCop
|
|
122
122
|
|
123
123
|
def call_as_argument_or_chain?(node)
|
124
124
|
node.parent &&
|
125
|
-
(node.parent.send_type? && !assigned_before?(node.parent, node) ||
|
125
|
+
((node.parent.send_type? && !assigned_before?(node.parent, node)) ||
|
126
126
|
node.parent.csend_type? || node.parent.super_type? || node.parent.yield_type?)
|
127
127
|
end
|
128
128
|
|
129
129
|
def hash_literal_in_arguments?(node)
|
130
130
|
node.arguments.any? do |n|
|
131
131
|
hash_literal?(n) ||
|
132
|
-
n.send_type? && node.descendants.any? { |descendant| hash_literal?(descendant) }
|
132
|
+
(n.send_type? && node.descendants.any? { |descendant| hash_literal?(descendant) })
|
133
133
|
end
|
134
134
|
end
|
135
135
|
|
@@ -171,8 +171,8 @@ module RuboCop
|
|
171
171
|
end
|
172
172
|
|
173
173
|
def unary_literal?(node)
|
174
|
-
node.numeric_type? && node.sign? ||
|
175
|
-
node.parent&.send_type? && node.parent&.unary_operation?
|
174
|
+
(node.numeric_type? && node.sign?) ||
|
175
|
+
(node.parent&.send_type? && node.parent&.unary_operation?)
|
176
176
|
end
|
177
177
|
|
178
178
|
def assigned_before?(node, target)
|
@@ -96,7 +96,7 @@ module RuboCop
|
|
96
96
|
MSG_MISSING = 'Use def with parentheses when there are parameters.'
|
97
97
|
|
98
98
|
def on_def(node)
|
99
|
-
return if node
|
99
|
+
return if forced_parentheses?(node)
|
100
100
|
|
101
101
|
args = node.arguments
|
102
102
|
|
@@ -129,6 +129,15 @@ module RuboCop
|
|
129
129
|
corrector.insert_after(arguments_range, ')')
|
130
130
|
end
|
131
131
|
|
132
|
+
def forced_parentheses?(node)
|
133
|
+
# Regardless of style, parentheses are necessary for:
|
134
|
+
# 1. Endless methods
|
135
|
+
# 2. Argument lists containing a `forward-arg` (`...`)
|
136
|
+
# Removing the parens would be a syntax error here.
|
137
|
+
|
138
|
+
node.endless? || node.arguments.any?(&:forward_arg_type?)
|
139
|
+
end
|
140
|
+
|
132
141
|
def require_parentheses?(args)
|
133
142
|
style == :require_parentheses ||
|
134
143
|
(style == :require_no_parentheses_except_multiline && args.multiline?)
|
@@ -5,6 +5,9 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# Checks for `if` expressions that do not have an `else` branch.
|
7
7
|
#
|
8
|
+
# NOTE: Pattern matching is allowed to have no `else` branch because unlike `if` and `case`,
|
9
|
+
# it raises `NoMatchingPatternError` if the pattern doesn't match and without having `else`.
|
10
|
+
#
|
8
11
|
# Supported styles are: if, case, both.
|
9
12
|
#
|
10
13
|
# @example EnforcedStyle: if
|
@@ -114,6 +117,10 @@ module RuboCop
|
|
114
117
|
check(node)
|
115
118
|
end
|
116
119
|
|
120
|
+
def on_case_match(node)
|
121
|
+
# do nothing.
|
122
|
+
end
|
123
|
+
|
117
124
|
private
|
118
125
|
|
119
126
|
def check(node)
|
@@ -14,8 +14,16 @@ module RuboCop
|
|
14
14
|
# positives. Luckily, there is no harm in freezing an already
|
15
15
|
# frozen object.
|
16
16
|
#
|
17
|
+
# From Ruby 3.0, this cop honours the magic comment
|
18
|
+
# 'shareable_constant_value'. When this magic comment is set to any
|
19
|
+
# acceptable value other than none, it will suppress the offenses
|
20
|
+
# raised by this cop. It enforces frozen state.
|
21
|
+
#
|
17
22
|
# NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
|
18
23
|
#
|
24
|
+
# NOTE: From Ruby 3.0, this cop allows explicit freezing of interpolated
|
25
|
+
# string literals when `# frozen-string-literal: true` is used.
|
26
|
+
#
|
19
27
|
# @example EnforcedStyle: literals (default)
|
20
28
|
# # bad
|
21
29
|
# CONST = [1, 2, 3]
|
@@ -52,7 +60,59 @@ module RuboCop
|
|
52
60
|
# puts 1
|
53
61
|
# end
|
54
62
|
# end.freeze
|
63
|
+
#
|
64
|
+
# @example
|
65
|
+
# # Magic comment - shareable_constant_value: literal
|
66
|
+
#
|
67
|
+
# # bad
|
68
|
+
# CONST = [1, 2, 3]
|
69
|
+
#
|
70
|
+
# # good
|
71
|
+
# # shareable_constant_value: literal
|
72
|
+
# CONST = [1, 2, 3]
|
73
|
+
#
|
74
|
+
# NOTE: This special directive helps to create constants
|
75
|
+
# that hold only immutable objects, or Ractor-shareable
|
76
|
+
# constants. - ruby docs
|
77
|
+
#
|
55
78
|
class MutableConstant < Base
|
79
|
+
# Handles magic comment shareable_constant_value with O(n ^ 2) complexity
|
80
|
+
# n - number of lines in the source
|
81
|
+
# Iterates over all lines before a CONSTANT
|
82
|
+
# until it reaches shareable_constant_value
|
83
|
+
module ShareableConstantValue
|
84
|
+
module_function
|
85
|
+
|
86
|
+
def recent_shareable_value?(node)
|
87
|
+
shareable_constant_comment = magic_comment_in_scope node
|
88
|
+
return false if shareable_constant_comment.nil?
|
89
|
+
|
90
|
+
shareable_constant_value = MagicComment.parse(shareable_constant_comment)
|
91
|
+
.shareable_constant_value
|
92
|
+
shareable_constant_value_enabled? shareable_constant_value
|
93
|
+
end
|
94
|
+
|
95
|
+
# Identifies the most recent magic comment with valid shareable constant values
|
96
|
+
# thats in scope for this node
|
97
|
+
def magic_comment_in_scope(node)
|
98
|
+
processed_source_till_node(node).reverse_each.find do |line|
|
99
|
+
MagicComment.parse(line).valid_shareable_constant_value?
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def processed_source_till_node(node)
|
106
|
+
processed_source.lines[0..(node.last_line - 1)]
|
107
|
+
end
|
108
|
+
|
109
|
+
def shareable_constant_value_enabled?(value)
|
110
|
+
%w[literal experimental_everything experimental_copy].include? value
|
111
|
+
end
|
112
|
+
end
|
113
|
+
private_constant :ShareableConstantValue
|
114
|
+
|
115
|
+
include ShareableConstantValue
|
56
116
|
include FrozenStringLiteral
|
57
117
|
include ConfigurableEnforcedStyle
|
58
118
|
extend AutoCorrector
|
@@ -85,18 +145,18 @@ module RuboCop
|
|
85
145
|
return if immutable_literal?(value)
|
86
146
|
return if operation_produces_immutable_object?(value)
|
87
147
|
return if frozen_string_literal?(value)
|
148
|
+
return if shareable_constant_value?(value)
|
88
149
|
|
89
150
|
add_offense(value) { |corrector| autocorrect(corrector, value) }
|
90
151
|
end
|
91
152
|
|
92
153
|
def check(value)
|
93
154
|
range_enclosed_in_parentheses = range_enclosed_in_parentheses?(value)
|
94
|
-
|
95
155
|
return unless mutable_literal?(value) ||
|
96
|
-
target_ruby_version <= 2.7 && range_enclosed_in_parentheses
|
156
|
+
(target_ruby_version <= 2.7 && range_enclosed_in_parentheses)
|
97
157
|
|
98
|
-
return if
|
99
|
-
|
158
|
+
return if frozen_string_literal?(value)
|
159
|
+
return if shareable_constant_value?(value)
|
100
160
|
|
101
161
|
add_offense(value) { |corrector| autocorrect(corrector, value) }
|
102
162
|
end
|
@@ -126,8 +186,10 @@ module RuboCop
|
|
126
186
|
frozen_regexp_or_range_literals?(node) || node.immutable_literal?
|
127
187
|
end
|
128
188
|
|
129
|
-
def
|
130
|
-
|
189
|
+
def shareable_constant_value?(node)
|
190
|
+
return false if target_ruby_version < 3.0
|
191
|
+
|
192
|
+
recent_shareable_value? node
|
131
193
|
end
|
132
194
|
|
133
195
|
def frozen_regexp_or_range_literals?(node)
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
63
63
|
|
64
64
|
def on_send(node)
|
65
65
|
return if ignored_node?(node) ||
|
66
|
-
!include_semantic_changes? && nil_comparison_style == 'comparison'
|
66
|
+
(!include_semantic_changes? && nil_comparison_style == 'comparison')
|
67
67
|
return unless register_offense?(node)
|
68
68
|
|
69
69
|
message = message(node)
|
@@ -87,7 +87,7 @@ module RuboCop
|
|
87
87
|
|
88
88
|
def register_offense?(node)
|
89
89
|
not_equal_to_nil?(node) ||
|
90
|
-
include_semantic_changes? && (not_and_nil_check?(node) || unless_and_nil_check?(node))
|
90
|
+
(include_semantic_changes? && (not_and_nil_check?(node) || unless_and_nil_check?(node)))
|
91
91
|
end
|
92
92
|
|
93
93
|
def autocorrect(corrector, node)
|
@@ -53,8 +53,8 @@ module RuboCop
|
|
53
53
|
|
54
54
|
def requires_parens?(child)
|
55
55
|
child.and_type? || child.or_type? ||
|
56
|
-
child.send_type? && child.binary_operation? ||
|
57
|
-
child.if_type? && child.ternary?
|
56
|
+
(child.send_type? && child.binary_operation?) ||
|
57
|
+
(child.if_type? && child.ternary?)
|
58
58
|
end
|
59
59
|
|
60
60
|
def correct_opposite_method(corrector, range, child)
|
@@ -153,7 +153,7 @@ module RuboCop
|
|
153
153
|
|
154
154
|
def dependency?(lhs, rhs)
|
155
155
|
uses_var?(rhs, var_name(lhs)) ||
|
156
|
-
lhs.send_type? && lhs.assignment_method? && accesses?(rhs, lhs)
|
156
|
+
(lhs.send_type? && lhs.assignment_method? && accesses?(rhs, lhs))
|
157
157
|
end
|
158
158
|
|
159
159
|
# `lhs` is an assignment method call like `obj.attr=` or `ary[idx]=`.
|
@@ -53,8 +53,8 @@ module RuboCop
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def correct_literal_style?(node)
|
56
|
-
style == :lower_case_q && type(node) == '%q' ||
|
57
|
-
style == :upper_case_q && type(node) == '%Q'
|
56
|
+
(style == :lower_case_q && type(node) == '%q') ||
|
57
|
+
(style == :upper_case_q && type(node) == '%Q')
|
58
58
|
end
|
59
59
|
|
60
60
|
def message(_range)
|
@@ -84,6 +84,7 @@ module RuboCop
|
|
84
84
|
|
85
85
|
def on_kwbegin(node)
|
86
86
|
return if empty_begin?(node) ||
|
87
|
+
begin_block_has_multiline_statements?(node) ||
|
87
88
|
contain_rescue_or_ensure?(node) ||
|
88
89
|
valid_context_using_only_begin?(node)
|
89
90
|
|
@@ -102,6 +103,9 @@ module RuboCop
|
|
102
103
|
corrector.remove(offense_range)
|
103
104
|
end
|
104
105
|
|
106
|
+
if use_modifier_form_after_multiline_begin_block?(node)
|
107
|
+
correct_modifier_form_after_multiline_begin_block(corrector, node)
|
108
|
+
end
|
105
109
|
corrector.remove(node.loc.end)
|
106
110
|
end
|
107
111
|
end
|
@@ -127,10 +131,31 @@ module RuboCop
|
|
127
131
|
corrector.insert_before(node.parent, comments) unless comments.blank?
|
128
132
|
end
|
129
133
|
|
134
|
+
def use_modifier_form_after_multiline_begin_block?(node)
|
135
|
+
return unless (parent = node.parent)
|
136
|
+
|
137
|
+
node.multiline? && parent.if_type? && parent.modifier_form?
|
138
|
+
end
|
139
|
+
|
140
|
+
def correct_modifier_form_after_multiline_begin_block(corrector, node)
|
141
|
+
condition_range = condition_range(node.parent)
|
142
|
+
|
143
|
+
corrector.insert_after(node.children.first, " #{condition_range.source}")
|
144
|
+
corrector.remove(range_by_whole_lines(condition_range, include_final_newline: true))
|
145
|
+
end
|
146
|
+
|
147
|
+
def condition_range(node)
|
148
|
+
range_between(node.loc.keyword.begin_pos, node.condition.source_range.end_pos)
|
149
|
+
end
|
150
|
+
|
130
151
|
def empty_begin?(node)
|
131
152
|
node.children.empty?
|
132
153
|
end
|
133
154
|
|
155
|
+
def begin_block_has_multiline_statements?(node)
|
156
|
+
node.children.count >= 2
|
157
|
+
end
|
158
|
+
|
134
159
|
def contain_rescue_or_ensure?(node)
|
135
160
|
first_child = node.children.first
|
136
161
|
|
@@ -120,11 +120,10 @@ module RuboCop
|
|
120
120
|
end
|
121
121
|
|
122
122
|
def require_parentheses?(node)
|
123
|
-
node.basic_conditional? &&
|
124
|
-
node.modifier_form? ||
|
123
|
+
(node.basic_conditional? && node.modifier_form?) ||
|
125
124
|
node.range_type? ||
|
126
125
|
node.rescue_type? ||
|
127
|
-
node.respond_to?(:semantic_operator?) && node.semantic_operator?
|
126
|
+
(node.respond_to?(:semantic_operator?) && node.semantic_operator?)
|
128
127
|
end
|
129
128
|
|
130
129
|
def without_argument_parentheses_method?(node)
|
@@ -7,6 +7,9 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# NOTE: Regexp and Range literals are frozen objects since Ruby 3.0.
|
9
9
|
#
|
10
|
+
# NOTE: From Ruby 3.0, this cop allows explicit freezing of interpolated
|
11
|
+
# string literals when `# frozen-string-literal: true` is used.
|
12
|
+
#
|
10
13
|
# @example
|
11
14
|
# # bad
|
12
15
|
# CONST = 1.freeze
|
@@ -37,9 +40,7 @@ module RuboCop
|
|
37
40
|
node = strip_parenthesis(node)
|
38
41
|
|
39
42
|
return true if node.immutable_literal?
|
40
|
-
|
41
|
-
return true if FROZEN_STRING_LITERAL_TYPES.include?(node.type) &&
|
42
|
-
frozen_string_literals_enabled?
|
43
|
+
return true if frozen_string_literal?(node)
|
43
44
|
|
44
45
|
target_ruby_version >= 3.0 && (node.regexp_type? || node.range_type?)
|
45
46
|
end
|
@@ -65,9 +65,8 @@ module RuboCop
|
|
65
65
|
end
|
66
66
|
|
67
67
|
def allowed_percent_q?(node)
|
68
|
-
node.source.start_with?(PERCENT_Q) && acceptable_q?(node) ||
|
69
|
-
node.source.start_with?(PERCENT_CAPITAL_Q) &&
|
70
|
-
acceptable_capital_q?(node)
|
68
|
+
(node.source.start_with?(PERCENT_Q) && acceptable_q?(node)) ||
|
69
|
+
(node.source.start_with?(PERCENT_CAPITAL_Q) && acceptable_capital_q?(node))
|
71
70
|
end
|
72
71
|
|
73
72
|
def message(node)
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for places where conditional branch makes redundant self-assignment.
|
7
|
+
#
|
8
|
+
# It only detects local variable because it may replace state of instance variable,
|
9
|
+
# class variable, and global variable that have state across methods with `nil`.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# foo = condition ? bar : foo
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# foo = bar if condition
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# foo = condition ? foo : bar
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# foo = bar unless condition
|
24
|
+
#
|
25
|
+
class RedundantSelfAssignmentBranch < Base
|
26
|
+
include RangeHelp
|
27
|
+
extend AutoCorrector
|
28
|
+
|
29
|
+
MSG = 'Remove the self-assignment branch.'
|
30
|
+
|
31
|
+
# @!method bad_method?(node)
|
32
|
+
def_node_matcher :bad_method?, <<~PATTERN
|
33
|
+
(send nil? :bad_method ...)
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def on_lvasgn(node)
|
37
|
+
variable, expression = *node
|
38
|
+
return unless use_if_and_else_branch?(expression)
|
39
|
+
|
40
|
+
if_branch = expression.if_branch
|
41
|
+
else_branch = expression.else_branch
|
42
|
+
return if inconvertible_to_modifier?(if_branch, else_branch)
|
43
|
+
|
44
|
+
if self_assign?(variable, if_branch)
|
45
|
+
register_offense(expression, if_branch, else_branch, 'unless')
|
46
|
+
elsif self_assign?(variable, else_branch)
|
47
|
+
register_offense(expression, else_branch, if_branch, 'if')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def use_if_and_else_branch?(expression)
|
54
|
+
return false unless expression&.if_type?
|
55
|
+
|
56
|
+
!expression.ternary? || !expression.else?
|
57
|
+
end
|
58
|
+
|
59
|
+
def inconvertible_to_modifier?(if_branch, else_branch)
|
60
|
+
multiple_statements?(if_branch) || multiple_statements?(else_branch) ||
|
61
|
+
(else_branch.respond_to?(:elsif?) && else_branch.elsif?)
|
62
|
+
end
|
63
|
+
|
64
|
+
def multiple_statements?(branch)
|
65
|
+
branch && branch.children.compact.count > 1
|
66
|
+
end
|
67
|
+
|
68
|
+
def self_assign?(variable, branch)
|
69
|
+
variable.to_s == branch&.source
|
70
|
+
end
|
71
|
+
|
72
|
+
def register_offense(if_node, offense_branch, opposite_branch, keyword)
|
73
|
+
add_offense(offense_branch) do |corrector|
|
74
|
+
assignment_value = opposite_branch ? opposite_branch.source : 'nil'
|
75
|
+
replacement = "#{assignment_value} #{keyword} #{if_node.condition.source}"
|
76
|
+
|
77
|
+
corrector.replace(if_node, replacement)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|