rubocop 1.32.0 → 1.35.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/config/default.yml +73 -16
- data/config/obsoletion.yml +23 -1
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cli/command/{auto_genenerate_config.rb → auto_generate_config.rb} +2 -2
- data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
- data/lib/rubocop/cli/command/suggest_extensions.rb +53 -15
- data/lib/rubocop/config.rb +1 -1
- data/lib/rubocop/config_finder.rb +68 -0
- data/lib/rubocop/config_loader.rb +12 -40
- data/lib/rubocop/config_loader_resolver.rb +1 -5
- data/lib/rubocop/config_obsoletion/changed_parameter.rb +5 -0
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +4 -0
- data/lib/rubocop/config_obsoletion.rb +7 -2
- data/lib/rubocop/cop/cop.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +58 -0
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/generator/require_file_injector.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +62 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/block_end_newline.rb +35 -5
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +2 -0
- data/lib/rubocop/cop/layout/end_of_line.rb +4 -4
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -0
- data/lib/rubocop/cop/layout/line_length.rb +4 -1
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +2 -0
- data/lib/rubocop/cop/legacy/corrections_proxy.rb +1 -1
- data/lib/rubocop/cop/legacy/corrector.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +21 -8
- data/lib/rubocop/cop/lint/debugger.rb +26 -16
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +65 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +9 -9
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +4 -0
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +25 -6
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +6 -6
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +12 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +24 -8
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +9 -3
- data/lib/rubocop/cop/lint/redundant_with_index.rb +13 -10
- data/lib/rubocop/cop/lint/redundant_with_object.rb +12 -11
- data/lib/rubocop/cop/lint/shadowed_exception.rb +15 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +10 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +7 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +6 -4
- data/lib/rubocop/cop/lint/void.rb +2 -0
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
- data/lib/rubocop/cop/metrics/block_length.rb +6 -7
- data/lib/rubocop/cop/metrics/method_length.rb +8 -8
- data/lib/rubocop/cop/mixin/allowed_methods.rb +15 -1
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +5 -1
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +2 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +76 -1
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +8 -13
- data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/range_help.rb +4 -5
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +2 -2
- data/lib/rubocop/cop/naming/predicate_name.rb +24 -3
- data/lib/rubocop/cop/style/arguments_forwarding.rb +2 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +26 -7
- data/lib/rubocop/cop/style/class_and_module_children.rb +4 -4
- data/lib/rubocop/cop/style/class_equality_comparison.rb +32 -7
- data/lib/rubocop/cop/style/class_methods_definitions.rb +2 -1
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +3 -1
- data/lib/rubocop/cop/style/double_negation.rb +2 -0
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +39 -8
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_heredoc.rb +15 -1
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/format_string_token.rb +21 -8
- data/lib/rubocop/cop/style/guard_clause.rb +27 -16
- data/lib/rubocop/cop/style/hash_each_methods.rb +3 -1
- data/lib/rubocop/cop/style/hash_except.rb +0 -4
- data/lib/rubocop/cop/style/hash_syntax.rb +17 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +8 -6
- data/lib/rubocop/cop/style/magic_comment_format.rb +307 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -7
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -6
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +4 -1
- data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -1
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
- data/lib/rubocop/cop/style/next.rb +3 -5
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +16 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +28 -8
- data/lib/rubocop/cop/style/object_then.rb +2 -0
- data/lib/rubocop/cop/style/proc.rb +4 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +2 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +19 -4
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +15 -22
- data/lib/rubocop/cop/style/redundant_self.rb +2 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +21 -6
- data/lib/rubocop/cop/style/redundant_sort_by.rb +24 -8
- data/lib/rubocop/cop/style/safe_navigation.rb +4 -2
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +14 -5
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +34 -9
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -13
- data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +1 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/ext/range.rb +15 -0
- data/lib/rubocop/feature_loader.rb +94 -0
- data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/formatter/html_formatter.rb +3 -3
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -1
- data/lib/rubocop/formatter/tap_formatter.rb +1 -1
- data/lib/rubocop/result_cache.rb +22 -20
- data/lib/rubocop/server/cache.rb +36 -1
- data/lib/rubocop/server/cli.rb +19 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -3
- metadata +15 -9
- data/lib/rubocop/cop/mixin/ignored_methods.rb +0 -52
@@ -15,9 +15,19 @@ module RuboCop
|
|
15
15
|
# [source,yaml]
|
16
16
|
# ----
|
17
17
|
# Lint/Debugger:
|
18
|
-
#
|
18
|
+
# DebuggerMethods:
|
19
|
+
# WebConsole: ~
|
19
20
|
# ----
|
20
21
|
#
|
22
|
+
# You can also add your own methods by adding a new category:
|
23
|
+
#
|
24
|
+
# [source,yaml]
|
25
|
+
# ----
|
26
|
+
# Lint/Debugger:
|
27
|
+
# DebuggerMethods:
|
28
|
+
# MyDebugger:
|
29
|
+
# MyDebugger.debug_this
|
30
|
+
# ----
|
21
31
|
#
|
22
32
|
# @example
|
23
33
|
#
|
@@ -57,19 +67,6 @@ module RuboCop
|
|
57
67
|
class Debugger < Base
|
58
68
|
MSG = 'Remove debugger entry point `%<source>s`.'
|
59
69
|
|
60
|
-
# @!method kernel?(node)
|
61
|
-
def_node_matcher :kernel?, <<~PATTERN
|
62
|
-
(const {nil? cbase} :Kernel)
|
63
|
-
PATTERN
|
64
|
-
|
65
|
-
# @!method valid_receiver?(node, arg1)
|
66
|
-
def_node_matcher :valid_receiver?, <<~PATTERN
|
67
|
-
{
|
68
|
-
(const {nil? cbase} %1)
|
69
|
-
(send {nil? #kernel?} %1)
|
70
|
-
}
|
71
|
-
PATTERN
|
72
|
-
|
73
70
|
def on_send(node)
|
74
71
|
return unless debugger_method?(node)
|
75
72
|
|
@@ -91,7 +88,7 @@ module RuboCop
|
|
91
88
|
|
92
89
|
*receiver, method_name = v.split('.')
|
93
90
|
{
|
94
|
-
receiver: receiver.empty? ? nil : receiver.
|
91
|
+
receiver: receiver.empty? ? nil : receiver.map(&:to_sym),
|
95
92
|
method_name: method_name.to_sym
|
96
93
|
}
|
97
94
|
end.compact
|
@@ -105,10 +102,23 @@ module RuboCop
|
|
105
102
|
if method[:receiver].nil?
|
106
103
|
send_node.receiver.nil?
|
107
104
|
else
|
108
|
-
|
105
|
+
method[:receiver] == receiver_chain(send_node)
|
109
106
|
end
|
110
107
|
end
|
111
108
|
end
|
109
|
+
|
110
|
+
def receiver_chain(send_node)
|
111
|
+
receivers = []
|
112
|
+
receiver = send_node.receiver
|
113
|
+
|
114
|
+
while receiver
|
115
|
+
name = receiver.send_type? ? receiver.method_name : receiver.const_name&.to_sym
|
116
|
+
receivers.unshift(name)
|
117
|
+
receiver = receiver.receiver
|
118
|
+
end
|
119
|
+
|
120
|
+
receivers
|
121
|
+
end
|
112
122
|
end
|
113
123
|
end
|
114
124
|
end
|
@@ -66,7 +66,7 @@ module RuboCop
|
|
66
66
|
private
|
67
67
|
|
68
68
|
def delimiter
|
69
|
-
|
69
|
+
CLASS_METHOD_DELIMITER
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
@@ -89,7 +89,7 @@ module RuboCop
|
|
89
89
|
private
|
90
90
|
|
91
91
|
def delimiter
|
92
|
-
instance_method? ?
|
92
|
+
instance_method? ? INSTANCE_METHOD_DELIMITER : CLASS_METHOD_DELIMITER
|
93
93
|
end
|
94
94
|
|
95
95
|
def instance_method?
|
@@ -126,8 +126,8 @@ module RuboCop
|
|
126
126
|
|
127
127
|
RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.keys.map(&:method).freeze
|
128
128
|
|
129
|
-
|
130
|
-
|
129
|
+
CLASS_METHOD_DELIMITER = '.'
|
130
|
+
INSTANCE_METHOD_DELIMITER = '#'
|
131
131
|
|
132
132
|
def on_send(node)
|
133
133
|
check(node) do |deprecated|
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
63
63
|
class EmptyBlock < Base
|
64
64
|
MSG = 'Empty block detected.'
|
65
65
|
|
66
|
-
def on_block(node)
|
66
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
67
67
|
return if node.body
|
68
68
|
return if allow_empty_lambdas? && lambda_or_proc?(node)
|
69
69
|
return if cop_config['AllowComments'] && allow_comment?(node)
|
@@ -4,6 +4,14 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
6
|
# Checks for the presence of `if`, `elsif` and `unless` branches without a body.
|
7
|
+
#
|
8
|
+
# NOTE: empty `else` branches are handled by `Style/EmptyElse`.
|
9
|
+
#
|
10
|
+
# @safety
|
11
|
+
# Autocorrection for this cop is not safe. The conditions for empty branches that
|
12
|
+
# the autocorrection removes may have side effects, or the logic in subsequent
|
13
|
+
# branches may change due to the removal of a previous condition.
|
14
|
+
#
|
7
15
|
# @example
|
8
16
|
# # bad
|
9
17
|
# if condition
|
@@ -53,7 +61,9 @@ module RuboCop
|
|
53
61
|
# end
|
54
62
|
#
|
55
63
|
class EmptyConditionalBody < Base
|
64
|
+
extend AutoCorrector
|
56
65
|
include CommentsHelp
|
66
|
+
include RangeHelp
|
57
67
|
|
58
68
|
MSG = 'Avoid `%<keyword>s` branches without a body.'
|
59
69
|
|
@@ -61,7 +71,61 @@ module RuboCop
|
|
61
71
|
return if node.body
|
62
72
|
return if cop_config['AllowComments'] && contains_comments?(node)
|
63
73
|
|
64
|
-
add_offense(node, message: format(MSG, keyword: node.keyword))
|
74
|
+
add_offense(node, message: format(MSG, keyword: node.keyword)) do |corrector|
|
75
|
+
autocorrect(corrector, node)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def autocorrect(corrector, node)
|
82
|
+
remove_comments(corrector, node)
|
83
|
+
remove_empty_branch(corrector, node)
|
84
|
+
correct_other_branches(corrector, node)
|
85
|
+
end
|
86
|
+
|
87
|
+
def remove_comments(corrector, node)
|
88
|
+
comments_in_range(node).each do |comment|
|
89
|
+
range = range_by_whole_lines(comment.loc.expression, include_final_newline: true)
|
90
|
+
corrector.remove(range)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def remove_empty_branch(corrector, node)
|
95
|
+
corrector.remove(deletion_range(branch_range(node)))
|
96
|
+
end
|
97
|
+
|
98
|
+
def correct_other_branches(corrector, node)
|
99
|
+
return unless (node.if? || node.unless?) && node.else_branch
|
100
|
+
|
101
|
+
if node.else_branch.if_type?
|
102
|
+
# Replace an orphaned `elsif` with `if`
|
103
|
+
corrector.replace(node.else_branch.loc.keyword, 'if')
|
104
|
+
else
|
105
|
+
# Flip orphaned `else`
|
106
|
+
corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def branch_range(node)
|
111
|
+
if node.loc.else
|
112
|
+
node.source_range.with(end_pos: node.loc.else.begin_pos - 1)
|
113
|
+
else
|
114
|
+
node.source_range
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def deletion_range(range)
|
119
|
+
# Collect a range between the start of the `if` node and the next relevant node,
|
120
|
+
# including final new line.
|
121
|
+
# Based on `RangeHelp#range_by_whole_lines` but allows the `if` to not start
|
122
|
+
# on the first column.
|
123
|
+
buffer = @processed_source.buffer
|
124
|
+
|
125
|
+
last_line = buffer.source_line(range.last_line)
|
126
|
+
end_offset = last_line.length - range.last_column + 1
|
127
|
+
|
128
|
+
range.adjust(end_pos: end_offset).intersect(buffer.source_range)
|
65
129
|
end
|
66
130
|
end
|
67
131
|
end
|
@@ -6,18 +6,18 @@ module RuboCop
|
|
6
6
|
#
|
7
7
|
# This cop emulates the following Ruby warnings in Ruby 2.6.
|
8
8
|
#
|
9
|
+
# [source,console]
|
10
|
+
# ----
|
9
11
|
# % cat example.rb
|
10
12
|
# ERB.new('hi', nil, '-', '@output_buffer')
|
11
13
|
# % ruby -rerb example.rb
|
12
|
-
# example.rb:1: warning: Passing safe_level with the 2nd argument of
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# ERB.new(str,
|
18
|
-
#
|
19
|
-
# is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...)
|
20
|
-
# instead.
|
14
|
+
# example.rb:1: warning: Passing safe_level with the 2nd argument of ERB.new is
|
15
|
+
# deprecated. Do not use it, and specify other arguments as keyword arguments.
|
16
|
+
# example.rb:1: warning: Passing trim_mode with the 3rd argument of ERB.new is
|
17
|
+
# deprecated. Use keyword argument like ERB.new(str, trim_mode:...) instead.
|
18
|
+
# example.rb:1: warning: Passing eoutvar with the 4th argument of ERB.new is
|
19
|
+
# deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.
|
20
|
+
# ----
|
21
21
|
#
|
22
22
|
# Now non-keyword arguments other than first one are softly deprecated
|
23
23
|
# and will be removed when Ruby 2.5 becomes EOL.
|
@@ -58,6 +58,7 @@ module RuboCop
|
|
58
58
|
(node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
|
59
59
|
end
|
60
60
|
|
61
|
+
# rubocop:disable Metrics/MethodLength
|
61
62
|
def autocorrected_value(node)
|
62
63
|
case node.type
|
63
64
|
when :int
|
@@ -70,10 +71,13 @@ module RuboCop
|
|
70
71
|
autocorrected_value_for_symbol(node)
|
71
72
|
when :array
|
72
73
|
autocorrected_value_for_array(node)
|
74
|
+
when :nil
|
75
|
+
''
|
73
76
|
else
|
74
77
|
node.source.gsub('"', '\"')
|
75
78
|
end
|
76
79
|
end
|
80
|
+
# rubocop:enable Metrics/MethodLength
|
77
81
|
|
78
82
|
def autocorrected_value_for_string(node)
|
79
83
|
if node.source.start_with?("'", '%q')
|
@@ -25,13 +25,8 @@ module RuboCop
|
|
25
25
|
class NextWithoutAccumulator < Base
|
26
26
|
MSG = 'Use `next` with an accumulator argument in a `reduce`.'
|
27
27
|
|
28
|
-
# @!method on_body_of_reduce(node)
|
29
|
-
def_node_matcher :on_body_of_reduce, <<~PATTERN
|
30
|
-
(block (send _recv {:reduce :inject} !sym) _blockargs $(begin ...))
|
31
|
-
PATTERN
|
32
|
-
|
33
28
|
def on_block(node)
|
34
|
-
|
29
|
+
on_block_body_of_reduce(node) do |body|
|
35
30
|
void_next = body.each_node(:next).find do |n|
|
36
31
|
n.children.empty? && parent_block_node(n) == node
|
37
32
|
end
|
@@ -40,11 +35,35 @@ module RuboCop
|
|
40
35
|
end
|
41
36
|
end
|
42
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
|
47
|
+
|
43
48
|
private
|
44
49
|
|
50
|
+
# @!method on_block_body_of_reduce(node)
|
51
|
+
def_node_matcher :on_block_body_of_reduce, <<~PATTERN
|
52
|
+
(block (send _recv {:reduce :inject} !sym) _blockargs $(begin ...))
|
53
|
+
PATTERN
|
54
|
+
|
55
|
+
# @!method on_numblock_body_of_reduce(node)
|
56
|
+
def_node_matcher :on_numblock_body_of_reduce, <<~PATTERN
|
57
|
+
(numblock (send _recv {:reduce :inject} !sym) _argscount $(begin ...))
|
58
|
+
PATTERN
|
59
|
+
|
45
60
|
def parent_block_node(node)
|
46
61
|
node.each_ancestor(:block).first
|
47
62
|
end
|
63
|
+
|
64
|
+
def parent_numblock_node(node)
|
65
|
+
node.each_ancestor(:numblock).first
|
66
|
+
end
|
48
67
|
end
|
49
68
|
end
|
50
69
|
end
|
@@ -99,19 +99,19 @@ module RuboCop
|
|
99
99
|
end
|
100
100
|
|
101
101
|
def register_offense(node, exist_node)
|
102
|
-
unless force_method?(node)
|
103
|
-
add_offense(node,
|
104
|
-
message: format(MSG_CHANGE_FORCE_METHOD,
|
105
|
-
method_name: replacement_method(node)))
|
106
|
-
end
|
102
|
+
add_offense(node, message: message_change_force_method(node)) unless force_method?(node)
|
107
103
|
|
108
104
|
range = range_between(node.parent.loc.keyword.begin_pos,
|
109
105
|
exist_node.loc.expression.end_pos)
|
110
106
|
add_offense(range, message: message_remove_file_exist_check(exist_node)) do |corrector|
|
111
|
-
autocorrect(corrector, node, range)
|
107
|
+
autocorrect(corrector, node, range) unless node.parent.elsif?
|
112
108
|
end
|
113
109
|
end
|
114
110
|
|
111
|
+
def message_change_force_method(node)
|
112
|
+
format(MSG_CHANGE_FORCE_METHOD, method_name: replacement_method(node))
|
113
|
+
end
|
114
|
+
|
115
115
|
def message_remove_file_exist_check(node)
|
116
116
|
receiver, method_name = receiver_and_method_name(node)
|
117
117
|
format(MSG_REMOVE_FILE_EXIST_CHECK, receiver: receiver, method_name: method_name)
|
@@ -74,6 +74,18 @@ module RuboCop
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
+
def on_numblock(node)
|
78
|
+
return if target_ruby_version >= 3.0
|
79
|
+
return unless node.body
|
80
|
+
return unless unsorted_dir_loop?(node.send_node)
|
81
|
+
|
82
|
+
node.argument_list
|
83
|
+
.filter { |argument| var_is_required?(node.body, argument.name) }
|
84
|
+
.each do
|
85
|
+
add_offense(node.send_node) { |corrector| correct_block(corrector, node.send_node) }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
77
89
|
def on_block_pass(node)
|
78
90
|
return if target_ruby_version >= 3.0
|
79
91
|
return unless method_require?(node)
|
@@ -16,8 +16,8 @@ module RuboCop
|
|
16
16
|
# NOTE: Some values cannot be converted properly using one of the `Kernel`
|
17
17
|
# method (for instance, `Time` and `DateTime` values are allowed by this
|
18
18
|
# cop by default). Similarly, Rails' duration methods do not work well
|
19
|
-
# with `Integer()` and can be
|
20
|
-
# there are no methods to
|
19
|
+
# with `Integer()` and can be allowed with `AllowedMethods`. By default,
|
20
|
+
# there are no methods to allowed.
|
21
21
|
#
|
22
22
|
# @safety
|
23
23
|
# Autocorrection is unsafe because it is not guaranteed that the
|
@@ -46,12 +46,22 @@ module RuboCop
|
|
46
46
|
# foo.try { |i| Float(i) }
|
47
47
|
# bar.send { |i| Complex(i) }
|
48
48
|
#
|
49
|
-
# @example
|
49
|
+
# @example AllowedMethods: [] (default)
|
50
50
|
#
|
51
51
|
# # bad
|
52
52
|
# 10.minutes.to_i
|
53
53
|
#
|
54
|
-
# @example
|
54
|
+
# @example AllowedMethods: [minutes]
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# 10.minutes.to_i
|
58
|
+
#
|
59
|
+
# @example AllowedPatterns: [] (default)
|
60
|
+
#
|
61
|
+
# # bad
|
62
|
+
# 10.minutes.to_i
|
63
|
+
#
|
64
|
+
# @example AllowedPatterns: [/min*/]
|
55
65
|
#
|
56
66
|
# # good
|
57
67
|
# 10.minutes.to_i
|
@@ -62,7 +72,8 @@ module RuboCop
|
|
62
72
|
# Time.now.to_datetime.to_i
|
63
73
|
class NumberConversion < Base
|
64
74
|
extend AutoCorrector
|
65
|
-
include
|
75
|
+
include AllowedMethods
|
76
|
+
include AllowedPattern
|
66
77
|
|
67
78
|
CONVERSION_METHOD_CLASS_MAPPING = {
|
68
79
|
to_i: "#{Integer.name}(%<number_object>s, 10)",
|
@@ -97,7 +108,7 @@ module RuboCop
|
|
97
108
|
|
98
109
|
def handle_conversion_method(node)
|
99
110
|
to_method(node) do |receiver, to_method|
|
100
|
-
next if receiver.nil? ||
|
111
|
+
next if receiver.nil? || allow_receiver?(receiver)
|
101
112
|
|
102
113
|
message = format(
|
103
114
|
MSG,
|
@@ -141,9 +152,10 @@ module RuboCop
|
|
141
152
|
corrector.remove(node.loc.end)
|
142
153
|
end
|
143
154
|
|
144
|
-
def
|
155
|
+
def allow_receiver?(receiver)
|
145
156
|
if receiver.numeric_type? || (receiver.send_type? &&
|
146
|
-
(conversion_method?(receiver.method_name) ||
|
157
|
+
(conversion_method?(receiver.method_name) ||
|
158
|
+
allowed_method_name?(receiver.method_name)))
|
147
159
|
true
|
148
160
|
elsif (receiver = top_receiver(receiver))
|
149
161
|
receiver.const_type? && ignored_class?(receiver.const_name)
|
@@ -152,6 +164,10 @@ module RuboCop
|
|
152
164
|
end
|
153
165
|
end
|
154
166
|
|
167
|
+
def allowed_method_name?(name)
|
168
|
+
allowed_method?(name) || matches_allowed_pattern?(name)
|
169
|
+
end
|
170
|
+
|
155
171
|
def top_receiver(node)
|
156
172
|
receiver = node
|
157
173
|
receiver = receiver.receiver until receiver.receiver.nil?
|
@@ -7,6 +7,11 @@ module RuboCop
|
|
7
7
|
# `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods
|
8
8
|
# are checked by default. These are customizable with `AllowedMethods` option.
|
9
9
|
#
|
10
|
+
# The `AllowedMethods` option specifies nil-safe methods,
|
11
|
+
# in other words, it is a method that is allowed to skip safe navigation.
|
12
|
+
# Note that the `AllowedMethod` option is not an option that specifies methods
|
13
|
+
# for which to suppress (allow) this cop's check.
|
14
|
+
#
|
10
15
|
# In the example below, the safe navigation operator (`&.`) is unnecessary
|
11
16
|
# because `NilClass` has methods like `respond_to?` and `is_a?`.
|
12
17
|
#
|
@@ -35,12 +40,13 @@ module RuboCop
|
|
35
40
|
# # good - without `&.` this will always return `true`
|
36
41
|
# foo&.respond_to?(:to_a)
|
37
42
|
#
|
38
|
-
# @example AllowedMethods: [
|
43
|
+
# @example AllowedMethods: [nil_safe_method]
|
39
44
|
# # bad
|
40
|
-
# do_something if attrs&.
|
45
|
+
# do_something if attrs&.nil_safe_method(:[])
|
41
46
|
#
|
42
47
|
# # good
|
43
|
-
# do_something if attrs
|
48
|
+
# do_something if attrs.nil_safe_method(:[])
|
49
|
+
# do_something if attrs&.not_nil_safe_method(:[])
|
44
50
|
#
|
45
51
|
class RedundantSafeNavigation < Base
|
46
52
|
include AllowedMethods
|
@@ -33,16 +33,6 @@ module RuboCop
|
|
33
33
|
MSG_EACH_WITH_INDEX = 'Use `each` instead of `each_with_index`.'
|
34
34
|
MSG_WITH_INDEX = 'Remove redundant `with_index`.'
|
35
35
|
|
36
|
-
# @!method redundant_with_index?(node)
|
37
|
-
def_node_matcher :redundant_with_index?, <<~PATTERN
|
38
|
-
(block
|
39
|
-
$(send
|
40
|
-
_ {:each_with_index :with_index} ...)
|
41
|
-
(args
|
42
|
-
(arg _))
|
43
|
-
...)
|
44
|
-
PATTERN
|
45
|
-
|
46
36
|
def on_block(node)
|
47
37
|
return unless (send = redundant_with_index?(node))
|
48
38
|
|
@@ -58,8 +48,21 @@ module RuboCop
|
|
58
48
|
end
|
59
49
|
end
|
60
50
|
|
51
|
+
alias on_numblock on_block
|
52
|
+
|
61
53
|
private
|
62
54
|
|
55
|
+
# @!method redundant_with_index?(node)
|
56
|
+
def_node_matcher :redundant_with_index?, <<~PATTERN
|
57
|
+
{
|
58
|
+
(block
|
59
|
+
$(send _ {:each_with_index :with_index} ...)
|
60
|
+
(args (arg _)) ...)
|
61
|
+
(numblock
|
62
|
+
$(send _ {:each_with_index :with_index} ...) 1 ...)
|
63
|
+
}
|
64
|
+
PATTERN
|
65
|
+
|
63
66
|
def message(node)
|
64
67
|
if node.method?(:each_with_index)
|
65
68
|
MSG_EACH_WITH_INDEX
|
@@ -31,19 +31,8 @@ module RuboCop
|
|
31
31
|
extend AutoCorrector
|
32
32
|
|
33
33
|
MSG_EACH_WITH_OBJECT = 'Use `each` instead of `each_with_object`.'
|
34
|
-
|
35
34
|
MSG_WITH_OBJECT = 'Remove redundant `with_object`.'
|
36
35
|
|
37
|
-
# @!method redundant_with_object?(node)
|
38
|
-
def_node_matcher :redundant_with_object?, <<~PATTERN
|
39
|
-
(block
|
40
|
-
$(send _ {:each_with_object :with_object}
|
41
|
-
_)
|
42
|
-
(args
|
43
|
-
(arg _))
|
44
|
-
...)
|
45
|
-
PATTERN
|
46
|
-
|
47
36
|
def on_block(node)
|
48
37
|
return unless (send = redundant_with_object?(node))
|
49
38
|
|
@@ -59,8 +48,20 @@ module RuboCop
|
|
59
48
|
end
|
60
49
|
end
|
61
50
|
|
51
|
+
alias on_numblock on_block
|
52
|
+
|
62
53
|
private
|
63
54
|
|
55
|
+
# @!method redundant_with_object?(node)
|
56
|
+
def_node_matcher :redundant_with_object?, <<~PATTERN
|
57
|
+
{
|
58
|
+
(block
|
59
|
+
$(send _ {:each_with_object :with_object} _) (args (arg _)) ...)
|
60
|
+
(numblock
|
61
|
+
$(send _ {:each_with_object :with_object} _) 1 ...)
|
62
|
+
}
|
63
|
+
PATTERN
|
64
|
+
|
64
65
|
def message(node)
|
65
66
|
if node.method?(:each_with_object)
|
66
67
|
MSG_EACH_WITH_OBJECT
|
@@ -7,6 +7,14 @@ module RuboCop
|
|
7
7
|
# less specific exception being rescued before a more specific
|
8
8
|
# exception is rescued.
|
9
9
|
#
|
10
|
+
# An exception is considered shadowed if it is rescued after its
|
11
|
+
# ancestor is, or if it and its ancestor are both rescued in the
|
12
|
+
# same `rescue` statement. In both cases, the more specific rescue is
|
13
|
+
# unnecessary because it is covered by rescuing the less specific
|
14
|
+
# exception. (ie. `rescue Exception, StandardError` has the same behavior
|
15
|
+
# whether `StandardError` is included or not, because all `StandardError`s
|
16
|
+
# are rescued by `rescue Exception`).
|
17
|
+
#
|
10
18
|
# @example
|
11
19
|
#
|
12
20
|
# # bad
|
@@ -19,6 +27,13 @@ module RuboCop
|
|
19
27
|
# handle_standard_error
|
20
28
|
# end
|
21
29
|
#
|
30
|
+
# # bad
|
31
|
+
# begin
|
32
|
+
# something
|
33
|
+
# rescue Exception, StandardError
|
34
|
+
# handle_error
|
35
|
+
# end
|
36
|
+
#
|
22
37
|
# # good
|
23
38
|
#
|
24
39
|
# begin
|
@@ -67,10 +67,19 @@ module RuboCop
|
|
67
67
|
variable_node = variable.scope.node.parent
|
68
68
|
return false unless variable_node.conditional?
|
69
69
|
|
70
|
-
outer_local_variable_node =
|
70
|
+
outer_local_variable_node =
|
71
|
+
find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
|
72
|
+
return true unless outer_local_variable_node
|
71
73
|
|
72
74
|
outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
|
73
75
|
end
|
76
|
+
|
77
|
+
def find_conditional_node_from_ascendant(node)
|
78
|
+
return unless (parent = node.parent)
|
79
|
+
return parent if parent.conditional?
|
80
|
+
|
81
|
+
find_conditional_node_from_ascendant(parent)
|
82
|
+
end
|
74
83
|
end
|
75
84
|
end
|
76
85
|
end
|
@@ -101,10 +101,14 @@ module RuboCop
|
|
101
101
|
check(node) if loop_method?(node)
|
102
102
|
end
|
103
103
|
|
104
|
+
def on_numblock(node)
|
105
|
+
check(node) if loop_method?(node)
|
106
|
+
end
|
107
|
+
|
104
108
|
private
|
105
109
|
|
106
110
|
def loop_method?(node)
|
107
|
-
return false unless node.block_type?
|
111
|
+
return false unless node.block_type? || node.numblock_type?
|
108
112
|
|
109
113
|
send_node = node.send_node
|
110
114
|
return false if matches_allowed_pattern?(send_node.source)
|
@@ -179,6 +183,8 @@ module RuboCop
|
|
179
183
|
|
180
184
|
def preceded_by_continue_statement?(break_statement)
|
181
185
|
break_statement.left_siblings.any? do |sibling|
|
186
|
+
# Numblocks have the arguments count as a number in the AST.
|
187
|
+
next if sibling.is_a?(Integer)
|
182
188
|
next if sibling.loop_keyword? || loop_method?(sibling)
|
183
189
|
|
184
190
|
sibling.each_descendant(*CONTINUE_KEYWORDS).any?
|
@@ -142,6 +142,8 @@ module RuboCop
|
|
142
142
|
check_node(node.body)
|
143
143
|
end
|
144
144
|
|
145
|
+
alias on_numblock on_block
|
146
|
+
|
145
147
|
private
|
146
148
|
|
147
149
|
def autocorrect(corrector, node)
|
@@ -157,17 +159,17 @@ module RuboCop
|
|
157
159
|
|
158
160
|
# @!method dynamic_method_definition?(node)
|
159
161
|
def_node_matcher :dynamic_method_definition?, <<~PATTERN
|
160
|
-
{(send nil? :define_method ...) (block (send nil? :define_method ...) ...)}
|
162
|
+
{(send nil? :define_method ...) ({block numblock} (send nil? :define_method ...) ...)}
|
161
163
|
PATTERN
|
162
164
|
|
163
165
|
# @!method class_or_instance_eval?(node)
|
164
166
|
def_node_matcher :class_or_instance_eval?, <<~PATTERN
|
165
|
-
(block (send _ {:class_eval :instance_eval}) ...)
|
167
|
+
({block numblock} (send _ {:class_eval :instance_eval}) ...)
|
166
168
|
PATTERN
|
167
169
|
|
168
170
|
# @!method class_or_module_or_struct_new_call?(node)
|
169
171
|
def_node_matcher :class_or_module_or_struct_new_call?, <<~PATTERN
|
170
|
-
(block (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...)
|
172
|
+
({block numblock} (send (const {nil? cbase} {:Class :Module :Struct}) :new ...) ...)
|
171
173
|
PATTERN
|
172
174
|
|
173
175
|
def check_node(node)
|
@@ -277,7 +279,7 @@ module RuboCop
|
|
277
279
|
matcher_name = "#{m}_block?".to_sym
|
278
280
|
unless respond_to?(matcher_name)
|
279
281
|
self.class.def_node_matcher matcher_name, <<~PATTERN
|
280
|
-
(block (send {nil? const} {:#{m}} ...) ...)
|
282
|
+
({block numblock} (send {nil? const} {:#{m}} ...) ...)
|
281
283
|
PATTERN
|
282
284
|
end
|
283
285
|
|
@@ -33,7 +33,9 @@ module RuboCop
|
|
33
33
|
# render 'pages/search/page'
|
34
34
|
# end
|
35
35
|
#
|
36
|
-
# This cop also takes into account `
|
36
|
+
# This cop also takes into account `AllowedMethods` (defaults to `[]`)
|
37
|
+
# And `AllowedPatterns` (defaults to `[]`)
|
38
|
+
#
|
37
39
|
class AbcSize < Base
|
38
40
|
include MethodComplexity
|
39
41
|
|