rubocop 1.67.0 → 1.69.0
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 +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
@@ -135,10 +135,10 @@ module RuboCop
|
|
135
135
|
grandparent.array_type? && grandparent.children.size > 1
|
136
136
|
end
|
137
137
|
|
138
|
+
# rubocop:disable Metrics/AbcSize
|
138
139
|
def replacement_range_and_content(node)
|
139
|
-
variable
|
140
|
-
|
141
|
-
expression = loc.expression
|
140
|
+
variable = node.children.first
|
141
|
+
expression = node.source_range
|
142
142
|
|
143
143
|
if array_new?(variable)
|
144
144
|
expression = node.parent.source_range if node.parent.array_type?
|
@@ -148,16 +148,17 @@ module RuboCop
|
|
148
148
|
elsif redundant_brackets?(node)
|
149
149
|
[expression, remove_brackets(variable)]
|
150
150
|
else
|
151
|
-
[loc.operator, '']
|
151
|
+
[node.loc.operator, '']
|
152
152
|
end
|
153
153
|
end
|
154
|
+
# rubocop:enable Metrics/AbcSize
|
154
155
|
|
155
156
|
def array_splat?(node)
|
156
157
|
node.children.first.array_type?
|
157
158
|
end
|
158
159
|
|
159
160
|
def method_argument?(node)
|
160
|
-
node.parent.
|
161
|
+
node.parent.call_type?
|
161
162
|
end
|
162
163
|
|
163
164
|
def part_of_an_array?(node)
|
@@ -171,7 +172,7 @@ module RuboCop
|
|
171
172
|
parent = node.parent
|
172
173
|
grandparent = node.parent.parent
|
173
174
|
|
174
|
-
parent.when_type? ||
|
175
|
+
parent.when_type? || method_argument?(node) || part_of_an_array?(node) ||
|
175
176
|
grandparent&.resbody_type?
|
176
177
|
end
|
177
178
|
|
@@ -196,7 +197,7 @@ module RuboCop
|
|
196
197
|
def use_percent_literal_array_argument?(node)
|
197
198
|
argument = node.children.first
|
198
199
|
|
199
|
-
node
|
200
|
+
method_argument?(node) &&
|
200
201
|
(argument.percent_literal?(:string) || argument.percent_literal?(:symbol))
|
201
202
|
end
|
202
203
|
|
@@ -42,15 +42,11 @@ module RuboCop
|
|
42
42
|
INVALID_TYPES = %i[array dstr float hash nil int str sym].freeze
|
43
43
|
|
44
44
|
def on_resbody(node)
|
45
|
-
|
46
|
-
return if rescued.nil?
|
47
|
-
|
48
|
-
exceptions = *rescued
|
49
|
-
invalid_exceptions = invalid_exceptions(exceptions)
|
45
|
+
invalid_exceptions = invalid_exceptions(node.exceptions)
|
50
46
|
return if invalid_exceptions.empty?
|
51
47
|
|
52
48
|
add_offense(
|
53
|
-
node.loc.keyword.join(
|
49
|
+
node.loc.keyword.join(node.children.first.source_range),
|
54
50
|
message: format(MSG, invalid_exceptions: invalid_exceptions.map(&:source).join(', '))
|
55
51
|
) do |corrector|
|
56
52
|
autocorrect(corrector, node)
|
@@ -58,7 +54,7 @@ module RuboCop
|
|
58
54
|
end
|
59
55
|
|
60
56
|
def autocorrect(corrector, node)
|
61
|
-
rescued
|
57
|
+
rescued = node.children.first
|
62
58
|
range = node.loc.keyword.end.join(rescued.source_range.end)
|
63
59
|
|
64
60
|
corrector.replace(range, correction(*rescued))
|
@@ -38,6 +38,8 @@ module RuboCop
|
|
38
38
|
PATTERN
|
39
39
|
|
40
40
|
def on_send(node)
|
41
|
+
return unless require_safe_navigation?(node)
|
42
|
+
|
41
43
|
bad_method?(node) do |safe_nav, method|
|
42
44
|
return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
|
43
45
|
|
@@ -52,6 +54,13 @@ module RuboCop
|
|
52
54
|
|
53
55
|
private
|
54
56
|
|
57
|
+
def require_safe_navigation?(node)
|
58
|
+
parent = node.parent
|
59
|
+
return true unless parent&.and_type?
|
60
|
+
|
61
|
+
parent.rhs != node || parent.lhs.receiver != parent.rhs.receiver
|
62
|
+
end
|
63
|
+
|
55
64
|
# @param [Parser::Source::Range] offense_range
|
56
65
|
# @param [RuboCop::AST::SendNode] send_node
|
57
66
|
# @return [String]
|
@@ -83,6 +83,8 @@ module RuboCop
|
|
83
83
|
def find_consistent_parts(grouped_operands)
|
84
84
|
csend_in_and, csend_in_or, send_in_and, send_in_or = most_left_indices(grouped_operands)
|
85
85
|
|
86
|
+
return if csend_in_and && csend_in_or && csend_in_and < csend_in_or
|
87
|
+
|
86
88
|
if csend_in_and
|
87
89
|
['.', (send_in_and ? [send_in_and, csend_in_and].min : csend_in_and) + 1]
|
88
90
|
elsif send_in_or && csend_in_or
|
@@ -94,7 +96,9 @@ module RuboCop
|
|
94
96
|
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
95
97
|
|
96
98
|
def already_appropriate_call?(operand, dot_op)
|
97
|
-
|
99
|
+
return true if operand.safe_navigation? && dot_op == '&.'
|
100
|
+
|
101
|
+
(operand.dot? || operand.operator_method?) && dot_op == '.'
|
98
102
|
end
|
99
103
|
|
100
104
|
def register_offense(operand, dot_operator)
|
@@ -43,23 +43,21 @@ module RuboCop
|
|
43
43
|
alias on_csend on_send
|
44
44
|
|
45
45
|
def on_lvasgn(node)
|
46
|
-
|
47
|
-
return unless rhs
|
46
|
+
return unless node.rhs
|
48
47
|
|
49
48
|
rhs_type = ASSIGNMENT_TYPE_TO_RHS_TYPE[node.type]
|
50
49
|
|
51
|
-
add_offense(node) if rhs.type == rhs_type && rhs.source == lhs.to_s
|
50
|
+
add_offense(node) if node.rhs.type == rhs_type && node.rhs.source == node.lhs.to_s
|
52
51
|
end
|
53
52
|
alias on_ivasgn on_lvasgn
|
54
53
|
alias on_cvasgn on_lvasgn
|
55
54
|
alias on_gvasgn on_lvasgn
|
56
55
|
|
57
56
|
def on_casgn(node)
|
58
|
-
|
59
|
-
return unless rhs&.const_type?
|
57
|
+
return unless node.rhs&.const_type?
|
60
58
|
|
61
|
-
|
62
|
-
|
59
|
+
add_offense(node) if node.namespace == node.rhs.namespace &&
|
60
|
+
node.short_name == node.rhs.short_name
|
63
61
|
end
|
64
62
|
|
65
63
|
def on_masgn(node)
|
@@ -67,15 +65,15 @@ module RuboCop
|
|
67
65
|
end
|
68
66
|
|
69
67
|
def on_or_asgn(node)
|
70
|
-
|
71
|
-
add_offense(node) if rhs_matches_lhs?(rhs, lhs)
|
68
|
+
add_offense(node) if rhs_matches_lhs?(node.rhs, node.lhs)
|
72
69
|
end
|
73
70
|
alias on_and_asgn on_or_asgn
|
74
71
|
|
75
72
|
private
|
76
73
|
|
77
74
|
def multiple_self_assignment?(node)
|
78
|
-
lhs
|
75
|
+
lhs = node.lhs
|
76
|
+
rhs = node.rhs
|
79
77
|
return false unless rhs.array_type?
|
80
78
|
return false unless lhs.children.size == rhs.children.size
|
81
79
|
|
@@ -67,7 +67,7 @@ module RuboCop
|
|
67
67
|
def on_rescue(node)
|
68
68
|
return if rescue_modifier?(node)
|
69
69
|
|
70
|
-
|
70
|
+
rescues = node.resbody_branches
|
71
71
|
rescued_groups = rescued_groups_for(rescues)
|
72
72
|
|
73
73
|
rescue_group_rescues_multiple_levels = rescued_groups.any? do |group|
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for Regexpes (both literals and via `Regexp.new` / `Regexp.compile`)
|
7
|
+
# that contain unescaped `]` characters.
|
8
|
+
#
|
9
|
+
# It emulates the following Ruby warning:
|
10
|
+
#
|
11
|
+
# [source,ruby]
|
12
|
+
# ----
|
13
|
+
# $ ruby -e '/abc]123/'
|
14
|
+
# -e:1: warning: regular expression has ']' without escape: /abc]123/
|
15
|
+
# ----
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# /abc]123/
|
20
|
+
# %r{abc]123}
|
21
|
+
# Regexp.new('abc]123')
|
22
|
+
# Regexp.compile('abc]123')
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# /abc\]123/
|
26
|
+
# %r{abc\]123}
|
27
|
+
# Regexp.new('abc\]123')
|
28
|
+
# Regexp.compile('abc\]123')
|
29
|
+
#
|
30
|
+
class UnescapedBracketInRegexp < Base
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
MSG = 'Regular expression has `]` without escape.'
|
34
|
+
RESTRICT_ON_SEND = %i[new compile].freeze
|
35
|
+
|
36
|
+
# @!method regexp_constructor(node)
|
37
|
+
def_node_search :regexp_constructor, <<~PATTERN
|
38
|
+
(send
|
39
|
+
(const {nil? cbase} :Regexp) {:new :compile}
|
40
|
+
$str
|
41
|
+
...
|
42
|
+
)
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
def on_regexp(node)
|
46
|
+
RuboCop::Util.silence_warnings do
|
47
|
+
node.parsed_tree&.each_expression do |expr|
|
48
|
+
detect_offenses(node, expr)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_send(node)
|
54
|
+
# Ignore nodes that contain interpolation
|
55
|
+
return if node.each_descendant(:dstr).any?
|
56
|
+
|
57
|
+
regexp_constructor(node) do |text|
|
58
|
+
Regexp::Parser.parse(text.value)&.each_expression do |expr|
|
59
|
+
detect_offenses(text, expr)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def detect_offenses(node, expr)
|
67
|
+
return unless expr.type?(:literal)
|
68
|
+
|
69
|
+
expr.text.scan(/(?<!\\)\]/) do
|
70
|
+
pos = Regexp.last_match.begin(0)
|
71
|
+
next if pos.zero? # if the unescaped bracket is the first character, Ruby does not warn
|
72
|
+
|
73
|
+
location = range_at_index(node, expr.ts, pos)
|
74
|
+
|
75
|
+
add_offense(location) do |corrector|
|
76
|
+
corrector.replace(location, '\]')
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def range_at_index(node, index, offset)
|
82
|
+
adjustment = index + offset
|
83
|
+
node.loc.begin.end.adjust(begin_pos: adjustment, end_pos: adjustment + 1)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -39,6 +39,8 @@ module RuboCop
|
|
39
39
|
# end
|
40
40
|
#
|
41
41
|
# @example IgnoreNotImplementedMethods: true (default)
|
42
|
+
# # with default value of `NotImplementedExceptions: ['NotImplementedError']`
|
43
|
+
#
|
42
44
|
# # good
|
43
45
|
# def do_something(unused)
|
44
46
|
# raise NotImplementedError
|
@@ -48,6 +50,14 @@ module RuboCop
|
|
48
50
|
# fail "TODO"
|
49
51
|
# end
|
50
52
|
#
|
53
|
+
# @example IgnoreNotImplementedMethods: true
|
54
|
+
# # with `NotImplementedExceptions: ['AbstractMethodError']`
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# def do_something(unused)
|
58
|
+
# raise AbstractMethodError
|
59
|
+
# end
|
60
|
+
#
|
51
61
|
# @example IgnoreNotImplementedMethods: false
|
52
62
|
# # bad
|
53
63
|
# def do_something(unused)
|
@@ -57,14 +67,13 @@ module RuboCop
|
|
57
67
|
# def do_something_else(unused)
|
58
68
|
# fail "TODO"
|
59
69
|
# end
|
60
|
-
#
|
61
70
|
class UnusedMethodArgument < Base
|
62
71
|
include UnusedArgument
|
63
72
|
extend AutoCorrector
|
64
73
|
|
65
74
|
# @!method not_implemented?(node)
|
66
75
|
def_node_matcher :not_implemented?, <<~PATTERN
|
67
|
-
{(send nil? :raise
|
76
|
+
{(send nil? :raise #allowed_exception_class? ...)
|
68
77
|
(send nil? :fail ...)}
|
69
78
|
PATTERN
|
70
79
|
|
@@ -115,6 +124,13 @@ module RuboCop
|
|
115
124
|
|
116
125
|
message
|
117
126
|
end
|
127
|
+
|
128
|
+
def allowed_exception_class?(node)
|
129
|
+
return false unless node.const_type?
|
130
|
+
|
131
|
+
allowed_class_names = Array(cop_config.fetch('NotImplementedExceptions', []))
|
132
|
+
allowed_class_names.include?(node.const_name)
|
133
|
+
end
|
118
134
|
end
|
119
135
|
end
|
120
136
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for calls to `defined?` with strings or symbols as the argument.
|
7
|
+
# Such calls will always return `'expression'`, you probably meant to
|
8
|
+
# check for the existence of a constant, method, or variable instead.
|
9
|
+
#
|
10
|
+
# `defined?` is part of the Ruby syntax and doesn't behave like normal methods.
|
11
|
+
# You can safely pass in what you are checking for directly, without encountering
|
12
|
+
# a `NameError`.
|
13
|
+
#
|
14
|
+
# When interpolation is used, oftentimes it is not possible to write the
|
15
|
+
# code with `defined?`. In these cases, switch to one of the more specific methods:
|
16
|
+
#
|
17
|
+
# * `class_variable_defined?`
|
18
|
+
# * `const_defined?`
|
19
|
+
# * `method_defined?`
|
20
|
+
# * `instance_variable_defined?`
|
21
|
+
# * `binding.local_variable_defined?`
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
#
|
25
|
+
# # bad
|
26
|
+
# defined?('FooBar')
|
27
|
+
# defined?(:FooBar)
|
28
|
+
# defined?(:foo_bar)
|
29
|
+
# defined?('foo_bar')
|
30
|
+
#
|
31
|
+
# # good
|
32
|
+
# defined?(FooBar)
|
33
|
+
# defined?(foo_bar)
|
34
|
+
#
|
35
|
+
# # bad - interpolation
|
36
|
+
# bar = 'Bar'
|
37
|
+
# defined?("Foo::#{bar}::Baz")
|
38
|
+
#
|
39
|
+
# # good
|
40
|
+
# bar = 'Bar'
|
41
|
+
# defined?(Foo) && Foo.const_defined?(bar) && Foo.const_get(bar).const_defined?(:Baz)
|
42
|
+
class UselessDefined < Base
|
43
|
+
MSG = 'Calling `defined?` with a %<type>s argument will always return a truthy value.'
|
44
|
+
TYPES = { str: 'string', dstr: 'string', sym: 'symbol', dsym: 'symbol' }.freeze
|
45
|
+
|
46
|
+
def on_defined?(node)
|
47
|
+
# NOTE: `defined?` always takes one argument. Anything else is a syntax error.
|
48
|
+
return unless (type = TYPES[node.first_argument.type])
|
49
|
+
|
50
|
+
add_offense(node, message: format(MSG, type: type))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -75,7 +75,7 @@ module RuboCop
|
|
75
75
|
def use_exception_variable_in_ensure?(resbody_node)
|
76
76
|
return false unless (exception_variable = resbody_node.exception_variable)
|
77
77
|
return false unless (ensure_node = resbody_node.each_ancestor(:ensure).first)
|
78
|
-
return false unless (ensure_body = ensure_node.
|
78
|
+
return false unless (ensure_body = ensure_node.branch)
|
79
79
|
|
80
80
|
ensure_body.each_descendant(:lvar).map(&:source).include?(exception_variable.source)
|
81
81
|
end
|
@@ -102,24 +102,18 @@ module RuboCop
|
|
102
102
|
when :op_asgn
|
103
103
|
process_binary_operator_assignment(node)
|
104
104
|
when *ASSIGNMENT_TYPES
|
105
|
-
|
106
|
-
process_assignment(node, rhs_node) if rhs_node
|
105
|
+
process_assignment(node, node.rhs) if node.rhs
|
107
106
|
end
|
108
107
|
end
|
109
108
|
|
110
109
|
def process_multiple_assignment(masgn_node)
|
111
|
-
|
112
|
-
|
113
|
-
mlhs_node.children.each_with_index do |lhs_node, index|
|
110
|
+
masgn_node.assignments.each_with_index do |lhs_node, index|
|
114
111
|
next unless ASSIGNMENT_TYPES.include?(lhs_node.type)
|
115
112
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
if mrhs_node.array_type? && rhs_node
|
120
|
-
process_assignment(lhs_variable_name, rhs_node)
|
113
|
+
if masgn_node.rhs.array_type? && (rhs_node = masgn_node.rhs.children[index])
|
114
|
+
process_assignment(lhs_node, rhs_node)
|
121
115
|
else
|
122
|
-
@local[
|
116
|
+
@local[lhs_node.name] = true
|
123
117
|
end
|
124
118
|
end
|
125
119
|
|
@@ -127,33 +121,28 @@ module RuboCop
|
|
127
121
|
end
|
128
122
|
|
129
123
|
def process_logical_operator_assignment(asgn_node)
|
130
|
-
|
131
|
-
return unless ASSIGNMENT_TYPES.include?(lhs_node.type)
|
124
|
+
return unless ASSIGNMENT_TYPES.include?(asgn_node.lhs.type)
|
132
125
|
|
133
|
-
process_assignment(
|
126
|
+
process_assignment(asgn_node.lhs, asgn_node.rhs)
|
134
127
|
|
135
128
|
throw :skip_children
|
136
129
|
end
|
137
130
|
|
138
131
|
def process_binary_operator_assignment(op_asgn_node)
|
139
|
-
lhs_node
|
132
|
+
lhs_node = op_asgn_node.lhs
|
140
133
|
return unless ASSIGNMENT_TYPES.include?(lhs_node.type)
|
141
134
|
|
142
|
-
|
143
|
-
@local[lhs_variable_name] = true
|
135
|
+
@local[lhs_node.name] = true
|
144
136
|
|
145
137
|
throw :skip_children
|
146
138
|
end
|
147
139
|
|
148
140
|
def process_assignment(asgn_node, rhs_node)
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
else
|
155
|
-
constructor?(rhs_node)
|
156
|
-
end
|
141
|
+
@local[asgn_node.name] = if rhs_node.variable?
|
142
|
+
@local[rhs_node.name]
|
143
|
+
else
|
144
|
+
constructor?(rhs_node)
|
145
|
+
end
|
157
146
|
end
|
158
147
|
|
159
148
|
def constructor?(node)
|
@@ -126,7 +126,7 @@ module RuboCop
|
|
126
126
|
|
127
127
|
def check_void_op(node, &block)
|
128
128
|
node = node.children.first while node.begin_type?
|
129
|
-
return unless node.
|
129
|
+
return unless node.call_type? && OPERATORS.include?(node.method_name)
|
130
130
|
return if block && yield(node)
|
131
131
|
|
132
132
|
add_offense(node.loc.selector,
|
@@ -196,7 +196,7 @@ module RuboCop
|
|
196
196
|
end
|
197
197
|
|
198
198
|
def check_ensure(node)
|
199
|
-
return unless (body = node.
|
199
|
+
return unless (body = node.branch)
|
200
200
|
# NOTE: the `begin` node case is already handled via `on_begin`
|
201
201
|
return if body.begin_type?
|
202
202
|
|
@@ -219,6 +219,7 @@ module RuboCop
|
|
219
219
|
if node.arguments.empty?
|
220
220
|
corrector.replace(node, node.receiver.source)
|
221
221
|
else
|
222
|
+
corrector.remove(node.loc.dot) if node.loc.dot
|
222
223
|
corrector.replace(
|
223
224
|
range_with_surrounding_space(range: node.loc.selector, side: :both,
|
224
225
|
newlines: false),
|
@@ -53,13 +53,13 @@ module RuboCop
|
|
53
53
|
def on_casgn(node)
|
54
54
|
parent = node.parent
|
55
55
|
|
56
|
-
if parent&.assignment?
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
56
|
+
block_node = if parent&.assignment?
|
57
|
+
parent.expression
|
58
|
+
elsif parent&.parent&.masgn_type?
|
59
|
+
parent.parent.expression
|
60
|
+
else
|
61
|
+
node.expression
|
62
|
+
end
|
63
63
|
|
64
64
|
return unless block_node.respond_to?(:class_definition?) && block_node.class_definition?
|
65
65
|
|
@@ -14,11 +14,14 @@ module RuboCop
|
|
14
14
|
# and ||/or is shorthand for a sequence of ifs, so they also add one.
|
15
15
|
# Loops can be said to have an exit condition, so they add one.
|
16
16
|
# Blocks that are calls to builtin iteration methods
|
17
|
-
# (e.g. `ary.map{...}) also add one, others are ignored.
|
17
|
+
# (e.g. `ary.map{...}`) also add one, others are ignored.
|
18
|
+
#
|
19
|
+
# @example
|
18
20
|
#
|
19
21
|
# def each_child_node(*types) # count begins: 1
|
20
22
|
# unless block_given? # unless: +1
|
21
23
|
# return to_enum(__method__, *types)
|
24
|
+
# end
|
22
25
|
#
|
23
26
|
# children.each do |child| # each{}: +1
|
24
27
|
# next unless child.is_a?(Node) # unless: +1
|
@@ -95,7 +95,7 @@ module RuboCop
|
|
95
95
|
def compound_assignment(node)
|
96
96
|
# Methods setter cannot be detected for multiple assignments
|
97
97
|
# and shorthand assigns, so we'll count them here instead
|
98
|
-
children = node.masgn_type? ? node.
|
98
|
+
children = node.masgn_type? ? node.assignments : node.children
|
99
99
|
|
100
100
|
will_be_miscounted = children.count do |child|
|
101
101
|
child.respond_to?(:setter_method?) && !child.setter_method?
|
@@ -17,9 +17,7 @@ module RuboCop
|
|
17
17
|
alias on_and_asgn on_lvasgn
|
18
18
|
|
19
19
|
def on_send(node)
|
20
|
-
rhs = extract_rhs(node)
|
21
|
-
|
22
|
-
return unless rhs
|
20
|
+
return unless (rhs = extract_rhs(node))
|
23
21
|
|
24
22
|
check_assignment(node, rhs)
|
25
23
|
end
|
@@ -27,17 +25,11 @@ module RuboCop
|
|
27
25
|
module_function
|
28
26
|
|
29
27
|
def extract_rhs(node)
|
30
|
-
if node.
|
31
|
-
|
32
|
-
elsif node.op_asgn_type?
|
33
|
-
_lhs, _op, rhs = *node
|
34
|
-
elsif node.call_type?
|
35
|
-
rhs = node.last_argument
|
28
|
+
if node.call_type?
|
29
|
+
node.last_argument
|
36
30
|
elsif node.assignment?
|
37
|
-
|
31
|
+
node.expression
|
38
32
|
end
|
39
|
-
|
40
|
-
rhs
|
41
33
|
end
|
42
34
|
end
|
43
35
|
end
|
@@ -44,6 +44,8 @@ module RuboCop
|
|
44
44
|
module CheckLineBreakable
|
45
45
|
def extract_breakable_node(node, max)
|
46
46
|
if node.send_type?
|
47
|
+
return if chained_to_heredoc?(node)
|
48
|
+
|
47
49
|
args = process_args(node.arguments)
|
48
50
|
return extract_breakable_node_from_elements(node, args, max)
|
49
51
|
elsif node.def_type?
|
@@ -222,6 +224,14 @@ module RuboCop
|
|
222
224
|
|
223
225
|
!node.single_line?
|
224
226
|
end
|
227
|
+
|
228
|
+
def chained_to_heredoc?(node)
|
229
|
+
while (node = node.receiver)
|
230
|
+
return true if (node.str_type? || node.dstr_type? || node.xstr_type?) && node.heredoc?
|
231
|
+
end
|
232
|
+
|
233
|
+
false
|
234
|
+
end
|
225
235
|
end
|
226
236
|
end
|
227
237
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Checks for code on multiple lines that could be rewritten on a single line
|
6
|
+
# without changing semantics or exceeding the `Max` parameter of `Layout/LineLength`.
|
7
|
+
module CheckSingleLineSuitability
|
8
|
+
def suitable_as_single_line?(node)
|
9
|
+
!too_long?(node) &&
|
10
|
+
!comment_within?(node) &&
|
11
|
+
safe_to_split?(node)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def too_long?(node)
|
17
|
+
lines = processed_source.lines[(node.first_line - 1)...node.last_line]
|
18
|
+
to_single_line(lines.join("\n")).length > max_line_length
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_single_line(source)
|
22
|
+
source
|
23
|
+
.gsub(/" *\\\n\s*'/, %q(" + ')) # Double quote, backslash, and then single quote
|
24
|
+
.gsub(/' *\\\n\s*"/, %q(' + ")) # Single quote, backslash, and then double quote
|
25
|
+
.gsub(/(["']) *\\\n\s*\1/, '') # Double or single quote, backslash, then same quote
|
26
|
+
.gsub(/\n\s*(?=(&)?\.\w)/, '') # Extra space within method chaining which includes `&.`
|
27
|
+
.gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
|
28
|
+
end
|
29
|
+
|
30
|
+
def max_line_length
|
31
|
+
config.for_cop('Layout/LineLength')['Max']
|
32
|
+
end
|
33
|
+
|
34
|
+
def comment_within?(node)
|
35
|
+
comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
|
36
|
+
|
37
|
+
comment_line_numbers.any? do |comment_line_number|
|
38
|
+
comment_line_number >= node.first_line && comment_line_number <= node.last_line
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def safe_to_split?(node)
|
43
|
+
node.each_descendant(:if, :case, :kwbegin, :def, :defs).none? &&
|
44
|
+
node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
|
45
|
+
node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|