rubocop 1.53.1 → 1.57.2
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 +3 -1
- data/config/default.yml +34 -8
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +10 -5
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config_finder.rb +2 -2
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +3 -1
- data/lib/rubocop/cop/base.rb +1 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
- data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
- data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
- data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +42 -21
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
- data/lib/rubocop/cop/layout/dot_position.rb +1 -5
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +26 -3
- data/lib/rubocop/cop/layout/end_alignment.rb +7 -1
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +3 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
- data/lib/rubocop/cop/layout/redundant_line_break.rb +13 -3
- data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_operators.rb +3 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
- data/lib/rubocop/cop/lint/debugger.rb +17 -4
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +3 -1
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +10 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +20 -4
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +11 -4
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +5 -3
- data/lib/rubocop/cop/lint/useless_assignment.rb +38 -12
- data/lib/rubocop/cop/lint/void.rb +32 -20
- 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/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
- data/lib/rubocop/cop/mixin/comments_help.rb +16 -12
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
- data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -2
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +5 -7
- data/lib/rubocop/cop/mixin/string_help.rb +4 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +1 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
- data/lib/rubocop/cop/style/alias.rb +9 -8
- data/lib/rubocop/cop/style/arguments_forwarding.rb +280 -63
- data/lib/rubocop/cop/style/array_intersect.rb +13 -5
- data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
- data/lib/rubocop/cop/style/class_equality_comparison.rb +7 -0
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +4 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
- data/lib/rubocop/cop/style/for.rb +1 -1
- data/lib/rubocop/cop/style/format_string.rb +24 -3
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
- data/lib/rubocop/cop/style/guard_clause.rb +26 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +25 -3
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
- data/lib/rubocop/cop/style/lambda.rb +3 -3
- data/lib/rubocop/cop/style/lambda_call.rb +5 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +8 -1
- data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +1 -1
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +6 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +6 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +9 -1
- data/lib/rubocop/cop/style/redundant_conditional.rb +1 -9
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
- data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +22 -5
- data/lib/rubocop/cop/style/redundant_parentheses.rb +41 -15
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -1
- data/lib/rubocop/cop/style/redundant_return.rb +7 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +5 -0
- data/lib/rubocop/cop/style/return_nil.rb +6 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +23 -9
- data/lib/rubocop/cop/style/semicolon.rb +0 -3
- data/lib/rubocop/cop/style/single_argument_dig.rb +2 -1
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
- data/lib/rubocop/cop/style/symbol_array.rb +35 -15
- data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
- data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
- data/lib/rubocop/cop/utils/regexp_ranges.rb +26 -13
- data/lib/rubocop/cop/variable_force/assignment.rb +14 -5
- data/lib/rubocop/file_finder.rb +4 -7
- data/lib/rubocop/formatter/html_formatter.rb +4 -2
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +41 -18
- data/lib/rubocop/lsp/runtime.rb +22 -2
- data/lib/rubocop/lsp/server.rb +10 -4
- data/lib/rubocop/magic_comment.rb +12 -10
- data/lib/rubocop/result_cache.rb +4 -0
- data/lib/rubocop/rspec/shared_contexts.rb +2 -3
- data/lib/rubocop/runner.rb +5 -3
- data/lib/rubocop/server/cache.rb +1 -0
- data/lib/rubocop/server/client_command/exec.rb +1 -1
- data/lib/rubocop/string_interpreter.rb +3 -3
- data/lib/rubocop/target_finder.rb +7 -3
- data/lib/rubocop/target_ruby.rb +9 -5
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +2 -0
- metadata +16 -14
@@ -4,8 +4,12 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Lint
|
6
6
|
# Checks for redundant safe navigation calls.
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# Use cases where a constant, named in camel case for classes and modules is `nil` are rare,
|
8
|
+
# and an offense is not detected when the receiver is a snake case constant.
|
9
|
+
#
|
10
|
+
# For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
|
11
|
+
# and `equal?` methods are checked by default.
|
12
|
+
# These are customizable with `AllowedMethods` option.
|
9
13
|
#
|
10
14
|
# The `AllowedMethods` option specifies nil-safe methods,
|
11
15
|
# in other words, it is a method that is allowed to skip safe navigation.
|
@@ -22,6 +26,9 @@ module RuboCop
|
|
22
26
|
#
|
23
27
|
# @example
|
24
28
|
# # bad
|
29
|
+
# CamelCaseConst&.do_something
|
30
|
+
#
|
31
|
+
# # bad
|
25
32
|
# do_something if attrs&.respond_to?(:[])
|
26
33
|
#
|
27
34
|
# # good
|
@@ -33,6 +40,9 @@ module RuboCop
|
|
33
40
|
# end
|
34
41
|
#
|
35
42
|
# # good
|
43
|
+
# CamelCaseConst.do_something
|
44
|
+
#
|
45
|
+
# # good
|
36
46
|
# while node.is_a?(BeginNode)
|
37
47
|
# node = node.parent
|
38
48
|
# end
|
@@ -57,18 +67,24 @@ module RuboCop
|
|
57
67
|
|
58
68
|
NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
|
59
69
|
|
70
|
+
SNAKE_CASE = /\A[[:digit:][:upper:]_]+\z/.freeze
|
71
|
+
|
60
72
|
# @!method respond_to_nil_specific_method?(node)
|
61
73
|
def_node_matcher :respond_to_nil_specific_method?, <<~PATTERN
|
62
74
|
(csend _ :respond_to? (sym %NIL_SPECIFIC_METHODS))
|
63
75
|
PATTERN
|
64
76
|
|
77
|
+
# rubocop:disable Metrics/AbcSize
|
65
78
|
def on_csend(node)
|
66
|
-
|
67
|
-
|
79
|
+
unless node.receiver.const_type? && !node.receiver.source.match?(SNAKE_CASE)
|
80
|
+
return unless check?(node) && allowed_method?(node.method_name)
|
81
|
+
return if respond_to_nil_specific_method?(node)
|
82
|
+
end
|
68
83
|
|
69
84
|
range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos)
|
70
85
|
add_offense(range) { |corrector| corrector.replace(node.loc.dot, '.') }
|
71
86
|
end
|
87
|
+
# rubocop:enable Metrics/AbcSize
|
72
88
|
|
73
89
|
private
|
74
90
|
|
@@ -82,16 +82,23 @@ module RuboCop
|
|
82
82
|
def autocorrect(corrector, offense_range:, send_node:)
|
83
83
|
corrector.replace(
|
84
84
|
offense_range,
|
85
|
-
add_safe_navigation_operator(
|
86
|
-
offense_range: offense_range,
|
87
|
-
send_node: send_node
|
88
|
-
)
|
85
|
+
add_safe_navigation_operator(offense_range: offense_range, send_node: send_node)
|
89
86
|
)
|
87
|
+
|
88
|
+
corrector.wrap(send_node, '(', ')') if require_parentheses?(send_node)
|
90
89
|
end
|
91
90
|
|
92
91
|
def brackets?(send_node)
|
93
92
|
send_node.method?(:[]) || send_node.method?(:[]=)
|
94
93
|
end
|
94
|
+
|
95
|
+
def require_parentheses?(send_node)
|
96
|
+
return false unless send_node.comparison_method?
|
97
|
+
return false unless (node = send_node.parent)
|
98
|
+
|
99
|
+
(node.respond_to?(:logical_operator?) && node.logical_operator?) ||
|
100
|
+
(node.respond_to?(:comparison_method?) && node.comparison_method?)
|
101
|
+
end
|
95
102
|
end
|
96
103
|
end
|
97
104
|
end
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
68
68
|
|
69
69
|
def same_conditions_node_different_branch?(variable, outer_local_variable)
|
70
70
|
variable_node = variable_node(variable)
|
71
|
-
return false unless variable_node
|
71
|
+
return false unless node_or_its_ascendant_conditional?(variable_node)
|
72
72
|
|
73
73
|
outer_local_variable_node =
|
74
74
|
find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
|
@@ -96,6 +96,12 @@ module RuboCop
|
|
96
96
|
|
97
97
|
find_conditional_node_from_ascendant(parent)
|
98
98
|
end
|
99
|
+
|
100
|
+
def node_or_its_ascendant_conditional?(node)
|
101
|
+
return true if node.conditional?
|
102
|
+
|
103
|
+
!!find_conditional_node_from_ascendant(node)
|
104
|
+
end
|
99
105
|
end
|
100
106
|
end
|
101
107
|
end
|
@@ -32,25 +32,25 @@ module RuboCop
|
|
32
32
|
# @!method struct_new(node)
|
33
33
|
def_node_matcher :struct_new, <<~PATTERN
|
34
34
|
(send
|
35
|
-
(const
|
35
|
+
(const {nil? cbase} :Struct) :new ...)
|
36
36
|
PATTERN
|
37
37
|
|
38
38
|
def on_send(node)
|
39
|
-
return unless struct_new(node)
|
40
|
-
node.arguments.each_with_index do |arg, index|
|
41
|
-
# Ignore if the first argument is a class name
|
42
|
-
next if index.zero? && arg.str_type?
|
39
|
+
return unless struct_new(node)
|
43
40
|
|
44
|
-
|
45
|
-
|
41
|
+
node.arguments.each_with_index do |arg, index|
|
42
|
+
# Ignore if the first argument is a class name
|
43
|
+
next if index.zero? && arg.str_type?
|
46
44
|
|
47
|
-
|
45
|
+
# Ignore if the argument is not a member name
|
46
|
+
next unless STRUCT_MEMBER_NAME_TYPES.include?(arg.type)
|
48
47
|
|
49
|
-
|
48
|
+
member_name = arg.value
|
50
49
|
|
51
|
-
|
52
|
-
|
53
|
-
|
50
|
+
next unless STRUCT_METHOD_NAMES.include?(member_name.to_sym)
|
51
|
+
|
52
|
+
message = format(MSG, member_name: member_name.inspect, method_name: member_name.to_s)
|
53
|
+
add_offense(arg, message: message)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
@@ -119,7 +119,7 @@ module RuboCop
|
|
119
119
|
ancestor = node.each_ancestor(:kwbegin, :def, :defs, :block, :numblock).first
|
120
120
|
return false unless ancestor
|
121
121
|
|
122
|
-
end_line = ancestor.loc.end.
|
122
|
+
end_line = ancestor.loc.end&.line || ancestor.loc.last_line
|
123
123
|
processed_source[node.first_line...end_line].any? { |line| comment_line?(line) }
|
124
124
|
end
|
125
125
|
|
@@ -74,7 +74,7 @@ module RuboCop
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
77
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
78
78
|
def argument_match?(send_arg, def_arg)
|
79
79
|
def_arg_name = def_arg.children[0]
|
80
80
|
|
@@ -87,12 +87,14 @@ module RuboCop
|
|
87
87
|
send_arg.hash_type? &&
|
88
88
|
send_arg.pairs.any? { |pair| passing_keyword_arg?(pair, def_arg_name) }
|
89
89
|
when :kwrestarg
|
90
|
-
send_arg.each_child_node(:kwsplat).any?
|
90
|
+
send_arg.each_child_node(:kwsplat, :forwarded_kwrestarg).any? do |child|
|
91
|
+
child.source == def_arg.source
|
92
|
+
end
|
91
93
|
when :forward_arg
|
92
94
|
send_arg.forwarded_args_type?
|
93
95
|
end
|
94
96
|
end
|
95
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
97
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
96
98
|
end
|
97
99
|
end
|
98
100
|
end
|
@@ -7,12 +7,18 @@ module RuboCop
|
|
7
7
|
# scope.
|
8
8
|
# The basic idea for this cop was from the warning of `ruby -cw`:
|
9
9
|
#
|
10
|
-
#
|
10
|
+
# [source,console]
|
11
|
+
# ----
|
12
|
+
# assigned but unused variable - foo
|
13
|
+
# ----
|
11
14
|
#
|
12
15
|
# Currently this cop has advanced logic that detects unreferenced
|
13
16
|
# reassignments and properly handles varied cases such as branch, loop,
|
14
17
|
# rescue, ensure, etc.
|
15
18
|
#
|
19
|
+
# NOTE: Given the assignment `foo = 1, bar = 2`, removing unused variables
|
20
|
+
# can lead to a syntax error, so this case is not autocorrected.
|
21
|
+
#
|
16
22
|
# @safety
|
17
23
|
# This cop's autocorrection is unsafe because removing assignment from
|
18
24
|
# operator assignment can cause NameError if this assignment has been used to declare
|
@@ -51,25 +57,24 @@ module RuboCop
|
|
51
57
|
scope.variables.each_value { |variable| check_for_unused_assignments(variable) }
|
52
58
|
end
|
53
59
|
|
60
|
+
# rubocop:disable Metrics/AbcSize
|
54
61
|
def check_for_unused_assignments(variable)
|
55
62
|
return if variable.should_be_unused?
|
56
63
|
|
57
64
|
variable.assignments.each do |assignment|
|
58
|
-
next if assignment.used?
|
65
|
+
next if assignment.used? || part_of_ignored_node?(assignment.node)
|
59
66
|
|
60
67
|
message = message_for_useless_assignment(assignment)
|
68
|
+
range = offense_range(assignment)
|
61
69
|
|
62
|
-
|
63
|
-
|
64
|
-
else
|
65
|
-
assignment.node.loc.name
|
66
|
-
end
|
67
|
-
|
68
|
-
add_offense(location, message: message) do |corrector|
|
69
|
-
autocorrect(corrector, assignment)
|
70
|
+
add_offense(range, message: message) do |corrector|
|
71
|
+
autocorrect(corrector, assignment) unless sequential_assignment?(assignment.node)
|
70
72
|
end
|
73
|
+
|
74
|
+
ignore_node(assignment.node) if chained_assignment?(assignment.node)
|
71
75
|
end
|
72
76
|
end
|
77
|
+
# rubocop:enable Metrics/AbcSize
|
73
78
|
|
74
79
|
def message_for_useless_assignment(assignment)
|
75
80
|
variable = assignment.variable
|
@@ -77,6 +82,28 @@ module RuboCop
|
|
77
82
|
format(MSG, variable: variable.name) + message_specification(assignment, variable).to_s
|
78
83
|
end
|
79
84
|
|
85
|
+
def offense_range(assignment)
|
86
|
+
if assignment.regexp_named_capture?
|
87
|
+
assignment.node.children.first.source_range
|
88
|
+
else
|
89
|
+
assignment.node.loc.name
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def sequential_assignment?(node)
|
94
|
+
if node.lvasgn_type? && node.expression&.array_type? &&
|
95
|
+
node.each_descendant.any?(&:assignment?)
|
96
|
+
return true
|
97
|
+
end
|
98
|
+
return false unless node.parent
|
99
|
+
|
100
|
+
sequential_assignment?(node.parent)
|
101
|
+
end
|
102
|
+
|
103
|
+
def chained_assignment?(node)
|
104
|
+
node.respond_to?(:expression) && node.expression&.lvasgn_type?
|
105
|
+
end
|
106
|
+
|
80
107
|
def message_specification(assignment, variable)
|
81
108
|
if assignment.multiple_assignment?
|
82
109
|
multiple_assignment_message(variable.name)
|
@@ -96,8 +123,7 @@ module RuboCop
|
|
96
123
|
return_value_node = return_value_node_of_scope(scope)
|
97
124
|
return unless assignment.meta_assignment_node.equal?(return_value_node)
|
98
125
|
|
99
|
-
" Use `#{assignment.operator.
|
100
|
-
"instead of `#{assignment.operator}`."
|
126
|
+
" Use `#{assignment.operator.delete_suffix('=')}` instead of `#{assignment.operator}`."
|
101
127
|
end
|
102
128
|
|
103
129
|
def similar_name_message(variable)
|
@@ -6,6 +6,16 @@ module RuboCop
|
|
6
6
|
# Checks for operators, variables, literals, lambda, proc and nonmutating
|
7
7
|
# methods used in void context.
|
8
8
|
#
|
9
|
+
# `each` blocks are allowed to prevent false positives.
|
10
|
+
# For example, the expression inside the `each` block below.
|
11
|
+
# It's not void, especially when the receiver is an `Enumerator`:
|
12
|
+
#
|
13
|
+
# [source,ruby]
|
14
|
+
# ----
|
15
|
+
# enumerator = [1, 2, 3].filter
|
16
|
+
# enumerator.each { |item| item >= 2 } #=> [2, 3]
|
17
|
+
# ----
|
18
|
+
#
|
9
19
|
# @example CheckForMethodsWithNoSideEffects: false (default)
|
10
20
|
# # bad
|
11
21
|
# def some_method
|
@@ -47,6 +57,7 @@ module RuboCop
|
|
47
57
|
|
48
58
|
OP_MSG = 'Operator `%<op>s` used in void context.'
|
49
59
|
VAR_MSG = 'Variable `%<var>s` used in void context.'
|
60
|
+
CONST_MSG = 'Constant `%<var>s` used in void context.'
|
50
61
|
LIT_MSG = 'Literal `%<lit>s` used in void context.'
|
51
62
|
SELF_MSG = '`self` used in void context.'
|
52
63
|
EXPRESSION_MSG = '`%<expression>s` used in void context.'
|
@@ -72,6 +83,7 @@ module RuboCop
|
|
72
83
|
return unless node.body && !node.body.begin_type?
|
73
84
|
return unless in_void_context?(node.body)
|
74
85
|
|
86
|
+
check_void_op(node.body) { node.method?(:each) }
|
75
87
|
check_expression(node.body)
|
76
88
|
end
|
77
89
|
|
@@ -87,11 +99,13 @@ module RuboCop
|
|
87
99
|
def check_begin(node)
|
88
100
|
expressions = *node
|
89
101
|
expressions.pop unless in_void_context?(node)
|
90
|
-
expressions.each
|
102
|
+
expressions.each do |expr|
|
103
|
+
check_void_op(expr)
|
104
|
+
check_expression(expr)
|
105
|
+
end
|
91
106
|
end
|
92
107
|
|
93
108
|
def check_expression(expr)
|
94
|
-
check_void_op(expr)
|
95
109
|
check_literal(expr)
|
96
110
|
check_var(expr)
|
97
111
|
check_self(expr)
|
@@ -101,8 +115,9 @@ module RuboCop
|
|
101
115
|
check_nonmutating(expr)
|
102
116
|
end
|
103
117
|
|
104
|
-
def check_void_op(node)
|
118
|
+
def check_void_op(node, &block)
|
105
119
|
return unless node.send_type? && OPERATORS.include?(node.method_name)
|
120
|
+
return if block && yield(node)
|
106
121
|
|
107
122
|
add_offense(node.loc.selector,
|
108
123
|
message: format(OP_MSG, op: node.method_name)) do |corrector|
|
@@ -113,9 +128,18 @@ module RuboCop
|
|
113
128
|
def check_var(node)
|
114
129
|
return unless node.variable? || node.const_type?
|
115
130
|
|
116
|
-
|
117
|
-
|
118
|
-
|
131
|
+
if node.const_type?
|
132
|
+
template = node.special_keyword? ? VAR_MSG : CONST_MSG
|
133
|
+
|
134
|
+
offense_range = node
|
135
|
+
message = format(template, var: node.source)
|
136
|
+
else
|
137
|
+
offense_range = node.loc.name
|
138
|
+
message = format(VAR_MSG, var: node.loc.name.source)
|
139
|
+
end
|
140
|
+
|
141
|
+
add_offense(offense_range, message: message) do |corrector|
|
142
|
+
autocorrect_void_expression(corrector, node)
|
119
143
|
end
|
120
144
|
end
|
121
145
|
|
@@ -123,7 +147,7 @@ module RuboCop
|
|
123
147
|
return if !node.literal? || node.xstr_type? || node.range_type?
|
124
148
|
|
125
149
|
add_offense(node, message: format(LIT_MSG, lit: node.source)) do |corrector|
|
126
|
-
|
150
|
+
autocorrect_void_expression(corrector, node)
|
127
151
|
end
|
128
152
|
end
|
129
153
|
|
@@ -131,7 +155,7 @@ module RuboCop
|
|
131
155
|
return unless node.self_type?
|
132
156
|
|
133
157
|
add_offense(node, message: SELF_MSG) do |corrector|
|
134
|
-
|
158
|
+
autocorrect_void_expression(corrector, node)
|
135
159
|
end
|
136
160
|
end
|
137
161
|
|
@@ -181,18 +205,6 @@ module RuboCop
|
|
181
205
|
end
|
182
206
|
end
|
183
207
|
|
184
|
-
def autocorrect_void_var(corrector, node)
|
185
|
-
corrector.remove(range_with_surrounding_space(range: node.loc.name, side: :left))
|
186
|
-
end
|
187
|
-
|
188
|
-
def autocorrect_void_literal(corrector, node)
|
189
|
-
corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
|
190
|
-
end
|
191
|
-
|
192
|
-
def autocorrect_void_self(corrector, node)
|
193
|
-
corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
|
194
|
-
end
|
195
|
-
|
196
208
|
def autocorrect_void_expression(corrector, node)
|
197
209
|
corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
|
198
210
|
end
|
@@ -12,6 +12,7 @@ module RuboCop
|
|
12
12
|
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
13
13
|
# will be counted as one line regardless of its actual size.
|
14
14
|
#
|
15
|
+
# NOTE: This cop does not apply for `Struct` definitions.
|
15
16
|
#
|
16
17
|
# NOTE: The `ExcludedMethods` configuration is deprecated and only kept
|
17
18
|
# for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns`
|
@@ -40,7 +41,6 @@ module RuboCop
|
|
40
41
|
# )
|
41
42
|
# end # 6 points
|
42
43
|
#
|
43
|
-
# NOTE: This cop does not apply for `Struct` definitions.
|
44
44
|
class BlockLength < Base
|
45
45
|
include CodeLength
|
46
46
|
include AllowedMethods
|
@@ -11,6 +11,8 @@ module RuboCop
|
|
11
11
|
# Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct
|
12
12
|
# will be counted as one line regardless of its actual size.
|
13
13
|
#
|
14
|
+
# NOTE: This cop also applies for `Struct` definitions.
|
15
|
+
#
|
14
16
|
# @example CountAsOne: ['array', 'heredoc', 'method_call']
|
15
17
|
#
|
16
18
|
# class Foo
|
@@ -34,15 +36,18 @@ module RuboCop
|
|
34
36
|
# )
|
35
37
|
# end # 6 points
|
36
38
|
#
|
37
|
-
#
|
38
|
-
# NOTE: This cop also applies for `Struct` definitions.
|
39
39
|
class ClassLength < Base
|
40
40
|
include CodeLength
|
41
41
|
|
42
42
|
def on_class(node)
|
43
43
|
check_code_length(node)
|
44
44
|
end
|
45
|
-
|
45
|
+
|
46
|
+
def on_sclass(node)
|
47
|
+
return if node.each_ancestor(:class).any?
|
48
|
+
|
49
|
+
on_class(node)
|
50
|
+
end
|
46
51
|
|
47
52
|
def on_casgn(node)
|
48
53
|
parent = node.parent
|
@@ -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: [])
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
63
63
|
types
|
64
64
|
end
|
65
65
|
|
66
|
-
def code_length(node)
|
66
|
+
def code_length(node) # rubocop:disable Metrics/MethodLength
|
67
67
|
if classlike_node?(node)
|
68
68
|
classlike_code_length(node)
|
69
69
|
elsif heredoc_node?(node)
|
@@ -72,7 +72,14 @@ module RuboCop
|
|
72
72
|
body = extract_body(node)
|
73
73
|
return 0 unless body
|
74
74
|
|
75
|
-
|
75
|
+
source =
|
76
|
+
if node_with_heredoc?(body)
|
77
|
+
source_from_node_with_heredoc(body)
|
78
|
+
else
|
79
|
+
body.source.lines
|
80
|
+
end
|
81
|
+
|
82
|
+
source.count { |line| !irrelevant_line?(line) }
|
76
83
|
end
|
77
84
|
end
|
78
85
|
|
@@ -138,7 +145,7 @@ module RuboCop
|
|
138
145
|
|
139
146
|
def extract_body(node)
|
140
147
|
case node.type
|
141
|
-
when :class, :module, :block, :numblock, :def, :defs
|
148
|
+
when :class, :module, :sclass, :block, :numblock, :def, :defs
|
142
149
|
node.body
|
143
150
|
when :casgn
|
144
151
|
_scope, _name, value = *node
|
@@ -175,6 +182,27 @@ module RuboCop
|
|
175
182
|
def another_args?(node)
|
176
183
|
node.call_type? && node.arguments.count > 1
|
177
184
|
end
|
185
|
+
|
186
|
+
def node_with_heredoc?(node)
|
187
|
+
node.each_descendant(:str, :dstr).any? { |descendant| heredoc_node?(descendant) }
|
188
|
+
end
|
189
|
+
|
190
|
+
def source_from_node_with_heredoc(node)
|
191
|
+
last_line = -1
|
192
|
+
node.each_descendant do |descendant|
|
193
|
+
next unless descendant.source
|
194
|
+
|
195
|
+
descendant_last_line =
|
196
|
+
if heredoc_node?(descendant)
|
197
|
+
descendant.loc.heredoc_end.line
|
198
|
+
else
|
199
|
+
descendant.last_line
|
200
|
+
end
|
201
|
+
|
202
|
+
last_line = [last_line, descendant_last_line].max
|
203
|
+
end
|
204
|
+
@processed_source[(node.first_line - 1)..(last_line - 1)]
|
205
|
+
end
|
178
206
|
end
|
179
207
|
end
|
180
208
|
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
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
|
20
20
|
# @!method non_public_modifier?(node)
|
21
21
|
def_node_matcher :non_public_modifier?, <<~PATTERN
|
22
|
-
(send nil? {:private :protected} ({def defs} ...))
|
22
|
+
(send nil? {:private :protected :private_class_method} ({def defs} ...))
|
23
23
|
PATTERN
|
24
24
|
end
|
25
25
|
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
|
|
@@ -26,11 +26,15 @@ module RuboCop
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def delimiter_string(node)
|
29
|
-
node.source.match(OPENING_DELIMITER)
|
29
|
+
return '' unless (match = node.source.match(OPENING_DELIMITER))
|
30
|
+
|
31
|
+
match.captures[1]
|
30
32
|
end
|
31
33
|
|
32
34
|
def heredoc_type(node)
|
33
|
-
node.source.match(OPENING_DELIMITER)
|
35
|
+
return '' unless (match = node.source.match(OPENING_DELIMITER))
|
36
|
+
|
37
|
+
match.captures[0]
|
34
38
|
end
|
35
39
|
end
|
36
40
|
end
|
@@ -20,16 +20,17 @@ module RuboCop
|
|
20
20
|
range = offending_range(node, lhs, rhs, style)
|
21
21
|
check(range, node, lhs, rhs)
|
22
22
|
end
|
23
|
+
alias on_csend on_send
|
23
24
|
|
24
25
|
private
|
25
26
|
|
26
|
-
# In a chain of method calls, we regard the top
|
27
|
+
# In a chain of method calls, we regard the top call node as the base
|
27
28
|
# for indentation of all lines following the first. For example:
|
28
29
|
# a.
|
29
30
|
# b c { block }. <-- b is indented relative to a
|
30
31
|
# d <-- d is indented relative to a
|
31
32
|
def left_hand_side(lhs)
|
32
|
-
while lhs.parent&.
|
33
|
+
while lhs.parent&.call_type? && lhs.parent.loc.dot && !lhs.parent.assignment_method?
|
33
34
|
lhs = lhs.parent
|
34
35
|
end
|
35
36
|
lhs
|