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
@@ -3,7 +3,23 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Layout
|
6
|
-
# Enforces empty line after guard clause
|
6
|
+
# Enforces empty line after guard clause.
|
7
|
+
#
|
8
|
+
# This cop allows `# :nocov:` directive after guard clause because
|
9
|
+
# SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
|
10
|
+
#
|
11
|
+
# [source,ruby]
|
12
|
+
# ----
|
13
|
+
# def foo
|
14
|
+
# # :nocov:
|
15
|
+
# return if condition
|
16
|
+
# # :nocov:
|
17
|
+
# bar
|
18
|
+
# end
|
19
|
+
# ----
|
20
|
+
#
|
21
|
+
# Refer to SimpleCov's documentation for more details:
|
22
|
+
# https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
|
7
23
|
#
|
8
24
|
# @example
|
9
25
|
#
|
@@ -42,19 +58,22 @@ module RuboCop
|
|
42
58
|
|
43
59
|
MSG = 'Add empty line after guard clause.'
|
44
60
|
END_OF_HEREDOC_LINE = 1
|
61
|
+
SIMPLE_DIRECTIVE_COMMENT_PATTERN = /\A# *:nocov:\z/.freeze
|
45
62
|
|
46
63
|
def on_if(node)
|
47
64
|
return if correct_style?(node)
|
48
65
|
return if multiple_statements_on_line?(node)
|
49
66
|
|
50
67
|
if node.modifier_form? && (heredoc_node = last_heredoc_argument(node))
|
51
|
-
|
68
|
+
if next_line_empty_or_allowed_directive_comment?(heredoc_line(node, heredoc_node))
|
69
|
+
return
|
70
|
+
end
|
52
71
|
|
53
72
|
add_offense(heredoc_node.loc.heredoc_end) do |corrector|
|
54
73
|
autocorrect(corrector, heredoc_node)
|
55
74
|
end
|
56
75
|
else
|
57
|
-
return if
|
76
|
+
return if next_line_empty_or_allowed_directive_comment?(node.last_line)
|
58
77
|
|
59
78
|
add_offense(offense_location(node)) { |corrector| autocorrect(corrector, node) }
|
60
79
|
end
|
@@ -70,7 +89,7 @@ module RuboCop
|
|
70
89
|
end
|
71
90
|
|
72
91
|
next_line = node_range.last_line + 1
|
73
|
-
if
|
92
|
+
if next_line_allowed_directive_comment?(next_line)
|
74
93
|
node_range = processed_source.comment_at_line(next_line)
|
75
94
|
end
|
76
95
|
|
@@ -88,21 +107,21 @@ module RuboCop
|
|
88
107
|
node.if_branch&.guard_clause?
|
89
108
|
end
|
90
109
|
|
91
|
-
def
|
110
|
+
def next_line_empty_or_allowed_directive_comment?(line)
|
92
111
|
return true if next_line_empty?(line)
|
93
112
|
|
94
113
|
next_line = line + 1
|
95
|
-
|
114
|
+
next_line_allowed_directive_comment?(next_line) && next_line_empty?(next_line)
|
96
115
|
end
|
97
116
|
|
98
117
|
def next_line_empty?(line)
|
99
118
|
processed_source[line].blank?
|
100
119
|
end
|
101
120
|
|
102
|
-
def
|
121
|
+
def next_line_allowed_directive_comment?(line)
|
103
122
|
return false unless (comment = processed_source.comment_at_line(line))
|
104
123
|
|
105
|
-
DirectiveComment.new(comment).enabled?
|
124
|
+
DirectiveComment.new(comment).enabled? || simplecov_directive_comment?(comment)
|
106
125
|
end
|
107
126
|
|
108
127
|
def next_line_rescue_or_ensure?(node)
|
@@ -137,7 +156,7 @@ module RuboCop
|
|
137
156
|
return node if node
|
138
157
|
end
|
139
158
|
|
140
|
-
|
159
|
+
last_heredoc_argument(n.receiver) if n.respond_to?(:receiver)
|
141
160
|
end
|
142
161
|
|
143
162
|
def last_heredoc_argument_node(node)
|
@@ -145,6 +164,8 @@ module RuboCop
|
|
145
164
|
|
146
165
|
if node.if_branch.and_type?
|
147
166
|
node.if_branch.children.first
|
167
|
+
elsif use_heredoc_in_condition?(node.condition)
|
168
|
+
node.condition
|
148
169
|
else
|
149
170
|
node.if_branch.children.last
|
150
171
|
end
|
@@ -161,6 +182,12 @@ module RuboCop
|
|
161
182
|
node.respond_to?(:heredoc?) && node.heredoc?
|
162
183
|
end
|
163
184
|
|
185
|
+
def use_heredoc_in_condition?(condition)
|
186
|
+
condition.descendants.any? do |descendant|
|
187
|
+
descendant.respond_to?(:heredoc?) && descendant.heredoc?
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
164
191
|
def offense_location(node)
|
165
192
|
if node.loc.respond_to?(:end) && node.loc.end
|
166
193
|
node.loc.end
|
@@ -175,6 +202,12 @@ module RuboCop
|
|
175
202
|
|
176
203
|
parent.begin_type? && parent.single_line?
|
177
204
|
end
|
205
|
+
|
206
|
+
# SimpleCov excludes code from the coverage report by wrapping it in `# :nocov:`:
|
207
|
+
# https://github.com/simplecov-ruby/simplecov#ignoringskipping-code
|
208
|
+
def simplecov_directive_comment?(comment)
|
209
|
+
SIMPLE_DIRECTIVE_COMMENT_PATTERN.match?(comment.text)
|
210
|
+
end
|
178
211
|
end
|
179
212
|
end
|
180
213
|
end
|
@@ -135,7 +135,8 @@ module RuboCop
|
|
135
135
|
return if nodes.all?(&:single_line?) && cop_config['AllowAdjacentOneLineDefs']
|
136
136
|
|
137
137
|
correction_node = nodes.last
|
138
|
-
|
138
|
+
|
139
|
+
location = def_location(correction_node)
|
139
140
|
add_offense(location, message: message(correction_node, count: count)) do |corrector|
|
140
141
|
autocorrect(corrector, *nodes, count)
|
141
142
|
end
|
@@ -159,10 +160,28 @@ module RuboCop
|
|
159
160
|
|
160
161
|
private
|
161
162
|
|
163
|
+
def def_location(correction_node)
|
164
|
+
if correction_node.block_type?
|
165
|
+
correction_node.source_range.join(correction_node.children.first.source_range)
|
166
|
+
else
|
167
|
+
correction_node.loc.keyword.join(correction_node.loc.name)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
162
171
|
def candidate?(node)
|
163
172
|
return false unless node
|
164
173
|
|
165
|
-
method_candidate?(node) || class_candidate?(node) || module_candidate?(node)
|
174
|
+
method_candidate?(node) || class_candidate?(node) || module_candidate?(node) ||
|
175
|
+
macro_candidate?(node)
|
176
|
+
end
|
177
|
+
|
178
|
+
def empty_line_between_macros
|
179
|
+
cop_config.fetch('DefLikeMacros', []).map(&:to_sym)
|
180
|
+
end
|
181
|
+
|
182
|
+
def macro_candidate?(node)
|
183
|
+
node.block_type? && node.children.first.macro? &&
|
184
|
+
empty_line_between_macros.include?(node.children.first.method_name)
|
166
185
|
end
|
167
186
|
|
168
187
|
def method_candidate?(node)
|
@@ -226,7 +245,11 @@ module RuboCop
|
|
226
245
|
end
|
227
246
|
|
228
247
|
def def_start(node)
|
229
|
-
node.
|
248
|
+
if node.block_type? && node.children.first.send_type?
|
249
|
+
node.source_range.line
|
250
|
+
else
|
251
|
+
node.loc.keyword.line
|
252
|
+
end
|
230
253
|
end
|
231
254
|
|
232
255
|
def def_end(node)
|
@@ -163,7 +163,13 @@ module RuboCop
|
|
163
163
|
when :keyword
|
164
164
|
node
|
165
165
|
when :variable
|
166
|
-
alignment_node_for_variable_style(node)
|
166
|
+
align_to = alignment_node_for_variable_style(node)
|
167
|
+
|
168
|
+
while (parent = align_to.parent) && parent.send_type? && same_line?(align_to, parent)
|
169
|
+
align_to = parent
|
170
|
+
end
|
171
|
+
|
172
|
+
align_to
|
167
173
|
else
|
168
174
|
start_line_range(node)
|
169
175
|
end
|
@@ -25,6 +25,9 @@ module RuboCop
|
|
25
25
|
include Alignment
|
26
26
|
include Heredoc
|
27
27
|
extend AutoCorrector
|
28
|
+
extend TargetRubyVersion
|
29
|
+
|
30
|
+
minimum_target_ruby_version 2.3
|
28
31
|
|
29
32
|
TYPE_MSG = 'Use %<indentation_width>d spaces for indentation in a ' \
|
30
33
|
'heredoc by using `<<~` instead of `%<current_indent_type>s`.'
|
@@ -354,7 +354,7 @@ module RuboCop
|
|
354
354
|
# Don't check indentation if the line doesn't start with the body.
|
355
355
|
# For example, lines like "else do_something".
|
356
356
|
first_char_pos_on_line = body_node.source_range.source_line =~ /\S/
|
357
|
-
|
357
|
+
body_node.loc.column != first_char_pos_on_line
|
358
358
|
end
|
359
359
|
|
360
360
|
def offending_range(body_node, indentation)
|
@@ -57,7 +57,7 @@ module RuboCop
|
|
57
57
|
|
58
58
|
def on_new_investigation
|
59
59
|
processed_source.comments.each do |comment|
|
60
|
-
next unless /\A#+[^#\s
|
60
|
+
next unless /\A(?!#\+\+|#--)(#+[^#\s=])/.match?(comment.text)
|
61
61
|
next if comment.loc.line == 1 && allowed_on_first_line?(comment)
|
62
62
|
next if doxygen_comment_style?(comment)
|
63
63
|
next if gemfile_ruby_comment?(comment)
|
@@ -57,16 +57,13 @@ module RuboCop
|
|
57
57
|
|
58
58
|
end_of_first_line = node.source_range.begin_pos - node.source_range.column
|
59
59
|
|
60
|
-
raw_lines(node)
|
60
|
+
lines = raw_lines(node)
|
61
|
+
lines.each_cons(2).with_index(node.first_line) do |(raw_line_one, raw_line_two), line_num|
|
61
62
|
end_of_first_line += raw_line_one.length
|
62
63
|
|
63
|
-
next unless continuation?(raw_line_one)
|
64
|
+
next unless continuation?(raw_line_one, line_num, node)
|
64
65
|
|
65
|
-
|
66
|
-
investigate_leading_style(raw_line_one, raw_line_two, end_of_first_line)
|
67
|
-
else
|
68
|
-
investigate_trailing_style(raw_line_one, raw_line_two, end_of_first_line)
|
69
|
-
end
|
66
|
+
investigate(raw_line_one, raw_line_two, end_of_first_line)
|
70
67
|
end
|
71
68
|
end
|
72
69
|
|
@@ -76,6 +73,14 @@ module RuboCop
|
|
76
73
|
processed_source.raw_source.lines[node.first_line - 1, line_range(node).size]
|
77
74
|
end
|
78
75
|
|
76
|
+
def investigate(first_line, second_line, end_of_first_line)
|
77
|
+
if enforced_style_leading?
|
78
|
+
investigate_leading_style(first_line, second_line, end_of_first_line)
|
79
|
+
else
|
80
|
+
investigate_trailing_style(first_line, second_line, end_of_first_line)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
79
84
|
def investigate_leading_style(first_line, second_line, end_of_first_line)
|
80
85
|
matches = first_line.match(LEADING_STYLE_OFFENSE)
|
81
86
|
return if matches.nil?
|
@@ -98,8 +103,11 @@ module RuboCop
|
|
98
103
|
end
|
99
104
|
end
|
100
105
|
|
101
|
-
def continuation?(line)
|
102
|
-
line.end_with?("\\\n")
|
106
|
+
def continuation?(line, line_num, node)
|
107
|
+
return false unless line.end_with?("\\\n")
|
108
|
+
|
109
|
+
# Ensure backslash isn't part of a token spanning to the next line.
|
110
|
+
node.children.none? { |c| c.first_line == line_num && c.multiline? }
|
103
111
|
end
|
104
112
|
|
105
113
|
def autocorrect(corrector, offense_range, insert_pos, spaces)
|
@@ -109,7 +109,7 @@ module RuboCop
|
|
109
109
|
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
110
110
|
|
111
111
|
def comment_ranges(comments)
|
112
|
-
comments.map(&:
|
112
|
+
comments.map(&:source_range)
|
113
113
|
end
|
114
114
|
|
115
115
|
def last_line(processed_source)
|
@@ -75,7 +75,7 @@ module RuboCop
|
|
75
75
|
def right_hand_side(send_node)
|
76
76
|
dot = send_node.loc.dot
|
77
77
|
selector = send_node.loc.selector
|
78
|
-
if send_node.dot? && selector && same_line?(dot, selector)
|
78
|
+
if (send_node.dot? || send_node.safe_navigation?) && selector && same_line?(dot, selector)
|
79
79
|
dot.join(selector)
|
80
80
|
elsif selector
|
81
81
|
selector
|
@@ -179,10 +179,10 @@ module RuboCop
|
|
179
179
|
# a.b
|
180
180
|
# .c
|
181
181
|
def semantic_alignment_base(node, rhs)
|
182
|
-
return unless rhs.source.start_with?('.')
|
182
|
+
return unless rhs.source.start_with?('.', '&.')
|
183
183
|
|
184
184
|
node = semantic_alignment_node(node)
|
185
|
-
return unless node&.loc&.selector
|
185
|
+
return unless node&.loc&.selector && node.loc.dot
|
186
186
|
|
187
187
|
node.loc.dot.join(node.loc.selector)
|
188
188
|
end
|
@@ -204,6 +204,10 @@ module RuboCop
|
|
204
204
|
dot_right_above = get_dot_right_above(node)
|
205
205
|
return dot_right_above if dot_right_above
|
206
206
|
|
207
|
+
if (multiline_block_chain_node = find_multiline_block_chain_node(node))
|
208
|
+
return multiline_block_chain_node
|
209
|
+
end
|
210
|
+
|
207
211
|
node = first_call_has_a_dot(node)
|
208
212
|
return if node.loc.dot.line != node.first_line
|
209
213
|
|
@@ -219,6 +223,17 @@ module RuboCop
|
|
219
223
|
end
|
220
224
|
end
|
221
225
|
|
226
|
+
def find_multiline_block_chain_node(node)
|
227
|
+
return unless (block_node = node.each_descendant(:block, :numblock).first)
|
228
|
+
return unless block_node.multiline? && block_node.parent.call_type?
|
229
|
+
|
230
|
+
if node.receiver.call_type?
|
231
|
+
node.receiver
|
232
|
+
else
|
233
|
+
block_node.parent
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
222
237
|
def first_call_has_a_dot(node)
|
223
238
|
# descend to root of method chain
|
224
239
|
node = node.receiver while node.receiver
|
@@ -48,6 +48,10 @@ module RuboCop
|
|
48
48
|
|
49
49
|
MSG = 'Redundant line break detected.'
|
50
50
|
|
51
|
+
def on_lvasgn(node)
|
52
|
+
super unless end_with_percent_blank_string?(processed_source)
|
53
|
+
end
|
54
|
+
|
51
55
|
def on_send(node)
|
52
56
|
# Include "the whole expression".
|
53
57
|
node = node.parent while node.parent&.send_type? ||
|
@@ -61,6 +65,10 @@ module RuboCop
|
|
61
65
|
|
62
66
|
private
|
63
67
|
|
68
|
+
def end_with_percent_blank_string?(processed_source)
|
69
|
+
processed_source.buffer.source.end_with?("%\n\n")
|
70
|
+
end
|
71
|
+
|
64
72
|
def check_assignment(node, _rhs)
|
65
73
|
return unless offense?(node)
|
66
74
|
|
@@ -98,9 +106,9 @@ module RuboCop
|
|
98
106
|
|
99
107
|
def suitable_as_single_line?(node)
|
100
108
|
!comment_within?(node) &&
|
101
|
-
node.each_descendant(:if, :case, :kwbegin, :def).none? &&
|
109
|
+
node.each_descendant(:if, :case, :kwbegin, :def, :defs).none? &&
|
102
110
|
node.each_descendant(:dstr, :str).none? { |n| n.heredoc? || n.value.include?("\n") } &&
|
103
|
-
node.each_descendant(:begin).none? { |b| !b.single_line? }
|
111
|
+
node.each_descendant(:begin, :sym).none? { |b| !b.single_line? }
|
104
112
|
end
|
105
113
|
|
106
114
|
def convertible_block?(node)
|
@@ -110,7 +118,9 @@ module RuboCop
|
|
110
118
|
end
|
111
119
|
|
112
120
|
def comment_within?(node)
|
113
|
-
processed_source.comments.map
|
121
|
+
comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
|
122
|
+
|
123
|
+
comment_line_numbers.any? do |comment_line_number|
|
114
124
|
comment_line_number >= node.first_line && comment_line_number <= node.last_line
|
115
125
|
end
|
116
126
|
end
|
@@ -24,7 +24,15 @@ module RuboCop
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def kind(token)
|
27
|
-
'comma' if token.comma?
|
27
|
+
'comma' if token.comma? && !before_semicolon?(token)
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def before_semicolon?(token)
|
33
|
+
tokens = processed_source.tokens
|
34
|
+
|
35
|
+
tokens[tokens.index(token) + 1].semicolon?
|
28
36
|
end
|
29
37
|
end
|
30
38
|
end
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
# foo &. bar
|
20
20
|
# foo &. bar&. buzz
|
21
21
|
# RuboCop:: Cop
|
22
|
-
# RuboCop:: Cop::
|
22
|
+
# RuboCop:: Cop:: Base
|
23
23
|
# :: RuboCop::Cop
|
24
24
|
#
|
25
25
|
# # good
|
@@ -31,7 +31,7 @@ module RuboCop
|
|
31
31
|
# foo&.bar
|
32
32
|
# foo&.bar&.buzz
|
33
33
|
# RuboCop::Cop
|
34
|
-
# RuboCop::Cop::
|
34
|
+
# RuboCop::Cop::Base
|
35
35
|
# ::RuboCop::Cop
|
36
36
|
#
|
37
37
|
class SpaceAroundMethodCallOperator < Base
|
@@ -153,7 +153,9 @@ module RuboCop
|
|
153
153
|
private
|
154
154
|
|
155
155
|
def regular_operator?(send_node)
|
156
|
-
|
156
|
+
return false if send_node.unary_operation? || send_node.dot? || send_node.double_colon?
|
157
|
+
|
158
|
+
operator_with_regular_syntax?(send_node)
|
157
159
|
end
|
158
160
|
|
159
161
|
def operator_with_regular_syntax?(send_node)
|
@@ -168,7 +168,7 @@ module RuboCop
|
|
168
168
|
# follows, and that the rules for space inside don't apply.
|
169
169
|
return true if token2.comment?
|
170
170
|
|
171
|
-
|
171
|
+
!same_line?(token1, token2) || token1.space_after?
|
172
172
|
end
|
173
173
|
end
|
174
174
|
end
|
@@ -51,6 +51,7 @@ module RuboCop
|
|
51
51
|
# there could be good reasons why it needs to end with a certain
|
52
52
|
# number of newlines.
|
53
53
|
return if ends_in_end?(processed_source)
|
54
|
+
return if end_with_percent_blank_string?(processed_source)
|
54
55
|
|
55
56
|
whitespace_at_end = buffer.source[/\s*\Z/]
|
56
57
|
blank_lines = whitespace_at_end.count("\n") - 1
|
@@ -86,6 +87,10 @@ module RuboCop
|
|
86
87
|
extra&.strip&.start_with?('__END__')
|
87
88
|
end
|
88
89
|
|
90
|
+
def end_with_percent_blank_string?(processed_source)
|
91
|
+
processed_source.buffer.source.end_with?("%\n\n")
|
92
|
+
end
|
93
|
+
|
89
94
|
def message(wanted_blank_lines, blank_lines)
|
90
95
|
case blank_lines
|
91
96
|
when -1
|
@@ -68,10 +68,7 @@ module RuboCop
|
|
68
68
|
MSG = 'Remove debugger entry point `%<source>s`.'
|
69
69
|
|
70
70
|
def on_send(node)
|
71
|
-
return
|
72
|
-
|
73
|
-
# Basically, debugger methods are not used as a method argument without arguments.
|
74
|
-
return if node.arguments.empty? && node.each_ancestor(:send, :csend).any?
|
71
|
+
return if !debugger_method?(node) || assumed_usage_context?(node)
|
75
72
|
|
76
73
|
add_offense(node)
|
77
74
|
end
|
@@ -95,6 +92,16 @@ module RuboCop
|
|
95
92
|
debugger_methods.include?(chained_method_name(send_node))
|
96
93
|
end
|
97
94
|
|
95
|
+
def assumed_usage_context?(node)
|
96
|
+
# Basically, debugger methods are not used as a method argument without arguments.
|
97
|
+
return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any?
|
98
|
+
return true if assumed_argument?(node)
|
99
|
+
|
100
|
+
node.each_ancestor.none? do |ancestor|
|
101
|
+
ancestor.block_type? || ancestor.numblock_type? || ancestor.lambda_or_proc?
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
98
105
|
def chained_method_name(send_node)
|
99
106
|
chained_method_name = send_node.method_name.to_s
|
100
107
|
receiver = send_node.receiver
|
@@ -105,6 +112,12 @@ module RuboCop
|
|
105
112
|
end
|
106
113
|
chained_method_name
|
107
114
|
end
|
115
|
+
|
116
|
+
def assumed_argument?(node)
|
117
|
+
parent = node.parent
|
118
|
+
|
119
|
+
parent.call_type? || parent.literal? || parent.pair_type?
|
120
|
+
end
|
108
121
|
end
|
109
122
|
end
|
110
123
|
end
|
@@ -5,7 +5,7 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# Checks for blocks without a body.
|
7
7
|
# Such empty blocks are typically an oversight or we should provide a comment
|
8
|
-
#
|
8
|
+
# to clarify what we're aiming for.
|
9
9
|
#
|
10
10
|
# Empty lambdas and procs are ignored by default.
|
11
11
|
#
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
34
34
|
# interpolation should not be removed if the expanded value
|
35
35
|
# contains a space character.
|
36
36
|
expanded_value = autocorrected_value(final_node)
|
37
|
-
return if in_array_percent_literal?(begin_node) && /\s/.match?(expanded_value)
|
37
|
+
return if in_array_percent_literal?(begin_node) && /\s|\A\z/.match?(expanded_value)
|
38
38
|
|
39
39
|
add_offense(final_node) do |corrector|
|
40
40
|
return if final_node.dstr_type? # nested, fixed in next iteration
|
@@ -84,6 +84,8 @@ module RuboCop
|
|
84
84
|
end
|
85
85
|
|
86
86
|
def unsafe_range?(range_start, range_end)
|
87
|
+
return false if range_start.length != 1 || range_end.length != 1
|
88
|
+
|
87
89
|
range_for(range_start) != range_for(range_end)
|
88
90
|
end
|
89
91
|
|
@@ -93,7 +95,7 @@ module RuboCop
|
|
93
95
|
|
94
96
|
def skip_range?(range_start, range_end)
|
95
97
|
[range_start, range_end].any? do |bound|
|
96
|
-
bound.type
|
98
|
+
bound.type != :literal
|
97
99
|
end
|
98
100
|
end
|
99
101
|
|
@@ -43,7 +43,6 @@ module RuboCop
|
|
43
43
|
#
|
44
44
|
class NonAtomicFileOperation < Base
|
45
45
|
extend AutoCorrector
|
46
|
-
include Alignment
|
47
46
|
|
48
47
|
MSG_REMOVE_FILE_EXIST_CHECK = 'Remove unnecessary existence check ' \
|
49
48
|
'`%<receiver>s.%<method_name>s`.'
|
@@ -51,18 +50,20 @@ module RuboCop
|
|
51
50
|
MAKE_FORCE_METHODS = %i[makedirs mkdir_p mkpath].freeze
|
52
51
|
MAKE_METHODS = %i[mkdir].freeze
|
53
52
|
REMOVE_FORCE_METHODS = %i[rm_f rm_rf].freeze
|
54
|
-
REMOVE_METHODS = %i[remove
|
55
|
-
|
56
|
-
RESTRICT_ON_SEND = (
|
57
|
-
|
53
|
+
REMOVE_METHODS = %i[remove delete unlink remove_file rm rmdir safe_unlink].freeze
|
54
|
+
RECURSIVE_REMOVE_METHODS = %i[remove_dir remove_entry remove_entry_secure].freeze
|
55
|
+
RESTRICT_ON_SEND = (
|
56
|
+
MAKE_METHODS + MAKE_FORCE_METHODS + REMOVE_METHODS + RECURSIVE_REMOVE_METHODS +
|
57
|
+
REMOVE_FORCE_METHODS
|
58
|
+
).freeze
|
58
59
|
|
59
60
|
# @!method send_exist_node(node)
|
60
|
-
def_node_search :send_exist_node,
|
61
|
+
def_node_search :send_exist_node, <<~PATTERN
|
61
62
|
$(send (const nil? {:FileTest :File :Dir :Shell}) {:exist? :exists?} ...)
|
62
63
|
PATTERN
|
63
64
|
|
64
65
|
# @!method receiver_and_method_name(node)
|
65
|
-
def_node_matcher :receiver_and_method_name,
|
66
|
+
def_node_matcher :receiver_and_method_name, <<~PATTERN
|
66
67
|
(send (const nil? $_) $_ ...)
|
67
68
|
PATTERN
|
68
69
|
|
@@ -140,6 +141,8 @@ module RuboCop
|
|
140
141
|
'mkdir_p'
|
141
142
|
elsif REMOVE_METHODS.include?(node.method_name)
|
142
143
|
'rm_f'
|
144
|
+
elsif RECURSIVE_REMOVE_METHODS.include?(node.method_name)
|
145
|
+
'rm_rf'
|
143
146
|
else
|
144
147
|
node.method_name
|
145
148
|
end
|
@@ -5,6 +5,14 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# Checks for redundant quantifiers inside Regexp literals.
|
7
7
|
#
|
8
|
+
# It is always allowed when interpolation is used in a regexp literal,
|
9
|
+
# because it's unknown what kind of string will be expanded as a result:
|
10
|
+
#
|
11
|
+
# [source,ruby]
|
12
|
+
# ----
|
13
|
+
# /(?:a*#{interpolation})?/x
|
14
|
+
# ----
|
15
|
+
#
|
8
16
|
# @example
|
9
17
|
# # bad
|
10
18
|
# /(?:x+)+/
|
@@ -32,6 +40,8 @@ module RuboCop
|
|
32
40
|
'with a single `%<replacement>s`.'
|
33
41
|
|
34
42
|
def on_regexp(node)
|
43
|
+
return if node.interpolation?
|
44
|
+
|
35
45
|
each_redundantly_quantified_pair(node) do |group, child|
|
36
46
|
replacement = merged_quantifier(group, child)
|
37
47
|
add_offense(
|
@@ -24,6 +24,10 @@ module RuboCop
|
|
24
24
|
#
|
25
25
|
# This cop target those features.
|
26
26
|
#
|
27
|
+
# @safety
|
28
|
+
# This cop's autocorrection is unsafe because if `require 'pp'` is removed from one file,
|
29
|
+
# `NameError` can be encountered when another file uses `PP.pp`.
|
30
|
+
#
|
27
31
|
# @example
|
28
32
|
# # bad
|
29
33
|
# require 'unloaded_feature'
|