rubocop 1.80.2 → 1.82.1
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 +35 -7
- data/config/obsoletion.yml +4 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
- data/lib/rubocop/cli.rb +3 -3
- data/lib/rubocop/comment_config.rb +62 -17
- data/lib/rubocop/config_loader.rb +5 -2
- data/lib/rubocop/config_loader_resolver.rb +7 -6
- data/lib/rubocop/config_store.rb +5 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +2 -4
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
- data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -4
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +12 -1
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +17 -5
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +6 -4
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
- data/lib/rubocop/cop/lint/debugger.rb +0 -2
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/else_layout.rb +19 -0
- data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +16 -6
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +10 -2
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
- data/lib/rubocop/cop/lint/useless_assignment.rb +44 -16
- data/lib/rubocop/cop/lint/useless_or.rb +15 -2
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +7 -0
- data/lib/rubocop/cop/message_annotator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -4
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
- data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
- data/lib/rubocop/cop/naming/method_name.rb +4 -2
- data/lib/rubocop/cop/naming/predicate_method.rb +16 -4
- data/lib/rubocop/cop/security/json_load.rb +33 -11
- data/lib/rubocop/cop/style/array_intersect.rb +2 -2
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
- data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
- data/lib/rubocop/cop/style/case_equality.rb +11 -13
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +8 -14
- data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +0 -6
- data/lib/rubocop/cop/style/endless_method.rb +15 -2
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/float_division.rb +15 -1
- data/lib/rubocop/cop/style/guard_clause.rb +0 -11
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
- data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
- data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
- data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
- data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +26 -5
- data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +1 -0
- data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
- data/lib/rubocop/cop/style/semicolon.rb +23 -7
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +8 -1
- data/lib/rubocop/cop/style/super_arguments.rb +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
- data/lib/rubocop/cop/style/unless_else.rb +10 -9
- data/lib/rubocop/cop/util.rb +2 -3
- data/lib/rubocop/cop/utils/format_string.rb +10 -0
- data/lib/rubocop/cops_documentation_generator.rb +4 -4
- data/lib/rubocop/directive_comment.rb +46 -3
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -0
- data/lib/rubocop/lsp/diagnostic.rb +10 -14
- data/lib/rubocop/lsp/stdin_runner.rb +0 -16
- data/lib/rubocop/magic_comment.rb +20 -0
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +7 -8
- data/lib/rubocop/result_cache.rb +38 -27
- data/lib/rubocop/rspec/shared_contexts.rb +2 -2
- data/lib/rubocop/rspec/support.rb +1 -1
- data/lib/rubocop/runner.rb +4 -0
- data/lib/rubocop/target_ruby.rb +11 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +2 -0
- data/lib/ruby_lsp/rubocop/addon.rb +23 -8
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
- metadata +9 -7
|
@@ -38,6 +38,24 @@ module RuboCop
|
|
|
38
38
|
# elsif do_this
|
|
39
39
|
# do_that
|
|
40
40
|
# end
|
|
41
|
+
#
|
|
42
|
+
# # bad
|
|
43
|
+
#
|
|
44
|
+
# # For single-line conditionals using `then` the layout is disallowed
|
|
45
|
+
# # when the `else` body is multiline because it is treated as a lint offense.
|
|
46
|
+
# if something then on_the_same_line_as_then
|
|
47
|
+
# else first_line
|
|
48
|
+
# second_line
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
51
|
+
# # good
|
|
52
|
+
#
|
|
53
|
+
# # For single-line conditional using `then` the layout is allowed
|
|
54
|
+
# # when `else` body is a single-line because it is treated as intentional.
|
|
55
|
+
#
|
|
56
|
+
# if something then on_the_same_line_as_then
|
|
57
|
+
# else single_line
|
|
58
|
+
# end
|
|
41
59
|
class ElseLayout < Base
|
|
42
60
|
include Alignment
|
|
43
61
|
include RangeHelp
|
|
@@ -47,6 +65,7 @@ module RuboCop
|
|
|
47
65
|
|
|
48
66
|
def on_if(node)
|
|
49
67
|
return if node.ternary?
|
|
68
|
+
return if node.then? && !node.else_branch&.begin_type?
|
|
50
69
|
|
|
51
70
|
# If the if is on a single line, it'll be handled by `Style/OneLineConditional`
|
|
52
71
|
return if node.single_line?
|
|
@@ -19,12 +19,23 @@ module RuboCop
|
|
|
19
19
|
MSG = 'Empty interpolation detected.'
|
|
20
20
|
|
|
21
21
|
def on_interpolation(begin_node)
|
|
22
|
+
return if in_percent_literal_array?(begin_node)
|
|
23
|
+
|
|
22
24
|
node_children = begin_node.children.dup
|
|
23
25
|
node_children.delete_if { |e| e.nil_type? || (e.basic_literal? && e.str_content&.empty?) }
|
|
24
26
|
return unless node_children.empty?
|
|
25
27
|
|
|
26
28
|
add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
|
|
27
29
|
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def in_percent_literal_array?(begin_node)
|
|
34
|
+
array_node = begin_node.each_ancestor(:array).first
|
|
35
|
+
return false unless array_node
|
|
36
|
+
|
|
37
|
+
array_node.percent_literal?
|
|
38
|
+
end
|
|
28
39
|
end
|
|
29
40
|
end
|
|
30
41
|
end
|
|
@@ -269,7 +269,11 @@ module RuboCop
|
|
|
269
269
|
end
|
|
270
270
|
|
|
271
271
|
add_offense(cond) do |corrector|
|
|
272
|
+
next if part_of_ignored_node?(node)
|
|
273
|
+
|
|
272
274
|
corrector.replace(node, new_node)
|
|
275
|
+
|
|
276
|
+
ignore_node(node)
|
|
273
277
|
end
|
|
274
278
|
end
|
|
275
279
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
|
66
66
|
|
|
67
67
|
def special_keyword?(node)
|
|
68
68
|
# handle strings like __FILE__
|
|
69
|
-
(node.str_type? && !node.loc
|
|
69
|
+
(node.str_type? && !node.loc?(:begin)) || node.source_range.is?('__LINE__')
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
def array_in_regexp?(node)
|
|
@@ -9,9 +9,21 @@ module RuboCop
|
|
|
9
9
|
# cop disables on wide ranges of code, that latter contributors to
|
|
10
10
|
# a file wouldn't be aware of.
|
|
11
11
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
12
|
+
# You can set `MaximumRangeSize` to define the maximum number of
|
|
13
|
+
# consecutive lines a cop can be disabled for.
|
|
14
|
+
#
|
|
15
|
+
# - `.inf` any size (default)
|
|
16
|
+
# - `0` allows only single-line disables
|
|
17
|
+
# - `1` means the maximum allowed is as follows:
|
|
18
|
+
#
|
|
19
|
+
# [source,ruby]
|
|
20
|
+
# ----
|
|
21
|
+
# # rubocop:disable SomeCop
|
|
22
|
+
# a = 1
|
|
23
|
+
# # rubocop:enable SomeCop
|
|
24
|
+
# ----
|
|
25
|
+
#
|
|
26
|
+
# @example MaximumRangeSize: .inf (default)
|
|
15
27
|
#
|
|
16
28
|
# # good
|
|
17
29
|
# # rubocop:disable Layout/SpaceAroundOperators
|
|
@@ -25,9 +37,7 @@ module RuboCop
|
|
|
25
37
|
# x= 0
|
|
26
38
|
# # EOF
|
|
27
39
|
#
|
|
28
|
-
# @example
|
|
29
|
-
# # Lint/MissingCopEnableDirective:
|
|
30
|
-
# # MaximumRangeSize: 2
|
|
40
|
+
# @example MaximumRangeSize: 2
|
|
31
41
|
#
|
|
32
42
|
# # good
|
|
33
43
|
# # rubocop:disable Layout/SpaceAroundOperators
|
|
@@ -112,22 +112,36 @@ module RuboCop
|
|
|
112
112
|
|
|
113
113
|
def each_line_range(cop, line_ranges)
|
|
114
114
|
line_ranges.each_with_index do |line_range, line_range_index|
|
|
115
|
-
next if
|
|
116
|
-
next if expected_final_disable?(cop, line_range)
|
|
115
|
+
next if should_skip_line_range?(cop, line_range)
|
|
117
116
|
|
|
118
117
|
comment = processed_source.comment_at_line(line_range.begin)
|
|
119
|
-
|
|
120
|
-
find_redundant_all(line_range, line_ranges[line_range_index + 1])
|
|
121
|
-
elsif department_disabled?(cop, comment)
|
|
122
|
-
find_redundant_department(cop, line_range)
|
|
123
|
-
else
|
|
124
|
-
find_redundant_cop(cop, line_range)
|
|
125
|
-
end
|
|
118
|
+
next if skip_directive?(comment)
|
|
126
119
|
|
|
120
|
+
next_range = line_ranges[line_range_index + 1]
|
|
121
|
+
redundant = find_redundant_directive(cop, comment, line_range, next_range)
|
|
127
122
|
yield comment, redundant if redundant
|
|
128
123
|
end
|
|
129
124
|
end
|
|
130
125
|
|
|
126
|
+
def should_skip_line_range?(cop, line_range)
|
|
127
|
+
ignore_offense?(line_range) || expected_final_disable?(cop, line_range)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def skip_directive?(comment)
|
|
131
|
+
directive = DirectiveComment.new(comment)
|
|
132
|
+
directive.push? || directive.pop?
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def find_redundant_directive(cop, comment, line_range, next_range)
|
|
136
|
+
if all_disabled?(comment)
|
|
137
|
+
find_redundant_all(line_range, next_range)
|
|
138
|
+
elsif department_disabled?(cop, comment)
|
|
139
|
+
find_redundant_department(cop, line_range)
|
|
140
|
+
else
|
|
141
|
+
find_redundant_cop(cop, line_range)
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
131
145
|
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
132
146
|
def each_already_disabled(cop, line_ranges)
|
|
133
147
|
line_ranges.each_cons(2) do |previous_range, range|
|
|
@@ -19,7 +19,8 @@ module RuboCop
|
|
|
19
19
|
# * 2.2+ ... Add `rational` and `complex` above
|
|
20
20
|
# * 2.7+ ... Add `ruby2_keywords` above
|
|
21
21
|
# * 3.1+ ... Add `fiber` above
|
|
22
|
-
# * 3.2+ ... `set`
|
|
22
|
+
# * 3.2+ ... Add `set` above
|
|
23
|
+
# * 4.0+ ... Add `pathname` above
|
|
23
24
|
#
|
|
24
25
|
# This cop target those features.
|
|
25
26
|
#
|
|
@@ -69,7 +70,8 @@ module RuboCop
|
|
|
69
70
|
(target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
|
|
70
71
|
(target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
|
|
71
72
|
(target_ruby_version >= 3.1 && feature_name == 'fiber') ||
|
|
72
|
-
(target_ruby_version >= 3.2 && feature_name == 'set')
|
|
73
|
+
(target_ruby_version >= 3.2 && feature_name == 'set') ||
|
|
74
|
+
(target_ruby_version >= 4.0 && feature_name == 'pathname')
|
|
73
75
|
end
|
|
74
76
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
75
77
|
end
|
|
@@ -144,7 +144,9 @@ module RuboCop
|
|
|
144
144
|
expression = node.parent.source_range if node.parent.array_type?
|
|
145
145
|
[expression, variable.source]
|
|
146
146
|
elsif !variable.array_type?
|
|
147
|
-
|
|
147
|
+
replacement = variable.source
|
|
148
|
+
replacement = "[#{replacement}]" if wrap_in_brackets?(node)
|
|
149
|
+
[expression, replacement]
|
|
148
150
|
elsif redundant_brackets?(node)
|
|
149
151
|
[expression, remove_brackets(variable)]
|
|
150
152
|
else
|
|
@@ -176,6 +178,10 @@ module RuboCop
|
|
|
176
178
|
grandparent&.resbody_type?
|
|
177
179
|
end
|
|
178
180
|
|
|
181
|
+
def wrap_in_brackets?(node)
|
|
182
|
+
node.parent.array_type? && !node.parent.bracketed?
|
|
183
|
+
end
|
|
184
|
+
|
|
179
185
|
def remove_brackets(array)
|
|
180
186
|
array_start = array.loc.begin.source
|
|
181
187
|
elements = *array
|
|
@@ -24,10 +24,7 @@ module RuboCop
|
|
|
24
24
|
MSG = 'Avoid rescuing the `Exception` class. Perhaps you meant to rescue `StandardError`?'
|
|
25
25
|
|
|
26
26
|
def on_resbody(node)
|
|
27
|
-
return unless node.
|
|
28
|
-
|
|
29
|
-
rescue_args = node.children.first.children
|
|
30
|
-
return unless rescue_args.any? { |a| targets_exception?(a) }
|
|
27
|
+
return unless node.exceptions.any? { |exception| targets_exception?(exception) }
|
|
31
28
|
|
|
32
29
|
add_offense(node)
|
|
33
30
|
end
|
|
@@ -23,7 +23,15 @@ module RuboCop
|
|
|
23
23
|
# # good (method calls possibly can return different results)
|
|
24
24
|
# hash[foo] = hash[foo]
|
|
25
25
|
#
|
|
26
|
-
# @example AllowRBSInlineAnnotation:
|
|
26
|
+
# @example AllowRBSInlineAnnotation: false (default)
|
|
27
|
+
# # bad
|
|
28
|
+
# foo = foo #: Integer
|
|
29
|
+
# foo, bar = foo, bar #: Integer
|
|
30
|
+
# Foo = Foo #: Integer
|
|
31
|
+
# hash['foo'] = hash['foo'] #: Integer
|
|
32
|
+
# obj.attr = obj.attr #: Integer
|
|
33
|
+
#
|
|
34
|
+
# @example AllowRBSInlineAnnotation: true
|
|
27
35
|
# # good
|
|
28
36
|
# foo = foo #: Integer
|
|
29
37
|
# foo, bar = foo, bar #: Integer
|
|
@@ -108,7 +116,7 @@ module RuboCop
|
|
|
108
116
|
value_node = node.last_argument
|
|
109
117
|
node_arguments = node.arguments[0...-1]
|
|
110
118
|
|
|
111
|
-
if value_node.
|
|
119
|
+
if value_node.respond_to?(:method?) && value_node.method?(:[]) &&
|
|
112
120
|
node.receiver == value_node.receiver &&
|
|
113
121
|
node_arguments.none?(&:call_type?) &&
|
|
114
122
|
node_arguments == value_node.arguments
|
|
@@ -125,13 +125,13 @@ module RuboCop
|
|
|
125
125
|
next false if assignment_node.shorthand_asgn?
|
|
126
126
|
next false unless assignment_node.parent
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
conditional_assignment =
|
|
129
|
+
conditional_assignment?(assignment_node.parent, argument.scope.node)
|
|
130
130
|
|
|
131
131
|
unless uses_var?(assignment_node, argument.name)
|
|
132
132
|
# It's impossible to decide whether a branch or block is executed,
|
|
133
133
|
# so the precise reassignment location is undecidable.
|
|
134
|
-
next false if
|
|
134
|
+
next false if conditional_assignment
|
|
135
135
|
|
|
136
136
|
yield(assignment.node, location_known)
|
|
137
137
|
break
|
|
@@ -147,13 +147,13 @@ module RuboCop
|
|
|
147
147
|
node.source_range.begin_pos
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
# Check whether the given node is
|
|
150
|
+
# Check whether the given node is always executed or not
|
|
151
151
|
#
|
|
152
|
-
def
|
|
152
|
+
def conditional_assignment?(node, stop_search_node)
|
|
153
153
|
return false if node == stop_search_node
|
|
154
154
|
|
|
155
|
-
node.conditional? || node.
|
|
156
|
-
|
|
155
|
+
node.conditional? || node.type?(:block, :rescue) ||
|
|
156
|
+
conditional_assignment?(node.parent, stop_search_node)
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
# Get argument references without assignments' references
|
|
@@ -78,6 +78,7 @@ module RuboCop
|
|
|
78
78
|
}
|
|
79
79
|
PATTERN
|
|
80
80
|
|
|
81
|
+
# rubocop:disable Metrics/MethodLength
|
|
81
82
|
def flow_expression?(node)
|
|
82
83
|
return report_on_flow_command?(node) if flow_command?(node)
|
|
83
84
|
|
|
@@ -89,12 +90,14 @@ module RuboCop
|
|
|
89
90
|
check_if(node)
|
|
90
91
|
when :case, :case_match
|
|
91
92
|
check_case(node)
|
|
92
|
-
when :def
|
|
93
|
+
when :def, :defs
|
|
93
94
|
register_redefinition(node)
|
|
95
|
+
false
|
|
94
96
|
else
|
|
95
97
|
false
|
|
96
98
|
end
|
|
97
99
|
end
|
|
100
|
+
# rubocop:enable Metrics/MethodLength
|
|
98
101
|
|
|
99
102
|
def check_if(node)
|
|
100
103
|
if_branch = node.if_branch
|
|
@@ -113,8 +116,7 @@ module RuboCop
|
|
|
113
116
|
end
|
|
114
117
|
|
|
115
118
|
def register_redefinition(node)
|
|
116
|
-
@redefined << node.method_name if redefinable_flow_method?
|
|
117
|
-
false
|
|
119
|
+
@redefined << node.method_name if redefinable_flow_method?(node.method_name)
|
|
118
120
|
end
|
|
119
121
|
|
|
120
122
|
def instance_eval_block?(node)
|
|
@@ -52,32 +52,39 @@ module RuboCop
|
|
|
52
52
|
scope.variables.each_value { |variable| check_for_unused_assignments(variable) }
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
# rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
|
56
55
|
def check_for_unused_assignments(variable)
|
|
57
56
|
return if variable.should_be_unused?
|
|
58
57
|
|
|
59
58
|
variable.assignments.reverse_each do |assignment|
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
check_for_unused_assignment(variable, assignment)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
def check_for_unused_assignment(variable, assignment)
|
|
64
|
+
assignment_node = assignment.node
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
# In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
|
|
68
|
-
# and where changing `x ||= 1` to `x = 1` would cause `NameError`,
|
|
69
|
-
# the autocorrect will be skipped, even if the variable is unused.
|
|
70
|
-
if sequential_assignment?(assignment_node) || assignment_node.parent&.or_asgn_type?
|
|
71
|
-
next
|
|
72
|
-
end
|
|
66
|
+
return if ignored_assignment?(variable, assignment_node, assignment)
|
|
73
67
|
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
message = message_for_useless_assignment(assignment)
|
|
69
|
+
range = offense_range(assignment)
|
|
76
70
|
|
|
77
|
-
|
|
71
|
+
add_offense(range, message: message) do |corrector|
|
|
72
|
+
# In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
|
|
73
|
+
# and where changing `x ||= 1` to `x = 1` would cause `NameError`,
|
|
74
|
+
# the autocorrect will be skipped, even if the variable is unused.
|
|
75
|
+
next if sequential_assignment?(assignment_node) ||
|
|
76
|
+
assignment_node.parent&.or_asgn_type?
|
|
77
|
+
|
|
78
|
+
autocorrect(corrector, assignment)
|
|
78
79
|
end
|
|
80
|
+
|
|
81
|
+
ignore_node(assignment_node) if chained_assignment?(assignment_node)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ignored_assignment?(variable, assignment_node, assignment)
|
|
85
|
+
assignment.used? || part_of_ignored_node?(assignment_node) ||
|
|
86
|
+
variable_in_loop_condition?(assignment_node, variable)
|
|
79
87
|
end
|
|
80
|
-
# rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
|
81
88
|
|
|
82
89
|
def message_for_useless_assignment(assignment)
|
|
83
90
|
variable = assignment.variable
|
|
@@ -208,6 +215,27 @@ module RuboCop
|
|
|
208
215
|
def remove_local_variable_assignment_part(corrector, node)
|
|
209
216
|
corrector.replace(node, node.expression.source)
|
|
210
217
|
end
|
|
218
|
+
|
|
219
|
+
def variable_in_loop_condition?(assignment_node, variable)
|
|
220
|
+
return false if assignment_node.each_ancestor(:any_def).any?
|
|
221
|
+
|
|
222
|
+
loop_node = assignment_node.each_ancestor.find do |ancestor|
|
|
223
|
+
ancestor.type?(*VariableForce::LOOP_TYPES)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
return false unless loop_node.respond_to?(:condition)
|
|
227
|
+
|
|
228
|
+
condition_node = loop_node.condition
|
|
229
|
+
variable_name = variable.name
|
|
230
|
+
|
|
231
|
+
return true if condition_node.lvar_type? && condition_node.children.first == variable_name
|
|
232
|
+
|
|
233
|
+
condition_node.each_descendant(:lvar) do |lvar_node|
|
|
234
|
+
return true if lvar_node.children.first == variable_name
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
false
|
|
238
|
+
end
|
|
211
239
|
end
|
|
212
240
|
end
|
|
213
241
|
end
|
|
@@ -9,6 +9,13 @@ module RuboCop
|
|
|
9
9
|
# on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
|
|
10
10
|
# appended after these methods will never evaluate.
|
|
11
11
|
#
|
|
12
|
+
# @safety
|
|
13
|
+
# As shown in the examples below, there are generally two possible ways to correct the
|
|
14
|
+
# offense, but this cop’s autocorrection always chooses the option that preserves the
|
|
15
|
+
# current behavior. While this does not change how the code behaves, that option is not
|
|
16
|
+
# necessarily the appropriate fix in every situation. For this reason, the autocorrection
|
|
17
|
+
# provided by this cop is considered unsafe.
|
|
18
|
+
#
|
|
12
19
|
# @example
|
|
13
20
|
#
|
|
14
21
|
# # bad
|
|
@@ -64,6 +71,8 @@ module RuboCop
|
|
|
64
71
|
# x&.to_s or fallback
|
|
65
72
|
#
|
|
66
73
|
class UselessOr < Base
|
|
74
|
+
extend AutoCorrector
|
|
75
|
+
|
|
67
76
|
MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
|
|
68
77
|
|
|
69
78
|
TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
|
|
@@ -89,8 +98,12 @@ module RuboCop
|
|
|
89
98
|
private
|
|
90
99
|
|
|
91
100
|
def report_offense(or_node, truthy_node)
|
|
92
|
-
add_offense(
|
|
93
|
-
|
|
101
|
+
add_offense(
|
|
102
|
+
or_node.loc.operator.join(or_node.rhs.source_range),
|
|
103
|
+
message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source)
|
|
104
|
+
) do |corrector|
|
|
105
|
+
corrector.replace(or_node, or_node.lhs.source)
|
|
106
|
+
end
|
|
94
107
|
end
|
|
95
108
|
end
|
|
96
109
|
end
|
|
@@ -16,6 +16,12 @@ module RuboCop
|
|
|
16
16
|
# enumerator.each { |item| item >= 2 } #=> [2, 3]
|
|
17
17
|
# ----
|
|
18
18
|
#
|
|
19
|
+
# NOTE: Return values in assignment method definitions such as `def foo=(arg)` are
|
|
20
|
+
# detected because they are in a void context. However, autocorrection does not remove
|
|
21
|
+
# the return value, as that would change behavior. In such cases, whether to remove
|
|
22
|
+
# the return value or rename the method to something more appropriate should be left to
|
|
23
|
+
# the user.
|
|
24
|
+
#
|
|
19
25
|
# @example CheckForMethodsWithNoSideEffects: false (default)
|
|
20
26
|
# # bad
|
|
21
27
|
# def some_method
|
|
@@ -233,6 +239,7 @@ module RuboCop
|
|
|
233
239
|
|
|
234
240
|
def autocorrect_void_expression(corrector, node)
|
|
235
241
|
return if node.parent.if_type?
|
|
242
|
+
return if (def_node = node.each_ancestor(:any_def).first) && def_node.assignment_method?
|
|
236
243
|
|
|
237
244
|
corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
|
|
238
245
|
end
|
|
@@ -84,7 +84,10 @@ module RuboCop
|
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def assignment?(node)
|
|
87
|
-
|
|
87
|
+
if node.masgn_type? || node.shorthand_asgn?
|
|
88
|
+
compound_assignment(node)
|
|
89
|
+
return false
|
|
90
|
+
end
|
|
88
91
|
|
|
89
92
|
node.for_type? ||
|
|
90
93
|
(node.respond_to?(:setter_method?) && node.setter_method?) ||
|
|
@@ -101,8 +104,6 @@ module RuboCop
|
|
|
101
104
|
child.respond_to?(:setter_method?) && !child.setter_method?
|
|
102
105
|
end
|
|
103
106
|
@assignment += will_be_miscounted
|
|
104
|
-
|
|
105
|
-
false
|
|
106
107
|
end
|
|
107
108
|
|
|
108
109
|
def simple_assignment?(node)
|
|
@@ -14,6 +14,8 @@ module RuboCop
|
|
|
14
14
|
private
|
|
15
15
|
|
|
16
16
|
def too_long?(node)
|
|
17
|
+
return false unless max_line_length
|
|
18
|
+
|
|
17
19
|
lines = processed_source.lines[(node.first_line - 1)...node.last_line]
|
|
18
20
|
to_single_line(lines.join("\n")).length > max_line_length
|
|
19
21
|
end
|
|
@@ -27,10 +29,6 @@ module RuboCop
|
|
|
27
29
|
.gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
|
|
28
30
|
end
|
|
29
31
|
|
|
30
|
-
def max_line_length
|
|
31
|
-
config.for_cop('Layout/LineLength')['Max']
|
|
32
|
-
end
|
|
33
|
-
|
|
34
32
|
def comment_within?(node)
|
|
35
33
|
comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
|
|
36
34
|
|
|
@@ -59,7 +59,7 @@ module RuboCop
|
|
|
59
59
|
return node.loc.name if node.casgn_type?
|
|
60
60
|
|
|
61
61
|
if LSP.enabled?
|
|
62
|
-
end_range = node.loc
|
|
62
|
+
end_range = node.loc?(:name) ? node.loc.name : node.loc.begin
|
|
63
63
|
node.source_range.begin.join(end_range)
|
|
64
64
|
else
|
|
65
65
|
node.source_range
|
|
@@ -8,8 +8,27 @@ module RuboCop
|
|
|
8
8
|
|
|
9
9
|
private
|
|
10
10
|
|
|
11
|
-
def
|
|
12
|
-
config.for_cop('Layout/LineLength')['
|
|
11
|
+
def allow_rbs_inline_annotation?
|
|
12
|
+
config.for_cop('Layout/LineLength')['AllowRBSInlineAnnotation']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def rbs_inline_annotation_on_source_line?(line_index)
|
|
16
|
+
source_line_number = line_index + processed_source.buffer.first_line
|
|
17
|
+
comment = processed_source.comment_at_line(source_line_number)
|
|
18
|
+
|
|
19
|
+
return false unless comment
|
|
20
|
+
|
|
21
|
+
comment.text.start_with?(/#:|#\[.+\]|#\|/)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def allow_cop_directives?
|
|
25
|
+
# TODO: This logic for backward compatibility with deprecated `IgnoreCopDirectives` option.
|
|
26
|
+
# The following three lines will be removed in RuboCop 2.0.
|
|
27
|
+
ignore_cop_directives = config.for_cop('Layout/LineLength')['IgnoreCopDirectives']
|
|
28
|
+
return true if ignore_cop_directives
|
|
29
|
+
return false if ignore_cop_directives == false
|
|
30
|
+
|
|
31
|
+
config.for_cop('Layout/LineLength')['AllowCopDirectives']
|
|
13
32
|
end
|
|
14
33
|
|
|
15
34
|
def directive_on_source_line?(line_index)
|
|
@@ -73,7 +73,7 @@ module RuboCop
|
|
|
73
73
|
|
|
74
74
|
def location(node)
|
|
75
75
|
if LSP.enabled?
|
|
76
|
-
end_range = node.loc
|
|
76
|
+
end_range = node.loc?(:name) ? node.loc.name : node.loc.begin
|
|
77
77
|
node.source_range.begin.join(end_range)
|
|
78
78
|
else
|
|
79
79
|
node.source_range
|
|
@@ -200,7 +200,7 @@ module RuboCop
|
|
|
200
200
|
end
|
|
201
201
|
|
|
202
202
|
def grouped_expression?(node)
|
|
203
|
-
node.begin_type? && node.loc
|
|
203
|
+
node.begin_type? && node.loc?(:begin) && node.loc.begin
|
|
204
204
|
end
|
|
205
205
|
|
|
206
206
|
def inside_arg_list_parentheses?(node, ancestor)
|
|
@@ -8,8 +8,8 @@ module RuboCop
|
|
|
8
8
|
MSG = 'Space missing after %<token>s.'
|
|
9
9
|
|
|
10
10
|
def on_new_investigation
|
|
11
|
-
each_missing_space(processed_source.tokens) do |token|
|
|
12
|
-
add_offense(token.pos, message: format(MSG, token: kind
|
|
11
|
+
each_missing_space(processed_source.tokens) do |token, kind|
|
|
12
|
+
add_offense(token.pos, message: format(MSG, token: kind)) do |corrector|
|
|
13
13
|
PunctuationCorrector.add_space(corrector, token)
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -19,11 +19,12 @@ module RuboCop
|
|
|
19
19
|
|
|
20
20
|
def each_missing_space(tokens)
|
|
21
21
|
tokens.each_cons(2) do |token1, token2|
|
|
22
|
-
|
|
22
|
+
kind = kind(token1, token2)
|
|
23
|
+
next unless kind
|
|
23
24
|
next unless space_missing?(token1, token2)
|
|
24
25
|
next unless space_required_before?(token2)
|
|
25
26
|
|
|
26
|
-
yield token1
|
|
27
|
+
yield token1, kind
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
30
|
|