rubocop 1.56.4 → 1.60.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +4 -4
- data/config/default.yml +57 -3
- data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +0 -2
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_obsoletion.rb +11 -8
- data/lib/rubocop/config_validator.rb +0 -2
- data/lib/rubocop/cop/base.rb +6 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
- data/lib/rubocop/cop/exclude_limit.rb +1 -1
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +12 -2
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +16 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +2 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
- data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +11 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
- data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +1 -1
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +0 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +9 -4
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +63 -4
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
- data/lib/rubocop/cop/lint/syntax.rb +6 -3
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +43 -12
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +8 -3
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +16 -12
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +12 -4
- data/lib/rubocop/cop/naming/constant_name.rb +1 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +120 -17
- data/lib/rubocop/cop/style/array_first_last.rb +64 -0
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
- data/lib/rubocop/cop/style/case_like_if.rb +4 -4
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/class_equality_comparison.rb +5 -0
- data/lib/rubocop/cop/style/collection_compact.rb +18 -8
- data/lib/rubocop/cop/style/combinable_loops.rb +13 -7
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -14
- data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/format_string.rb +24 -3
- data/lib/rubocop/cop/style/guard_clause.rb +26 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +83 -10
- data/lib/rubocop/cop/style/hash_except.rb +2 -1
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +28 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +39 -2
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +3 -2
- data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +14 -5
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -3
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +2 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +3 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +9 -1
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
- data/lib/rubocop/cop/style/redundant_each.rb +7 -4
- data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +22 -5
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +10 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +68 -21
- data/lib/rubocop/cop/style/redundant_return.rb +1 -1
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_sort.rb +9 -8
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
- data/lib/rubocop/cop/style/sample.rb +2 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +7 -6
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +8 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
- data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cops_documentation_generator.rb +11 -1
- data/lib/rubocop/ext/regexp_node.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +5 -4
- data/lib/rubocop/formatter/json_formatter.rb +0 -1
- data/lib/rubocop/formatter.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/options.rb +0 -8
- data/lib/rubocop/result_cache.rb +0 -1
- data/lib/rubocop/rspec/shared_contexts.rb +6 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/server/cache.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -0
- metadata +16 -24
- /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
# interpolation should not be removed if the expanded value
|
35
35
|
# contains a space character.
|
36
36
|
expanded_value = autocorrected_value(final_node)
|
37
|
-
return if in_array_percent_literal?(begin_node) && /\s/.match?(expanded_value)
|
37
|
+
return if in_array_percent_literal?(begin_node) && /\s|\A\z/.match?(expanded_value)
|
38
38
|
|
39
39
|
add_offense(final_node) do |corrector|
|
40
40
|
return if final_node.dstr_type? # nested, fixed in next iteration
|
@@ -34,35 +34,20 @@ module RuboCop
|
|
34
34
|
add_offense(void_next) if void_next
|
35
35
|
end
|
36
36
|
end
|
37
|
-
|
38
|
-
def on_numblock(node)
|
39
|
-
on_numblock_body_of_reduce(node) do |body|
|
40
|
-
void_next = body.each_node(:next).find do |n|
|
41
|
-
n.children.empty? && parent_numblock_node(n) == node
|
42
|
-
end
|
43
|
-
|
44
|
-
add_offense(void_next) if void_next
|
45
|
-
end
|
46
|
-
end
|
37
|
+
alias on_numblock on_block
|
47
38
|
|
48
39
|
private
|
49
40
|
|
50
41
|
# @!method on_block_body_of_reduce(node)
|
51
42
|
def_node_matcher :on_block_body_of_reduce, <<~PATTERN
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def_node_matcher :on_numblock_body_of_reduce, <<~PATTERN
|
57
|
-
(numblock (send _recv {:reduce :inject} !sym) _argscount $(begin ...))
|
43
|
+
{
|
44
|
+
(block (call _recv {:reduce :inject} !sym) _blockargs $(begin ...))
|
45
|
+
(numblock (call _recv {:reduce :inject} !sym) _argscount $(begin ...))
|
46
|
+
}
|
58
47
|
PATTERN
|
59
48
|
|
60
49
|
def parent_block_node(node)
|
61
|
-
node.each_ancestor(:block).first
|
62
|
-
end
|
63
|
-
|
64
|
-
def parent_numblock_node(node)
|
65
|
-
node.each_ancestor(:numblock).first
|
50
|
+
node.each_ancestor(:block, :numblock).first
|
66
51
|
end
|
67
52
|
end
|
68
53
|
end
|
@@ -94,7 +94,7 @@ module RuboCop
|
|
94
94
|
parent_node = node.parent
|
95
95
|
|
96
96
|
add_offense(parent_node) do |corrector|
|
97
|
-
if parent_node.
|
97
|
+
if parent_node.last_argument&.block_pass_type?
|
98
98
|
correct_block_pass(corrector, parent_node)
|
99
99
|
else
|
100
100
|
correct_block(corrector, parent_node)
|
@@ -116,7 +116,7 @@ module RuboCop
|
|
116
116
|
|
117
117
|
def correct_block_pass(corrector, node)
|
118
118
|
if unsorted_dir_glob_pass?(node)
|
119
|
-
block_arg = node.
|
119
|
+
block_arg = node.last_argument
|
120
120
|
|
121
121
|
corrector.remove(last_arg_range(node))
|
122
122
|
corrector.insert_after(node, ".sort.each(#{block_arg.source})")
|
@@ -130,9 +130,7 @@ module RuboCop
|
|
130
130
|
# @return [Parser::Source::Range]
|
131
131
|
#
|
132
132
|
def last_arg_range(node)
|
133
|
-
node.
|
134
|
-
begin_pos: node.arguments[-2].source_range.end_pos
|
135
|
-
)
|
133
|
+
node.last_argument.source_range.with(begin_pos: node.arguments[-2].source_range.end_pos)
|
136
134
|
end
|
137
135
|
|
138
136
|
def unsorted_dir_loop?(node)
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
9
9
|
#
|
10
10
|
# Conversion with `Integer`, `Float`, etc. will raise an `ArgumentError`
|
11
11
|
# if given input that is not numeric (eg. an empty string), whereas
|
12
|
-
# `to_i`, etc. will try to convert regardless of input (
|
12
|
+
# `to_i`, etc. will try to convert regardless of input (``''.to_i => 0``).
|
13
13
|
# As such, this cop is disabled by default because it's not necessarily
|
14
14
|
# always correct to raise if a value is not numeric.
|
15
15
|
#
|
@@ -91,19 +91,24 @@ module RuboCop
|
|
91
91
|
|
92
92
|
# @!method to_method(node)
|
93
93
|
def_node_matcher :to_method, <<~PATTERN
|
94
|
-
(
|
94
|
+
(call $_ ${#{METHODS}})
|
95
95
|
PATTERN
|
96
96
|
|
97
97
|
# @!method to_method_symbol(node)
|
98
98
|
def_node_matcher :to_method_symbol, <<~PATTERN
|
99
|
-
|
100
|
-
|
99
|
+
(call _ $_ ${
|
100
|
+
{
|
101
|
+
(sym ${#{METHODS}})
|
102
|
+
(block_pass (sym ${#{METHODS}}))
|
103
|
+
}
|
104
|
+
} ...)
|
101
105
|
PATTERN
|
102
106
|
|
103
107
|
def on_send(node)
|
104
108
|
handle_conversion_method(node)
|
105
109
|
handle_as_symbol(node)
|
106
110
|
end
|
111
|
+
alias on_csend on_send
|
107
112
|
|
108
113
|
private
|
109
114
|
|
@@ -24,6 +24,10 @@ module RuboCop
|
|
24
24
|
#
|
25
25
|
# This cop target those features.
|
26
26
|
#
|
27
|
+
# @safety
|
28
|
+
# This cop's autocorrection is unsafe because if `require 'pp'` is removed from one file,
|
29
|
+
# `NameError` can be encountered when another file uses `PP.pp`.
|
30
|
+
#
|
27
31
|
# @example
|
28
32
|
# # bad
|
29
33
|
# require 'unloaded_feature'
|
@@ -4,8 +4,12 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
6
|
# Checks for redundant safe navigation calls.
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# Use cases where a constant, named in camel case for classes and modules is `nil` are rare,
|
8
|
+
# and an offense is not detected when the receiver is a snake case constant.
|
9
|
+
#
|
10
|
+
# For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
|
11
|
+
# and `equal?` methods are checked by default.
|
12
|
+
# These are customizable with `AllowedMethods` option.
|
9
13
|
#
|
10
14
|
# The `AllowedMethods` option specifies nil-safe methods,
|
11
15
|
# in other words, it is a method that is allowed to skip safe navigation.
|
@@ -22,6 +26,9 @@ module RuboCop
|
|
22
26
|
#
|
23
27
|
# @example
|
24
28
|
# # bad
|
29
|
+
# CamelCaseConst&.do_something
|
30
|
+
#
|
31
|
+
# # bad
|
25
32
|
# do_something if attrs&.respond_to?(:[])
|
26
33
|
#
|
27
34
|
# # good
|
@@ -33,6 +40,9 @@ module RuboCop
|
|
33
40
|
# end
|
34
41
|
#
|
35
42
|
# # good
|
43
|
+
# CamelCaseConst.do_something
|
44
|
+
#
|
45
|
+
# # good
|
36
46
|
# while node.is_a?(BeginNode)
|
37
47
|
# node = node.parent
|
38
48
|
# end
|
@@ -40,6 +50,22 @@ module RuboCop
|
|
40
50
|
# # good - without `&.` this will always return `true`
|
41
51
|
# foo&.respond_to?(:to_a)
|
42
52
|
#
|
53
|
+
# # bad - for `nil`s conversion methods return default values for the type
|
54
|
+
# foo&.to_h || {}
|
55
|
+
# foo&.to_h { |k, v| [k, v] } || {}
|
56
|
+
# foo&.to_a || []
|
57
|
+
# foo&.to_i || 0
|
58
|
+
# foo&.to_f || 0.0
|
59
|
+
# foo&.to_s || ''
|
60
|
+
#
|
61
|
+
# # good
|
62
|
+
# foo.to_h
|
63
|
+
# foo.to_h { |k, v| [k, v] }
|
64
|
+
# foo.to_a
|
65
|
+
# foo.to_i
|
66
|
+
# foo.to_f
|
67
|
+
# foo.to_s
|
68
|
+
#
|
43
69
|
# @example AllowedMethods: [nil_safe_method]
|
44
70
|
# # bad
|
45
71
|
# do_something if attrs&.nil_safe_method(:[])
|
@@ -54,22 +80,55 @@ module RuboCop
|
|
54
80
|
extend AutoCorrector
|
55
81
|
|
56
82
|
MSG = 'Redundant safe navigation detected.'
|
83
|
+
MSG_LITERAL = 'Redundant safe navigation with default literal detected.'
|
57
84
|
|
58
85
|
NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
|
59
86
|
|
87
|
+
SNAKE_CASE = /\A[[:digit:][:upper:]_]+\z/.freeze
|
88
|
+
|
60
89
|
# @!method respond_to_nil_specific_method?(node)
|
61
90
|
def_node_matcher :respond_to_nil_specific_method?, <<~PATTERN
|
62
91
|
(csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
|
63
92
|
PATTERN
|
64
93
|
|
94
|
+
# @!method conversion_with_default?(node)
|
95
|
+
def_node_matcher :conversion_with_default?, <<~PATTERN
|
96
|
+
{
|
97
|
+
(or $(csend _ :to_h) (hash))
|
98
|
+
(or (block $(csend _ :to_h) ...) (hash))
|
99
|
+
(or $(csend _ :to_a) (array))
|
100
|
+
(or $(csend _ :to_i) (int 0))
|
101
|
+
(or $(csend _ :to_f) (float 0.0))
|
102
|
+
(or $(csend _ :to_s) (str empty?))
|
103
|
+
}
|
104
|
+
PATTERN
|
105
|
+
|
106
|
+
# rubocop:disable Metrics/AbcSize
|
65
107
|
def on_csend(node)
|
66
|
-
|
67
|
-
|
108
|
+
unless node.receiver.const_type? && !node.receiver.source.match?(SNAKE_CASE)
|
109
|
+
return unless check?(node) && allowed_method?(node.method_name)
|
110
|
+
return if respond_to_nil_specific_method?(node)
|
111
|
+
end
|
68
112
|
|
69
113
|
range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
|
70
114
|
add_offense(range) { |corrector| corrector.replace(node.loc.dot, '.') }
|
71
115
|
end
|
72
116
|
|
117
|
+
def on_or(node)
|
118
|
+
conversion_with_default?(node) do |send_node|
|
119
|
+
range = range_between(send_node.loc.dot.begin_pos, node.source_range.end_pos)
|
120
|
+
|
121
|
+
add_offense(range, message: MSG_LITERAL) do |corrector|
|
122
|
+
corrector.replace(send_node.loc.dot, '.')
|
123
|
+
|
124
|
+
range_with_default = range_between(node.lhs.source_range.end.begin_pos,
|
125
|
+
node.source_range.end.end_pos)
|
126
|
+
corrector.remove(range_with_default)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
# rubocop:enable Metrics/AbcSize
|
131
|
+
|
73
132
|
private
|
74
133
|
|
75
134
|
def check?(node)
|
@@ -56,10 +56,10 @@ module RuboCop
|
|
56
56
|
def_node_matcher :redundant_with_index?, <<~PATTERN
|
57
57
|
{
|
58
58
|
(block
|
59
|
-
$(
|
59
|
+
$(call _ {:each_with_index :with_index} ...)
|
60
60
|
(args (arg _)) ...)
|
61
61
|
(numblock
|
62
|
-
$(
|
62
|
+
$(call _ {:each_with_index :with_index} ...) 1 ...)
|
63
63
|
}
|
64
64
|
PATTERN
|
65
65
|
|
@@ -56,9 +56,9 @@ module RuboCop
|
|
56
56
|
def_node_matcher :redundant_with_object?, <<~PATTERN
|
57
57
|
{
|
58
58
|
(block
|
59
|
-
$(
|
59
|
+
$(call _ {:each_with_object :with_object} _) (args (arg _)) ...)
|
60
60
|
(numblock
|
61
|
-
$(
|
61
|
+
$(call _ {:each_with_object :with_object} _) 1 ...)
|
62
62
|
}
|
63
63
|
PATTERN
|
64
64
|
|
@@ -45,10 +45,9 @@ module RuboCop
|
|
45
45
|
bad_method?(node) do |safe_nav, method|
|
46
46
|
return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name)
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
node.source_range.end_pos)
|
48
|
+
begin_range = node.loc.dot || safe_nav.source_range.end
|
49
|
+
location = begin_range.join(node.source_range.end)
|
50
|
+
|
52
51
|
add_offense(location) do |corrector|
|
53
52
|
autocorrect(corrector, offense_range: location, send_node: node)
|
54
53
|
end
|
@@ -10,11 +10,18 @@ module RuboCop
|
|
10
10
|
# foo = foo
|
11
11
|
# foo, bar = foo, bar
|
12
12
|
# Foo = Foo
|
13
|
+
# hash['foo'] = hash['foo']
|
14
|
+
# obj.attr = obj.attr
|
13
15
|
#
|
14
16
|
# # good
|
15
17
|
# foo = bar
|
16
18
|
# foo, bar = bar, foo
|
17
19
|
# Foo = Bar
|
20
|
+
# hash['foo'] = hash['bar']
|
21
|
+
# obj.attr = obj.attr2
|
22
|
+
#
|
23
|
+
# # good (method calls possibly can return different results)
|
24
|
+
# hash[foo] = hash[foo]
|
18
25
|
#
|
19
26
|
class SelfAssignment < Base
|
20
27
|
MSG = 'Self-assignment detected.'
|
@@ -26,6 +33,15 @@ module RuboCop
|
|
26
33
|
gvasgn: :gvar
|
27
34
|
}.freeze
|
28
35
|
|
36
|
+
def on_send(node)
|
37
|
+
if node.method?(:[]=)
|
38
|
+
handle_key_assignment(node) if node.arguments.size == 2
|
39
|
+
elsif node.assignment_method?
|
40
|
+
handle_attribute_assignment(node) if node.arguments.size == 1
|
41
|
+
end
|
42
|
+
end
|
43
|
+
alias on_csend on_send
|
44
|
+
|
29
45
|
def on_lvasgn(node)
|
30
46
|
lhs, rhs = *node
|
31
47
|
return unless rhs
|
@@ -72,6 +88,28 @@ module RuboCop
|
|
72
88
|
rhs.type == ASSIGNMENT_TYPE_TO_RHS_TYPE[lhs.type] &&
|
73
89
|
rhs.children.first == lhs.children.first
|
74
90
|
end
|
91
|
+
|
92
|
+
def handle_key_assignment(node)
|
93
|
+
value_node = node.arguments[1]
|
94
|
+
|
95
|
+
if value_node.send_type? && value_node.method?(:[]) &&
|
96
|
+
node.receiver == value_node.receiver &&
|
97
|
+
!node.first_argument.call_type? &&
|
98
|
+
node.first_argument == value_node.first_argument
|
99
|
+
add_offense(node)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def handle_attribute_assignment(node)
|
104
|
+
first_argument = node.first_argument
|
105
|
+
return unless first_argument.respond_to?(:arguments) && first_argument.arguments.empty?
|
106
|
+
|
107
|
+
if first_argument.call_type? &&
|
108
|
+
node.receiver == first_argument.receiver &&
|
109
|
+
first_argument.method_name.to_s == node.method_name.to_s.delete_suffix('=')
|
110
|
+
add_offense(node)
|
111
|
+
end
|
112
|
+
end
|
75
113
|
end
|
76
114
|
end
|
77
115
|
end
|
@@ -123,6 +123,7 @@ module RuboCop
|
|
123
123
|
|
124
124
|
# Shorthand assignments always use their arguments
|
125
125
|
next false if assignment_node.shorthand_asgn?
|
126
|
+
next false unless assignment_node.parent
|
126
127
|
|
127
128
|
node_within_block_or_conditional =
|
128
129
|
node_within_block_or_conditional?(assignment_node.parent, argument.scope.node)
|
@@ -19,6 +19,7 @@ module RuboCop
|
|
19
19
|
# 'underscored_string'.to_sym
|
20
20
|
# :'underscored_symbol'
|
21
21
|
# 'hyphenated-string'.to_sym
|
22
|
+
# "string_#{interpolation}".to_sym
|
22
23
|
#
|
23
24
|
# # good
|
24
25
|
# :string
|
@@ -26,6 +27,7 @@ module RuboCop
|
|
26
27
|
# :underscored_string
|
27
28
|
# :underscored_symbol
|
28
29
|
# :'hyphenated-string'
|
30
|
+
# :"string_#{interpolation}"
|
29
31
|
#
|
30
32
|
# @example EnforcedStyle: strict (default)
|
31
33
|
#
|
@@ -75,9 +77,12 @@ module RuboCop
|
|
75
77
|
|
76
78
|
def on_send(node)
|
77
79
|
return unless node.receiver
|
78
|
-
return unless node.receiver.str_type? || node.receiver.sym_type?
|
79
80
|
|
80
|
-
|
81
|
+
if node.receiver.str_type? || node.receiver.sym_type?
|
82
|
+
register_offense(node, correction: node.receiver.value.to_sym.inspect)
|
83
|
+
elsif node.receiver.dstr_type?
|
84
|
+
register_offense(node, correction: ":\"#{node.receiver.value.to_sym}\"")
|
85
|
+
end
|
81
86
|
end
|
82
87
|
|
83
88
|
def on_sym(node)
|
@@ -17,9 +17,12 @@ module RuboCop
|
|
17
17
|
private
|
18
18
|
|
19
19
|
def add_offense_from_diagnostic(diagnostic, ruby_version)
|
20
|
-
message =
|
21
|
-
|
22
|
-
|
20
|
+
message = if lsp_mode?
|
21
|
+
diagnostic.message
|
22
|
+
else
|
23
|
+
"#{diagnostic.message}\n(Using Ruby #{ruby_version} parser; " \
|
24
|
+
'configure using `TargetRubyVersion` parameter, under `AllCops`)'
|
25
|
+
end
|
23
26
|
add_offense(diagnostic.location, message: message, severity: diagnostic.level)
|
24
27
|
end
|
25
28
|
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
MSG = 'Avoid leaving a trailing comma in attribute declarations.'
|
35
35
|
|
36
36
|
def on_send(node)
|
37
|
-
return unless node.attribute_accessor? && node.
|
37
|
+
return unless node.attribute_accessor? && node.last_argument.def_type?
|
38
38
|
|
39
39
|
trailing_comma = trailing_comma_range(node)
|
40
40
|
|
@@ -69,8 +69,8 @@ module RuboCop
|
|
69
69
|
# @!method reduce_with_block?(node)
|
70
70
|
def_node_matcher :reduce_with_block?, <<~PATTERN
|
71
71
|
{
|
72
|
-
(block (
|
73
|
-
(numblock (
|
72
|
+
(block (call _recv {:reduce :inject} ...) args ...)
|
73
|
+
(numblock (call _recv {:reduce :inject} ...) ...)
|
74
74
|
}
|
75
75
|
PATTERN
|
76
76
|
|
@@ -256,7 +256,7 @@ module RuboCop
|
|
256
256
|
|
257
257
|
def any_method_definition?(child)
|
258
258
|
cop_config.fetch('MethodCreatingMethods', []).any? do |m|
|
259
|
-
matcher_name = "#{m}_method?"
|
259
|
+
matcher_name = :"#{m}_method?"
|
260
260
|
unless respond_to?(matcher_name)
|
261
261
|
self.class.def_node_matcher matcher_name, <<~PATTERN
|
262
262
|
{def (send nil? :#{m} ...)}
|
@@ -279,7 +279,7 @@ module RuboCop
|
|
279
279
|
|
280
280
|
def any_context_creating_methods?(child)
|
281
281
|
cop_config.fetch('ContextCreatingMethods', []).any? do |m|
|
282
|
-
matcher_name = "#{m}_block?"
|
282
|
+
matcher_name = :"#{m}_block?"
|
283
283
|
unless respond_to?(matcher_name)
|
284
284
|
self.class.def_node_matcher matcher_name, <<~PATTERN
|
285
285
|
({block numblock} (send {nil? const} {:#{m}} ...) ...)
|
@@ -6,6 +6,16 @@ module RuboCop
|
|
6
6
|
# Checks for operators, variables, literals, lambda, proc and nonmutating
|
7
7
|
# methods used in void context.
|
8
8
|
#
|
9
|
+
# `each` blocks are allowed to prevent false positives.
|
10
|
+
# For example, the expression inside the `each` block below.
|
11
|
+
# It's not void, especially when the receiver is an `Enumerator`:
|
12
|
+
#
|
13
|
+
# [source,ruby]
|
14
|
+
# ----
|
15
|
+
# enumerator = [1, 2, 3].filter
|
16
|
+
# enumerator.each { |item| item >= 2 } #=> [2, 3]
|
17
|
+
# ----
|
18
|
+
#
|
9
19
|
# @example CheckForMethodsWithNoSideEffects: false (default)
|
10
20
|
# # bad
|
11
21
|
# def some_method
|
@@ -47,6 +57,7 @@ module RuboCop
|
|
47
57
|
|
48
58
|
OP_MSG = 'Operator `%<op>s` used in void context.'
|
49
59
|
VAR_MSG = 'Variable `%<var>s` used in void context.'
|
60
|
+
CONST_MSG = 'Constant `%<var>s` used in void context.'
|
50
61
|
LIT_MSG = 'Literal `%<lit>s` used in void context.'
|
51
62
|
SELF_MSG = '`self` used in void context.'
|
52
63
|
EXPRESSION_MSG = '`%<expression>s` used in void context.'
|
@@ -72,6 +83,7 @@ module RuboCop
|
|
72
83
|
return unless node.body && !node.body.begin_type?
|
73
84
|
return unless in_void_context?(node.body)
|
74
85
|
|
86
|
+
check_void_op(node.body) { node.method?(:each) }
|
75
87
|
check_expression(node.body)
|
76
88
|
end
|
77
89
|
|
@@ -87,11 +99,13 @@ module RuboCop
|
|
87
99
|
def check_begin(node)
|
88
100
|
expressions = *node
|
89
101
|
expressions.pop unless in_void_context?(node)
|
90
|
-
expressions.each
|
102
|
+
expressions.each do |expr|
|
103
|
+
check_void_op(expr)
|
104
|
+
check_expression(expr)
|
105
|
+
end
|
91
106
|
end
|
92
107
|
|
93
108
|
def check_expression(expr)
|
94
|
-
check_void_op(expr)
|
95
109
|
check_literal(expr)
|
96
110
|
check_var(expr)
|
97
111
|
check_self(expr)
|
@@ -101,8 +115,9 @@ module RuboCop
|
|
101
115
|
check_nonmutating(expr)
|
102
116
|
end
|
103
117
|
|
104
|
-
def check_void_op(node)
|
118
|
+
def check_void_op(node, &block)
|
105
119
|
return unless node.send_type? && OPERATORS.include?(node.method_name)
|
120
|
+
return if block && yield(node)
|
106
121
|
|
107
122
|
add_offense(node.loc.selector,
|
108
123
|
message: format(OP_MSG, op: node.method_name)) do |corrector|
|
@@ -113,20 +128,23 @@ module RuboCop
|
|
113
128
|
def check_var(node)
|
114
129
|
return unless node.variable? || node.const_type?
|
115
130
|
|
116
|
-
if node.const_type?
|
117
|
-
|
118
|
-
|
119
|
-
|
131
|
+
if node.const_type?
|
132
|
+
template = node.special_keyword? ? VAR_MSG : CONST_MSG
|
133
|
+
|
134
|
+
offense_range = node
|
135
|
+
message = format(template, var: node.source)
|
120
136
|
else
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
137
|
+
offense_range = node.loc.name
|
138
|
+
message = format(VAR_MSG, var: node.loc.name.source)
|
139
|
+
end
|
140
|
+
|
141
|
+
add_offense(offense_range, message: message) do |corrector|
|
142
|
+
autocorrect_void_expression(corrector, node)
|
125
143
|
end
|
126
144
|
end
|
127
145
|
|
128
146
|
def check_literal(node)
|
129
|
-
return if !node
|
147
|
+
return if !entirely_literal?(node) || node.xstr_type? || node.range_type?
|
130
148
|
|
131
149
|
add_offense(node, message: format(LIT_MSG, lit: node.source)) do |corrector|
|
132
150
|
autocorrect_void_expression(corrector, node)
|
@@ -199,6 +217,19 @@ module RuboCop
|
|
199
217
|
end
|
200
218
|
corrector.replace(send_node.loc.selector, suggestion)
|
201
219
|
end
|
220
|
+
|
221
|
+
def entirely_literal?(node)
|
222
|
+
case node.type
|
223
|
+
when :array
|
224
|
+
node.each_value.all? { |value| entirely_literal?(value) }
|
225
|
+
when :hash
|
226
|
+
return false unless node.each_key.all? { |key| entirely_literal?(key) }
|
227
|
+
|
228
|
+
node.each_value.all? { |value| entirely_literal?(value) }
|
229
|
+
else
|
230
|
+
node.literal?
|
231
|
+
end
|
232
|
+
end
|
202
233
|
end
|
203
234
|
end
|
204
235
|
end
|
@@ -10,9 +10,9 @@ module RuboCop
|
|
10
10
|
#
|
11
11
|
# Interpreting ABC size:
|
12
12
|
#
|
13
|
-
# *
|
14
|
-
# * 18..30 unsatisfactory
|
15
|
-
# *
|
13
|
+
# * ``<= 17`` satisfactory
|
14
|
+
# * `18..30` unsatisfactory
|
15
|
+
# * `>` 30 dangerous
|
16
16
|
#
|
17
17
|
# You can have repeated "attributes" calls count as a single "branch".
|
18
18
|
# For this purpose, attributes are any method with no argument; no attempt
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
12
12
|
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
13
13
|
# will be counted as one line regardless of its actual size.
|
14
14
|
#
|
15
|
+
# NOTE: This cop does not apply for `Struct` definitions.
|
15
16
|
#
|
16
17
|
# NOTE: The `ExcludedMethods` configuration is deprecated and only kept
|
17
18
|
# for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns`
|
@@ -40,7 +41,6 @@ module RuboCop
|
|
40
41
|
# )
|
41
42
|
# end # 6 points
|
42
43
|
#
|
43
|
-
# NOTE: This cop does not apply for `Struct` definitions.
|
44
44
|
class BlockLength < Base
|
45
45
|
include CodeLength
|
46
46
|
include AllowedMethods
|
@@ -11,6 +11,8 @@ module RuboCop
|
|
11
11
|
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
12
12
|
# will be counted as one line regardless of its actual size.
|
13
13
|
#
|
14
|
+
# NOTE: This cop also applies for `Struct` definitions.
|
15
|
+
#
|
14
16
|
# @example CountAsOne: ['array', 'heredoc', 'method_call']
|
15
17
|
#
|
16
18
|
# class Foo
|
@@ -34,15 +36,18 @@ module RuboCop
|
|
34
36
|
# )
|
35
37
|
# end # 6 points
|
36
38
|
#
|
37
|
-
#
|
38
|
-
# NOTE: This cop also applies for `Struct` definitions.
|
39
39
|
class ClassLength < Base
|
40
40
|
include CodeLength
|
41
41
|
|
42
42
|
def on_class(node)
|
43
43
|
check_code_length(node)
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
|
+
def on_sclass(node)
|
47
|
+
return if node.each_ancestor(:class).any?
|
48
|
+
|
49
|
+
on_class(node)
|
50
|
+
end
|
46
51
|
|
47
52
|
def on_casgn(node)
|
48
53
|
parent = node.parent
|