rubocop 1.20.0 → 1.22.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +64 -15
- data/lib/rubocop/config.rb +5 -0
- data/lib/rubocop/config_loader.rb +3 -1
- data/lib/rubocop/config_validator.rb +9 -1
- data/lib/rubocop/cop/base.rb +3 -3
- data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
- data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
- 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/ordered_gem_corrector.rb +11 -10
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +31 -24
- data/lib/rubocop/cop/generator.rb +14 -8
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -1
- data/lib/rubocop/cop/layout/dot_position.rb +30 -5
- data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
- data/lib/rubocop/cop/layout/end_alignment.rb +2 -3
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +9 -7
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -3
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
- 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_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 +74 -28
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +9 -9
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
- data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
- data/lib/rubocop/cop/lint/debugger.rb +0 -2
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
- data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
- data/lib/rubocop/cop/lint/else_layout.rb +10 -6
- 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/hash_compare_by_identity.rb +12 -3
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
- data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
- data/lib/rubocop/cop/lint/loop.rb +4 -3
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +12 -1
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
- data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
- data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
- data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
- data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
- data/lib/rubocop/cop/lint/useless_times.rb +4 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
- data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
- 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/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +15 -6
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
- data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
- data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
- data/lib/rubocop/cop/mixin/percent_array.rb +6 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +5 -1
- data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
- data/lib/rubocop/cop/security/io_methods.rb +49 -0
- data/lib/rubocop/cop/security/json_load.rb +8 -7
- data/lib/rubocop/cop/security/open.rb +4 -0
- data/lib/rubocop/cop/security/yaml_load.rb +4 -0
- data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
- data/lib/rubocop/cop/style/and_or.rb +5 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
- data/lib/rubocop/cop/style/array_coercion.rb +21 -3
- data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
- data/lib/rubocop/cop/style/case_equality.rb +6 -9
- data/lib/rubocop/cop/style/case_like_if.rb +5 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
- data/lib/rubocop/cop/style/collection_compact.rb +7 -5
- data/lib/rubocop/cop/style/collection_methods.rb +8 -6
- data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
- data/lib/rubocop/cop/style/commented_keyword.rb +9 -4
- data/lib/rubocop/cop/style/date_time.rb +5 -0
- 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 +15 -5
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
- data/lib/rubocop/cop/style/float_division.rb +10 -2
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -1
- data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
- data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
- data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
- data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
- data/lib/rubocop/cop/style/lambda_call.rb +1 -1
- data/lib/rubocop/cop/style/line_end_concatenation.rb +14 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
- data/lib/rubocop/cop/style/module_function.rb +8 -9
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +13 -8
- 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/numbered_parameters.rb +46 -0
- data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
- data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
- data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
- data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
- 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/preferred_hash_methods.rb +9 -4
- data/lib/rubocop/cop/style/quoted_symbols.rb +10 -6
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
- data/lib/rubocop/cop/style/redundant_freeze.rb +0 -1
- 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.rb +10 -0
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +51 -18
- 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/safe_navigation.rb +13 -2
- data/lib/rubocop/cop/style/select_by_regexp.rb +138 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
- data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
- data/lib/rubocop/cop/style/static_class.rb +5 -5
- data/lib/rubocop/cop/style/string_chars.rb +4 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
- data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +3 -2
- data/lib/rubocop/cop/style/swap_values.rb +4 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
- data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
- data/lib/rubocop/cop/util.rb +15 -4
- data/lib/rubocop/cops_documentation_generator.rb +17 -5
- data/lib/rubocop/options.rb +126 -112
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/result_cache.rb +3 -3
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/runner.rb +2 -3
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +8 -1
- metadata +14 -5
@@ -33,6 +33,27 @@ module RuboCop
|
|
33
33
|
# g = ( a + 3 )
|
34
34
|
# y()
|
35
35
|
#
|
36
|
+
# @example EnforcedStyle: compact
|
37
|
+
# # The `compact` style enforces that parentheses have a space at the
|
38
|
+
# # beginning with the exception that successive parentheses are allowed.
|
39
|
+
# # Note: Empty parentheses should not have spaces.
|
40
|
+
#
|
41
|
+
# # bad
|
42
|
+
# f(3)
|
43
|
+
# g = (a + 3)
|
44
|
+
# y( )
|
45
|
+
# g( f( x ) )
|
46
|
+
# g( f( x( 3 ) ), 5 )
|
47
|
+
# g( ( ( 3 + 5 ) * f) ** x, 5 )
|
48
|
+
#
|
49
|
+
# # good
|
50
|
+
# f( 3 )
|
51
|
+
# g = ( a + 3 )
|
52
|
+
# y()
|
53
|
+
# g( f( x ))
|
54
|
+
# g( f( x( 3 )), 5 )
|
55
|
+
# g((( 3 + 5 ) * f ) ** x, 5 )
|
56
|
+
#
|
36
57
|
class SpaceInsideParens < Base
|
37
58
|
include SurroundingSpace
|
38
59
|
include RangeHelp
|
@@ -45,14 +66,13 @@ module RuboCop
|
|
45
66
|
def on_new_investigation
|
46
67
|
tokens = processed_source.sorted_tokens
|
47
68
|
|
48
|
-
|
69
|
+
case style
|
70
|
+
when :space
|
49
71
|
process_with_space_style(tokens)
|
72
|
+
when :compact
|
73
|
+
process_with_compact_style(tokens)
|
50
74
|
else
|
51
|
-
|
52
|
-
add_offense(range) do |corrector|
|
53
|
-
corrector.remove(range)
|
54
|
-
end
|
55
|
-
end
|
75
|
+
correct_extraneous_space(tokens)
|
56
76
|
end
|
57
77
|
end
|
58
78
|
|
@@ -60,20 +80,23 @@ module RuboCop
|
|
60
80
|
|
61
81
|
def process_with_space_style(tokens)
|
62
82
|
tokens.each_cons(2) do |token1, token2|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
83
|
+
correct_extraneous_space_in_empty_parens(token1, token2)
|
84
|
+
correct_missing_space(token1, token2)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def process_with_compact_style(tokens)
|
89
|
+
tokens.each_cons(2) do |token1, token2|
|
90
|
+
correct_extraneous_space_in_empty_parens(token1, token2)
|
91
|
+
if !left_parens?(token1, token2) && !right_parens?(token1, token2)
|
92
|
+
correct_missing_space(token1, token2)
|
93
|
+
else
|
94
|
+
correct_extaneus_space_between_consecutive_parens(token1, token2)
|
72
95
|
end
|
73
96
|
end
|
74
97
|
end
|
75
98
|
|
76
|
-
def
|
99
|
+
def correct_extraneous_space(tokens)
|
77
100
|
tokens.each_cons(2) do |token1, token2|
|
78
101
|
next unless parens?(token1, token2)
|
79
102
|
|
@@ -82,36 +105,59 @@ module RuboCop
|
|
82
105
|
next if token2.comment?
|
83
106
|
next unless same_line?(token1, token2) && token1.space_after?
|
84
107
|
|
85
|
-
|
108
|
+
range = range_between(token1.end_pos, token2.begin_pos)
|
109
|
+
add_offense(range) do |corrector|
|
110
|
+
corrector.remove(range)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def correct_extaneus_space_between_consecutive_parens(token1, token2)
|
116
|
+
return if range_between(token1.end_pos, token2.begin_pos).source != ' '
|
117
|
+
|
118
|
+
range = range_between(token1.end_pos, token2.begin_pos)
|
119
|
+
add_offense(range) do |corrector|
|
120
|
+
corrector.remove(range)
|
86
121
|
end
|
87
122
|
end
|
88
123
|
|
89
|
-
def
|
124
|
+
def correct_extraneous_space_in_empty_parens(token1, token2)
|
90
125
|
return unless token1.left_parens? && token2.right_parens?
|
91
126
|
|
92
127
|
return if range_between(token1.begin_pos, token2.end_pos).source == '()'
|
93
128
|
|
94
|
-
|
129
|
+
range = range_between(token1.end_pos, token2.begin_pos)
|
130
|
+
add_offense(range) do |corrector|
|
131
|
+
corrector.remove(range)
|
132
|
+
end
|
95
133
|
end
|
96
134
|
|
97
|
-
def
|
135
|
+
def correct_missing_space(token1, token2)
|
98
136
|
return if can_be_ignored?(token1, token2)
|
99
137
|
|
100
|
-
if token1.left_parens?
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
end
|
138
|
+
range = if token1.left_parens?
|
139
|
+
range_between(token2.begin_pos, token2.begin_pos + 1)
|
140
|
+
elsif token2.right_parens?
|
141
|
+
range_between(token2.begin_pos, token2.end_pos)
|
142
|
+
end
|
106
143
|
|
107
|
-
|
108
|
-
|
144
|
+
add_offense(range, message: MSG_SPACE) do |corrector|
|
145
|
+
corrector.insert_before(range, ' ')
|
146
|
+
end
|
109
147
|
end
|
110
148
|
|
111
149
|
def parens?(token1, token2)
|
112
150
|
token1.left_parens? || token2.right_parens?
|
113
151
|
end
|
114
152
|
|
153
|
+
def left_parens?(token1, token2)
|
154
|
+
token1.left_parens? && token2.left_parens?
|
155
|
+
end
|
156
|
+
|
157
|
+
def right_parens?(token1, token2)
|
158
|
+
token1.right_parens? && token2.right_parens?
|
159
|
+
end
|
160
|
+
|
115
161
|
def can_be_ignored?(token1, token2)
|
116
162
|
return true unless parens?(token1, token2)
|
117
163
|
|
@@ -107,7 +107,7 @@ module RuboCop
|
|
107
107
|
current_token = tokens.reverse.find(&:left_ref_bracket?)
|
108
108
|
previous_token = previous_token(current_token)
|
109
109
|
|
110
|
-
if node.method?(:[]=) || previous_token && !previous_token.right_bracket?
|
110
|
+
if node.method?(:[]=) || (previous_token && !previous_token.right_bracket?)
|
111
111
|
tokens.find(&:left_ref_bracket?)
|
112
112
|
else
|
113
113
|
current_token
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop looks for expressions containing multiple binary operators
|
7
|
+
# where precedence is ambiguous due to lack of parentheses. For example,
|
8
|
+
# in `1 + 2 * 3`, the multiplication will happen before the addition, but
|
9
|
+
# lexically it appears that the addition will happen first.
|
10
|
+
#
|
11
|
+
# The cop does not consider unary operators (ie. `!a` or `-b`) or comparison
|
12
|
+
# operators (ie. `a =~ b`) because those are not ambiguous.
|
13
|
+
#
|
14
|
+
# NOTE: Ranges are handled by `Lint/AmbiguousRange`.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# # bad
|
18
|
+
# a + b * c
|
19
|
+
# a || b && c
|
20
|
+
# a ** b + c
|
21
|
+
#
|
22
|
+
# # good (different precedence)
|
23
|
+
# a + (b * c)
|
24
|
+
# a || (b && c)
|
25
|
+
# (a ** b) + c
|
26
|
+
#
|
27
|
+
# # good (same precedence)
|
28
|
+
# a + b + c
|
29
|
+
# a * b / c % d
|
30
|
+
class AmbiguousOperatorPrecedence < Base
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
# See https://ruby-doc.org/core-3.0.2/doc/syntax/precedence_rdoc.html
|
34
|
+
PRECEDENCE = [
|
35
|
+
%i[**],
|
36
|
+
%i[* / %],
|
37
|
+
%i[+ -],
|
38
|
+
%i[<< >>],
|
39
|
+
%i[&],
|
40
|
+
%i[| ^],
|
41
|
+
%i[&&],
|
42
|
+
%i[||]
|
43
|
+
].freeze
|
44
|
+
RESTRICT_ON_SEND = PRECEDENCE.flatten.freeze
|
45
|
+
MSG = 'Wrap expressions with varying precedence with parentheses to avoid ambiguity.'
|
46
|
+
|
47
|
+
def on_new_investigation
|
48
|
+
# Cache the precedence of each node being investigated
|
49
|
+
# so that we only need to calculate it once
|
50
|
+
@node_precedences = {}
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
def on_and(node)
|
55
|
+
return unless (parent = node.parent)
|
56
|
+
|
57
|
+
return if parent.begin_type? # if the `and` is in a `begin`, it's parenthesized already
|
58
|
+
return unless parent.or_type?
|
59
|
+
|
60
|
+
add_offense(node) do |corrector|
|
61
|
+
autocorrect(corrector, node)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_send(node)
|
66
|
+
return if node.parenthesized?
|
67
|
+
|
68
|
+
return unless (parent = node.parent)
|
69
|
+
return unless operator?(parent)
|
70
|
+
return unless greater_precedence?(node, parent)
|
71
|
+
|
72
|
+
add_offense(node) do |corrector|
|
73
|
+
autocorrect(corrector, node)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def precedence(node)
|
80
|
+
@node_precedences.fetch(node) do
|
81
|
+
PRECEDENCE.index { |operators| operators.include?(operator_name(node)) }
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def operator?(node)
|
86
|
+
(node.send_type? && RESTRICT_ON_SEND.include?(node.method_name)) || node.operator_keyword?
|
87
|
+
end
|
88
|
+
|
89
|
+
def greater_precedence?(node1, node2)
|
90
|
+
node1_precedence = precedence(node1)
|
91
|
+
node2_precedence = precedence(node2)
|
92
|
+
return false unless node1_precedence && node2_precedence
|
93
|
+
|
94
|
+
node2_precedence > node1_precedence
|
95
|
+
end
|
96
|
+
|
97
|
+
def operator_name(node)
|
98
|
+
if node.send_type?
|
99
|
+
node.method_name
|
100
|
+
else
|
101
|
+
node.operator.to_sym
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def autocorrect(corrector, node)
|
106
|
+
corrector.wrap(node, '(', ')')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -10,12 +10,6 @@ module RuboCop
|
|
10
10
|
# explicit by requiring parenthesis around complex range boundaries (anything
|
11
11
|
# that is not a basic literal: numerics, strings, symbols, etc.).
|
12
12
|
#
|
13
|
-
# NOTE: The cop auto-corrects by wrapping the entire boundary in parentheses, which
|
14
|
-
# makes the outcome more explicit but is possible to not be the intention of the
|
15
|
-
# programmer. For this reason, this cop's auto-correct is marked as unsafe (it
|
16
|
-
# will not change the behaviour of the code, but will not necessarily match the
|
17
|
-
# intent of the program).
|
18
|
-
#
|
19
13
|
# This cop can be configured with `RequireParenthesesForMethodChains` in order to
|
20
14
|
# specify whether method chains (including `self.foo`) should be wrapped in parens
|
21
15
|
# by this cop.
|
@@ -23,6 +17,13 @@ module RuboCop
|
|
23
17
|
# NOTE: Regardless of this configuration, if a method receiver is a basic literal
|
24
18
|
# value, it will be wrapped in order to prevent the ambiguity of `1..2.to_a`.
|
25
19
|
#
|
20
|
+
# @safety
|
21
|
+
# The cop auto-corrects by wrapping the entire boundary in parentheses, which
|
22
|
+
# makes the outcome more explicit but is possible to not be the intention of the
|
23
|
+
# programmer. For this reason, this cop's auto-correct is unsafe (it will not
|
24
|
+
# change the behaviour of the code, but will not necessarily match the
|
25
|
+
# intent of the program).
|
26
|
+
#
|
26
27
|
# @example
|
27
28
|
# # bad
|
28
29
|
# x || 1..2
|
@@ -55,7 +56,6 @@ module RuboCop
|
|
55
56
|
#
|
56
57
|
# # good
|
57
58
|
# (a.foo)..(b.bar)
|
58
|
-
#
|
59
59
|
class AmbiguousRange < Base
|
60
60
|
extend AutoCorrector
|
61
61
|
|
@@ -82,8 +82,8 @@ module RuboCop
|
|
82
82
|
def acceptable?(node)
|
83
83
|
node.begin_type? ||
|
84
84
|
node.basic_literal? ||
|
85
|
-
node.variable? || node.const_type? ||
|
86
|
-
node.call_type? && acceptable_call?(node)
|
85
|
+
node.variable? || node.const_type? || node.self_type? ||
|
86
|
+
(node.call_type? && acceptable_call?(node))
|
87
87
|
end
|
88
88
|
|
89
89
|
def acceptable_call?(node)
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
49
49
|
def on_if(node)
|
50
50
|
return if node.condition.block_type?
|
51
51
|
|
52
|
-
traverse_node(node.condition
|
52
|
+
traverse_node(node.condition) do |asgn_node|
|
53
53
|
next :skip_children if skip_children?(asgn_node)
|
54
54
|
next if allowed_construct?(asgn_node)
|
55
55
|
|
@@ -83,13 +83,15 @@ module RuboCop
|
|
83
83
|
(safe_assignment_allowed? && safe_assignment?(asgn_node))
|
84
84
|
end
|
85
85
|
|
86
|
-
|
87
|
-
|
88
|
-
|
86
|
+
def traverse_node(node, &block)
|
87
|
+
# if the node is a block, any assignments are irrelevant
|
88
|
+
return if node.block_type?
|
89
|
+
|
90
|
+
result = yield node if ASGN_TYPES.include?(node.type)
|
89
91
|
|
90
92
|
return if result == :skip_children
|
91
93
|
|
92
|
-
node.each_child_node { |child| traverse_node(child,
|
94
|
+
node.each_child_node { |child| traverse_node(child, &block) }
|
93
95
|
end
|
94
96
|
end
|
95
97
|
end
|
@@ -5,15 +5,28 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# This cop checks for places where binary operator has identical operands.
|
7
7
|
#
|
8
|
-
# It covers arithmetic operators:
|
8
|
+
# It covers arithmetic operators: `-`, `/`, `%`;
|
9
9
|
# comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, `<=`;
|
10
|
-
# bitwise operators: `|`, `^`,
|
10
|
+
# bitwise operators: `|`, `^`, `&`;
|
11
11
|
# boolean operators: `&&`, `||`
|
12
12
|
# and "spaceship" operator - `<=>`.
|
13
13
|
#
|
14
|
-
#
|
15
|
-
#
|
14
|
+
# Simple arithmetic operations are allowed by this cop: `+`, `*`, `**`, `<<` and `>>`.
|
15
|
+
# Although these can be rewritten in a different way, it should not be necessary to
|
16
|
+
# do so. This does not include operations such as `-` or `/` where the result will
|
17
|
+
# always be the same (`x - x` will always be 0; `x / x` will always be 1), and
|
18
|
+
# thus are legitimate offenses.
|
19
|
+
#
|
20
|
+
# @safety
|
21
|
+
# This cop is unsafe as it does not consider side effects when calling methods
|
22
|
+
# and thus can generate false positives, for example:
|
23
|
+
#
|
24
|
+
# [source,ruby]
|
25
|
+
# ----
|
16
26
|
# if wr.take_char == '\0' && wr.take_char == '\0'
|
27
|
+
# # ...
|
28
|
+
# end
|
29
|
+
# ----
|
17
30
|
#
|
18
31
|
# @example
|
19
32
|
# # bad
|
@@ -24,7 +37,7 @@ module RuboCop
|
|
24
37
|
# do_something
|
25
38
|
# end
|
26
39
|
#
|
27
|
-
# def
|
40
|
+
# def child?
|
28
41
|
# left_child || left_child
|
29
42
|
# end
|
30
43
|
#
|
@@ -6,6 +6,11 @@ module RuboCop
|
|
6
6
|
# This cop checks for `:true` and `:false` symbols.
|
7
7
|
# In most cases it would be a typo.
|
8
8
|
#
|
9
|
+
# @safety
|
10
|
+
# Autocorrection is unsafe for this cop because code relying
|
11
|
+
# on `:true` or `:false` symbols will break when those are
|
12
|
+
# changed to actual booleans.
|
13
|
+
#
|
9
14
|
# @example
|
10
15
|
#
|
11
16
|
# # bad
|
@@ -58,12 +58,12 @@ module RuboCop
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def to_s
|
61
|
-
[class_constant, method].compact.join(
|
61
|
+
[class_constant, method].compact.join(delimiter)
|
62
62
|
end
|
63
63
|
|
64
64
|
private
|
65
65
|
|
66
|
-
def
|
66
|
+
def delimiter
|
67
67
|
CLASS_METHOD_DELIMETER
|
68
68
|
end
|
69
69
|
end
|
@@ -81,12 +81,12 @@ module RuboCop
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def to_s
|
84
|
-
[class_constant, method].compact.join(
|
84
|
+
[class_constant, method].compact.join(delimiter)
|
85
85
|
end
|
86
86
|
|
87
87
|
private
|
88
88
|
|
89
|
-
def
|
89
|
+
def delimiter
|
90
90
|
instance_method? ? INSTANCE_METHOD_DELIMETER : CLASS_METHOD_DELIMETER
|
91
91
|
end
|
92
92
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# This cop checks constructors for disjunctive assignments that should
|
6
|
+
# This cop checks constructors for disjunctive assignments (`||=`) that should
|
7
7
|
# be plain assignments.
|
8
8
|
#
|
9
9
|
# So far, this cop is only concerned with disjunctive assignment of
|
@@ -12,6 +12,29 @@ module RuboCop
|
|
12
12
|
# In ruby, an instance variable is nil until a value is assigned, so the
|
13
13
|
# disjunction is unnecessary. A plain assignment has the same effect.
|
14
14
|
#
|
15
|
+
# @safety
|
16
|
+
# This cop is unsafe because it can register a false positive when a
|
17
|
+
# method is redefined in a subclass that calls super. For example:
|
18
|
+
#
|
19
|
+
# [source,ruby]
|
20
|
+
# ----
|
21
|
+
# class Base
|
22
|
+
# def initialize
|
23
|
+
# @config ||= 'base'
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# class Derived < Base
|
28
|
+
# def initialize
|
29
|
+
# @config = 'derived'
|
30
|
+
# super
|
31
|
+
# end
|
32
|
+
# end
|
33
|
+
# ----
|
34
|
+
#
|
35
|
+
# Without the disjunctive assignment, `Derived` will be unable to override
|
36
|
+
# the value for `@config`.
|
37
|
+
#
|
15
38
|
# @example
|
16
39
|
# # bad
|
17
40
|
# def initialize
|
@@ -49,6 +49,9 @@ module RuboCop
|
|
49
49
|
def on_if(node)
|
50
50
|
return if node.ternary?
|
51
51
|
|
52
|
+
# If the if is on a single line, it'll be handled by `Style/OneLineConditional`
|
53
|
+
return if node.single_line?
|
54
|
+
|
52
55
|
check(node)
|
53
56
|
end
|
54
57
|
|
@@ -66,13 +69,10 @@ module RuboCop
|
|
66
69
|
|
67
70
|
def check_else(node)
|
68
71
|
else_branch = node.else_branch
|
69
|
-
|
70
|
-
return unless else_branch.begin_type?
|
71
|
-
|
72
|
-
first_else = else_branch.children.first
|
72
|
+
first_else = else_branch.begin_type? ? else_branch.children.first : else_branch
|
73
73
|
|
74
74
|
return unless first_else
|
75
|
-
return unless first_else
|
75
|
+
return unless same_line?(first_else, node.loc.else)
|
76
76
|
|
77
77
|
add_offense(first_else) { |corrector| autocorrect(corrector, node, first_else) }
|
78
78
|
end
|
@@ -81,9 +81,13 @@ module RuboCop
|
|
81
81
|
corrector.insert_after(node.loc.else, "\n")
|
82
82
|
|
83
83
|
blank_range = range_between(node.loc.else.end_pos, first_else.loc.expression.begin_pos)
|
84
|
-
indentation = indent(node
|
84
|
+
indentation = indent(node, offset: indentation_width)
|
85
85
|
corrector.replace(blank_range, indentation)
|
86
86
|
end
|
87
|
+
|
88
|
+
def indentation_width
|
89
|
+
@config.for_cop('Layout/IndentationWidth')['Width'] || 2
|
90
|
+
end
|
87
91
|
end
|
88
92
|
end
|
89
93
|
end
|
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
|
52
52
|
def on_case_match(node)
|
53
53
|
node.in_pattern_branches.each do |branch|
|
54
|
-
next if branch.body || cop_config['AllowComments'] && comment_lines?(node)
|
54
|
+
next if branch.body || (cop_config['AllowComments'] && comment_lines?(node))
|
55
55
|
|
56
56
|
add_offense(branch)
|
57
57
|
end
|
@@ -118,7 +118,7 @@ module RuboCop
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def correct_arguments?(arguments)
|
121
|
-
arguments.size == 1 || arguments.size == 2 && arguments[1].hash_type?
|
121
|
+
arguments.size == 1 || (arguments.size == 2 && arguments[1].hash_type?)
|
122
122
|
end
|
123
123
|
|
124
124
|
def build_kwargs(node)
|
@@ -3,10 +3,19 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
|
-
# Prefer using `Hash#compare_by_identity` than using `object_id`
|
6
|
+
# Prefer using `Hash#compare_by_identity` rather than using `object_id`
|
7
|
+
# for hash keys.
|
7
8
|
#
|
8
|
-
# This cop
|
9
|
-
#
|
9
|
+
# This cop looks for hashes being keyed by objects' `object_id`, using
|
10
|
+
# one of these methods: `key?`, `has_key?`, `fetch`, `[]` and `[]=`.
|
11
|
+
#
|
12
|
+
# @safety
|
13
|
+
# This cop is unsafe. Although unlikely, the hash could store both object
|
14
|
+
# ids and other values that need be compared by value, and thus
|
15
|
+
# could be a false positive.
|
16
|
+
#
|
17
|
+
# Furthermore, this cop cannot guarantee that the receiver of one of the
|
18
|
+
# methods (`key?`, etc.) is actually a hash.
|
10
19
|
#
|
11
20
|
# @example
|
12
21
|
# # bad
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
#
|
7
|
+
# This cop checks for `IO.select` that is incompatible with Fiber Scheduler since Ruby 3.0.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# IO.select([io], [], [], timeout)
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# io.wait_readable(timeout)
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# IO.select([], [io], [], timeout)
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# io.wait_writable(timeout)
|
22
|
+
#
|
23
|
+
class IncompatibleIoSelectWithFiberScheduler < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
|
26
|
+
MSG = 'Use `%<preferred>s` instead of `%<current>s`.'
|
27
|
+
RESTRICT_ON_SEND = %i[select].freeze
|
28
|
+
|
29
|
+
# @!method io_select(node)
|
30
|
+
def_node_matcher :io_select, <<~PATTERN
|
31
|
+
(send
|
32
|
+
(const {nil? cbase} :IO) :select $_ $_ {(array) nil} $...)
|
33
|
+
PATTERN
|
34
|
+
|
35
|
+
def on_send(node)
|
36
|
+
return unless (read, write, timeout = io_select(node))
|
37
|
+
return unless scheduler_compatible?(read, write) || scheduler_compatible?(write, read)
|
38
|
+
|
39
|
+
preferred = preferred_method(read, write, timeout)
|
40
|
+
message = format(MSG, preferred: preferred, current: node.source)
|
41
|
+
|
42
|
+
add_offense(node, message: message) do |corrector|
|
43
|
+
corrector.replace(node, preferred)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def scheduler_compatible?(io1, io2)
|
50
|
+
return false unless io1.array_type? && io1.values.size == 1
|
51
|
+
|
52
|
+
io2.array_type? ? io2.values.empty? : io2.nil_type?
|
53
|
+
end
|
54
|
+
|
55
|
+
def preferred_method(read, write, timeout)
|
56
|
+
timeout_argument = timeout.empty? ? '' : "(#{timeout[0].source})"
|
57
|
+
|
58
|
+
if read.array_type? && read.values[0]
|
59
|
+
"#{read.values[0].source}.wait_readable#{timeout_argument}"
|
60
|
+
else
|
61
|
+
"#{write.values[0].source}.wait_writable#{timeout_argument}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -5,6 +5,11 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# This cop checks for interpolation in a single quoted string.
|
7
7
|
#
|
8
|
+
# @safety
|
9
|
+
# This cop is generally safe, but is marked as unsafe because
|
10
|
+
# it is possible to actually intentionally have text inside
|
11
|
+
# `#{...}` in a single quoted string.
|
12
|
+
#
|
8
13
|
# @example
|
9
14
|
#
|
10
15
|
# # bad
|
@@ -5,9 +5,10 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# This cop checks for uses of `begin...end while/until something`.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
# loop body
|
8
|
+
# @safety
|
9
|
+
# The cop is unsafe because behaviour can change in some cases, including
|
10
|
+
# if a local variable inside the loop body is accessed outside of it, or if the
|
11
|
+
# loop body raises a `StopIteration` exception (which `Kernel#loop` rescues).
|
11
12
|
#
|
12
13
|
# @example
|
13
14
|
#
|