rubocop 1.42.0 → 1.45.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/README.md +1 -1
- data/config/default.yml +73 -31
- data/lib/rubocop/cli.rb +54 -8
- data/lib/rubocop/config_loader.rb +12 -15
- data/lib/rubocop/config_loader_resolver.rb +3 -4
- data/lib/rubocop/cop/base.rb +27 -9
- data/lib/rubocop/cop/commissioner.rb +8 -2
- data/lib/rubocop/cop/cop.rb +23 -3
- data/lib/rubocop/cop/corrector.rb +10 -2
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -16
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +2 -6
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +11 -13
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +4 -4
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +5 -4
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +4 -0
- data/lib/rubocop/cop/lint/debugger.rb +8 -27
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
- data/lib/rubocop/cop/lint/else_layout.rb +2 -6
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +14 -7
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +15 -17
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +8 -5
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +7 -4
- data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
- data/lib/rubocop/cop/lint/useless_rescue.rb +85 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +9 -1
- data/lib/rubocop/cop/lint/void.rb +19 -10
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/parameter_lists.rb +27 -0
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +2 -5
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_methods.rb +3 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +5 -3
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +57 -23
- data/lib/rubocop/cop/mixin/line_length_help.rb +3 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -0
- data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -3
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +4 -0
- data/lib/rubocop/cop/naming/class_and_module_camel_case.rb +1 -1
- data/lib/rubocop/cop/registry.rb +12 -7
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -11
- data/lib/rubocop/cop/style/arguments_forwarding.rb +1 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +3 -10
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/documentation_method.rb +6 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +13 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -0
- data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +23 -14
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
- data/lib/rubocop/cop/style/min_max_comparison.rb +11 -1
- data/lib/rubocop/cop/style/missing_else.rb +13 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
- data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +18 -3
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
- data/lib/rubocop/cop/style/numbered_parameters_limit.rb +11 -3
- data/lib/rubocop/cop/style/one_line_conditional.rb +3 -6
- data/lib/rubocop/cop/style/operator_method_call.rb +16 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -1
- data/lib/rubocop/cop/style/redundant_condition.rb +16 -1
- data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -10
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +58 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
- data/lib/rubocop/cop/style/require_order.rb +2 -9
- data/lib/rubocop/cop/style/self_assignment.rb +2 -2
- data/lib/rubocop/cop/style/semicolon.rb +24 -2
- data/lib/rubocop/cop/style/string_hash_keys.rb +4 -1
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/word_array.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +12 -5
- data/lib/rubocop/cop/style/yoda_expression.rb +18 -2
- data/lib/rubocop/cop/team.rb +19 -14
- data/lib/rubocop/cop/variable_force/scope.rb +3 -3
- data/lib/rubocop/cop/variable_force/variable_table.rb +3 -1
- data/lib/rubocop/cop/variable_force.rb +1 -1
- data/lib/rubocop/formatter.rb +0 -1
- data/lib/rubocop/options.rb +22 -1
- data/lib/rubocop/path_util.rb +11 -6
- data/lib/rubocop/rspec/expect_offense.rb +6 -4
- data/lib/rubocop/runner.rb +40 -4
- data/lib/rubocop/server/cache.rb +10 -3
- data/lib/rubocop/server/cli.rb +37 -18
- data/lib/rubocop/server/client_command/exec.rb +1 -1
- data/lib/rubocop/server/client_command/start.rb +6 -1
- data/lib/rubocop/server/core.rb +23 -8
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -0
- metadata +12 -27
@@ -11,6 +11,8 @@ module RuboCop
|
|
11
11
|
# File.exists?(some_path)
|
12
12
|
# Dir.exists?(some_path)
|
13
13
|
# iterator?
|
14
|
+
# attr :name, true
|
15
|
+
# attr :name, false
|
14
16
|
# ENV.freeze # Calling `Env.freeze` raises `TypeError` since Ruby 2.7.
|
15
17
|
# ENV.clone
|
16
18
|
# ENV.dup # Calling `Env.dup` raises `TypeError` since Ruby 3.1.
|
@@ -21,6 +23,8 @@ module RuboCop
|
|
21
23
|
# File.exist?(some_path)
|
22
24
|
# Dir.exist?(some_path)
|
23
25
|
# block_given?
|
26
|
+
# attr_accessor :name
|
27
|
+
# attr_reader :name
|
24
28
|
# ENV # `ENV.freeze` cannot prohibit changes to environment variables.
|
25
29
|
# ENV.to_h
|
26
30
|
# ENV.to_h # `ENV.dup` cannot dup `ENV`, use `ENV.to_h` to get a copy of `ENV` as a hash.
|
@@ -29,138 +33,84 @@ module RuboCop
|
|
29
33
|
class DeprecatedClassMethods < Base
|
30
34
|
extend AutoCorrector
|
31
35
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
36
|
+
MSG = '`%<current>s` is deprecated in favor of `%<prefer>s`.'
|
37
|
+
RESTRICT_ON_SEND = %i[
|
38
|
+
attr clone dup exists? freeze gethostbyaddr gethostbyname iterator?
|
39
|
+
].freeze
|
40
|
+
|
41
|
+
PREFERRED_METHDOS = {
|
42
|
+
clone: 'to_h',
|
43
|
+
dup: 'to_h',
|
44
|
+
exists?: 'exist?',
|
45
|
+
gethostbyaddr: 'Addrinfo#getnameinfo',
|
46
|
+
gethostbyname: 'Addrinfo#getaddrinfo',
|
47
|
+
iterator?: 'block_given?'
|
48
|
+
}.freeze
|
37
49
|
|
38
|
-
|
50
|
+
DIR_ENV_FILE_CONSTANTS = %i[Dir ENV File].freeze
|
39
51
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
s(:const, nil, class_constant),
|
51
|
-
s(:const, s(:cbase), class_constant)
|
52
|
-
]
|
53
|
-
else
|
54
|
-
[nil]
|
55
|
-
end
|
56
|
-
end
|
52
|
+
# @!method deprecated_class_method?(node)
|
53
|
+
def_node_matcher :deprecated_class_method?, <<~PATTERN
|
54
|
+
{
|
55
|
+
(send (const {cbase nil?} {:ENV}) {:clone :dup :freeze})
|
56
|
+
(send (const {cbase nil?} {:File :Dir}) :exists? _)
|
57
|
+
(send (const {cbase nil?} :Socket) {:gethostbyaddr :gethostbyname} ...)
|
58
|
+
(send nil? :attr _ boolean)
|
59
|
+
(send nil? :iterator?)
|
60
|
+
}
|
61
|
+
PATTERN
|
57
62
|
|
58
|
-
|
59
|
-
|
60
|
-
end
|
63
|
+
def on_send(node)
|
64
|
+
return unless deprecated_class_method?(node)
|
61
65
|
|
62
|
-
|
63
|
-
|
64
|
-
|
66
|
+
offense_range = offense_range(node)
|
67
|
+
prefer = preferred_method(node)
|
68
|
+
message = format(MSG, current: offense_range.source, prefer: prefer)
|
65
69
|
|
66
|
-
|
70
|
+
add_offense(offense_range, message: message) do |corrector|
|
71
|
+
next if socket_const?(node.receiver)
|
67
72
|
|
68
|
-
|
69
|
-
|
73
|
+
if node.method?(:freeze)
|
74
|
+
corrector.replace(node, 'ENV')
|
75
|
+
else
|
76
|
+
corrector.replace(offense_range, prefer)
|
77
|
+
end
|
70
78
|
end
|
71
79
|
end
|
72
80
|
|
73
|
-
|
74
|
-
# This class exists to add abstraction and clean naming
|
75
|
-
# to the replacements for deprecated objects
|
76
|
-
class Replacement
|
77
|
-
attr_reader :method, :class_constant
|
78
|
-
|
79
|
-
def initialize(method, class_constant: nil, instance_method: false)
|
80
|
-
@method = method
|
81
|
-
@class_constant = class_constant
|
82
|
-
@instance_method = instance_method
|
83
|
-
end
|
84
|
-
|
85
|
-
def to_s
|
86
|
-
[class_constant, method].compact.join(delimiter)
|
87
|
-
end
|
88
|
-
|
89
|
-
private
|
90
|
-
|
91
|
-
def delimiter
|
92
|
-
instance_method? ? INSTANCE_METHOD_DELIMITER : CLASS_METHOD_DELIMITER
|
93
|
-
end
|
81
|
+
private
|
94
82
|
|
95
|
-
|
96
|
-
|
83
|
+
def offense_range(node)
|
84
|
+
if socket_const?(node.receiver) || dir_env_file_const?(node.receiver)
|
85
|
+
node.loc.expression.begin.join(node.loc.selector.end)
|
86
|
+
elsif node.method?(:attr)
|
87
|
+
node
|
88
|
+
else
|
89
|
+
node.loc.selector
|
97
90
|
end
|
98
91
|
end
|
99
92
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
Replacement.new(:exist?, class_constant: :File),
|
105
|
-
|
106
|
-
DeprecatedClassMethod.new(:exists?, class_constant: :Dir) =>
|
107
|
-
Replacement.new(:exist?, class_constant: :Dir),
|
108
|
-
|
109
|
-
DeprecatedClassMethod.new(:iterator?) => Replacement.new(:block_given?),
|
110
|
-
|
111
|
-
DeprecatedClassMethod.new(:freeze, class_constant: :ENV) =>
|
112
|
-
Replacement.new(nil, class_constant: :ENV),
|
93
|
+
def preferred_method(node)
|
94
|
+
if node.method?(:attr)
|
95
|
+
boolean_argument = node.arguments[1].source
|
96
|
+
preferred_attr_method = boolean_argument == 'true' ? 'attr_accessor' : 'attr_reader'
|
113
97
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
DeprecatedClassMethod.new(:dup, class_constant: :ENV) =>
|
118
|
-
Replacement.new(:to_h, class_constant: :ENV),
|
119
|
-
|
120
|
-
DeprecatedClassMethod.new(:gethostbyaddr, class_constant: :Socket, correctable: false) =>
|
121
|
-
Replacement.new(:getnameinfo, class_constant: :Addrinfo, instance_method: true),
|
122
|
-
|
123
|
-
DeprecatedClassMethod.new(:gethostbyname, class_constant: :Socket, correctable: false) =>
|
124
|
-
Replacement.new(:getaddrinfo, class_constant: :Addrinfo, instance_method: true)
|
125
|
-
}.freeze
|
98
|
+
"#{preferred_attr_method} #{node.first_argument.source}"
|
99
|
+
elsif dir_env_file_const?(node.receiver)
|
100
|
+
prefer = PREFERRED_METHDOS[node.method_name]
|
126
101
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
INSTANCE_METHOD_DELIMITER = '#'
|
131
|
-
|
132
|
-
def on_send(node)
|
133
|
-
check(node) do |deprecated|
|
134
|
-
prefer = replacement(deprecated)
|
135
|
-
message = format(MSG, current: deprecated, prefer: prefer)
|
136
|
-
current_method = node.loc.selector
|
137
|
-
|
138
|
-
add_offense(current_method, message: message) do |corrector|
|
139
|
-
next unless deprecated.correctable?
|
140
|
-
|
141
|
-
if (preferred_method = prefer.method)
|
142
|
-
corrector.replace(current_method, preferred_method)
|
143
|
-
else
|
144
|
-
corrector.remove(node.loc.dot)
|
145
|
-
corrector.remove(current_method)
|
146
|
-
end
|
147
|
-
end
|
102
|
+
prefer ? "#{node.receiver.source}.#{prefer}" : 'ENV'
|
103
|
+
else
|
104
|
+
PREFERRED_METHDOS[node.method_name]
|
148
105
|
end
|
149
106
|
end
|
150
107
|
|
151
|
-
|
152
|
-
|
153
|
-
def check(node)
|
154
|
-
DEPRECATED_METHODS_OBJECT.each_key do |deprecated|
|
155
|
-
next unless deprecated.class_nodes.include?(node.receiver)
|
156
|
-
next unless node.method?(deprecated.method)
|
157
|
-
|
158
|
-
yield deprecated
|
159
|
-
end
|
108
|
+
def socket_const?(node)
|
109
|
+
node&.short_name == :Socket
|
160
110
|
end
|
161
111
|
|
162
|
-
def
|
163
|
-
|
112
|
+
def dir_env_file_const?(node)
|
113
|
+
DIR_ENV_FILE_CONSTANTS.include?(node&.short_name)
|
164
114
|
end
|
165
115
|
end
|
166
116
|
end
|
@@ -41,6 +41,7 @@ module RuboCop
|
|
41
41
|
# do_that
|
42
42
|
# end
|
43
43
|
class ElseLayout < Base
|
44
|
+
include Alignment
|
44
45
|
include RangeHelp
|
45
46
|
extend AutoCorrector
|
46
47
|
|
@@ -81,12 +82,7 @@ module RuboCop
|
|
81
82
|
corrector.insert_after(node.loc.else, "\n")
|
82
83
|
|
83
84
|
blank_range = range_between(node.loc.else.end_pos, first_else.loc.expression.begin_pos)
|
84
|
-
indentation
|
85
|
-
corrector.replace(blank_range, indentation)
|
86
|
-
end
|
87
|
-
|
88
|
-
def indentation_width
|
89
|
-
@config.for_cop('Layout/IndentationWidth')['Width'] || 2
|
85
|
+
corrector.replace(blank_range, indentation(node))
|
90
86
|
end
|
91
87
|
end
|
92
88
|
end
|
@@ -81,6 +81,10 @@ module RuboCop
|
|
81
81
|
|
82
82
|
return false if num_of_format_args == :unknown
|
83
83
|
|
84
|
+
first_arg = node.first_argument
|
85
|
+
return false if num_of_expected_fields.zero? &&
|
86
|
+
(first_arg.dstr_type? || first_arg.array_type?)
|
87
|
+
|
84
88
|
matched_arguments_count?(num_of_expected_fields, num_of_format_args)
|
85
89
|
end
|
86
90
|
|
@@ -94,8 +98,8 @@ module RuboCop
|
|
94
98
|
|
95
99
|
# @!method called_on_string?(node)
|
96
100
|
def_node_matcher :called_on_string?, <<~PATTERN
|
97
|
-
{(send {nil? const_type?} _
|
98
|
-
(send
|
101
|
+
{(send {nil? const_type?} _ {str dstr} ...)
|
102
|
+
(send {str dstr} ...)}
|
99
103
|
PATTERN
|
100
104
|
|
101
105
|
def method_with_format_args?(node)
|
@@ -143,11 +147,11 @@ module RuboCop
|
|
143
147
|
return false if node.const_receiver? && !node.receiver.loc.name.is?(KERNEL)
|
144
148
|
return false unless node.method?(name)
|
145
149
|
|
146
|
-
node.arguments.size > 1 && node.first_argument
|
150
|
+
node.arguments.size > 1 && string_type?(node.first_argument)
|
147
151
|
end
|
148
152
|
|
149
153
|
def expected_fields_count(node)
|
150
|
-
return :unknown unless node
|
154
|
+
return :unknown unless string_type?(node)
|
151
155
|
|
152
156
|
format_string = RuboCop::Cop::Utils::FormatString.new(node.source)
|
153
157
|
return 1 if format_string.named_interpolation?
|
@@ -172,10 +176,9 @@ module RuboCop
|
|
172
176
|
def percent?(node)
|
173
177
|
receiver = node.receiver
|
174
178
|
|
175
|
-
percent = node.method?(:%) &&
|
176
|
-
(STRING_TYPES.include?(receiver.type) || node.first_argument.array_type?)
|
179
|
+
percent = node.method?(:%) && (string_type?(receiver) || node.first_argument.array_type?)
|
177
180
|
|
178
|
-
return false if percent &&
|
181
|
+
return false if percent && string_type?(receiver) && heredoc?(node)
|
179
182
|
|
180
183
|
percent
|
181
184
|
end
|
@@ -188,6 +191,10 @@ module RuboCop
|
|
188
191
|
format(MSG, arg_num: num_args_for_format, method: method_name,
|
189
192
|
field_num: num_expected_fields)
|
190
193
|
end
|
194
|
+
|
195
|
+
def string_type?(node)
|
196
|
+
STRING_TYPES.include?(node.type)
|
197
|
+
end
|
191
198
|
end
|
192
199
|
end
|
193
200
|
end
|
@@ -8,27 +8,25 @@ module RuboCop
|
|
8
8
|
#
|
9
9
|
# @example
|
10
10
|
# # bad
|
11
|
+
# <<-SQL
|
12
|
+
# bar
|
13
|
+
# SQL
|
14
|
+
# .strip_indent
|
11
15
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
16
|
-
#
|
17
|
-
# <<-SQL
|
18
|
-
# bar
|
19
|
-
# SQL
|
20
|
-
# .strip_indent
|
21
|
-
# .trim
|
16
|
+
# <<-SQL
|
17
|
+
# bar
|
18
|
+
# SQL
|
19
|
+
# .strip_indent
|
20
|
+
# .trim
|
22
21
|
#
|
23
22
|
# # good
|
23
|
+
# <<~SQL
|
24
|
+
# bar
|
25
|
+
# SQL
|
24
26
|
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
# <<~SQL.trim
|
30
|
-
# bar
|
31
|
-
# SQL
|
27
|
+
# <<~SQL.trim
|
28
|
+
# bar
|
29
|
+
# SQL
|
32
30
|
#
|
33
31
|
class HeredocMethodCallPosition < Base
|
34
32
|
include RangeHelp
|
@@ -108,7 +108,7 @@ module RuboCop
|
|
108
108
|
return unless def_ancestor
|
109
109
|
|
110
110
|
within_scoping_def =
|
111
|
-
node.each_ancestor(:block, :sclass).any? do |ancestor|
|
111
|
+
node.each_ancestor(:block, :numblock, :sclass).any? do |ancestor|
|
112
112
|
scoping_method_call?(ancestor)
|
113
113
|
end
|
114
114
|
|
@@ -120,7 +120,7 @@ module RuboCop
|
|
120
120
|
|
121
121
|
def scoping_method_call?(child)
|
122
122
|
child.sclass_type? || eval_call?(child) || exec_call?(child) ||
|
123
|
-
|
123
|
+
class_constructor?(child) || allowed_method_name?(child)
|
124
124
|
end
|
125
125
|
|
126
126
|
def allowed_method_name?(node)
|
@@ -139,9 +139,12 @@ module RuboCop
|
|
139
139
|
(block (send _ {:instance_exec :class_exec :module_exec} ...) ...)
|
140
140
|
PATTERN
|
141
141
|
|
142
|
-
# @!method
|
143
|
-
def_node_matcher :
|
144
|
-
(block
|
142
|
+
# @!method class_constructor?(node)
|
143
|
+
def_node_matcher :class_constructor?, <<~PATTERN
|
144
|
+
({block numblock} {
|
145
|
+
(send (const {nil? cbase} {:Class :Module :Struct}) :new ...)
|
146
|
+
(send (const {nil? cbase} :Data) :define ...)
|
147
|
+
} ...)
|
145
148
|
PATTERN
|
146
149
|
end
|
147
150
|
end
|
@@ -38,6 +38,10 @@ module RuboCop
|
|
38
38
|
MSG = 'Remove unnecessary `require` statement.'
|
39
39
|
RESTRICT_ON_SEND = %i[require].freeze
|
40
40
|
RUBY_22_LOADED_FEATURES = %w[rational complex].freeze
|
41
|
+
PRETTY_PRINT_METHODS = %i[
|
42
|
+
pretty_inspect pretty_print pretty_print_cycle
|
43
|
+
pretty_print_inspect pretty_print_instance_variables
|
44
|
+
].freeze
|
41
45
|
|
42
46
|
# @!method redundant_require_statement?(node)
|
43
47
|
def_node_matcher :redundant_require_statement?, <<~PATTERN
|
@@ -68,12 +72,18 @@ module RuboCop
|
|
68
72
|
feature_name == 'enumerator' ||
|
69
73
|
(target_ruby_version >= 2.1 && feature_name == 'thread') ||
|
70
74
|
(target_ruby_version >= 2.2 && RUBY_22_LOADED_FEATURES.include?(feature_name)) ||
|
71
|
-
(target_ruby_version >= 2.5 && feature_name == 'pp') ||
|
75
|
+
(target_ruby_version >= 2.5 && feature_name == 'pp' && !use_pretty_print_method?) ||
|
72
76
|
(target_ruby_version >= 2.7 && feature_name == 'ruby2_keywords') ||
|
73
77
|
(target_ruby_version >= 3.1 && feature_name == 'fiber') ||
|
74
78
|
(target_ruby_version >= 3.2 && feature_name == 'set')
|
75
79
|
end
|
76
80
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
81
|
+
|
82
|
+
def use_pretty_print_method?
|
83
|
+
processed_source.ast.each_descendant(:send).any? do |node|
|
84
|
+
PRETTY_PRINT_METHODS.include?(node.method_name)
|
85
|
+
end
|
86
|
+
end
|
77
87
|
end
|
78
88
|
end
|
79
89
|
end
|
@@ -167,9 +167,12 @@ module RuboCop
|
|
167
167
|
({block numblock} (send _ {:class_eval :instance_eval}) ...)
|
168
168
|
PATTERN
|
169
169
|
|
170
|
-
# @!method
|
171
|
-
def_node_matcher :
|
172
|
-
({block numblock}
|
170
|
+
# @!method class_constructor?(node)
|
171
|
+
def_node_matcher :class_constructor?, <<~PATTERN
|
172
|
+
({block numblock} {
|
173
|
+
(send (const {nil? cbase} {:Class :Module :Struct}) :new ...)
|
174
|
+
(send (const {nil? cbase} :Data) :define ...)
|
175
|
+
} ...)
|
173
176
|
PATTERN
|
174
177
|
|
175
178
|
def check_node(node)
|
@@ -270,7 +273,7 @@ module RuboCop
|
|
270
273
|
|
271
274
|
def eval_call?(child)
|
272
275
|
class_or_instance_eval?(child) ||
|
273
|
-
|
276
|
+
class_constructor?(child) ||
|
274
277
|
any_context_creating_methods?(child)
|
275
278
|
end
|
276
279
|
|
@@ -41,7 +41,7 @@ module RuboCop
|
|
41
41
|
MSG = 'Useless method definition detected.'
|
42
42
|
|
43
43
|
def on_def(node)
|
44
|
-
return if
|
44
|
+
return if use_rest_or_optional_args?(node)
|
45
45
|
return unless delegating?(node.body, node)
|
46
46
|
|
47
47
|
add_offense(node) { |corrector| corrector.remove(node) }
|
@@ -50,8 +50,8 @@ module RuboCop
|
|
50
50
|
|
51
51
|
private
|
52
52
|
|
53
|
-
def
|
54
|
-
node.arguments.any? { |arg| arg.optarg_type? || arg.kwoptarg_type? }
|
53
|
+
def use_rest_or_optional_args?(node)
|
54
|
+
node.arguments.any? { |arg| arg.restarg_type? || arg.optarg_type? || arg.kwoptarg_type? }
|
55
55
|
end
|
56
56
|
|
57
57
|
def delegating?(node, def_node)
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for useless `rescue`s, which only reraise rescued exceptions.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# def foo
|
11
|
+
# do_something
|
12
|
+
# rescue
|
13
|
+
# raise
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# def foo
|
18
|
+
# do_something
|
19
|
+
# rescue => e
|
20
|
+
# raise # or 'raise e', or 'raise $!', or 'raise $ERROR_INFO'
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# def foo
|
25
|
+
# do_something
|
26
|
+
# rescue
|
27
|
+
# do_cleanup
|
28
|
+
# raise
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# # bad (latest rescue)
|
32
|
+
# def foo
|
33
|
+
# do_something
|
34
|
+
# rescue ArgumentError
|
35
|
+
# # noop
|
36
|
+
# rescue
|
37
|
+
# raise
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # good (not the latest rescue)
|
41
|
+
# def foo
|
42
|
+
# do_something
|
43
|
+
# rescue ArgumentError
|
44
|
+
# raise
|
45
|
+
# rescue
|
46
|
+
# # noop
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
class UselessRescue < Base
|
50
|
+
MSG = 'Useless `rescue` detected.'
|
51
|
+
|
52
|
+
def on_rescue(node)
|
53
|
+
resbody_node = node.resbody_branches.last
|
54
|
+
add_offense(resbody_node) if only_reraising?(resbody_node)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def only_reraising?(resbody_node)
|
60
|
+
return false if use_exception_variable_in_ensure?(resbody_node)
|
61
|
+
|
62
|
+
body = resbody_node.body
|
63
|
+
return false if body.nil? || !body.send_type? || !body.method?(:raise)
|
64
|
+
return true unless body.arguments?
|
65
|
+
return false if body.arguments.size > 1
|
66
|
+
|
67
|
+
exception_name = body.first_argument.source
|
68
|
+
|
69
|
+
exception_objects(resbody_node).include?(exception_name)
|
70
|
+
end
|
71
|
+
|
72
|
+
def use_exception_variable_in_ensure?(resbody_node)
|
73
|
+
return false unless (exception_variable = resbody_node.exception_variable)
|
74
|
+
return false unless (ensure_node = resbody_node.each_ancestor(:ensure).first)
|
75
|
+
|
76
|
+
ensure_node.body.each_descendant(:lvar).map(&:source).include?(exception_variable.source)
|
77
|
+
end
|
78
|
+
|
79
|
+
def exception_objects(resbody_node)
|
80
|
+
[resbody_node.exception_variable&.source, '$!', '$ERROR_INFO']
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -98,7 +98,7 @@ module RuboCop
|
|
98
98
|
return unless node.parent
|
99
99
|
|
100
100
|
method_name = sym_node.value
|
101
|
-
definition = node
|
101
|
+
definition = find_method_definition(node, method_name)
|
102
102
|
|
103
103
|
return unless definition
|
104
104
|
return if allowed_arguments(definition.arguments)
|
@@ -106,6 +106,14 @@ module RuboCop
|
|
106
106
|
add_offense(node, message: format(MSG, method_name: method_name))
|
107
107
|
end
|
108
108
|
|
109
|
+
def find_method_definition(node, method_name)
|
110
|
+
node.each_ancestor.lazy.map do |ancestor|
|
111
|
+
ancestor.each_child_node(:def, :block, :numblock).find do |child|
|
112
|
+
method_definition(child, method_name)
|
113
|
+
end
|
114
|
+
end.find(&:itself)
|
115
|
+
end
|
116
|
+
|
109
117
|
# `ruby2_keywords` is only allowed if there's a `restarg` and no keyword arguments
|
110
118
|
def allowed_arguments(arguments)
|
111
119
|
return false if arguments.empty?
|
@@ -46,19 +46,23 @@ module RuboCop
|
|
46
46
|
LIT_MSG = 'Literal `%<lit>s` used in void context.'
|
47
47
|
SELF_MSG = '`self` used in void context.'
|
48
48
|
EXPRESSION_MSG = '`%<expression>s` used in void context.'
|
49
|
-
NONMUTATING_MSG = 'Method `#%<method>s` used in void context. Did you mean `#%<
|
49
|
+
NONMUTATING_MSG = 'Method `#%<method>s` used in void context. Did you mean `#%<suggest>s`?'
|
50
50
|
|
51
51
|
BINARY_OPERATORS = %i[* / % + - == === != < > <= >= <=>].freeze
|
52
52
|
UNARY_OPERATORS = %i[+@ -@ ~ !].freeze
|
53
53
|
OPERATORS = (BINARY_OPERATORS + UNARY_OPERATORS).freeze
|
54
54
|
VOID_CONTEXT_TYPES = %i[def for block].freeze
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
55
|
+
NONMUTATING_METHODS_WITH_BANG_VERSION = %i[capitalize chomp chop compact
|
56
|
+
delete_prefix delete_suffix downcase
|
57
|
+
encode flatten gsub lstrip merge next
|
58
|
+
reject reverse rotate rstrip scrub select
|
59
|
+
shuffle slice sort sort_by squeeze strip sub
|
60
|
+
succ swapcase tr tr_s transform_values
|
61
|
+
unicode_normalize uniq upcase].freeze
|
62
|
+
METHODS_REPLACABLE_BY_EACH = %i[collect map].freeze
|
63
|
+
|
64
|
+
NONMUTATING_METHODS = (NONMUTATING_METHODS_WITH_BANG_VERSION +
|
65
|
+
METHODS_REPLACABLE_BY_EACH).freeze
|
62
66
|
|
63
67
|
def on_block(node)
|
64
68
|
return unless node.body && !node.body.begin_type?
|
@@ -124,9 +128,14 @@ module RuboCop
|
|
124
128
|
end
|
125
129
|
|
126
130
|
def check_nonmutating(node)
|
127
|
-
return unless node.
|
131
|
+
return unless node.respond_to?(:method_name)
|
128
132
|
|
129
|
-
|
133
|
+
method_name = node.method_name
|
134
|
+
return unless NONMUTATING_METHODS.include?(method_name)
|
135
|
+
|
136
|
+
suggestion = METHODS_REPLACABLE_BY_EACH.include?(method_name) ? 'each' : "#{method_name}!"
|
137
|
+
add_offense(node,
|
138
|
+
message: format(NONMUTATING_MSG, method: method_name, suggest: suggestion))
|
130
139
|
end
|
131
140
|
|
132
141
|
def in_void_context?(node)
|
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
def on_block(node)
|
52
52
|
return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
|
53
53
|
return if method_receiver_excluded?(node)
|
54
|
-
return if node.class_constructor?
|
54
|
+
return if node.class_constructor?
|
55
55
|
|
56
56
|
check_code_length(node)
|
57
57
|
end
|
@@ -12,7 +12,7 @@ module RuboCop
|
|
12
12
|
#
|
13
13
|
# The maximum level of nesting allowed is configurable.
|
14
14
|
class BlockNesting < Base
|
15
|
-
NESTING_BLOCKS = %i[case if while while_post until until_post for resbody].freeze
|
15
|
+
NESTING_BLOCKS = %i[case case_match if while while_post until until_post for resbody].freeze
|
16
16
|
|
17
17
|
exclude_limit 'Max'
|
18
18
|
|
@@ -35,7 +35,7 @@ module RuboCop
|
|
35
35
|
|
36
36
|
MSG = 'Cyclomatic complexity for %<method>s is too high. [%<complexity>d/%<max>d]'
|
37
37
|
COUNTED_NODES = %i[if while until for csend block block_pass
|
38
|
-
rescue when and or or_asgn and_asgn].freeze
|
38
|
+
rescue when in_pattern and or or_asgn and_asgn].freeze
|
39
39
|
|
40
40
|
private
|
41
41
|
|