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
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
include Util
|
11
11
|
|
12
12
|
FOLDABLE_TYPES = %i[array hash heredoc send csend].freeze
|
13
|
-
CLASSLIKE_TYPES = %i[class module
|
13
|
+
CLASSLIKE_TYPES = %i[class module].freeze
|
14
14
|
private_constant :FOLDABLE_TYPES, :CLASSLIKE_TYPES
|
15
15
|
|
16
16
|
def initialize(node, processed_source, count_comments: false, foldable_types: [])
|
@@ -145,7 +145,7 @@ module RuboCop
|
|
145
145
|
|
146
146
|
def extract_body(node)
|
147
147
|
case node.type
|
148
|
-
when :class, :module, :block, :numblock, :def, :defs
|
148
|
+
when :class, :module, :sclass, :block, :numblock, :def, :defs
|
149
149
|
node.body
|
150
150
|
when :casgn
|
151
151
|
_scope, _name, value = *node
|
@@ -218,7 +218,7 @@ module RuboCop
|
|
218
218
|
|
219
219
|
# @api private
|
220
220
|
def already_on_multiple_lines?(node)
|
221
|
-
return node.first_line != node.
|
221
|
+
return node.first_line != node.last_argument.last_line if node.def_type?
|
222
222
|
|
223
223
|
!node.single_line?
|
224
224
|
end
|
@@ -62,25 +62,29 @@ module RuboCop
|
|
62
62
|
# Returns the end line of a node, which might be a comment and not part of the AST
|
63
63
|
# End line is considered either the line at which another node starts, or
|
64
64
|
# the line at which the parent node ends.
|
65
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
65
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
66
66
|
def find_end_line(node)
|
67
|
-
if node.if_type?
|
68
|
-
node.
|
69
|
-
|
70
|
-
node.
|
71
|
-
|
72
|
-
node.
|
67
|
+
if node.if_type?
|
68
|
+
if node.else?
|
69
|
+
node.loc.else.line
|
70
|
+
elsif node.ternary?
|
71
|
+
node.else_branch.loc.line
|
72
|
+
elsif node.elsif?
|
73
|
+
node.each_ancestor(:if).find(&:if?).loc.end.line
|
74
|
+
end
|
73
75
|
elsif node.block_type? || node.numblock_type?
|
74
76
|
node.loc.end.line
|
75
77
|
elsif (next_sibling = node.right_sibling) && next_sibling.is_a?(AST::Node)
|
76
78
|
next_sibling.loc.line
|
77
79
|
elsif (parent = node.parent)
|
78
|
-
parent.loc.respond_to?(:end) && parent.loc.end
|
79
|
-
|
80
|
-
|
81
|
-
|
80
|
+
if parent.loc.respond_to?(:end) && parent.loc.end
|
81
|
+
parent.loc.end.line
|
82
|
+
else
|
83
|
+
parent.loc.line
|
84
|
+
end
|
85
|
+
end || node.loc.end.line
|
82
86
|
end
|
83
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
87
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
84
88
|
end
|
85
89
|
end
|
86
90
|
end
|
@@ -48,18 +48,21 @@ module RuboCop
|
|
48
48
|
|
49
49
|
def register_offense(node, message, replacement) # rubocop:disable Metrics/AbcSize
|
50
50
|
add_offense(node.value, message: message) do |corrector|
|
51
|
-
if (def_node = def_node_that_require_parentheses(node))
|
52
|
-
last_argument = def_node.last_argument
|
53
|
-
if last_argument.nil? || !last_argument.hash_type?
|
54
|
-
next corrector.replace(node, replacement)
|
55
|
-
end
|
56
|
-
|
57
|
-
white_spaces = range_between(def_node.selector.end_pos,
|
58
|
-
def_node.first_argument.source_range.begin_pos)
|
59
|
-
corrector.replace(white_spaces, '(')
|
60
|
-
corrector.insert_after(last_argument, ')') if node == last_argument.pairs.last
|
61
|
-
end
|
62
51
|
corrector.replace(node, replacement)
|
52
|
+
|
53
|
+
next unless (def_node = def_node_that_require_parentheses(node))
|
54
|
+
|
55
|
+
last_argument = def_node.last_argument
|
56
|
+
if last_argument.nil? || !last_argument.hash_type?
|
57
|
+
next corrector.replace(node, replacement)
|
58
|
+
end
|
59
|
+
|
60
|
+
white_spaces = range_between(def_node.selector.end_pos,
|
61
|
+
def_node.first_argument.source_range.begin_pos)
|
62
|
+
next if node.parent.braces?
|
63
|
+
|
64
|
+
corrector.replace(white_spaces, '(')
|
65
|
+
corrector.insert_after(last_argument, ')') if node == last_argument.pairs.last
|
63
66
|
end
|
64
67
|
end
|
65
68
|
|
@@ -48,24 +48,32 @@ module RuboCop
|
|
48
48
|
MSG = 'Use %<style>s block forwarding.'
|
49
49
|
|
50
50
|
def self.autocorrect_incompatible_with
|
51
|
-
[Lint::AmbiguousOperator]
|
51
|
+
[Lint::AmbiguousOperator, Style::ArgumentsForwarding]
|
52
52
|
end
|
53
53
|
|
54
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
54
55
|
def on_def(node)
|
55
56
|
return if node.arguments.empty?
|
56
57
|
|
57
|
-
last_argument = node.
|
58
|
+
last_argument = node.last_argument
|
58
59
|
return if expected_block_forwarding_style?(node, last_argument)
|
59
60
|
|
60
|
-
|
61
|
-
|
61
|
+
invalid_syntax = false
|
62
62
|
node.each_descendant(:block_pass) do |block_pass_node|
|
63
63
|
next if block_pass_node.children.first&.sym_type? ||
|
64
64
|
last_argument.source != block_pass_node.source
|
65
65
|
|
66
|
+
if block_pass_node.each_ancestor(:block, :numblock).any?
|
67
|
+
invalid_syntax = true
|
68
|
+
next
|
69
|
+
end
|
70
|
+
|
66
71
|
register_offense(block_pass_node, node)
|
67
72
|
end
|
73
|
+
|
74
|
+
register_offense(last_argument, node) unless invalid_syntax
|
68
75
|
end
|
76
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
69
77
|
alias on_defs on_def
|
70
78
|
|
71
79
|
private
|
@@ -61,8 +61,7 @@ module RuboCop
|
|
61
61
|
end
|
62
62
|
|
63
63
|
def allowed_method_call_on_rhs?(node)
|
64
|
-
node&.send_type? &&
|
65
|
-
(node.receiver.nil? || !literal_receiver?(node))
|
64
|
+
node&.send_type? && (node.receiver.nil? || !literal_receiver?(node))
|
66
65
|
end
|
67
66
|
|
68
67
|
# @!method literal_receiver?(node)
|
@@ -203,7 +203,7 @@ module RuboCop
|
|
203
203
|
|
204
204
|
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
205
205
|
def on_defined?(node)
|
206
|
-
arg = node.
|
206
|
+
arg = node.first_argument
|
207
207
|
return false unless arg.ivar_type?
|
208
208
|
|
209
209
|
method_node, method_name = find_definition(node)
|
@@ -23,6 +23,7 @@ module RuboCop
|
|
23
23
|
# # bad
|
24
24
|
# open(something)
|
25
25
|
# open("| #{something}")
|
26
|
+
# open("| foo")
|
26
27
|
# URI.open(something)
|
27
28
|
#
|
28
29
|
# # good
|
@@ -32,7 +33,6 @@ module RuboCop
|
|
32
33
|
#
|
33
34
|
# # good (literal strings)
|
34
35
|
# open("foo.text")
|
35
|
-
# open("| foo")
|
36
36
|
# URI.open("http://example.com")
|
37
37
|
class Open < Base
|
38
38
|
MSG = 'The use of `%<receiver>sopen` is a serious security risk.'
|
@@ -40,7 +40,7 @@ module RuboCop
|
|
40
40
|
|
41
41
|
# @!method open?(node)
|
42
42
|
def_node_matcher :open?, <<~PATTERN
|
43
|
-
(send ${nil? (const {nil? cbase} :URI)} :open
|
43
|
+
(send ${nil? (const {nil? cbase} :URI)} :open $_ ...)
|
44
44
|
PATTERN
|
45
45
|
|
46
46
|
def on_send(node)
|
@@ -168,12 +168,12 @@ module RuboCop
|
|
168
168
|
|
169
169
|
def find_corresponding_def_node(node)
|
170
170
|
if access_modifier_with_symbol?(node)
|
171
|
-
method_name = node.
|
171
|
+
method_name = node.first_argument.value
|
172
172
|
node.parent.each_child_node(:def).find do |child|
|
173
173
|
child.method?(method_name)
|
174
174
|
end
|
175
175
|
else
|
176
|
-
node.
|
176
|
+
node.first_argument
|
177
177
|
end
|
178
178
|
end
|
179
179
|
|
@@ -12,7 +12,16 @@ module RuboCop
|
|
12
12
|
#
|
13
13
|
# This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
|
14
14
|
# replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
|
15
|
-
# by setting UseAnonymousForwarding: false
|
15
|
+
# by setting `UseAnonymousForwarding: false`.
|
16
|
+
#
|
17
|
+
# And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
|
18
|
+
# and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
|
19
|
+
# that are sufficient for anonymizing meaningless naming.
|
20
|
+
#
|
21
|
+
# Meaningless names that are commonly used can be anonymized by default:
|
22
|
+
# e.g., `*args`, `**options`, `&block`, and so on.
|
23
|
+
#
|
24
|
+
# Names not on this list are likely to be meaningful and are allowed by default.
|
16
25
|
#
|
17
26
|
# @example
|
18
27
|
# # bad
|
@@ -72,6 +81,38 @@ module RuboCop
|
|
72
81
|
# bar(**kwargs)
|
73
82
|
# end
|
74
83
|
#
|
84
|
+
# @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
|
85
|
+
# # bad
|
86
|
+
# def foo(*args)
|
87
|
+
# bar(*args)
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# # good
|
91
|
+
# def foo(*)
|
92
|
+
# bar(*)
|
93
|
+
# end
|
94
|
+
#
|
95
|
+
# @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
|
96
|
+
# # bad
|
97
|
+
# def foo(**kwargs)
|
98
|
+
# bar(**kwargs)
|
99
|
+
# end
|
100
|
+
#
|
101
|
+
# # good
|
102
|
+
# def foo(**)
|
103
|
+
# bar(**)
|
104
|
+
# end
|
105
|
+
#
|
106
|
+
# @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
|
107
|
+
# # bad
|
108
|
+
# def foo(&block)
|
109
|
+
# bar(&block)
|
110
|
+
# end
|
111
|
+
#
|
112
|
+
# # good
|
113
|
+
# def foo(&)
|
114
|
+
# bar(&)
|
115
|
+
# end
|
75
116
|
class ArgumentsForwarding < Base
|
76
117
|
include RangeHelp
|
77
118
|
extend AutoCorrector
|
@@ -85,17 +126,21 @@ module RuboCop
|
|
85
126
|
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
86
127
|
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
87
128
|
KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
|
129
|
+
BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
|
130
|
+
|
131
|
+
def self.autocorrect_incompatible_with
|
132
|
+
[Naming::BlockForwarding]
|
133
|
+
end
|
88
134
|
|
89
135
|
def on_def(node)
|
90
136
|
return unless node.body
|
91
137
|
|
92
|
-
|
138
|
+
restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
|
139
|
+
forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
140
|
+
send_nodes = node.each_descendant(:send).to_a
|
93
141
|
|
94
142
|
send_classifications = classify_send_nodes(
|
95
|
-
node,
|
96
|
-
node.each_descendant(:send).to_a,
|
97
|
-
non_splat_or_block_pass_lvar_references(node.body),
|
98
|
-
forwardable_args
|
143
|
+
node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
|
99
144
|
)
|
100
145
|
|
101
146
|
return if send_classifications.empty?
|
@@ -115,31 +160,54 @@ module RuboCop
|
|
115
160
|
[args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
|
116
161
|
end
|
117
162
|
|
163
|
+
def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
164
|
+
restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
|
165
|
+
kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
|
166
|
+
blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
|
167
|
+
|
168
|
+
[restarg_node, kwrestarg_node, blockarg_node]
|
169
|
+
end
|
170
|
+
|
118
171
|
def only_forwards_all?(send_classifications)
|
119
172
|
send_classifications.all? { |_, c, _, _| c == :all }
|
120
173
|
end
|
121
174
|
|
175
|
+
# rubocop:disable Metrics/MethodLength
|
122
176
|
def add_forward_all_offenses(node, send_classifications, forwardable_args)
|
123
|
-
|
124
|
-
|
177
|
+
_rest_arg, _kwrest_arg, block_arg = *forwardable_args
|
178
|
+
registered_block_arg_offense = false
|
179
|
+
|
180
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
181
|
+
if !forward_rest && !forward_kwrest && outside_block?(forward_block_arg)
|
182
|
+
register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
|
183
|
+
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
184
|
+
|
185
|
+
registered_block_arg_offense = true
|
186
|
+
break
|
187
|
+
else
|
188
|
+
register_forward_all_offense(send_node, send_node, forward_rest)
|
189
|
+
end
|
125
190
|
end
|
126
191
|
|
192
|
+
return if registered_block_arg_offense
|
193
|
+
|
127
194
|
rest_arg, _kwrest_arg, _block_arg = *forwardable_args
|
128
195
|
register_forward_all_offense(node, node.arguments, rest_arg)
|
129
196
|
end
|
197
|
+
# rubocop:enable Metrics/MethodLength
|
130
198
|
|
131
199
|
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
132
200
|
return unless use_anonymous_forwarding?
|
133
201
|
|
134
202
|
rest_arg, kwrest_arg, _block_arg = *forwardable_args
|
135
203
|
|
136
|
-
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest|
|
137
|
-
if forward_rest
|
204
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, _forward_block_arg| # rubocop:disable Layout/LineLength
|
205
|
+
if outside_block?(forward_rest)
|
138
206
|
register_forward_args_offense(def_node.arguments, rest_arg)
|
139
207
|
register_forward_args_offense(send_node, forward_rest)
|
140
208
|
end
|
141
209
|
|
142
|
-
if forward_kwrest
|
210
|
+
if outside_block?(forward_kwrest)
|
143
211
|
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
144
212
|
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
145
213
|
end
|
@@ -173,10 +241,7 @@ module RuboCop
|
|
173
241
|
|
174
242
|
def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
|
175
243
|
classifier = SendNodeClassifier.new(
|
176
|
-
def_node,
|
177
|
-
send_node,
|
178
|
-
referenced_lvars,
|
179
|
-
forwardable_args,
|
244
|
+
def_node, send_node, referenced_lvars, forwardable_args,
|
180
245
|
target_ruby_version: target_ruby_version,
|
181
246
|
allow_only_rest_arguments: allow_only_rest_arguments?
|
182
247
|
)
|
@@ -185,7 +250,28 @@ module RuboCop
|
|
185
250
|
|
186
251
|
return unless classification
|
187
252
|
|
188
|
-
[
|
253
|
+
[
|
254
|
+
classification,
|
255
|
+
classifier.forwarded_rest_arg,
|
256
|
+
classifier.forwarded_kwrest_arg,
|
257
|
+
classifier.forwarded_block_arg
|
258
|
+
]
|
259
|
+
end
|
260
|
+
|
261
|
+
def redundant_named_arg(arg, config_name, keyword)
|
262
|
+
return nil unless arg
|
263
|
+
|
264
|
+
redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
|
265
|
+
"#{keyword}#{redundant_arg_name}"
|
266
|
+
end << keyword
|
267
|
+
|
268
|
+
redundant_arg_names.include?(arg.source) ? arg : nil
|
269
|
+
end
|
270
|
+
|
271
|
+
def outside_block?(node)
|
272
|
+
return false unless node
|
273
|
+
|
274
|
+
node.each_ancestor(:block, :numblock).none?
|
189
275
|
end
|
190
276
|
|
191
277
|
def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
|
@@ -204,6 +290,16 @@ module RuboCop
|
|
204
290
|
end
|
205
291
|
end
|
206
292
|
|
293
|
+
def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
|
294
|
+
return if target_ruby_version <= 3.0
|
295
|
+
|
296
|
+
add_offense(block_arg, message: BLOCK_MSG) do |corrector|
|
297
|
+
add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
|
298
|
+
|
299
|
+
corrector.replace(block_arg, '&')
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
207
303
|
def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
|
208
304
|
arg_range = arguments_range(def_or_send, rest_or_splat)
|
209
305
|
|
@@ -278,7 +374,7 @@ module RuboCop
|
|
278
374
|
end
|
279
375
|
|
280
376
|
def classification
|
281
|
-
return nil unless forwarded_rest_arg || forwarded_kwrest_arg
|
377
|
+
return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
|
282
378
|
|
283
379
|
if can_forward_all?
|
284
380
|
:all
|
@@ -362,9 +458,16 @@ module RuboCop
|
|
362
458
|
def no_additional_args?
|
363
459
|
forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
|
364
460
|
|
461
|
+
return false if missing_rest_arg_or_kwrest_arg?
|
462
|
+
|
365
463
|
@def_node.arguments.size == forwardable_count &&
|
366
464
|
@send_node.arguments.size == forwardable_count
|
367
465
|
end
|
466
|
+
|
467
|
+
def missing_rest_arg_or_kwrest_arg?
|
468
|
+
(@rest_arg_name && !forwarded_rest_arg) ||
|
469
|
+
(@kwrest_arg_name && !forwarded_kwrest_arg)
|
470
|
+
end
|
368
471
|
end
|
369
472
|
end
|
370
473
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
|
7
|
+
# them to use `arr.first` and `arr.last` instead.
|
8
|
+
#
|
9
|
+
# The cop is disabled by default due to safety concerns.
|
10
|
+
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because `[0]` or `[-1]` can be called on a Hash,
|
13
|
+
# which returns a value for `0` or `-1` key, but changing these to use
|
14
|
+
# `.first` or `.last` will return first/last tuple instead. Also, String
|
15
|
+
# does not implement `first`/`last` methods.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# arr[0]
|
20
|
+
# arr[-1]
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# arr.first
|
24
|
+
# arr.last
|
25
|
+
# arr[0] = 2
|
26
|
+
# arr[0][-2]
|
27
|
+
#
|
28
|
+
class ArrayFirstLast < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
31
|
+
MSG = 'Use `%<preferred>s`.'
|
32
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
33
|
+
|
34
|
+
# rubocop:disable Metrics/AbcSize
|
35
|
+
def on_send(node)
|
36
|
+
return unless node.arguments.size == 1 && node.first_argument.int_type?
|
37
|
+
|
38
|
+
value = node.first_argument.value
|
39
|
+
return unless [0, -1].include?(value)
|
40
|
+
|
41
|
+
node = innermost_braces_node(node)
|
42
|
+
return if node.parent && brace_method?(node.parent)
|
43
|
+
|
44
|
+
preferred = (value.zero? ? 'first' : 'last')
|
45
|
+
add_offense(node.loc.selector, message: format(MSG, preferred: preferred)) do |corrector|
|
46
|
+
corrector.replace(node.loc.selector, ".#{preferred}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# rubocop:enable Metrics/AbcSize
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def innermost_braces_node(node)
|
54
|
+
node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
|
55
|
+
node
|
56
|
+
end
|
57
|
+
|
58
|
+
def brace_method?(node)
|
59
|
+
node.send_type? && (node.method?(:[]) || node.method?(:[]=))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -16,31 +16,38 @@ module RuboCop
|
|
16
16
|
# File.open('file') do |f|
|
17
17
|
# # ...
|
18
18
|
# end
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# f = Tempfile.open('temp')
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# Tempfile.open('temp') do |f|
|
25
|
+
# # ...
|
26
|
+
# end
|
19
27
|
class AutoResourceCleanup < Base
|
20
|
-
MSG = 'Use the block version of `%<
|
21
|
-
|
22
|
-
TARGET_METHODS = { File: :open }.freeze
|
28
|
+
MSG = 'Use the block version of `%<current>s`.'
|
29
|
+
RESTRICT_ON_SEND = %i[open].freeze
|
23
30
|
|
24
|
-
|
31
|
+
# @!method file_open_method?(node)
|
32
|
+
def_node_matcher :file_open_method?, <<~PATTERN
|
33
|
+
(send (const {nil? cbase} {:File :Tempfile}) :open ...)
|
34
|
+
PATTERN
|
25
35
|
|
26
36
|
def on_send(node)
|
27
|
-
|
28
|
-
next if node.method_name != target_method
|
37
|
+
return if !file_open_method?(node) || cleanup?(node)
|
29
38
|
|
30
|
-
|
31
|
-
next if node.receiver != target_receiver
|
39
|
+
current = node.receiver.source_range.begin.join(node.selector.end).source
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
add_offense(node, message: format(MSG, class: target_class, method: target_method))
|
36
|
-
end
|
41
|
+
add_offense(node, message: format(MSG, current: current))
|
37
42
|
end
|
38
43
|
|
39
44
|
private
|
40
45
|
|
41
46
|
def cleanup?(node)
|
42
|
-
|
43
|
-
|
47
|
+
return true if node.block_argument?
|
48
|
+
return false unless (parent = node.parent)
|
49
|
+
|
50
|
+
parent.block_type? || !parent.lvasgn_type?
|
44
51
|
end
|
45
52
|
end
|
46
53
|
end
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
def on_class(class_node)
|
34
34
|
@macros_to_rewrite[class_node] = Set.new
|
35
35
|
|
36
|
-
find_macros(class_node.body).
|
36
|
+
find_macros(class_node.body).each_value do |macros|
|
37
37
|
bisected = find_bisection(macros)
|
38
38
|
next unless bisected.any?
|
39
39
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
def find_macros(class_def)
|
75
75
|
# Find all the macros (`attr_reader`, `attr_writer`, etc.) in the class body
|
76
76
|
# and turn them into `Macro` objects so that they can be processed.
|
77
|
-
return
|
77
|
+
return {} if !class_def || class_def.def_type?
|
78
78
|
|
79
79
|
send_nodes =
|
80
80
|
if class_def.send_type?
|
@@ -125,7 +125,7 @@ module RuboCop
|
|
125
125
|
when :==, :eql?, :equal?
|
126
126
|
find_target_in_equality_node(node)
|
127
127
|
when :===
|
128
|
-
node.
|
128
|
+
node.first_argument
|
129
129
|
when :include?, :cover?
|
130
130
|
find_target_in_include_or_cover_node(node)
|
131
131
|
when :match, :match?, :=~
|
@@ -134,7 +134,7 @@ module RuboCop
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def find_target_in_equality_node(node)
|
137
|
-
argument = node.
|
137
|
+
argument = node.first_argument
|
138
138
|
receiver = node.receiver
|
139
139
|
return unless argument && receiver
|
140
140
|
|
@@ -152,7 +152,7 @@ module RuboCop
|
|
152
152
|
end
|
153
153
|
|
154
154
|
def find_target_in_match_node(node)
|
155
|
-
argument = node.
|
155
|
+
argument = node.first_argument
|
156
156
|
receiver = node.receiver
|
157
157
|
return unless receiver
|
158
158
|
|
@@ -185,7 +185,7 @@ module RuboCop
|
|
185
185
|
def condition_from_send_node(node, target)
|
186
186
|
case node.method_name
|
187
187
|
when :is_a?
|
188
|
-
node.
|
188
|
+
node.first_argument if node.receiver == target
|
189
189
|
when :==, :eql?, :equal?
|
190
190
|
condition_from_equality_node(node, target)
|
191
191
|
when :=~, :match, :match?
|
@@ -8,6 +8,11 @@ module RuboCop
|
|
8
8
|
# `==`, `equal?`, and `eql?` custom method definitions are allowed by default.
|
9
9
|
# These are customizable with `AllowedMethods` option.
|
10
10
|
#
|
11
|
+
# @safety
|
12
|
+
# This cop's autocorrection is unsafe because there is no guarantee that
|
13
|
+
# the constant `Foo` exists when autocorrecting `var.class.name == 'Foo'` to
|
14
|
+
# `var.instance_of?(Foo)`.
|
15
|
+
#
|
11
16
|
# @example
|
12
17
|
# # bad
|
13
18
|
# var.class == Date
|