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
@@ -4,8 +4,8 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# Checks for uses of if/then/else/end constructs on a single line.
|
7
|
-
# AlwaysCorrectToMultiline config option can be set to true to
|
8
|
-
# multi-line constructs. When AlwaysCorrectToMultiline is false (default case) the
|
7
|
+
# `AlwaysCorrectToMultiline` config option can be set to true to autocorrect all offenses to
|
8
|
+
# multi-line constructs. When `AlwaysCorrectToMultiline` is false (default case) the
|
9
9
|
# autocorrect will first try converting them to ternary operators.
|
10
10
|
#
|
11
11
|
# @example
|
@@ -30,6 +30,25 @@ module RuboCop
|
|
30
30
|
# else
|
31
31
|
# baz
|
32
32
|
# end
|
33
|
+
#
|
34
|
+
# @example AlwaysCorrectToMultiline: false (default)
|
35
|
+
# # bad
|
36
|
+
# if cond then run else dont end
|
37
|
+
#
|
38
|
+
# # good
|
39
|
+
# cond ? run : dont
|
40
|
+
#
|
41
|
+
# @example AlwaysCorrectToMultiline: true
|
42
|
+
# # bad
|
43
|
+
# if cond then run else dont end
|
44
|
+
#
|
45
|
+
# # good
|
46
|
+
# if cond
|
47
|
+
# run
|
48
|
+
# else
|
49
|
+
# dont
|
50
|
+
# end
|
51
|
+
#
|
33
52
|
class OneLineConditional < Base
|
34
53
|
include Alignment
|
35
54
|
include ConfigurableEnforcedStyle
|
@@ -83,11 +102,13 @@ module RuboCop
|
|
83
102
|
end
|
84
103
|
|
85
104
|
def cannot_replace_to_ternary?(node)
|
86
|
-
node.elsif_conditional?
|
105
|
+
return true if node.elsif_conditional?
|
106
|
+
|
107
|
+
node.else_branch.begin_type? && node.else_branch.children.compact.count >= 2
|
87
108
|
end
|
88
109
|
|
89
110
|
def ternary_replacement(node)
|
90
|
-
condition, if_branch, else_branch = *node
|
111
|
+
condition, if_branch, else_branch = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
91
112
|
|
92
113
|
"#{expr_replacement(condition)} ? " \
|
93
114
|
"#{expr_replacement(if_branch)} : " \
|
@@ -31,10 +31,9 @@ module RuboCop
|
|
31
31
|
return unless (dot = node.loc.dot)
|
32
32
|
return if node.receiver.const_type? || !node.arguments.one?
|
33
33
|
|
34
|
-
|
35
|
-
if
|
36
|
-
|
37
|
-
end
|
34
|
+
return unless (rhs = node.first_argument)
|
35
|
+
return if method_call_with_parenthesized_arg?(rhs)
|
36
|
+
return if invalid_syntax_argument?(rhs)
|
38
37
|
|
39
38
|
add_offense(dot) do |corrector|
|
40
39
|
wrap_in_parentheses_if_chained(corrector, node)
|
@@ -73,7 +72,7 @@ module RuboCop
|
|
73
72
|
end
|
74
73
|
|
75
74
|
def insert_space_after?(node)
|
76
|
-
|
75
|
+
rhs = node.first_argument
|
77
76
|
selector = node.loc.selector
|
78
77
|
|
79
78
|
return true if selector.end_pos == rhs.source_range.begin_pos
|
@@ -82,7 +81,7 @@ module RuboCop
|
|
82
81
|
# For `/` operations, if the RHS starts with a `(` without space,
|
83
82
|
# add one to avoid a syntax error.
|
84
83
|
range = selector.end.join(rhs.source_range.begin)
|
85
|
-
return true if
|
84
|
+
return true if node.method?(:/) && range.source == '('
|
86
85
|
|
87
86
|
false
|
88
87
|
end
|
@@ -78,18 +78,15 @@ module RuboCop
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def take_variable_and_default_from_ternary(node)
|
81
|
-
|
82
|
-
[variable, if_statement.else_branch]
|
81
|
+
[node.name, node.expression.else_branch]
|
83
82
|
end
|
84
83
|
|
85
84
|
def take_variable_and_default_from_unless(node)
|
86
85
|
if node.if_branch
|
87
|
-
|
86
|
+
[node.if_branch.name, node.if_branch.expression]
|
88
87
|
else
|
89
|
-
|
88
|
+
[node.else_branch.name, node.else_branch.expression]
|
90
89
|
end
|
91
|
-
|
92
|
-
[variable, default]
|
93
90
|
end
|
94
91
|
end
|
95
92
|
end
|
@@ -28,28 +28,25 @@ module RuboCop
|
|
28
28
|
|
29
29
|
MSG = 'Do not use parallel assignment.'
|
30
30
|
|
31
|
-
def on_masgn(node)
|
32
|
-
|
33
|
-
lhs_elements = *lhs
|
31
|
+
def on_masgn(node) # rubocop:disable Metrics/AbcSize
|
32
|
+
rhs = node.rhs
|
34
33
|
rhs = rhs.body if rhs.rescue_type?
|
35
34
|
rhs_elements = Array(rhs).compact # edge case for one constant
|
36
35
|
|
37
|
-
return if allowed_lhs?(
|
38
|
-
allowed_masign?(
|
36
|
+
return if allowed_lhs?(node.assignments) || allowed_rhs?(rhs) ||
|
37
|
+
allowed_masign?(node.assignments, rhs_elements)
|
39
38
|
|
40
39
|
range = node.source_range.begin.join(rhs.source_range.end)
|
41
40
|
|
42
41
|
add_offense(range) do |corrector|
|
43
|
-
autocorrect(corrector, node,
|
42
|
+
autocorrect(corrector, node, rhs)
|
44
43
|
end
|
45
44
|
end
|
46
45
|
|
47
46
|
private
|
48
47
|
|
49
|
-
def autocorrect(corrector, node,
|
50
|
-
|
51
|
-
right_elements = Array(rhs).compact
|
52
|
-
order = find_valid_order(left_elements, right_elements)
|
48
|
+
def autocorrect(corrector, node, rhs)
|
49
|
+
order = find_valid_order(node.assignments, Array(rhs).compact)
|
53
50
|
correction = assignment_corrector(node, rhs, order)
|
54
51
|
|
55
52
|
corrector.replace(correction.correction_range, correction.correction)
|
@@ -61,9 +58,7 @@ module RuboCop
|
|
61
58
|
add_self_to_getters(rhs_elements))
|
62
59
|
end
|
63
60
|
|
64
|
-
def allowed_lhs?(
|
65
|
-
elements = *node
|
66
|
-
|
61
|
+
def allowed_lhs?(elements)
|
67
62
|
# Account for edge cases using one variable with a comma
|
68
63
|
# E.g.: `foo, = *bar`
|
69
64
|
elements.one? || elements.any?(&:splat_type?)
|
@@ -5,6 +5,19 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# Checks for unnecessary conditional expressions.
|
7
7
|
#
|
8
|
+
# NOTE: Since the intention of the comment cannot be automatically determined,
|
9
|
+
# autocorrection is not applied when a comment is used, as shown below:
|
10
|
+
#
|
11
|
+
# [source,ruby]
|
12
|
+
# -----
|
13
|
+
# if b
|
14
|
+
# # Important note.
|
15
|
+
# b
|
16
|
+
# else
|
17
|
+
# c
|
18
|
+
# end
|
19
|
+
# -----
|
20
|
+
#
|
8
21
|
# @example
|
9
22
|
# # bad
|
10
23
|
# a = b ? b : c
|
@@ -30,6 +43,7 @@ module RuboCop
|
|
30
43
|
# end
|
31
44
|
#
|
32
45
|
class RedundantCondition < Base
|
46
|
+
include CommentsHelp
|
33
47
|
include RangeHelp
|
34
48
|
extend AutoCorrector
|
35
49
|
|
@@ -39,25 +53,15 @@ module RuboCop
|
|
39
53
|
splat block_pass forwarded_restarg forwarded_kwrestarg forwarded_args
|
40
54
|
].freeze
|
41
55
|
|
42
|
-
# rubocop:disable Metrics/AbcSize
|
43
56
|
def on_if(node)
|
44
57
|
return if node.modifier_form? || node.elsif_conditional? || !offense?(node)
|
45
58
|
|
46
59
|
message = message(node)
|
47
60
|
|
48
61
|
add_offense(range_of_offense(node), message: message) do |corrector|
|
49
|
-
|
50
|
-
correct_ternary(corrector, node)
|
51
|
-
elsif redundant_condition?(node)
|
52
|
-
corrector.replace(node, node.if_branch.source)
|
53
|
-
else
|
54
|
-
corrected = make_ternary_form(node)
|
55
|
-
|
56
|
-
corrector.replace(node, corrected)
|
57
|
-
end
|
62
|
+
autocorrect(corrector, node)
|
58
63
|
end
|
59
64
|
end
|
60
|
-
# rubocop:enable Metrics/AbcSize
|
61
65
|
|
62
66
|
private
|
63
67
|
|
@@ -69,6 +73,20 @@ module RuboCop
|
|
69
73
|
end
|
70
74
|
end
|
71
75
|
|
76
|
+
def autocorrect(corrector, node)
|
77
|
+
return if node.each_descendant.any? { |descendant| contains_comments?(descendant) }
|
78
|
+
|
79
|
+
if node.ternary? && !branches_have_method?(node)
|
80
|
+
correct_ternary(corrector, node)
|
81
|
+
elsif redundant_condition?(node)
|
82
|
+
corrector.replace(node, node.if_branch.source)
|
83
|
+
else
|
84
|
+
corrected = make_ternary_form(node)
|
85
|
+
|
86
|
+
corrector.replace(node, corrected)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
72
90
|
def range_of_offense(node)
|
73
91
|
return node.source_range unless node.ternary?
|
74
92
|
return node.source_range if node.ternary? && branches_have_method?(node)
|
@@ -77,8 +95,7 @@ module RuboCop
|
|
77
95
|
end
|
78
96
|
|
79
97
|
def offense?(node)
|
80
|
-
_condition, _if_branch, else_branch = *node
|
81
|
-
|
98
|
+
_condition, _if_branch, else_branch = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
82
99
|
return false if use_if_branch?(else_branch) || use_hash_key_assignment?(else_branch)
|
83
100
|
|
84
101
|
synonymous_condition_and_branch?(node) && !node.elsif? &&
|
@@ -102,7 +119,7 @@ module RuboCop
|
|
102
119
|
end
|
103
120
|
|
104
121
|
def synonymous_condition_and_branch?(node)
|
105
|
-
condition, if_branch, _else_branch = *node
|
122
|
+
condition, if_branch, _else_branch = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
106
123
|
# e.g.
|
107
124
|
# if var
|
108
125
|
# var
|
@@ -130,7 +147,7 @@ module RuboCop
|
|
130
147
|
end
|
131
148
|
|
132
149
|
def branches_have_assignment?(node)
|
133
|
-
_condition, if_branch, else_branch = *node
|
150
|
+
_condition, if_branch, else_branch = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
134
151
|
|
135
152
|
return false unless if_branch && else_branch
|
136
153
|
|
@@ -144,12 +161,10 @@ module RuboCop
|
|
144
161
|
end
|
145
162
|
|
146
163
|
def branches_have_method?(node)
|
147
|
-
|
148
|
-
|
149
|
-
return false unless if_branch && else_branch
|
164
|
+
return false unless node.if_branch && node.else_branch
|
150
165
|
|
151
|
-
single_argument_method?(if_branch) && single_argument_method?(else_branch) &&
|
152
|
-
same_method?(if_branch, else_branch)
|
166
|
+
single_argument_method?(node.if_branch) && single_argument_method?(node.else_branch) &&
|
167
|
+
same_method?(node.if_branch, node.else_branch)
|
153
168
|
end
|
154
169
|
|
155
170
|
def single_argument_method?(node)
|
@@ -221,7 +236,7 @@ module RuboCop
|
|
221
236
|
end
|
222
237
|
|
223
238
|
def make_ternary_form(node)
|
224
|
-
_condition, if_branch, else_branch = *node
|
239
|
+
_condition, if_branch, else_branch = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
225
240
|
arithmetic_operation = use_arithmetic_operation?(if_branch)
|
226
241
|
|
227
242
|
ternary_form = [
|
@@ -69,6 +69,8 @@ module RuboCop
|
|
69
69
|
extend AutoCorrector
|
70
70
|
|
71
71
|
MSG = 'Redundant line continuation.'
|
72
|
+
LINE_CONTINUATION = '\\'
|
73
|
+
LINE_CONTINUATION_PATTERN = /(\\\n)/.freeze
|
72
74
|
ALLOWED_STRING_TOKENS = %i[tSTRING tSTRING_CONTENT].freeze
|
73
75
|
ARGUMENT_TYPES = %i[
|
74
76
|
kFALSE kNIL kSELF kTRUE tCONSTANT tCVAR tFLOAT tGVAR tIDENTIFIER tINTEGER tIVAR
|
@@ -79,7 +81,7 @@ module RuboCop
|
|
79
81
|
def on_new_investigation
|
80
82
|
return unless processed_source.ast
|
81
83
|
|
82
|
-
each_match_range(processed_source.ast.source_range,
|
84
|
+
each_match_range(processed_source.ast.source_range, LINE_CONTINUATION_PATTERN) do |range|
|
83
85
|
next if require_line_continuation?(range)
|
84
86
|
next unless redundant_line_continuation?(range)
|
85
87
|
|
@@ -87,6 +89,8 @@ module RuboCop
|
|
87
89
|
corrector.remove_leading(range, 1)
|
88
90
|
end
|
89
91
|
end
|
92
|
+
|
93
|
+
inspect_end_of_ruby_code_line_continuation
|
90
94
|
end
|
91
95
|
|
92
96
|
private
|
@@ -125,10 +129,25 @@ module RuboCop
|
|
125
129
|
return true unless (node = find_node_for_line(range.last_line))
|
126
130
|
return false if argument_newline?(node)
|
127
131
|
|
128
|
-
source = node.
|
132
|
+
source = node.source
|
133
|
+
while (node = node.parent)
|
134
|
+
source = node.source
|
135
|
+
end
|
129
136
|
parse(source.gsub("\\\n", "\n")).valid_syntax?
|
130
137
|
end
|
131
138
|
|
139
|
+
def inspect_end_of_ruby_code_line_continuation
|
140
|
+
last_line = processed_source.lines[processed_source.ast.last_line - 1]
|
141
|
+
return unless last_line.end_with?(LINE_CONTINUATION)
|
142
|
+
|
143
|
+
last_column = last_line.length
|
144
|
+
line_continuation_range = range_between(last_column - 1, last_column)
|
145
|
+
|
146
|
+
add_offense(line_continuation_range) do |corrector|
|
147
|
+
corrector.remove_trailing(line_continuation_range, 1)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
132
151
|
def inside_string_literal?(range, token)
|
133
152
|
ALLOWED_STRING_TOKENS.include?(token.type) && token.pos.overlaps?(range)
|
134
153
|
end
|
@@ -31,9 +31,6 @@ module RuboCop
|
|
31
31
|
# @!method allowed_pin_operator?(node)
|
32
32
|
def_node_matcher :allowed_pin_operator?, '^(pin (begin !{lvar ivar cvar gvar}))'
|
33
33
|
|
34
|
-
# @!method arg_in_call_with_block?(node)
|
35
|
-
def_node_matcher :arg_in_call_with_block?, '^^(block (send _ _ equal?(%0) ...) ...)'
|
36
|
-
|
37
34
|
def on_begin(node)
|
38
35
|
return if !parentheses?(node) || parens_allowed?(node) || ignore_syntax?(node)
|
39
36
|
|
@@ -59,7 +56,6 @@ module RuboCop
|
|
59
56
|
|
60
57
|
def allowed_expression?(node)
|
61
58
|
allowed_ancestor?(node) ||
|
62
|
-
allowed_method_call?(node) ||
|
63
59
|
allowed_multiple_expression?(node) ||
|
64
60
|
allowed_ternary?(node) ||
|
65
61
|
node.parent&.range_type?
|
@@ -70,11 +66,6 @@ module RuboCop
|
|
70
66
|
keyword_ancestor?(node) && parens_required?(node)
|
71
67
|
end
|
72
68
|
|
73
|
-
def allowed_method_call?(node)
|
74
|
-
# Don't flag `method (arg) { }`
|
75
|
-
arg_in_call_with_block?(node) && !parentheses?(node.parent)
|
76
|
-
end
|
77
|
-
|
78
69
|
def allowed_multiple_expression?(node)
|
79
70
|
return false if node.children.one?
|
80
71
|
|
@@ -156,7 +147,7 @@ module RuboCop
|
|
156
147
|
|
157
148
|
return if begin_node.chained?
|
158
149
|
|
159
|
-
if node.
|
150
|
+
if node.operator_keyword?
|
160
151
|
return if node.semantic_operator? && begin_node.parent
|
161
152
|
return if node.multiline? && allow_in_multiline_conditions?
|
162
153
|
return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
|
@@ -185,7 +176,8 @@ module RuboCop
|
|
185
176
|
return check_unary(begin_node, node) if node.unary_operation?
|
186
177
|
|
187
178
|
return unless method_call_with_redundant_parentheses?(node)
|
188
|
-
return if call_chain_starts_with_int?(begin_node, node)
|
179
|
+
return if call_chain_starts_with_int?(begin_node, node) ||
|
180
|
+
do_end_block_in_method_chain?(begin_node, node)
|
189
181
|
|
190
182
|
offense(begin_node, 'a method call')
|
191
183
|
end
|
@@ -285,6 +277,12 @@ module RuboCop
|
|
285
277
|
recv&.int_type? && (parent = begin_node.parent) &&
|
286
278
|
parent.send_type? && (parent.method?(:-@) || parent.method?(:+@))
|
287
279
|
end
|
280
|
+
|
281
|
+
def do_end_block_in_method_chain?(begin_node, node)
|
282
|
+
return false unless (block = node.each_descendant(:block, :numblock).first)
|
283
|
+
|
284
|
+
block.keywords? && begin_node.each_ancestor(:send, :csend).any?
|
285
|
+
end
|
288
286
|
end
|
289
287
|
end
|
290
288
|
end
|
@@ -61,9 +61,9 @@ module RuboCop
|
|
61
61
|
RESTRICT_ON_SEND = %i[define_method define_singleton_method lambda].freeze
|
62
62
|
|
63
63
|
def on_send(node)
|
64
|
-
return unless
|
64
|
+
return unless node.block_literal?
|
65
65
|
|
66
|
-
check_branch(parent.body)
|
66
|
+
check_branch(node.parent.body)
|
67
67
|
end
|
68
68
|
|
69
69
|
def on_def(node)
|
@@ -66,14 +66,12 @@ module RuboCop
|
|
66
66
|
# Assignment of self.x
|
67
67
|
|
68
68
|
def on_or_asgn(node)
|
69
|
-
lhs
|
70
|
-
allow_self(lhs)
|
69
|
+
allow_self(node.lhs)
|
71
70
|
end
|
72
71
|
alias on_and_asgn on_or_asgn
|
73
72
|
|
74
73
|
def on_op_asgn(node)
|
75
|
-
lhs
|
76
|
-
allow_self(lhs)
|
74
|
+
allow_self(node.lhs)
|
77
75
|
end
|
78
76
|
|
79
77
|
# Using self.x to distinguish from local variable x
|
@@ -92,13 +90,11 @@ module RuboCop
|
|
92
90
|
end
|
93
91
|
|
94
92
|
def on_masgn(node)
|
95
|
-
|
96
|
-
add_masgn_lhs_variables(rhs, lhs)
|
93
|
+
add_masgn_lhs_variables(node.rhs, node.lhs)
|
97
94
|
end
|
98
95
|
|
99
96
|
def on_lvasgn(node)
|
100
|
-
|
101
|
-
add_lhs_to_local_variables_scopes(rhs, lhs)
|
97
|
+
add_lhs_to_local_variables_scopes(node.rhs, node.lhs)
|
102
98
|
end
|
103
99
|
|
104
100
|
def on_in_pattern(node)
|
@@ -127,12 +123,10 @@ module RuboCop
|
|
127
123
|
# Allow conditional nodes to use `self` in the condition if that variable
|
128
124
|
# name is used in an `lvasgn` or `masgn` within the `if`.
|
129
125
|
node.child_nodes.each do |child_node|
|
130
|
-
lhs, _rhs = *child_node
|
131
|
-
|
132
126
|
if child_node.lvasgn_type?
|
133
|
-
add_lhs_to_local_variables_scopes(node.condition, lhs)
|
127
|
+
add_lhs_to_local_variables_scopes(node.condition, child_node.lhs)
|
134
128
|
elsif child_node.masgn_type?
|
135
|
-
add_masgn_lhs_variables(node.condition, lhs)
|
129
|
+
add_masgn_lhs_variables(node.condition, child_node.lhs)
|
136
130
|
end
|
137
131
|
end
|
138
132
|
end
|
@@ -182,8 +176,7 @@ module RuboCop
|
|
182
176
|
if node.mlhs_type?
|
183
177
|
on_args(node)
|
184
178
|
else
|
185
|
-
|
186
|
-
@local_variables_scopes[node] << name
|
179
|
+
@local_variables_scopes[node] << node.name
|
187
180
|
end
|
188
181
|
end
|
189
182
|
|
@@ -49,19 +49,21 @@ module RuboCop
|
|
49
49
|
gvasgn: :gvar
|
50
50
|
}.freeze
|
51
51
|
|
52
|
+
# rubocop:disable Metrics/AbcSize
|
52
53
|
def on_lvasgn(node)
|
53
|
-
|
54
|
-
|
55
|
-
return unless receiver
|
54
|
+
return unless (rhs = node.rhs)
|
55
|
+
return unless rhs.send_type? && method_returning_self?(rhs.method_name)
|
56
|
+
return unless (receiver = rhs.receiver)
|
56
57
|
|
57
58
|
receiver_type = ASSIGNMENT_TYPE_TO_RECEIVER_TYPE[node.type]
|
58
|
-
return unless receiver.type == receiver_type && receiver.children.first == lhs
|
59
|
+
return unless receiver.type == receiver_type && receiver.children.first == node.lhs
|
59
60
|
|
60
|
-
message = format(MSG, method_name: method_name)
|
61
|
+
message = format(MSG, method_name: rhs.method_name)
|
61
62
|
add_offense(node.loc.operator, message: message) do |corrector|
|
62
63
|
corrector.replace(node, rhs.source)
|
63
64
|
end
|
64
65
|
end
|
66
|
+
# rubocop:enable Metrics/AbcSize
|
65
67
|
alias on_ivasgn on_lvasgn
|
66
68
|
alias on_cvasgn on_lvasgn
|
67
69
|
alias on_gvasgn on_lvasgn
|
@@ -23,7 +23,6 @@ module RuboCop
|
|
23
23
|
# foo = bar unless condition
|
24
24
|
#
|
25
25
|
class RedundantSelfAssignmentBranch < Base
|
26
|
-
include RangeHelp
|
27
26
|
extend AutoCorrector
|
28
27
|
|
29
28
|
MSG = 'Remove the self-assignment branch.'
|
@@ -34,16 +33,17 @@ module RuboCop
|
|
34
33
|
PATTERN
|
35
34
|
|
36
35
|
def on_lvasgn(node)
|
37
|
-
|
36
|
+
expression = node.expression
|
37
|
+
|
38
38
|
return unless use_if_and_else_branch?(expression)
|
39
39
|
|
40
40
|
if_branch = expression.if_branch
|
41
41
|
else_branch = expression.else_branch
|
42
42
|
return if inconvertible_to_modifier?(if_branch, else_branch)
|
43
43
|
|
44
|
-
if self_assign?(
|
44
|
+
if self_assign?(node.name, if_branch)
|
45
45
|
register_offense(expression, if_branch, else_branch, 'unless')
|
46
|
-
elsif self_assign?(
|
46
|
+
elsif self_assign?(node.name, else_branch)
|
47
47
|
register_offense(expression, else_branch, if_branch, 'if')
|
48
48
|
end
|
49
49
|
end
|
@@ -68,8 +68,7 @@ module RuboCop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def correct_rescue_block(corrector, node, parenthesized)
|
71
|
-
operation
|
72
|
-
*_, rescue_args = *rescue_modifier
|
71
|
+
operation = node.body
|
73
72
|
|
74
73
|
node_indentation, node_offset = indentation_and_offset(node, parenthesized)
|
75
74
|
|
@@ -78,7 +77,7 @@ module RuboCop
|
|
78
77
|
corrector.insert_after(heredoc_end(operation) || operation, <<~RESCUE_CLAUSE.chop)
|
79
78
|
|
80
79
|
#{node_offset}rescue
|
81
|
-
#{node_indentation}#{
|
80
|
+
#{node_indentation}#{node.resbody_branches.first.body.source}
|
82
81
|
#{node_offset}end
|
83
82
|
RESCUE_CLAUSE
|
84
83
|
end
|
@@ -21,6 +21,11 @@ module RuboCop
|
|
21
21
|
# We have limited the cop to not register an offense for method chains
|
22
22
|
# that exceed this option's value.
|
23
23
|
#
|
24
|
+
# NOTE: This cop will recognize offenses but not autocorrect code when the
|
25
|
+
# right hand side (RHS) of the `&&` statement is an `||` statement
|
26
|
+
# (eg. `foo && (foo.bar? || foo.baz?)`). It can be corrected
|
27
|
+
# manually by removing the `foo &&` and adding `&.` to each `foo` on the RHS.
|
28
|
+
#
|
24
29
|
# @safety
|
25
30
|
# Autocorrection is unsafe because if a value is `false`, the resulting
|
26
31
|
# code will have different behavior or raise an error.
|
@@ -121,6 +126,9 @@ module RuboCop
|
|
121
126
|
}
|
122
127
|
PATTERN
|
123
128
|
|
129
|
+
# @!method and_with_rhs_or?(node)
|
130
|
+
def_node_matcher :and_with_rhs_or?, '(and _ {or (begin or)})'
|
131
|
+
|
124
132
|
# @!method not_nil_check?(node)
|
125
133
|
def_node_matcher :not_nil_check?, '(send (send $_ :nil?) :!)'
|
126
134
|
|
@@ -172,6 +180,10 @@ module RuboCop
|
|
172
180
|
|
173
181
|
def report_offense(node, rhs, rhs_receiver, *removal_ranges, offense_range: node)
|
174
182
|
add_offense(offense_range) do |corrector|
|
183
|
+
# If the RHS is an `or` we cannot safely autocorrect because in order to remove
|
184
|
+
# the non-nil check we need to add safe-navs to all clauses where the receiver is used
|
185
|
+
next if and_with_rhs_or?(node)
|
186
|
+
|
175
187
|
removal_ranges.each { |range| corrector.remove(range) }
|
176
188
|
yield corrector if block_given?
|
177
189
|
|
@@ -300,7 +312,7 @@ module RuboCop
|
|
300
312
|
end
|
301
313
|
|
302
314
|
def chain_length(method_chain, method)
|
303
|
-
method.each_ancestor(:send).inject(0) do |total, ancestor|
|
315
|
+
method.each_ancestor(:send, :csend).inject(0) do |total, ancestor|
|
304
316
|
break total + 1 if ancestor == method_chain
|
305
317
|
|
306
318
|
total + 1
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Enforces safe navigation chains length to not exceed the configured maximum.
|
7
|
+
# The longer the chain is, the harder it becomes to track what on it could be
|
8
|
+
# returning `nil`.
|
9
|
+
#
|
10
|
+
# There is a potential interplay with `Style/SafeNavigation` - if both are enabled
|
11
|
+
# and their settings are "incompatible", one of the cops will complain about what
|
12
|
+
# the other proposes.
|
13
|
+
#
|
14
|
+
# E.g. if `Style/SafeNavigation` is configured with `MaxChainLength: 2` (default)
|
15
|
+
# and this cop is configured with `Max: 1`, then for `foo.bar.baz if foo` the former
|
16
|
+
# will suggest `foo&.bar&.baz`, which is an offense for the latter.
|
17
|
+
#
|
18
|
+
# @example Max: 2 (default)
|
19
|
+
# # bad
|
20
|
+
# user&.address&.zip&.upcase
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# user&.address&.zip
|
24
|
+
# user.address.zip if user
|
25
|
+
#
|
26
|
+
class SafeNavigationChainLength < Base
|
27
|
+
MSG = 'Avoid safe navigation chains longer than %<max>d calls.'
|
28
|
+
|
29
|
+
def on_csend(node)
|
30
|
+
safe_navigation_chains = safe_navigation_chains(node)
|
31
|
+
return if safe_navigation_chains.size < max
|
32
|
+
|
33
|
+
add_offense(safe_navigation_chains.last, message: format(MSG, max: max))
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def safe_navigation_chains(node)
|
39
|
+
node.each_ancestor.with_object([]) do |parent, chains|
|
40
|
+
break chains unless parent.csend_type?
|
41
|
+
|
42
|
+
chains << parent
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def max
|
47
|
+
cop_config['Max'] || 2
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|