rubocop 1.81.1 → 1.82.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +25 -7
- data/config/obsoletion.yml +4 -0
- data/lib/rubocop/cli.rb +2 -1
- data/lib/rubocop/comment_config.rb +62 -17
- data/lib/rubocop/config_loader.rb +2 -1
- data/lib/rubocop/config_loader_resolver.rb +7 -6
- data/lib/rubocop/cop/autocorrect_logic.rb +4 -0
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -3
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -4
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +12 -1
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +8 -4
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +5 -3
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
- data/lib/rubocop/cop/lint/debugger.rb +0 -2
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/else_layout.rb +19 -0
- data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +16 -6
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +10 -2
- data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
- data/lib/rubocop/cop/lint/useless_assignment.rb +44 -16
- data/lib/rubocop/cop/lint/useless_or.rb +15 -2
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -4
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
- data/lib/rubocop/cop/mixin/trailing_comma.rb +7 -4
- data/lib/rubocop/cop/naming/method_name.rb +4 -2
- data/lib/rubocop/cop/naming/predicate_method.rb +4 -4
- data/lib/rubocop/cop/security/json_load.rb +33 -11
- data/lib/rubocop/cop/style/array_intersect.rb +2 -2
- data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
- data/lib/rubocop/cop/style/case_equality.rb +11 -13
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +8 -14
- data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
- data/lib/rubocop/cop/style/empty_method.rb +0 -6
- data/lib/rubocop/cop/style/endless_method.rb +15 -2
- data/lib/rubocop/cop/style/float_division.rb +15 -1
- data/lib/rubocop/cop/style/guard_clause.rb +0 -11
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
- data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
- data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
- data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
- data/lib/rubocop/cop/style/redundant_format.rb +10 -4
- data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
- data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +5 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
- data/lib/rubocop/cop/style/semicolon.rb +23 -7
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +8 -1
- data/lib/rubocop/cop/style/super_arguments.rb +2 -2
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
- data/lib/rubocop/cop/util.rb +2 -3
- data/lib/rubocop/cops_documentation_generator.rb +4 -4
- data/lib/rubocop/directive_comment.rb +46 -3
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -0
- data/lib/rubocop/lsp/diagnostic.rb +12 -17
- data/lib/rubocop/lsp/routes.rb +9 -36
- data/lib/rubocop/lsp/runtime.rb +2 -2
- data/lib/rubocop/lsp/server.rb +2 -2
- data/lib/rubocop/magic_comment.rb +20 -0
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +7 -8
- data/lib/rubocop/result_cache.rb +38 -27
- data/lib/rubocop/rspec/shared_contexts.rb +2 -2
- data/lib/rubocop/rspec/support.rb +1 -1
- data/lib/rubocop/runner.rb +4 -0
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +1 -0
- metadata +8 -10
|
@@ -52,32 +52,39 @@ module RuboCop
|
|
|
52
52
|
scope.variables.each_value { |variable| check_for_unused_assignments(variable) }
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
-
# rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
|
56
55
|
def check_for_unused_assignments(variable)
|
|
57
56
|
return if variable.should_be_unused?
|
|
58
57
|
|
|
59
58
|
variable.assignments.reverse_each do |assignment|
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
check_for_unused_assignment(variable, assignment)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
def check_for_unused_assignment(variable, assignment)
|
|
64
|
+
assignment_node = assignment.node
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
# In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
|
|
68
|
-
# and where changing `x ||= 1` to `x = 1` would cause `NameError`,
|
|
69
|
-
# the autocorrect will be skipped, even if the variable is unused.
|
|
70
|
-
if sequential_assignment?(assignment_node) || assignment_node.parent&.or_asgn_type?
|
|
71
|
-
next
|
|
72
|
-
end
|
|
66
|
+
return if ignored_assignment?(variable, assignment_node, assignment)
|
|
73
67
|
|
|
74
|
-
|
|
75
|
-
|
|
68
|
+
message = message_for_useless_assignment(assignment)
|
|
69
|
+
range = offense_range(assignment)
|
|
76
70
|
|
|
77
|
-
|
|
71
|
+
add_offense(range, message: message) do |corrector|
|
|
72
|
+
# In cases like `x = 1, y = 2`, where removing a variable would cause a syntax error,
|
|
73
|
+
# and where changing `x ||= 1` to `x = 1` would cause `NameError`,
|
|
74
|
+
# the autocorrect will be skipped, even if the variable is unused.
|
|
75
|
+
next if sequential_assignment?(assignment_node) ||
|
|
76
|
+
assignment_node.parent&.or_asgn_type?
|
|
77
|
+
|
|
78
|
+
autocorrect(corrector, assignment)
|
|
78
79
|
end
|
|
80
|
+
|
|
81
|
+
ignore_node(assignment_node) if chained_assignment?(assignment_node)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def ignored_assignment?(variable, assignment_node, assignment)
|
|
85
|
+
assignment.used? || part_of_ignored_node?(assignment_node) ||
|
|
86
|
+
variable_in_loop_condition?(assignment_node, variable)
|
|
79
87
|
end
|
|
80
|
-
# rubocop:enable Metrics/AbcSize, Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
|
81
88
|
|
|
82
89
|
def message_for_useless_assignment(assignment)
|
|
83
90
|
variable = assignment.variable
|
|
@@ -208,6 +215,27 @@ module RuboCop
|
|
|
208
215
|
def remove_local_variable_assignment_part(corrector, node)
|
|
209
216
|
corrector.replace(node, node.expression.source)
|
|
210
217
|
end
|
|
218
|
+
|
|
219
|
+
def variable_in_loop_condition?(assignment_node, variable)
|
|
220
|
+
return false if assignment_node.each_ancestor(:any_def).any?
|
|
221
|
+
|
|
222
|
+
loop_node = assignment_node.each_ancestor.find do |ancestor|
|
|
223
|
+
ancestor.type?(*VariableForce::LOOP_TYPES)
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
return false unless loop_node.respond_to?(:condition)
|
|
227
|
+
|
|
228
|
+
condition_node = loop_node.condition
|
|
229
|
+
variable_name = variable.name
|
|
230
|
+
|
|
231
|
+
return true if condition_node.lvar_type? && condition_node.children.first == variable_name
|
|
232
|
+
|
|
233
|
+
condition_node.each_descendant(:lvar) do |lvar_node|
|
|
234
|
+
return true if lvar_node.children.first == variable_name
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
false
|
|
238
|
+
end
|
|
211
239
|
end
|
|
212
240
|
end
|
|
213
241
|
end
|
|
@@ -9,6 +9,13 @@ module RuboCop
|
|
|
9
9
|
# on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
|
|
10
10
|
# appended after these methods will never evaluate.
|
|
11
11
|
#
|
|
12
|
+
# @safety
|
|
13
|
+
# As shown in the examples below, there are generally two possible ways to correct the
|
|
14
|
+
# offense, but this cop’s autocorrection always chooses the option that preserves the
|
|
15
|
+
# current behavior. While this does not change how the code behaves, that option is not
|
|
16
|
+
# necessarily the appropriate fix in every situation. For this reason, the autocorrection
|
|
17
|
+
# provided by this cop is considered unsafe.
|
|
18
|
+
#
|
|
12
19
|
# @example
|
|
13
20
|
#
|
|
14
21
|
# # bad
|
|
@@ -64,6 +71,8 @@ module RuboCop
|
|
|
64
71
|
# x&.to_s or fallback
|
|
65
72
|
#
|
|
66
73
|
class UselessOr < Base
|
|
74
|
+
extend AutoCorrector
|
|
75
|
+
|
|
67
76
|
MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
|
|
68
77
|
|
|
69
78
|
TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
|
|
@@ -89,8 +98,12 @@ module RuboCop
|
|
|
89
98
|
private
|
|
90
99
|
|
|
91
100
|
def report_offense(or_node, truthy_node)
|
|
92
|
-
add_offense(
|
|
93
|
-
|
|
101
|
+
add_offense(
|
|
102
|
+
or_node.loc.operator.join(or_node.rhs.source_range),
|
|
103
|
+
message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source)
|
|
104
|
+
) do |corrector|
|
|
105
|
+
corrector.replace(or_node, or_node.lhs.source)
|
|
106
|
+
end
|
|
94
107
|
end
|
|
95
108
|
end
|
|
96
109
|
end
|
|
@@ -84,7 +84,10 @@ module RuboCop
|
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
def assignment?(node)
|
|
87
|
-
|
|
87
|
+
if node.masgn_type? || node.shorthand_asgn?
|
|
88
|
+
compound_assignment(node)
|
|
89
|
+
return false
|
|
90
|
+
end
|
|
88
91
|
|
|
89
92
|
node.for_type? ||
|
|
90
93
|
(node.respond_to?(:setter_method?) && node.setter_method?) ||
|
|
@@ -101,8 +104,6 @@ module RuboCop
|
|
|
101
104
|
child.respond_to?(:setter_method?) && !child.setter_method?
|
|
102
105
|
end
|
|
103
106
|
@assignment += will_be_miscounted
|
|
104
|
-
|
|
105
|
-
false
|
|
106
107
|
end
|
|
107
108
|
|
|
108
109
|
def simple_assignment?(node)
|
|
@@ -14,6 +14,8 @@ module RuboCop
|
|
|
14
14
|
private
|
|
15
15
|
|
|
16
16
|
def too_long?(node)
|
|
17
|
+
return false unless max_line_length
|
|
18
|
+
|
|
17
19
|
lines = processed_source.lines[(node.first_line - 1)...node.last_line]
|
|
18
20
|
to_single_line(lines.join("\n")).length > max_line_length
|
|
19
21
|
end
|
|
@@ -27,10 +29,6 @@ module RuboCop
|
|
|
27
29
|
.gsub(/\s*\\?\n\s*/, ' ') # Any other line break, with or without backslash
|
|
28
30
|
end
|
|
29
31
|
|
|
30
|
-
def max_line_length
|
|
31
|
-
config.for_cop('Layout/LineLength')['Max']
|
|
32
|
-
end
|
|
33
|
-
|
|
34
32
|
def comment_within?(node)
|
|
35
33
|
comment_line_numbers = processed_source.comments.map { |comment| comment.loc.line }
|
|
36
34
|
|
|
@@ -59,7 +59,7 @@ module RuboCop
|
|
|
59
59
|
return node.loc.name if node.casgn_type?
|
|
60
60
|
|
|
61
61
|
if LSP.enabled?
|
|
62
|
-
end_range = node.loc
|
|
62
|
+
end_range = node.loc?(:name) ? node.loc.name : node.loc.begin
|
|
63
63
|
node.source_range.begin.join(end_range)
|
|
64
64
|
else
|
|
65
65
|
node.source_range
|
|
@@ -8,8 +8,27 @@ module RuboCop
|
|
|
8
8
|
|
|
9
9
|
private
|
|
10
10
|
|
|
11
|
-
def
|
|
12
|
-
config.for_cop('Layout/LineLength')['
|
|
11
|
+
def allow_rbs_inline_annotation?
|
|
12
|
+
config.for_cop('Layout/LineLength')['AllowRBSInlineAnnotation']
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def rbs_inline_annotation_on_source_line?(line_index)
|
|
16
|
+
source_line_number = line_index + processed_source.buffer.first_line
|
|
17
|
+
comment = processed_source.comment_at_line(source_line_number)
|
|
18
|
+
|
|
19
|
+
return false unless comment
|
|
20
|
+
|
|
21
|
+
comment.text.start_with?(/#:|#\[.+\]|#\|/)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def allow_cop_directives?
|
|
25
|
+
# TODO: This logic for backward compatibility with deprecated `IgnoreCopDirectives` option.
|
|
26
|
+
# The following three lines will be removed in RuboCop 2.0.
|
|
27
|
+
ignore_cop_directives = config.for_cop('Layout/LineLength')['IgnoreCopDirectives']
|
|
28
|
+
return true if ignore_cop_directives
|
|
29
|
+
return false if ignore_cop_directives == false
|
|
30
|
+
|
|
31
|
+
config.for_cop('Layout/LineLength')['AllowCopDirectives']
|
|
13
32
|
end
|
|
14
33
|
|
|
15
34
|
def directive_on_source_line?(line_index)
|
|
@@ -73,7 +73,7 @@ module RuboCop
|
|
|
73
73
|
|
|
74
74
|
def location(node)
|
|
75
75
|
if LSP.enabled?
|
|
76
|
-
end_range = node.loc
|
|
76
|
+
end_range = node.loc?(:name) ? node.loc.name : node.loc.begin
|
|
77
77
|
node.source_range.begin.join(end_range)
|
|
78
78
|
else
|
|
79
79
|
node.source_range
|
|
@@ -200,7 +200,7 @@ module RuboCop
|
|
|
200
200
|
end
|
|
201
201
|
|
|
202
202
|
def grouped_expression?(node)
|
|
203
|
-
node.begin_type? && node.loc
|
|
203
|
+
node.begin_type? && node.loc?(:begin) && node.loc.begin
|
|
204
204
|
end
|
|
205
205
|
|
|
206
206
|
def inside_arg_list_parentheses?(node, ancestor)
|
|
@@ -8,8 +8,8 @@ module RuboCop
|
|
|
8
8
|
MSG = 'Space missing after %<token>s.'
|
|
9
9
|
|
|
10
10
|
def on_new_investigation
|
|
11
|
-
each_missing_space(processed_source.tokens) do |token|
|
|
12
|
-
add_offense(token.pos, message: format(MSG, token: kind
|
|
11
|
+
each_missing_space(processed_source.tokens) do |token, kind|
|
|
12
|
+
add_offense(token.pos, message: format(MSG, token: kind)) do |corrector|
|
|
13
13
|
PunctuationCorrector.add_space(corrector, token)
|
|
14
14
|
end
|
|
15
15
|
end
|
|
@@ -19,11 +19,12 @@ module RuboCop
|
|
|
19
19
|
|
|
20
20
|
def each_missing_space(tokens)
|
|
21
21
|
tokens.each_cons(2) do |token1, token2|
|
|
22
|
-
|
|
22
|
+
kind = kind(token1, token2)
|
|
23
|
+
next unless kind
|
|
23
24
|
next unless space_missing?(token1, token2)
|
|
24
25
|
next unless space_required_before?(token2)
|
|
25
26
|
|
|
26
|
-
yield token1
|
|
27
|
+
yield token1, kind
|
|
27
28
|
end
|
|
28
29
|
end
|
|
29
30
|
|
|
@@ -100,12 +100,6 @@ module RuboCop
|
|
|
100
100
|
node.parent.send_type?
|
|
101
101
|
end
|
|
102
102
|
|
|
103
|
-
def max_line_length
|
|
104
|
-
return unless config.cop_enabled?('Layout/LineLength')
|
|
105
|
-
|
|
106
|
-
config.for_cop('Layout/LineLength')['Max']
|
|
107
|
-
end
|
|
108
|
-
|
|
109
103
|
def comment_disables_cop?(comment)
|
|
110
104
|
regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
|
|
111
105
|
Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
|
|
@@ -95,13 +95,16 @@ module RuboCop
|
|
|
95
95
|
node.multiline? && !allowed_multiline_argument?(node)
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
# rubocop:disable Metrics/AbcSize
|
|
98
99
|
def method_name_and_arguments_on_same_line?(node)
|
|
99
|
-
return false
|
|
100
|
+
return false if !node.call_type? || node.last_line != node.last_argument.last_line
|
|
101
|
+
return true if node.last_argument.hash_type? && node.last_argument.braces?
|
|
100
102
|
|
|
101
|
-
line = node.loc.selector
|
|
103
|
+
line = node.loc.selector&.line || node.loc.line
|
|
102
104
|
|
|
103
|
-
line == node.last_argument.last_line
|
|
105
|
+
line == node.last_argument.last_line
|
|
104
106
|
end
|
|
107
|
+
# rubocop:enable Metrics/AbcSize
|
|
105
108
|
|
|
106
109
|
# A single argument with the closing bracket on the same line as the end
|
|
107
110
|
# of the argument is not considered multiline, even if the argument
|
|
@@ -185,7 +188,7 @@ module RuboCop
|
|
|
185
188
|
|
|
186
189
|
def heredoc?(node)
|
|
187
190
|
return false unless node.is_a?(RuboCop::AST::Node)
|
|
188
|
-
return true if node.loc
|
|
191
|
+
return true if node.loc?(:heredoc_body)
|
|
189
192
|
|
|
190
193
|
return heredoc_send?(node) if node.send_type?
|
|
191
194
|
|
|
@@ -147,7 +147,9 @@ module RuboCop
|
|
|
147
147
|
alias on_defs on_def
|
|
148
148
|
|
|
149
149
|
def on_alias(node)
|
|
150
|
-
|
|
150
|
+
return unless (new_identifier = node.new_identifier).sym_type?
|
|
151
|
+
|
|
152
|
+
handle_method_name(new_identifier, new_identifier.value)
|
|
151
153
|
end
|
|
152
154
|
|
|
153
155
|
private
|
|
@@ -232,7 +234,7 @@ module RuboCop
|
|
|
232
234
|
end
|
|
233
235
|
|
|
234
236
|
def range_position(node)
|
|
235
|
-
if node.loc
|
|
237
|
+
if node.loc?(:selector)
|
|
236
238
|
selector_end_pos = node.loc.selector.end_pos + 1
|
|
237
239
|
expr_end_pos = node.source_range.end_pos
|
|
238
240
|
|
|
@@ -193,8 +193,7 @@ module RuboCop
|
|
|
193
193
|
return_values << extract_return_value(return_node)
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
-
|
|
197
|
-
return_values << last_value if last_value
|
|
196
|
+
return_values << last_value(node)
|
|
198
197
|
|
|
199
198
|
process_return_values(return_values)
|
|
200
199
|
end
|
|
@@ -247,8 +246,9 @@ module RuboCop
|
|
|
247
246
|
end
|
|
248
247
|
|
|
249
248
|
def last_value(node)
|
|
250
|
-
value = node.begin_type? ? node.children.last : node
|
|
251
|
-
|
|
249
|
+
value = node.begin_type? ? node.children.last || s(:nil) : node
|
|
250
|
+
|
|
251
|
+
value.return_type? ? extract_return_value(value) : value
|
|
252
252
|
end
|
|
253
253
|
|
|
254
254
|
def process_return_values(return_values)
|
|
@@ -6,22 +6,40 @@ module RuboCop
|
|
|
6
6
|
# Checks for the use of JSON class methods which have potential
|
|
7
7
|
# security issues.
|
|
8
8
|
#
|
|
9
|
+
# `JSON.load` and similar methods allow deserialization of arbitrary ruby objects:
|
|
10
|
+
#
|
|
11
|
+
# [source,ruby]
|
|
12
|
+
# ----
|
|
13
|
+
# require 'json/add/string'
|
|
14
|
+
# result = JSON.load('{ "json_class": "String", "raw": [72, 101, 108, 108, 111] }')
|
|
15
|
+
# pp result # => "Hello"
|
|
16
|
+
# ----
|
|
17
|
+
#
|
|
18
|
+
# Never use `JSON.load` for untrusted user input. Prefer `JSON.parse` unless you have
|
|
19
|
+
# a concrete use-case for `JSON.load`.
|
|
20
|
+
#
|
|
21
|
+
# NOTE: Starting with `json` gem version 2.8.0, triggering this behavior without explicitly
|
|
22
|
+
# passing the `create_additions` keyword argument emits a deprecation warning, with the
|
|
23
|
+
# goal of being secure by default in the next major version 3.0.0.
|
|
24
|
+
#
|
|
9
25
|
# @safety
|
|
10
26
|
# This cop's autocorrection is unsafe because it's potentially dangerous.
|
|
11
|
-
# If using a stream, like `JSON.load(open('file'))`,
|
|
27
|
+
# If using a stream, like `JSON.load(open('file'))`, you will need to call
|
|
12
28
|
# `#read` manually, like `JSON.parse(open('file').read)`.
|
|
13
|
-
# If reading single values (rather than proper JSON objects), like
|
|
14
|
-
# `JSON.load('false')`, it will need to pass the `quirks_mode: true`
|
|
15
|
-
# option, like `JSON.parse('false', quirks_mode: true)`.
|
|
16
29
|
# Other similar issues may apply.
|
|
17
30
|
#
|
|
18
31
|
# @example
|
|
19
32
|
# # bad
|
|
20
|
-
# JSON.load(
|
|
21
|
-
# JSON.restore(
|
|
33
|
+
# JSON.load('{}')
|
|
34
|
+
# JSON.restore('{}')
|
|
22
35
|
#
|
|
23
36
|
# # good
|
|
24
|
-
# JSON.parse(
|
|
37
|
+
# JSON.parse('{}')
|
|
38
|
+
# JSON.unsafe_load('{}')
|
|
39
|
+
#
|
|
40
|
+
# # good - explicit use of `create_additions` option
|
|
41
|
+
# JSON.load('{}', create_additions: true)
|
|
42
|
+
# JSON.load('{}', create_additions: false)
|
|
25
43
|
#
|
|
26
44
|
class JSONLoad < Base
|
|
27
45
|
extend AutoCorrector
|
|
@@ -29,13 +47,17 @@ module RuboCop
|
|
|
29
47
|
MSG = 'Prefer `JSON.parse` over `JSON.%<method>s`.'
|
|
30
48
|
RESTRICT_ON_SEND = %i[load restore].freeze
|
|
31
49
|
|
|
32
|
-
# @!method
|
|
33
|
-
def_node_matcher :
|
|
34
|
-
(
|
|
50
|
+
# @!method insecure_json_load(node)
|
|
51
|
+
def_node_matcher :insecure_json_load, <<~PATTERN
|
|
52
|
+
(
|
|
53
|
+
send (const {nil? cbase} :JSON) ${:load :restore}
|
|
54
|
+
...
|
|
55
|
+
!(hash `(sym $:create_additions))
|
|
56
|
+
)
|
|
35
57
|
PATTERN
|
|
36
58
|
|
|
37
59
|
def on_send(node)
|
|
38
|
-
|
|
60
|
+
insecure_json_load(node) do |method|
|
|
39
61
|
add_offense(node.loc.selector, message: format(MSG, method: method)) do |corrector|
|
|
40
62
|
corrector.replace(node.loc.selector, 'parse')
|
|
41
63
|
end
|
|
@@ -95,7 +95,7 @@ module RuboCop
|
|
|
95
95
|
$(call
|
|
96
96
|
{
|
|
97
97
|
(begin (send $_ :& $_))
|
|
98
|
-
(call
|
|
98
|
+
(call $!nil? :intersection $_)
|
|
99
99
|
}
|
|
100
100
|
$%1
|
|
101
101
|
)
|
|
@@ -107,7 +107,7 @@ module RuboCop
|
|
|
107
107
|
$(call
|
|
108
108
|
{
|
|
109
109
|
(begin (send $_ :& $_))
|
|
110
|
-
(call
|
|
110
|
+
(call $!nil? :intersection $_)
|
|
111
111
|
}
|
|
112
112
|
%ARRAY_SIZE_METHODS
|
|
113
113
|
)
|
|
@@ -3,31 +3,36 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for uses of the case equality operator(
|
|
6
|
+
# Checks for uses of the case equality operator (`===`).
|
|
7
7
|
#
|
|
8
8
|
# If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
|
|
9
9
|
# the case equality operator is a constant.
|
|
10
|
-
|
|
10
|
+
#
|
|
11
11
|
# If `AllowOnSelfClass` option is enabled, the cop will ignore violations when the receiver of
|
|
12
12
|
# the case equality operator is `self.class`. Note intermediate variables are not accepted.
|
|
13
13
|
#
|
|
14
|
+
# NOTE: Regexp case equality (`/regexp/ === var`) is allowed because changing it to
|
|
15
|
+
# `/regexp/.match?(var)` needs to take into account `Regexp.last_match?`, `$~`, `$1`, etc.
|
|
16
|
+
# This potentially incompatible transformation is handled by `Performance/RegexpMatch` cop.
|
|
17
|
+
#
|
|
14
18
|
# @example
|
|
15
19
|
# # bad
|
|
16
20
|
# (1..100) === 7
|
|
17
|
-
# /something/ === some_string
|
|
18
21
|
#
|
|
19
22
|
# # good
|
|
20
|
-
# something.is_a?(Array)
|
|
21
23
|
# (1..100).include?(7)
|
|
22
|
-
# /something/.match?(some_string)
|
|
23
24
|
#
|
|
24
25
|
# @example AllowOnConstant: false (default)
|
|
25
26
|
# # bad
|
|
26
27
|
# Array === something
|
|
27
28
|
#
|
|
29
|
+
# # good
|
|
30
|
+
# something.is_a?(Array)
|
|
31
|
+
#
|
|
28
32
|
# @example AllowOnConstant: true
|
|
29
33
|
# # good
|
|
30
34
|
# Array === something
|
|
35
|
+
# something.is_a?(Array)
|
|
31
36
|
#
|
|
32
37
|
# @example AllowOnSelfClass: false (default)
|
|
33
38
|
# # bad
|
|
@@ -51,7 +56,7 @@ module RuboCop
|
|
|
51
56
|
|
|
52
57
|
def on_send(node)
|
|
53
58
|
case_equality?(node) do |lhs, rhs|
|
|
54
|
-
return if lhs.const_type? && !lhs.module_name?
|
|
59
|
+
return if lhs.regexp_type? || (lhs.const_type? && !lhs.module_name?)
|
|
55
60
|
|
|
56
61
|
add_offense(node.loc.selector) do |corrector|
|
|
57
62
|
replacement = replacement(lhs, rhs)
|
|
@@ -71,13 +76,6 @@ module RuboCop
|
|
|
71
76
|
|
|
72
77
|
def replacement(lhs, rhs)
|
|
73
78
|
case lhs.type
|
|
74
|
-
when :regexp
|
|
75
|
-
# The automatic correction from `a === b` to `a.match?(b)` needs to
|
|
76
|
-
# consider `Regexp.last_match?`, `$~`, `$1`, and etc.
|
|
77
|
-
# This correction is expected to be supported by `Performance/Regexp` cop.
|
|
78
|
-
# See: https://github.com/rubocop/rubocop-performance/issues/152
|
|
79
|
-
#
|
|
80
|
-
# So here is noop.
|
|
81
79
|
when :begin
|
|
82
80
|
begin_replacement(lhs, rhs)
|
|
83
81
|
when :const
|
|
@@ -213,9 +213,7 @@ module RuboCop
|
|
|
213
213
|
ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals.'
|
|
214
214
|
VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
|
|
215
215
|
ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
|
|
216
|
-
LINE_LENGTH = 'Layout/LineLength'
|
|
217
216
|
ENABLED = 'Enabled'
|
|
218
|
-
MAX = 'Max'
|
|
219
217
|
SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'
|
|
220
218
|
|
|
221
219
|
# The shovel operator `<<` does not have its own type. It is a `send`
|
|
@@ -399,7 +397,7 @@ module RuboCop
|
|
|
399
397
|
# of the longest line + the length of the corrected assignment is
|
|
400
398
|
# greater than the max configured line length
|
|
401
399
|
def correction_exceeds_line_limit?(node, branches)
|
|
402
|
-
return false unless
|
|
400
|
+
return false unless config.cop_enabled?('Layout/LineLength')
|
|
403
401
|
|
|
404
402
|
assignment = lhs(tail(branches[0]))
|
|
405
403
|
|
|
@@ -417,14 +415,6 @@ module RuboCop
|
|
|
417
415
|
assignment + longest_line
|
|
418
416
|
end
|
|
419
417
|
|
|
420
|
-
def line_length_cop_enabled?
|
|
421
|
-
config.for_cop(LINE_LENGTH)[ENABLED]
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
def max_line_length
|
|
425
|
-
config.for_cop(LINE_LENGTH)[MAX]
|
|
426
|
-
end
|
|
427
|
-
|
|
428
418
|
def single_line_conditions_only?
|
|
429
419
|
cop_config[SINGLE_LINE_CONDITIONS_ONLY]
|
|
430
420
|
end
|
|
@@ -444,7 +434,7 @@ module RuboCop
|
|
|
444
434
|
next if child.parent.dstr_type?
|
|
445
435
|
|
|
446
436
|
white_space = white_space_range(child, column)
|
|
447
|
-
corrector.remove(white_space) if white_space
|
|
437
|
+
corrector.remove(white_space) if white_space
|
|
448
438
|
end
|
|
449
439
|
|
|
450
440
|
if condition.loc.else && !same_line?(condition.else_branch, condition)
|
|
@@ -465,9 +455,13 @@ module RuboCop
|
|
|
465
455
|
|
|
466
456
|
def white_space_range(node, column)
|
|
467
457
|
expression = node.source_range
|
|
468
|
-
|
|
458
|
+
end_pos = expression.begin_pos
|
|
459
|
+
begin_pos = end_pos - (expression.column - column - 2)
|
|
460
|
+
|
|
461
|
+
return nil if begin_pos > end_pos
|
|
469
462
|
|
|
470
|
-
Parser::Source::Range.new(expression.source_buffer, begin_pos,
|
|
463
|
+
white_space = Parser::Source::Range.new(expression.source_buffer, begin_pos, end_pos)
|
|
464
|
+
white_space if white_space.source.strip.empty?
|
|
471
465
|
end
|
|
472
466
|
|
|
473
467
|
def assignment(node)
|
|
@@ -29,25 +29,30 @@ module RuboCop
|
|
|
29
29
|
# @example IgnoreModules: false (default)
|
|
30
30
|
# # bad
|
|
31
31
|
# class Foo
|
|
32
|
-
# MyClass = Struct.new
|
|
32
|
+
# MyClass = Struct.new
|
|
33
33
|
# end
|
|
34
34
|
#
|
|
35
35
|
# # good
|
|
36
36
|
# class Foo
|
|
37
|
-
# MyClass = Struct.new
|
|
37
|
+
# MyClass = Struct.new
|
|
38
38
|
# public_constant :MyClass
|
|
39
39
|
# end
|
|
40
40
|
#
|
|
41
41
|
# @example IgnoreModules: true
|
|
42
42
|
# # good
|
|
43
43
|
# class Foo
|
|
44
|
-
# MyClass = Struct.new
|
|
44
|
+
# MyClass = Struct.new
|
|
45
45
|
# end
|
|
46
46
|
#
|
|
47
47
|
class ConstantVisibility < Base
|
|
48
48
|
MSG = 'Explicitly make `%<constant_name>s` public or private using ' \
|
|
49
49
|
'either `#public_constant` or `#private_constant`.'
|
|
50
50
|
|
|
51
|
+
# @!method visibility_declaration_for(node)
|
|
52
|
+
def_node_matcher :visibility_declaration_for, <<~PATTERN
|
|
53
|
+
(send nil? {:public_constant :private_constant} $...)
|
|
54
|
+
PATTERN
|
|
55
|
+
|
|
51
56
|
def on_casgn(node)
|
|
52
57
|
return unless class_or_module_scope?(node)
|
|
53
58
|
return if visibility_declaration?(node)
|
|
@@ -77,20 +82,20 @@ module RuboCop
|
|
|
77
82
|
end
|
|
78
83
|
end
|
|
79
84
|
|
|
85
|
+
# rubocop:disable Metrics/AbcSize
|
|
80
86
|
def visibility_declaration?(node)
|
|
81
87
|
node.parent.each_child_node(:send).any? do |child|
|
|
82
|
-
visibility_declaration_for
|
|
83
|
-
end
|
|
84
|
-
end
|
|
88
|
+
next false unless (arguments = visibility_declaration_for(child))
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
arguments = arguments.first.children.first.to_a if arguments.first&.splat_type?
|
|
91
|
+
constant_values = arguments.map do |argument|
|
|
92
|
+
argument.value.to_sym if argument.respond_to?(:value)
|
|
93
|
+
end
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
constant_values.include?(node.name)
|
|
96
|
+
end
|
|
93
97
|
end
|
|
98
|
+
# rubocop:enable Metrics/AbcSize
|
|
94
99
|
end
|
|
95
100
|
end
|
|
96
101
|
end
|