rubocop 1.60.2 → 1.63.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/assets/output.css.erb +159 -0
- data/assets/output.html.erb +1 -160
- data/config/default.yml +64 -15
- data/lib/rubocop/cli/command/auto_generate_config.rb +12 -3
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli.rb +6 -1
- data/lib/rubocop/config.rb +37 -10
- data/lib/rubocop/config_finder.rb +12 -2
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_validator.rb +14 -5
- data/lib/rubocop/cop/autocorrect_logic.rb +6 -1
- data/lib/rubocop/cop/base.rb +52 -6
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +122 -28
- data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
- data/lib/rubocop/cop/layout/end_alignment.rb +3 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +11 -3
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -4
- data/lib/rubocop/cop/lint/debugger.rb +27 -2
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +14 -9
- data/lib/rubocop/cop/lint/redundant_with_index.rb +4 -0
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
- data/lib/rubocop/cop/lint/script_permission.rb +3 -3
- data/lib/rubocop/cop/lint/syntax.rb +1 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +7 -2
- data/lib/rubocop/cop/lint/useless_times.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +6 -1
- data/lib/rubocop/cop/mixin/code_length.rb +12 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +15 -6
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +31 -12
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/inclusive_language.rb +1 -2
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/style/alias.rb +1 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +29 -8
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/class_vars.rb +3 -3
- data/lib/rubocop/cop/style/collection_compact.rb +3 -3
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -5
- data/lib/rubocop/cop/style/copyright.rb +16 -11
- data/lib/rubocop/cop/style/eval_with_location.rb +2 -0
- data/lib/rubocop/cop/style/exact_regexp_match.rb +2 -1
- data/lib/rubocop/cop/style/for.rb +2 -0
- data/lib/rubocop/cop/style/format_string.rb +9 -9
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +8 -8
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +10 -5
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +5 -8
- data/lib/rubocop/cop/style/map_into_array.rb +175 -0
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -1
- data/lib/rubocop/cop/style/map_to_set.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +4 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
- data/lib/rubocop/cop/style/object_then.rb +5 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -3
- data/lib/rubocop/cop/style/raise_args.rb +4 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +25 -2
- data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +5 -4
- data/lib/rubocop/cop/style/redundant_each.rb +1 -1
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +5 -0
- data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -1
- data/lib/rubocop/cop/style/redundant_return.rb +6 -0
- data/lib/rubocop/cop/style/sample.rb +1 -3
- data/lib/rubocop/cop/team.rb +3 -0
- data/lib/rubocop/cop/utils/regexp_ranges.rb +1 -1
- data/lib/rubocop/cops_documentation_generator.rb +4 -2
- data/lib/rubocop/directive_comment.rb +10 -8
- data/lib/rubocop/formatter/clang_style_formatter.rb +3 -7
- data/lib/rubocop/formatter/html_formatter.rb +30 -10
- data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
- data/lib/rubocop/formatter/tap_formatter.rb +3 -7
- data/lib/rubocop/lockfile.rb +34 -4
- data/lib/rubocop/lsp/logger.rb +1 -1
- data/lib/rubocop/lsp/routes.rb +1 -1
- data/lib/rubocop/lsp/runtime.rb +1 -1
- data/lib/rubocop/lsp/server.rb +5 -2
- data/lib/rubocop/lsp/severity.rb +1 -1
- data/lib/rubocop/lsp.rb +29 -0
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/options.rb +11 -0
- data/lib/rubocop/path_util.rb +6 -2
- data/lib/rubocop/rspec/cop_helper.rb +8 -2
- data/lib/rubocop/rspec/expect_offense.rb +16 -8
- data/lib/rubocop/rspec/shared_contexts.rb +49 -18
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +12 -2
- data/lib/rubocop/target_finder.rb +84 -78
- data/lib/rubocop/target_ruby.rb +82 -80
- data/lib/rubocop/version.rb +19 -4
- data/lib/rubocop.rb +1 -0
- metadata +10 -6
@@ -27,9 +27,9 @@ module RuboCop
|
|
27
27
|
MSG = 'Add an empty line after magic comments.'
|
28
28
|
|
29
29
|
def on_new_investigation
|
30
|
-
return unless processed_source
|
31
|
-
|
32
|
-
return if
|
30
|
+
return unless (last_magic_comment = last_magic_comment(processed_source))
|
31
|
+
return unless (next_line = processed_source[last_magic_comment.loc.line])
|
32
|
+
return if next_line.strip.empty?
|
33
33
|
|
34
34
|
offending_range = offending_range(last_magic_comment)
|
35
35
|
|
@@ -46,18 +46,25 @@ module RuboCop
|
|
46
46
|
|
47
47
|
# Find the last magic comment in the source file.
|
48
48
|
#
|
49
|
-
# Take all comments that precede the first line of code
|
49
|
+
# Take all comments that precede the first line of code (or just take
|
50
|
+
# them all in the case when there is no code), select the
|
50
51
|
# magic comments, and return the last magic comment in the file.
|
51
52
|
#
|
52
53
|
# @return [Parser::Source::Comment] if magic comments exist before code
|
53
54
|
# @return [nil] otherwise
|
54
55
|
def last_magic_comment(source)
|
55
|
-
source
|
56
|
-
.comments
|
57
|
-
.take_while { |comment| comment.loc.line < source.ast.loc.line }
|
56
|
+
comments_before_code(source)
|
58
57
|
.reverse
|
59
58
|
.find { |comment| MagicComment.parse(comment.text).any? }
|
60
59
|
end
|
60
|
+
|
61
|
+
def comments_before_code(source)
|
62
|
+
if source.ast
|
63
|
+
source.comments.take_while { |comment| comment.loc.line < source.ast.loc.line }
|
64
|
+
else
|
65
|
+
source.comments
|
66
|
+
end
|
67
|
+
end
|
61
68
|
end
|
62
69
|
end
|
63
70
|
end
|
@@ -20,7 +20,9 @@ module RuboCop
|
|
20
20
|
# This `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`)
|
21
21
|
# by default. On the other hand, `Layout/BeginEndAlignment` cop aligns with
|
22
22
|
# `EnforcedStyleAlignWith: start_of_line` by default due to `||= begin` tends
|
23
|
-
# to align with the start of the line.
|
23
|
+
# to align with the start of the line. `Layout/DefEndAlignment` cop also aligns with
|
24
|
+
# `EnforcedStyleAlignWith: start_of_line` by default.
|
25
|
+
# These style can be configured by each cop.
|
24
26
|
#
|
25
27
|
# @example EnforcedStyleAlignWith: keyword (default)
|
26
28
|
# # bad
|
@@ -84,12 +84,20 @@ module RuboCop
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def offense?(node)
|
87
|
-
node.multiline?
|
88
|
-
|
87
|
+
return false if !node.multiline? || too_long?(node) || !suitable_as_single_line?(node)
|
88
|
+
return require_backslash?(node) if node.and_type? || node.or_type?
|
89
|
+
|
90
|
+
!index_access_call_chained?(node) && !configured_to_not_be_inspected?(node)
|
91
|
+
end
|
92
|
+
|
93
|
+
def require_backslash?(node)
|
94
|
+
processed_source.lines[node.loc.operator.line - 1].end_with?('\\')
|
89
95
|
end
|
90
96
|
|
91
97
|
def index_access_call_chained?(node)
|
92
|
-
|
98
|
+
return false unless node.send_type? && node.method?(:[])
|
99
|
+
|
100
|
+
node.children.first.send_type? && node.children.first.method?(:[])
|
93
101
|
end
|
94
102
|
|
95
103
|
def configured_to_not_be_inspected?(node)
|
@@ -81,19 +81,28 @@ module RuboCop
|
|
81
81
|
private
|
82
82
|
|
83
83
|
def check_empty(left_brace, space_plus_brace, used_style)
|
84
|
-
|
85
|
-
|
86
|
-
|
84
|
+
if style_for_empty_braces == used_style
|
85
|
+
handle_different_styles_for_empty_braces(used_style)
|
86
|
+
return
|
87
|
+
elsif !config_to_allow_offenses.key?('Enabled')
|
88
|
+
config_to_allow_offenses['EnforcedStyleForEmptyBraces'] = used_style.to_s
|
89
|
+
end
|
87
90
|
|
88
91
|
if style_for_empty_braces == :space
|
89
|
-
|
90
|
-
|
91
|
-
end
|
92
|
+
range = left_brace
|
93
|
+
msg = MISSING_MSG
|
92
94
|
else
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
95
|
+
range = range_between(space_plus_brace.begin_pos, left_brace.begin_pos)
|
96
|
+
msg = DETECTED_MSG
|
97
|
+
end
|
98
|
+
add_offense(range, message: msg) { |corrector| autocorrect(corrector, range) }
|
99
|
+
end
|
100
|
+
|
101
|
+
def handle_different_styles_for_empty_braces(used_style)
|
102
|
+
if config_to_allow_offenses['EnforcedStyleForEmptyBraces'] &&
|
103
|
+
config_to_allow_offenses['EnforcedStyleForEmptyBraces'].to_sym != used_style
|
104
|
+
config_to_allow_offenses.clear
|
105
|
+
config_to_allow_offenses['Enabled'] = false
|
97
106
|
end
|
98
107
|
end
|
99
108
|
|
@@ -116,7 +116,7 @@ module RuboCop
|
|
116
116
|
|
117
117
|
def incorrect_style_detected(token1, token2,
|
118
118
|
expect_space, is_empty_braces)
|
119
|
-
brace = (token1.
|
119
|
+
brace = (token1.left_brace? ? token1 : token2).pos
|
120
120
|
range = expect_space ? brace : space_range(brace)
|
121
121
|
detected_style = expect_space ? 'no_space' : 'space'
|
122
122
|
|
@@ -50,7 +50,7 @@ module RuboCop
|
|
50
50
|
MSG_WITHOUT_SAFE_ASSIGNMENT_ALLOWED =
|
51
51
|
'Use `==` if you meant to do a comparison or move the assignment ' \
|
52
52
|
'up out of the condition.'
|
53
|
-
ASGN_TYPES = [:begin, *AST::Node::EQUALS_ASSIGNMENTS, :send].freeze
|
53
|
+
ASGN_TYPES = [:begin, *AST::Node::EQUALS_ASSIGNMENTS, :send, :csend].freeze
|
54
54
|
|
55
55
|
def on_if(node)
|
56
56
|
return if node.condition.block_type?
|
@@ -88,9 +88,7 @@ module RuboCop
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def skip_children?(asgn_node)
|
91
|
-
(asgn_node
|
92
|
-
empty_condition?(asgn_node) ||
|
93
|
-
(safe_assignment_allowed? && safe_assignment?(asgn_node))
|
91
|
+
empty_condition?(asgn_node) || (safe_assignment_allowed? && safe_assignment?(asgn_node))
|
94
92
|
end
|
95
93
|
|
96
94
|
def traverse_node(node, &block)
|
@@ -29,6 +29,11 @@ module RuboCop
|
|
29
29
|
# MyDebugger.debug_this
|
30
30
|
# ----
|
31
31
|
#
|
32
|
+
# Some gems also ship files that will start a debugging session when required,
|
33
|
+
# for example `require 'debug/start'` from `ruby/debug`. These requires can
|
34
|
+
# be configured through `DebuggerRequires`. It has the same structure as
|
35
|
+
# `DebuggerMethods`, which you can read about above.
|
36
|
+
#
|
32
37
|
# @example
|
33
38
|
#
|
34
39
|
# # bad (ok during development)
|
@@ -64,14 +69,20 @@ module RuboCop
|
|
64
69
|
# def some_method
|
65
70
|
# my_debugger
|
66
71
|
# end
|
72
|
+
#
|
73
|
+
# @example DebuggerRequires: [my_debugger/start]
|
74
|
+
#
|
75
|
+
# # bad (ok during development)
|
76
|
+
#
|
77
|
+
# require 'my_debugger/start'
|
67
78
|
class Debugger < Base
|
68
79
|
MSG = 'Remove debugger entry point `%<source>s`.'
|
69
80
|
BLOCK_TYPES = %i[block numblock kwbegin].freeze
|
70
81
|
|
71
82
|
def on_send(node)
|
72
|
-
return if
|
83
|
+
return if assumed_usage_context?(node)
|
73
84
|
|
74
|
-
add_offense(node)
|
85
|
+
add_offense(node) if debugger_method?(node) || debugger_require?(node)
|
75
86
|
end
|
76
87
|
|
77
88
|
private
|
@@ -87,12 +98,26 @@ module RuboCop
|
|
87
98
|
end
|
88
99
|
end
|
89
100
|
|
101
|
+
def debugger_requires
|
102
|
+
@debugger_requires ||= begin
|
103
|
+
config = cop_config.fetch('DebuggerRequires', [])
|
104
|
+
config.is_a?(Array) ? config : config.values.flatten
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
90
108
|
def debugger_method?(send_node)
|
91
109
|
return false if send_node.parent&.send_type? && send_node.parent.receiver == send_node
|
92
110
|
|
93
111
|
debugger_methods.include?(chained_method_name(send_node))
|
94
112
|
end
|
95
113
|
|
114
|
+
def debugger_require?(send_node)
|
115
|
+
return false unless send_node.method?(:require) && send_node.arguments.one?
|
116
|
+
return false unless (argument = send_node.first_argument).str_type?
|
117
|
+
|
118
|
+
debugger_requires.include?(argument.value)
|
119
|
+
end
|
120
|
+
|
96
121
|
def assumed_usage_context?(node)
|
97
122
|
# Basically, debugger methods are not used as a method argument without arguments.
|
98
123
|
return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any?
|
@@ -104,7 +104,7 @@ module RuboCop
|
|
104
104
|
def correct_other_branches(corrector, node)
|
105
105
|
return unless require_other_branches_correction?(node)
|
106
106
|
|
107
|
-
if node.else_branch&.if_type?
|
107
|
+
if node.else_branch&.if_type? && !node.else_branch.modifier_form?
|
108
108
|
# Replace an orphaned `elsif` with `if`
|
109
109
|
corrector.replace(node.else_branch.loc.keyword, 'if')
|
110
110
|
else
|
@@ -5,7 +5,8 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# Checks for redundant safe navigation calls.
|
7
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
|
8
|
+
# and an offense is not detected when the receiver is a constant. The detection also applies
|
9
|
+
# to literal receivers, except for `nil`.
|
9
10
|
#
|
10
11
|
# For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`,
|
11
12
|
# and `equal?` methods are checked by default.
|
@@ -76,10 +77,9 @@ module RuboCop
|
|
76
77
|
#
|
77
78
|
class RedundantSafeNavigation < Base
|
78
79
|
include AllowedMethods
|
79
|
-
include RangeHelp
|
80
80
|
extend AutoCorrector
|
81
81
|
|
82
|
-
MSG = 'Redundant safe navigation detected.'
|
82
|
+
MSG = 'Redundant safe navigation detected, use `.` instead.'
|
83
83
|
MSG_LITERAL = 'Redundant safe navigation with default literal detected.'
|
84
84
|
|
85
85
|
NIL_SPECIFIC_METHODS = (nil.methods - Object.new.methods).to_set.freeze
|
@@ -105,24 +105,23 @@ module RuboCop
|
|
105
105
|
|
106
106
|
# rubocop:disable Metrics/AbcSize
|
107
107
|
def on_csend(node)
|
108
|
-
unless
|
108
|
+
unless assume_receiver_instance_exists?(node.receiver)
|
109
109
|
return unless check?(node) && allowed_method?(node.method_name)
|
110
110
|
return if respond_to_nil_specific_method?(node)
|
111
111
|
end
|
112
112
|
|
113
|
-
range =
|
114
|
-
add_offense(range) { |corrector| corrector.replace(
|
113
|
+
range = node.loc.dot
|
114
|
+
add_offense(range) { |corrector| corrector.replace(range, '.') }
|
115
115
|
end
|
116
116
|
|
117
117
|
def on_or(node)
|
118
118
|
conversion_with_default?(node) do |send_node|
|
119
|
-
range =
|
119
|
+
range = send_node.loc.dot.begin.join(node.source_range.end)
|
120
120
|
|
121
121
|
add_offense(range, message: MSG_LITERAL) do |corrector|
|
122
122
|
corrector.replace(send_node.loc.dot, '.')
|
123
123
|
|
124
|
-
range_with_default =
|
125
|
-
node.source_range.end.end_pos)
|
124
|
+
range_with_default = node.lhs.source_range.end.begin.join(node.source_range.end)
|
126
125
|
corrector.remove(range_with_default)
|
127
126
|
end
|
128
127
|
end
|
@@ -131,6 +130,12 @@ module RuboCop
|
|
131
130
|
|
132
131
|
private
|
133
132
|
|
133
|
+
def assume_receiver_instance_exists?(receiver)
|
134
|
+
return true if receiver.const_type? && !receiver.source.match?(SNAKE_CASE)
|
135
|
+
|
136
|
+
receiver.literal? && !receiver.nil_type?
|
137
|
+
end
|
138
|
+
|
134
139
|
def check?(node)
|
135
140
|
parent = node.parent
|
136
141
|
return false unless parent
|
@@ -33,7 +33,10 @@ 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
|
+
# rubocop:disable Metrics/AbcSize
|
36
37
|
def on_block(node)
|
38
|
+
return unless node.receiver
|
39
|
+
return if node.method?(:with_index) && !node.receiver.receiver
|
37
40
|
return unless (send = redundant_with_index?(node))
|
38
41
|
|
39
42
|
range = with_index_range(send)
|
@@ -47,6 +50,7 @@ module RuboCop
|
|
47
50
|
end
|
48
51
|
end
|
49
52
|
end
|
53
|
+
# rubocop:enable Metrics/AbcSize
|
50
54
|
|
51
55
|
alias on_numblock on_block
|
52
56
|
|
@@ -59,9 +59,7 @@ module RuboCop
|
|
59
59
|
|
60
60
|
def autocorrect(corrector, node)
|
61
61
|
rescued, _, _body = *node
|
62
|
-
range =
|
63
|
-
node.loc.keyword.end_pos,
|
64
|
-
rescued.source_range.end_pos)
|
62
|
+
range = node.loc.keyword.end.join(rescued.source_range.end)
|
65
63
|
|
66
64
|
corrector.replace(range, correction(*rescued))
|
67
65
|
end
|
@@ -46,14 +46,14 @@ module RuboCop
|
|
46
46
|
message = format_message_from(processed_source)
|
47
47
|
|
48
48
|
add_offense(comment, message: message) do
|
49
|
-
autocorrect
|
49
|
+
autocorrect if autocorrect_requested?
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
private
|
54
54
|
|
55
|
-
def autocorrect
|
56
|
-
FileUtils.chmod('+x',
|
55
|
+
def autocorrect
|
56
|
+
FileUtils.chmod('+x', processed_source.file_path)
|
57
57
|
end
|
58
58
|
|
59
59
|
def executable?(processed_source)
|
@@ -51,8 +51,13 @@ module RuboCop
|
|
51
51
|
enum_conversion_call?(node) do |method_node, arguments|
|
52
52
|
next if method_node.call_type? &&
|
53
53
|
!method_node.method?(:__method__) && !method_node.method?(:__callee__)
|
54
|
-
|
55
|
-
|
54
|
+
|
55
|
+
valid = if method_name?(method_node, def_node.method_name)
|
56
|
+
arguments_match?(arguments, def_node)
|
57
|
+
else
|
58
|
+
def_node.arguments.empty?
|
59
|
+
end
|
60
|
+
return if valid
|
56
61
|
|
57
62
|
add_offense(node)
|
58
63
|
end
|
@@ -100,7 +100,12 @@ module RuboCop
|
|
100
100
|
expressions = *node
|
101
101
|
expressions.pop unless in_void_context?(node)
|
102
102
|
expressions.each do |expr|
|
103
|
-
check_void_op(expr)
|
103
|
+
check_void_op(expr) do
|
104
|
+
block_node = node.each_ancestor(:block).first
|
105
|
+
|
106
|
+
block_node&.method?(:each)
|
107
|
+
end
|
108
|
+
|
104
109
|
check_expression(expr)
|
105
110
|
end
|
106
111
|
end
|
@@ -36,7 +36,7 @@ module RuboCop
|
|
36
36
|
length = calculator.calculate
|
37
37
|
return if length <= max_length
|
38
38
|
|
39
|
-
location = node
|
39
|
+
location = location(node)
|
40
40
|
|
41
41
|
add_offense(location, message: message(length, max_length)) { self.max = length }
|
42
42
|
end
|
@@ -54,6 +54,17 @@ module RuboCop
|
|
54
54
|
foldable_types: count_as_one
|
55
55
|
)
|
56
56
|
end
|
57
|
+
|
58
|
+
def location(node)
|
59
|
+
return node.loc.name if node.casgn_type?
|
60
|
+
|
61
|
+
if LSP.enabled?
|
62
|
+
end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
|
63
|
+
node.source_range.begin.join(end_range)
|
64
|
+
else
|
65
|
+
node.source_range
|
66
|
+
end
|
67
|
+
end
|
57
68
|
end
|
58
69
|
end
|
59
70
|
end
|
@@ -49,13 +49,13 @@ module RuboCop
|
|
49
49
|
|
50
50
|
return unless complexity > max
|
51
51
|
|
52
|
-
msg = format(
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
52
|
+
msg = format(
|
53
|
+
self.class::MSG,
|
54
|
+
method: method_name, complexity: complexity, abc_vector: abc_vector, max: max
|
55
|
+
)
|
56
|
+
location = location(node)
|
57
57
|
|
58
|
-
add_offense(
|
58
|
+
add_offense(location, message: msg) { self.max = complexity.ceil }
|
59
59
|
end
|
60
60
|
|
61
61
|
def complexity(body)
|
@@ -69,6 +69,15 @@ module RuboCop
|
|
69
69
|
end
|
70
70
|
score
|
71
71
|
end
|
72
|
+
|
73
|
+
def location(node)
|
74
|
+
if LSP.enabled?
|
75
|
+
end_range = node.loc.respond_to?(:name) ? node.loc.name : node.loc.begin
|
76
|
+
node.source_range.begin.join(end_range)
|
77
|
+
else
|
78
|
+
node.source_range
|
79
|
+
end
|
80
|
+
end
|
72
81
|
end
|
73
82
|
end
|
74
83
|
end
|
@@ -189,7 +189,7 @@ module RuboCop
|
|
189
189
|
case node.type
|
190
190
|
when :casgn then _scope, _lhs, rhs = *node
|
191
191
|
when :op_asgn then _lhs, _op, rhs = *node
|
192
|
-
when :send
|
192
|
+
when :send, :csend then rhs = node.last_argument
|
193
193
|
else _lhs, rhs = *node
|
194
194
|
end
|
195
195
|
rhs
|
@@ -14,7 +14,7 @@ module RuboCop
|
|
14
14
|
def_node_matcher :empty_condition?, '(begin)'
|
15
15
|
|
16
16
|
# @!method setter_method?(node)
|
17
|
-
def_node_matcher :setter_method?, '[(
|
17
|
+
def_node_matcher :setter_method?, '[(call ...) setter_method?]'
|
18
18
|
|
19
19
|
# @!method safe_assignment?(node)
|
20
20
|
def_node_matcher :safe_assignment?, '(begin {equals_asgn? #setter_method?})'
|
@@ -51,29 +51,25 @@ module RuboCop
|
|
51
51
|
[Lint::AmbiguousOperator, Style::ArgumentsForwarding]
|
52
52
|
end
|
53
53
|
|
54
|
-
# rubocop:disable Metrics/CyclomaticComplexity
|
55
54
|
def on_def(node)
|
56
55
|
return if node.arguments.empty?
|
57
56
|
|
58
57
|
last_argument = node.last_argument
|
59
58
|
return if expected_block_forwarding_style?(node, last_argument)
|
60
59
|
|
61
|
-
|
62
|
-
|
63
|
-
next
|
64
|
-
last_argument.source != block_pass_node.source
|
60
|
+
forwarded_args = node.each_descendant(:block_pass).with_object([]) do |block_pass, result|
|
61
|
+
return nil if invalidates_syntax?(block_pass)
|
62
|
+
next unless block_argument_name_matched?(block_pass, last_argument)
|
65
63
|
|
66
|
-
|
67
|
-
|
68
|
-
next
|
69
|
-
end
|
64
|
+
result << block_pass
|
65
|
+
end
|
70
66
|
|
71
|
-
|
67
|
+
forwarded_args.each do |forwarded_arg|
|
68
|
+
register_offense(forwarded_arg, node)
|
72
69
|
end
|
73
70
|
|
74
|
-
register_offense(last_argument, node)
|
71
|
+
register_offense(last_argument, node)
|
75
72
|
end
|
76
|
-
# rubocop:enable Metrics/CyclomaticComplexity
|
77
73
|
alias on_defs on_def
|
78
74
|
|
79
75
|
private
|
@@ -88,6 +84,29 @@ module RuboCop
|
|
88
84
|
end
|
89
85
|
end
|
90
86
|
|
87
|
+
def block_argument_name_matched?(block_pass_node, last_argument)
|
88
|
+
return false if block_pass_node.children.first&.sym_type?
|
89
|
+
|
90
|
+
last_argument.source == block_pass_node.source
|
91
|
+
end
|
92
|
+
|
93
|
+
# Prevents the following syntax error:
|
94
|
+
#
|
95
|
+
# # foo.rb
|
96
|
+
# def foo(&)
|
97
|
+
# block_method do
|
98
|
+
# bar(&)
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
#
|
102
|
+
# $ ruby -vc foo.rb
|
103
|
+
# ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-darwin22]
|
104
|
+
# foo.rb: foo.rb:4: anonymous block parameter is also used within block (SyntaxError)
|
105
|
+
#
|
106
|
+
def invalidates_syntax?(block_pass_node)
|
107
|
+
block_pass_node.each_ancestor(:block, :numblock).any?
|
108
|
+
end
|
109
|
+
|
91
110
|
def use_kwarg_in_method_definition?(node)
|
92
111
|
node.arguments.each_descendant(:kwarg, :kwoptarg).any?
|
93
112
|
end
|
@@ -57,7 +57,7 @@ module RuboCop
|
|
57
57
|
file_path = processed_source.file_path
|
58
58
|
return if config.file_to_exclude?(file_path) || config.allowed_camel_case_file?(file_path)
|
59
59
|
|
60
|
-
for_bad_filename(file_path)
|
60
|
+
for_bad_filename(file_path)
|
61
61
|
end
|
62
62
|
|
63
63
|
private
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
71
71
|
msg = other_message(basename) unless bad_filename_allowed?
|
72
72
|
end
|
73
73
|
|
74
|
-
|
74
|
+
add_global_offense(msg) if msg
|
75
75
|
end
|
76
76
|
|
77
77
|
def perform_class_and_module_naming_checks(file_path, basename)
|
@@ -207,8 +207,7 @@ module RuboCop
|
|
207
207
|
message = create_multiple_word_message_for_file(words)
|
208
208
|
end
|
209
209
|
|
210
|
-
|
211
|
-
add_offense(range, message: message)
|
210
|
+
add_global_offense(message)
|
212
211
|
end
|
213
212
|
|
214
213
|
def create_single_word_message_for_file(word)
|
@@ -99,7 +99,7 @@ module RuboCop
|
|
99
99
|
!(method_name.start_with?(prefix) && # cheap check to avoid allocating Regexp
|
100
100
|
method_name.match?(/^#{prefix}[^0-9]/)) ||
|
101
101
|
method_name == expected_name(method_name, prefix) ||
|
102
|
-
method_name.end_with?('=') ||
|
102
|
+
method_name.end_with?('=') ||
|
103
103
|
allowed_method?(method_name)
|
104
104
|
end
|
105
105
|
|
@@ -109,7 +109,7 @@ module RuboCop
|
|
109
109
|
else
|
110
110
|
method_name.dup
|
111
111
|
end
|
112
|
-
new_name << '?' unless method_name.end_with?('?')
|
112
|
+
new_name << '?' unless method_name.end_with?('?')
|
113
113
|
new_name
|
114
114
|
end
|
115
115
|
|
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -300,7 +300,7 @@ module RuboCop
|
|
300
300
|
unless given_badge.match?(real_badge)
|
301
301
|
path = PathUtil.smart_path(source_path)
|
302
302
|
warn "#{path}: #{given_badge} has the wrong namespace - " \
|
303
|
-
"
|
303
|
+
"replace it with #{given_badge.with_department(real_badge.department)}"
|
304
304
|
end
|
305
305
|
|
306
306
|
real_badge.to_s
|
@@ -41,6 +41,7 @@ module RuboCop
|
|
41
41
|
def on_send(node)
|
42
42
|
return unless node.command?(:alias_method)
|
43
43
|
return unless style == :prefer_alias && alias_keyword_possible?(node)
|
44
|
+
return unless node.arguments.count == 2
|
44
45
|
|
45
46
|
msg = format(MSG_ALIAS_METHOD, current: lexical_scope_type(node))
|
46
47
|
add_offense(node.loc.selector, message: msg) do |corrector|
|