rubocop 1.57.0 → 1.58.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/config/default.yml +37 -2
- data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
- data/lib/rubocop/config_obsoletion.rb +11 -8
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
- 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 +7 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +6 -6
- 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/multiline_method_call_indentation.rb +6 -2
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +4 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/debugger.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_methods.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/literal_assignment_in_condition.rb +64 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +52 -5
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +37 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +43 -12
- data/lib/rubocop/cop/metrics/class_length.rb +6 -1
- 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/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 +2 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- 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 +68 -6
- 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/combinable_loops.rb +2 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +58 -10
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +9 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
- data/lib/rubocop/cop/style/map_to_hash.rb +9 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
- 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/redundant_argument.rb +2 -2
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +34 -9
- data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +4 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +2 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +28 -12
- data/lib/rubocop/cop/style/redundant_return.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
- data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
- 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 +2 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
- data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/formatter/html_formatter.rb +5 -4
- data/lib/rubocop/result_cache.rb +0 -1
- data/lib/rubocop/runner.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +3 -0
- metadata +13 -23
|
@@ -17,10 +17,16 @@ module RuboCop
|
|
|
17
17
|
# @example
|
|
18
18
|
# # bad
|
|
19
19
|
# hash.keys.each { |k| p k }
|
|
20
|
-
# hash.
|
|
20
|
+
# hash.each { |k, unused_value| p k }
|
|
21
21
|
#
|
|
22
22
|
# # good
|
|
23
23
|
# hash.each_key { |k| p k }
|
|
24
|
+
#
|
|
25
|
+
# # bad
|
|
26
|
+
# hash.values.each { |v| p v }
|
|
27
|
+
# hash.each { |unused_key, v| p v }
|
|
28
|
+
#
|
|
29
|
+
# # good
|
|
24
30
|
# hash.each_value { |v| p v }
|
|
25
31
|
#
|
|
26
32
|
# @example AllowedReceivers: ['execute']
|
|
@@ -33,22 +39,44 @@ module RuboCop
|
|
|
33
39
|
extend AutoCorrector
|
|
34
40
|
|
|
35
41
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
|
42
|
+
UNUSED_BLOCK_ARG_MSG = "#{MSG.chop} and remove the unused `%<unused_code>s` block argument."
|
|
36
43
|
|
|
37
44
|
# @!method kv_each(node)
|
|
38
45
|
def_node_matcher :kv_each, <<~PATTERN
|
|
39
|
-
({block numblock} $(
|
|
46
|
+
({block numblock} $(call (call _ ${:keys :values}) :each) ...)
|
|
47
|
+
PATTERN
|
|
48
|
+
|
|
49
|
+
# @!method each_arguments(node)
|
|
50
|
+
def_node_matcher :each_arguments, <<~PATTERN
|
|
51
|
+
(block (call _ :each)(args $_key $_value) ...)
|
|
40
52
|
PATTERN
|
|
41
53
|
|
|
42
54
|
# @!method kv_each_with_block_pass(node)
|
|
43
55
|
def_node_matcher :kv_each_with_block_pass, <<~PATTERN
|
|
44
|
-
(
|
|
56
|
+
(call $(call _ ${:keys :values}) :each (block_pass (sym _)))
|
|
45
57
|
PATTERN
|
|
46
58
|
|
|
59
|
+
# rubocop:disable Metrics/AbcSize
|
|
47
60
|
def on_block(node)
|
|
48
61
|
kv_each(node) do |target, method|
|
|
49
|
-
register_kv_offense(target, method)
|
|
62
|
+
register_kv_offense(target, method) and return
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
return unless (key, value = each_arguments(node))
|
|
66
|
+
|
|
67
|
+
if unused_block_arg_exist?(node, value.source)
|
|
68
|
+
message = message('each_key', node.method_name, value.source)
|
|
69
|
+
unused_range = key.source_range.end.join(value.source_range.end)
|
|
70
|
+
|
|
71
|
+
register_each_args_offense(node, message, 'each_key', unused_range)
|
|
72
|
+
elsif unused_block_arg_exist?(node, key.source)
|
|
73
|
+
message = message('each_value', node.method_name, key.source)
|
|
74
|
+
unused_range = key.source_range.begin.join(value.source_range.begin)
|
|
75
|
+
|
|
76
|
+
register_each_args_offense(node, message, 'each_value', unused_range)
|
|
50
77
|
end
|
|
51
78
|
end
|
|
79
|
+
# rubocop:enable Metrics/AbcSize
|
|
52
80
|
|
|
53
81
|
alias on_numblock on_block
|
|
54
82
|
|
|
@@ -64,23 +92,43 @@ module RuboCop
|
|
|
64
92
|
return unless (parent_receiver = target.receiver.receiver)
|
|
65
93
|
return if allowed_receiver?(parent_receiver)
|
|
66
94
|
|
|
67
|
-
|
|
95
|
+
current = target.receiver.loc.selector.join(target.source_range.end).source
|
|
96
|
+
|
|
97
|
+
add_offense(kv_range(target), message: format_message(method, current)) do |corrector|
|
|
68
98
|
correct_key_value_each(target, corrector)
|
|
69
99
|
end
|
|
70
100
|
end
|
|
71
101
|
|
|
102
|
+
def unused_block_arg_exist?(node, block_arg_source)
|
|
103
|
+
node.body.each_descendant(:lvar).map(&:source).none?(block_arg_source)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def message(prefer, method_name, unused_code)
|
|
107
|
+
format(
|
|
108
|
+
UNUSED_BLOCK_ARG_MSG, prefer: prefer, current: method_name, unused_code: unused_code
|
|
109
|
+
)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def register_each_args_offense(node, message, prefer, unused_range)
|
|
113
|
+
add_offense(node, message: message) do |corrector|
|
|
114
|
+
corrector.replace(node.send_node.loc.selector, prefer)
|
|
115
|
+
corrector.remove(unused_range)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
72
119
|
def register_kv_with_block_pass_offense(node, target, method)
|
|
73
120
|
return unless (parent_receiver = node.parent.receiver.receiver)
|
|
74
121
|
return if allowed_receiver?(parent_receiver)
|
|
75
122
|
|
|
76
|
-
range = target.loc.selector.
|
|
77
|
-
|
|
123
|
+
range = target.loc.selector.join(node.parent.loc.selector.end)
|
|
124
|
+
|
|
125
|
+
add_offense(range, message: format_message(method, range.source)) do |corrector|
|
|
78
126
|
corrector.replace(range, "each_#{method[0..-2]}")
|
|
79
127
|
end
|
|
80
128
|
end
|
|
81
129
|
|
|
82
|
-
def format_message(method_name)
|
|
83
|
-
format(MSG, prefer: "each_#{method_name[0..-2]}", current:
|
|
130
|
+
def format_message(method_name, current)
|
|
131
|
+
format(MSG, prefer: "each_#{method_name[0..-2]}", current: current)
|
|
84
132
|
end
|
|
85
133
|
|
|
86
134
|
def check_argument(variable)
|
|
@@ -103,7 +151,7 @@ module RuboCop
|
|
|
103
151
|
name = "each_#{node.receiver.method_name.to_s.chop}"
|
|
104
152
|
return correct_implicit(node, corrector, name) unless receiver
|
|
105
153
|
|
|
106
|
-
new_source = receiver.source + "
|
|
154
|
+
new_source = receiver.source + "#{node.loc.dot.source}#{name}"
|
|
107
155
|
corrector.replace(node, new_source)
|
|
108
156
|
end
|
|
109
157
|
|
|
@@ -153,7 +153,15 @@ module RuboCop
|
|
|
153
153
|
return unless duplicated_expressions?(node, heads)
|
|
154
154
|
|
|
155
155
|
condition_variable = assignable_condition_value(node)
|
|
156
|
-
|
|
156
|
+
|
|
157
|
+
head = heads.first
|
|
158
|
+
if head.assignment?
|
|
159
|
+
# The `send` node is used instead of the `indexasgn` node, so `name` cannot be used.
|
|
160
|
+
# https://github.com/rubocop/rubocop-ast/blob/v1.29.0/lib/rubocop/ast/node/indexasgn_node.rb
|
|
161
|
+
assigned_value = head.send_type? ? head.receiver.source : head.name.to_s
|
|
162
|
+
|
|
163
|
+
return if condition_variable == assigned_value
|
|
164
|
+
end
|
|
157
165
|
|
|
158
166
|
check_expressions(node, heads, :before_condition)
|
|
159
167
|
end
|
|
@@ -60,17 +60,17 @@ module RuboCop
|
|
|
60
60
|
# @!method inverse_candidate?(node)
|
|
61
61
|
def_node_matcher :inverse_candidate?, <<~PATTERN
|
|
62
62
|
{
|
|
63
|
-
(send $(
|
|
64
|
-
(send ({block numblock} $(
|
|
65
|
-
(send (begin $(
|
|
63
|
+
(send $(call $(...) $_ $...) :!)
|
|
64
|
+
(send ({block numblock} $(call $(...) $_) $...) :!)
|
|
65
|
+
(send (begin $(call $(...) $_ $...)) :!)
|
|
66
66
|
}
|
|
67
67
|
PATTERN
|
|
68
68
|
|
|
69
69
|
# @!method inverse_block?(node)
|
|
70
70
|
def_node_matcher :inverse_block?, <<~PATTERN
|
|
71
|
-
({block numblock} $(
|
|
71
|
+
({block numblock} $(call (...) $_) ... { $(call ... :!)
|
|
72
72
|
$(send (...) {:!= :!~} ...)
|
|
73
|
-
(begin ... $(
|
|
73
|
+
(begin ... $(call ... :!))
|
|
74
74
|
(begin ... $(send (...) {:!= :!~} ...))
|
|
75
75
|
})
|
|
76
76
|
PATTERN
|
|
@@ -87,6 +87,7 @@ module RuboCop
|
|
|
87
87
|
end
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
|
+
alias on_csend on_send
|
|
90
91
|
|
|
91
92
|
def on_block(node)
|
|
92
93
|
inverse_block?(node) do |_method_call, method, block|
|
|
@@ -34,21 +34,25 @@ module RuboCop
|
|
|
34
34
|
|
|
35
35
|
minimum_target_ruby_version 2.6
|
|
36
36
|
|
|
37
|
-
MSG = 'Pass a block to `to_h` instead of calling `%<method>s
|
|
37
|
+
MSG = 'Pass a block to `to_h` instead of calling `%<method>s%<dot>sto_h`.'
|
|
38
38
|
RESTRICT_ON_SEND = %i[to_h].freeze
|
|
39
39
|
|
|
40
40
|
# @!method map_to_h?(node)
|
|
41
41
|
def_node_matcher :map_to_h?, <<~PATTERN
|
|
42
42
|
{
|
|
43
|
-
$(
|
|
44
|
-
$(
|
|
43
|
+
$(call ({block numblock} $(call _ {:map :collect}) ...) :to_h)
|
|
44
|
+
$(call $(call _ {:map :collect} (block_pass sym)) :to_h)
|
|
45
45
|
}
|
|
46
46
|
PATTERN
|
|
47
47
|
|
|
48
|
+
def self.autocorrect_incompatible_with
|
|
49
|
+
[Layout::SingleLineBlockChain]
|
|
50
|
+
end
|
|
51
|
+
|
|
48
52
|
def on_send(node)
|
|
49
53
|
return unless (to_h_node, map_node = map_to_h?(node))
|
|
50
54
|
|
|
51
|
-
message = format(MSG, method: map_node.loc.selector.source)
|
|
55
|
+
message = format(MSG, method: map_node.loc.selector.source, dot: map_node.loc.dot.source)
|
|
52
56
|
add_offense(map_node.loc.selector, message: message) do |corrector|
|
|
53
57
|
# If the `to_h` call already has a block, do not autocorrect.
|
|
54
58
|
next if to_h_node.block_node
|
|
@@ -56,6 +60,7 @@ module RuboCop
|
|
|
56
60
|
autocorrect(corrector, to_h_node, map_node)
|
|
57
61
|
end
|
|
58
62
|
end
|
|
63
|
+
alias on_csend on_send
|
|
59
64
|
|
|
60
65
|
private
|
|
61
66
|
|
|
@@ -170,7 +170,7 @@ module RuboCop
|
|
|
170
170
|
return true if node.arguments.any? do |arg|
|
|
171
171
|
arg.forward_arg_type? || arg.restarg_type? || arg.kwrestarg_type?
|
|
172
172
|
end
|
|
173
|
-
return false unless (last_argument = node.
|
|
173
|
+
return false unless (last_argument = node.last_argument)
|
|
174
174
|
|
|
175
175
|
last_argument.blockarg_type? && last_argument.name.nil?
|
|
176
176
|
end
|
|
@@ -67,7 +67,7 @@ module RuboCop
|
|
|
67
67
|
return unless redundant_argument?(node)
|
|
68
68
|
|
|
69
69
|
offense_range = argument_range(node)
|
|
70
|
-
message = format(MSG, arg: node.
|
|
70
|
+
message = format(MSG, arg: node.first_argument.source)
|
|
71
71
|
|
|
72
72
|
add_offense(offense_range, message: message) do |corrector|
|
|
73
73
|
corrector.remove(offense_range)
|
|
@@ -80,7 +80,7 @@ module RuboCop
|
|
|
80
80
|
redundant_argument = redundant_arg_for_method(node.method_name.to_s)
|
|
81
81
|
return false if redundant_argument.nil?
|
|
82
82
|
|
|
83
|
-
node.
|
|
83
|
+
node.first_argument == redundant_argument
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def redundant_arg_for_method(method_name)
|
|
@@ -25,21 +25,33 @@ module RuboCop
|
|
|
25
25
|
MSG = 'Remove the redundant double splat and braces, use keyword arguments directly.'
|
|
26
26
|
MERGE_METHODS = %i[merge merge!].freeze
|
|
27
27
|
|
|
28
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
28
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
29
29
|
def on_hash(node)
|
|
30
|
-
return if
|
|
30
|
+
return if node.pairs.empty? || node.pairs.any?(&:hash_rocket?)
|
|
31
31
|
return unless (parent = node.parent)
|
|
32
|
+
return unless parent.call_type? || parent.kwsplat_type?
|
|
33
|
+
return unless mergeable?(parent)
|
|
32
34
|
return unless (kwsplat = node.each_ancestor(:kwsplat).first)
|
|
33
|
-
return if
|
|
35
|
+
return if !node.braces? || allowed_double_splat_receiver?(kwsplat)
|
|
34
36
|
|
|
35
37
|
add_offense(kwsplat) do |corrector|
|
|
36
38
|
autocorrect(corrector, node, kwsplat)
|
|
37
39
|
end
|
|
38
40
|
end
|
|
39
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
41
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
40
42
|
|
|
41
43
|
private
|
|
42
44
|
|
|
45
|
+
def allowed_double_splat_receiver?(kwsplat)
|
|
46
|
+
first_child = kwsplat.children.first
|
|
47
|
+
return true if first_child.block_type? || first_child.numblock_type?
|
|
48
|
+
return false unless first_child.call_type?
|
|
49
|
+
|
|
50
|
+
root_receiver = root_receiver(first_child)
|
|
51
|
+
|
|
52
|
+
!root_receiver&.hash_type?
|
|
53
|
+
end
|
|
54
|
+
|
|
43
55
|
def autocorrect(corrector, node, kwsplat)
|
|
44
56
|
corrector.remove(kwsplat.loc.operator)
|
|
45
57
|
corrector.remove(opening_brace(node))
|
|
@@ -51,9 +63,18 @@ module RuboCop
|
|
|
51
63
|
autocorrect_merge_methods(corrector, merge_methods, kwsplat)
|
|
52
64
|
end
|
|
53
65
|
|
|
66
|
+
def root_receiver(node)
|
|
67
|
+
receiver = node.receiver
|
|
68
|
+
if receiver&.receiver
|
|
69
|
+
root_receiver(receiver)
|
|
70
|
+
else
|
|
71
|
+
receiver
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
54
75
|
def select_merge_method_nodes(kwsplat)
|
|
55
76
|
extract_send_methods(kwsplat).select do |node|
|
|
56
|
-
|
|
77
|
+
mergeable?(node)
|
|
57
78
|
end
|
|
58
79
|
end
|
|
59
80
|
|
|
@@ -84,11 +105,11 @@ module RuboCop
|
|
|
84
105
|
end
|
|
85
106
|
|
|
86
107
|
def extract_send_methods(kwsplat)
|
|
87
|
-
|
|
108
|
+
kwsplat.each_descendant(:send, :csend)
|
|
88
109
|
end
|
|
89
110
|
|
|
90
111
|
def convert_to_new_arguments(node)
|
|
91
|
-
return unless
|
|
112
|
+
return unless mergeable?(node)
|
|
92
113
|
|
|
93
114
|
node.arguments.map do |arg|
|
|
94
115
|
if arg.hash_type?
|
|
@@ -99,8 +120,12 @@ module RuboCop
|
|
|
99
120
|
end
|
|
100
121
|
end
|
|
101
122
|
|
|
102
|
-
def
|
|
103
|
-
|
|
123
|
+
def mergeable?(node)
|
|
124
|
+
return true unless node.call_type?
|
|
125
|
+
return false unless MERGE_METHODS.include?(node.method_name)
|
|
126
|
+
return true unless (parent = node.parent)
|
|
127
|
+
|
|
128
|
+
mergeable?(parent)
|
|
104
129
|
end
|
|
105
130
|
end
|
|
106
131
|
end
|
|
@@ -5,17 +5,21 @@ module RuboCop
|
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for RuntimeError as the argument of raise/fail.
|
|
7
7
|
#
|
|
8
|
-
# It checks for code like this:
|
|
9
|
-
#
|
|
10
8
|
# @example
|
|
11
|
-
# #
|
|
9
|
+
# # bad
|
|
12
10
|
# raise RuntimeError, 'message'
|
|
13
|
-
#
|
|
14
|
-
# # Bad
|
|
15
11
|
# raise RuntimeError.new('message')
|
|
16
12
|
#
|
|
17
|
-
# #
|
|
13
|
+
# # good
|
|
18
14
|
# raise 'message'
|
|
15
|
+
#
|
|
16
|
+
# # bad - message is not a string
|
|
17
|
+
# raise RuntimeError, Object.new
|
|
18
|
+
# raise RuntimeError.new(Object.new)
|
|
19
|
+
#
|
|
20
|
+
# # good
|
|
21
|
+
# raise Object.new.to_s
|
|
22
|
+
#
|
|
19
23
|
class RedundantException < Base
|
|
20
24
|
extend AutoCorrector
|
|
21
25
|
|
|
@@ -30,26 +34,42 @@ module RuboCop
|
|
|
30
34
|
fix_exploded(node) || fix_compact(node)
|
|
31
35
|
end
|
|
32
36
|
|
|
37
|
+
private
|
|
38
|
+
|
|
33
39
|
def fix_exploded(node)
|
|
34
40
|
exploded?(node) do |command, message|
|
|
35
41
|
add_offense(node, message: MSG_1) do |corrector|
|
|
36
|
-
|
|
37
|
-
corrector.replace(node, "#{command}(#{message.source})")
|
|
38
|
-
else
|
|
39
|
-
corrector.replace(node, "#{command} #{message.source}")
|
|
40
|
-
end
|
|
42
|
+
corrector.replace(node, replaced_exploded(node, command, message))
|
|
41
43
|
end
|
|
42
44
|
end
|
|
43
45
|
end
|
|
44
46
|
|
|
47
|
+
def replaced_exploded(node, command, message)
|
|
48
|
+
arg = string_message?(message) ? message.source : "#{message.source}.to_s"
|
|
49
|
+
arg = node.parenthesized? ? "(#{arg})" : " #{arg}"
|
|
50
|
+
"#{command}#{arg}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def string_message?(message)
|
|
54
|
+
message.str_type? || message.dstr_type? || message.xstr_type?
|
|
55
|
+
end
|
|
56
|
+
|
|
45
57
|
def fix_compact(node)
|
|
46
58
|
compact?(node) do |new_call, message|
|
|
47
59
|
add_offense(node, message: MSG_2) do |corrector|
|
|
48
|
-
corrector.replace(new_call, message
|
|
60
|
+
corrector.replace(new_call, replaced_compact(message))
|
|
49
61
|
end
|
|
50
62
|
end
|
|
51
63
|
end
|
|
52
64
|
|
|
65
|
+
def replaced_compact(message)
|
|
66
|
+
if string_message?(message)
|
|
67
|
+
message.source
|
|
68
|
+
else
|
|
69
|
+
"#{message.source}.to_s"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
53
73
|
# @!method exploded?(node)
|
|
54
74
|
def_node_matcher :exploded?, <<~PATTERN
|
|
55
75
|
(send nil? ${:raise :fail} (const {nil? cbase} :RuntimeError) $_)
|
|
@@ -60,10 +60,10 @@ module RuboCop
|
|
|
60
60
|
|
|
61
61
|
# @!method select_predicate?(node)
|
|
62
62
|
def_node_matcher :select_predicate?, <<~PATTERN
|
|
63
|
-
(
|
|
63
|
+
(call
|
|
64
64
|
{
|
|
65
|
-
(block $(
|
|
66
|
-
$(
|
|
65
|
+
(block $(call _ {:select :filter :find_all}) ...)
|
|
66
|
+
$(call _ {:select :filter :find_all} block_pass_type?)
|
|
67
67
|
}
|
|
68
68
|
${:#{RESTRICT_ON_SEND.join(' :')}})
|
|
69
69
|
PATTERN
|
|
@@ -87,6 +87,7 @@ module RuboCop
|
|
|
87
87
|
register_offense(select_node, node)
|
|
88
88
|
end
|
|
89
89
|
end
|
|
90
|
+
alias on_csend on_send
|
|
90
91
|
|
|
91
92
|
private
|
|
92
93
|
|
|
@@ -107,6 +107,8 @@ module RuboCop
|
|
|
107
107
|
|
|
108
108
|
def inside_string_literal_or_method_with_argument?(range)
|
|
109
109
|
processed_source.tokens.each_cons(2).any? do |token, next_token|
|
|
110
|
+
next if token.line == next_token.line
|
|
111
|
+
|
|
110
112
|
inside_string_literal?(range, token) || method_with_argument?(token, next_token)
|
|
111
113
|
end
|
|
112
114
|
end
|
|
@@ -17,6 +17,8 @@ module RuboCop
|
|
|
17
17
|
include Parentheses
|
|
18
18
|
extend AutoCorrector
|
|
19
19
|
|
|
20
|
+
ALLOWED_NODE_TYPES = %i[and or send splat kwsplat].freeze
|
|
21
|
+
|
|
20
22
|
# @!method square_brackets?(node)
|
|
21
23
|
def_node_matcher :square_brackets?, '(send {(send _recv _msg) str array hash} :[] ...)'
|
|
22
24
|
|
|
@@ -111,17 +113,19 @@ module RuboCop
|
|
|
111
113
|
|
|
112
114
|
def first_arg_begins_with_hash_literal?(node)
|
|
113
115
|
# Don't flag `method ({key: value})` or `method ({key: value}.method)`
|
|
114
|
-
method_chain_begins_with_hash_literal
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
hash_literal = method_chain_begins_with_hash_literal(node.children.first)
|
|
117
|
+
if (root_method = node.each_ancestor(:send).to_a.last)
|
|
118
|
+
parenthesized = root_method.parenthesized_call?
|
|
119
|
+
end
|
|
120
|
+
hash_literal && first_argument?(node) && !parentheses?(hash_literal) && !parenthesized
|
|
117
121
|
end
|
|
118
122
|
|
|
119
|
-
def method_chain_begins_with_hash_literal
|
|
120
|
-
return
|
|
121
|
-
return
|
|
122
|
-
return
|
|
123
|
+
def method_chain_begins_with_hash_literal(node)
|
|
124
|
+
return if node.nil?
|
|
125
|
+
return node if node.hash_type?
|
|
126
|
+
return unless node.send_type?
|
|
123
127
|
|
|
124
|
-
method_chain_begins_with_hash_literal
|
|
128
|
+
method_chain_begins_with_hash_literal(node.children.first)
|
|
125
129
|
end
|
|
126
130
|
|
|
127
131
|
def check(begin_node)
|
|
@@ -134,23 +138,29 @@ module RuboCop
|
|
|
134
138
|
check_send(begin_node, node) if node.call_type?
|
|
135
139
|
end
|
|
136
140
|
|
|
137
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
141
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
138
142
|
def find_offense_message(begin_node, node)
|
|
139
143
|
return 'a keyword' if keyword_with_redundant_parentheses?(node)
|
|
140
144
|
return 'a literal' if disallowed_literal?(begin_node, node)
|
|
141
145
|
return 'a variable' if node.variable?
|
|
142
146
|
return 'a constant' if node.const_type?
|
|
147
|
+
return 'an expression' if node.lambda_or_proc?
|
|
143
148
|
return 'an interpolated expression' if interpolation?(begin_node)
|
|
144
149
|
|
|
145
|
-
return if begin_node.chained?
|
|
150
|
+
return if begin_node.chained?
|
|
146
151
|
|
|
147
152
|
if node.and_type? || node.or_type?
|
|
153
|
+
return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
|
|
154
|
+
return if begin_node.parent&.if_type? && begin_node.parent&.ternary?
|
|
155
|
+
|
|
148
156
|
'a logical expression'
|
|
149
157
|
elsif node.respond_to?(:comparison_method?) && node.comparison_method?
|
|
158
|
+
return unless begin_node.parent.nil?
|
|
159
|
+
|
|
150
160
|
'a comparison expression'
|
|
151
161
|
end
|
|
152
162
|
end
|
|
153
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
163
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
154
164
|
|
|
155
165
|
# @!method interpolation?(node)
|
|
156
166
|
def_node_matcher :interpolation?, '[^begin ^^dstr]'
|
|
@@ -231,7 +241,13 @@ module RuboCop
|
|
|
231
241
|
end
|
|
232
242
|
|
|
233
243
|
def first_argument?(node)
|
|
234
|
-
first_send_argument?(node) ||
|
|
244
|
+
if first_send_argument?(node) ||
|
|
245
|
+
first_super_argument?(node) ||
|
|
246
|
+
first_yield_argument?(node)
|
|
247
|
+
return true
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
node.each_ancestor.any? { |ancestor| first_argument?(ancestor) }
|
|
235
251
|
end
|
|
236
252
|
|
|
237
253
|
# @!method first_send_argument?(node)
|
|
@@ -58,7 +58,7 @@ module RuboCop
|
|
|
58
58
|
|
|
59
59
|
MSG = 'Redundant `return` detected.'
|
|
60
60
|
MULTI_RETURN_MSG = 'To return multiple values, use an array.'
|
|
61
|
-
RESTRICT_ON_SEND = %i[define_method define_singleton_method].freeze
|
|
61
|
+
RESTRICT_ON_SEND = %i[define_method define_singleton_method lambda].freeze
|
|
62
62
|
|
|
63
63
|
def on_send(node)
|
|
64
64
|
return unless (parent = node.parent) && parent.block_type?
|
|
@@ -133,7 +133,7 @@ module RuboCop
|
|
|
133
133
|
end
|
|
134
134
|
|
|
135
135
|
def percent_array_literal?(node)
|
|
136
|
-
|
|
136
|
+
percent_w_literal?(node) || percent_w_upper_literal?(node)
|
|
137
137
|
end
|
|
138
138
|
|
|
139
139
|
def heredoc_with_disabled_interpolation?(node)
|
|
@@ -146,7 +146,7 @@ module RuboCop
|
|
|
146
146
|
return node.child_nodes.first if node.match_with_lvasgn_type?
|
|
147
147
|
|
|
148
148
|
if node.receiver.lvar_type? &&
|
|
149
|
-
(block.numblock_type? || node.receiver.source == block.
|
|
149
|
+
(block.numblock_type? || node.receiver.source == block.first_argument.source)
|
|
150
150
|
node.first_argument
|
|
151
151
|
elsif node.first_argument.lvar_type?
|
|
152
152
|
node.receiver
|
|
@@ -80,6 +80,7 @@ module RuboCop
|
|
|
80
80
|
processed_source.tokens.group_by(&:line)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
|
+
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
83
84
|
def semicolon_position(tokens)
|
|
84
85
|
if tokens.last.semicolon?
|
|
85
86
|
-1
|
|
@@ -90,10 +91,13 @@ module RuboCop
|
|
|
90
91
|
elsif exist_semicolon_after_left_curly_brace?(tokens) ||
|
|
91
92
|
exist_semicolon_after_left_string_interpolation_brace?(tokens)
|
|
92
93
|
2
|
|
94
|
+
elsif exist_semicolon_after_left_lambda_curly_brace?(tokens)
|
|
95
|
+
3
|
|
93
96
|
elsif exist_semicolon_before_right_string_interpolation_brace?(tokens)
|
|
94
97
|
-4
|
|
95
98
|
end
|
|
96
99
|
end
|
|
100
|
+
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
97
101
|
|
|
98
102
|
def exist_semicolon_before_right_curly_brace?(tokens)
|
|
99
103
|
tokens[-2]&.right_curly_brace? && tokens[-3]&.semicolon?
|
|
@@ -103,6 +107,10 @@ module RuboCop
|
|
|
103
107
|
tokens[1]&.left_curly_brace? && tokens[2]&.semicolon?
|
|
104
108
|
end
|
|
105
109
|
|
|
110
|
+
def exist_semicolon_after_left_lambda_curly_brace?(tokens)
|
|
111
|
+
tokens[2]&.type == :tLAMBEG && tokens[3]&.semicolon?
|
|
112
|
+
end
|
|
113
|
+
|
|
106
114
|
def exist_semicolon_before_right_string_interpolation_brace?(tokens)
|
|
107
115
|
tokens[-3]&.type == :tSTRING_DEND && tokens[-4]&.semicolon?
|
|
108
116
|
end
|
|
@@ -33,6 +33,7 @@ module RuboCop
|
|
|
33
33
|
|
|
34
34
|
MSG = 'Use `%<receiver>s[%<argument>s]` instead of `%<original>s`.'
|
|
35
35
|
RESTRICT_ON_SEND = %i[dig].freeze
|
|
36
|
+
IGNORED_ARGUMENT_TYPES = %i[block_pass forwarded_restarg forwarded_args hash].freeze
|
|
36
37
|
|
|
37
38
|
# @!method single_argument_dig?(node)
|
|
38
39
|
def_node_matcher :single_argument_dig?, <<~PATTERN
|
|
@@ -44,7 +45,7 @@ module RuboCop
|
|
|
44
45
|
|
|
45
46
|
expression = single_argument_dig?(node)
|
|
46
47
|
return unless expression
|
|
47
|
-
return if expression.
|
|
48
|
+
return if IGNORED_ARGUMENT_TYPES.include?(expression.type)
|
|
48
49
|
|
|
49
50
|
receiver = node.receiver.source
|
|
50
51
|
argument = expression.source
|
|
@@ -30,6 +30,7 @@ module RuboCop
|
|
|
30
30
|
|
|
31
31
|
MSG = 'Prefer multiline `do`...`end` block.'
|
|
32
32
|
|
|
33
|
+
# rubocop:disable Metrics/AbcSize
|
|
33
34
|
def on_block(node)
|
|
34
35
|
return if !node.single_line? || node.braces?
|
|
35
36
|
|
|
@@ -42,10 +43,11 @@ module RuboCop
|
|
|
42
43
|
corrector.remove(node.loc.end)
|
|
43
44
|
corrector.insert_after(node_body.loc.heredoc_end, "\nend")
|
|
44
45
|
else
|
|
45
|
-
corrector.
|
|
46
|
+
corrector.insert_before(node.loc.end, "\n")
|
|
46
47
|
end
|
|
47
48
|
end
|
|
48
49
|
end
|
|
50
|
+
# rubocop:enable Metrics/AbcSize
|
|
49
51
|
alias on_numblock on_block
|
|
50
52
|
|
|
51
53
|
private
|