rubocop 0.91.1 → 1.1.0
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 +8 -5
- data/config/default.yml +143 -56
- data/lib/rubocop.rb +17 -5
- data/lib/rubocop/cached_data.rb +2 -1
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
- data/lib/rubocop/cli/command/version.rb +1 -1
- data/lib/rubocop/comment_config.rb +1 -1
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_loader.rb +19 -2
- data/lib/rubocop/config_loader_resolver.rb +7 -5
- data/lib/rubocop/config_regeneration.rb +33 -0
- data/lib/rubocop/config_validator.rb +7 -6
- data/lib/rubocop/cop/badge.rb +9 -24
- data/lib/rubocop/cop/base.rb +16 -1
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +23 -3
- data/lib/rubocop/cop/commissioner.rb +36 -22
- data/lib/rubocop/cop/corrector.rb +3 -1
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +1 -1
- data/lib/rubocop/cop/force.rb +1 -1
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -10
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -0
- data/lib/rubocop/cop/layout/class_structure.rb +7 -0
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +6 -9
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +7 -7
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +1 -2
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -11
- data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +37 -13
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +2 -0
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +18 -1
- data/lib/rubocop/cop/lint/boolean_symbol.rb +3 -0
- data/lib/rubocop/cop/lint/debugger.rb +2 -3
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +77 -0
- data/lib/rubocop/cop/lint/empty_block.rb +46 -0
- data/lib/rubocop/cop/lint/flip_flop.rb +8 -2
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +17 -3
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +46 -13
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +27 -8
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +95 -0
- data/lib/rubocop/cop/lint/to_json.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +185 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/metrics/block_length.rb +3 -1
- data/lib/rubocop/cop/metrics/class_length.rb +14 -6
- data/lib/rubocop/cop/metrics/parameter_lists.rb +4 -1
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +1 -1
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -1
- data/lib/rubocop/cop/offense.rb +18 -5
- data/lib/rubocop/cop/security/open.rb +12 -10
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +6 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +3 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +142 -0
- data/lib/rubocop/cop/style/array_coercion.rb +4 -0
- data/lib/rubocop/cop/style/case_like_if.rb +20 -4
- data/lib/rubocop/cop/style/class_equality_comparison.rb +64 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +8 -1
- data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
- data/lib/rubocop/cop/style/date_time.rb +12 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +67 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +6 -2
- data/lib/rubocop/cop/style/for.rb +0 -4
- data/lib/rubocop/cop/style/format_string_token.rb +48 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +10 -13
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -11
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +7 -11
- data/lib/rubocop/cop/style/method_def_parentheses.rb +0 -4
- data/lib/rubocop/cop/style/mixin_usage.rb +7 -27
- data/lib/rubocop/cop/style/multiple_comparison.rb +54 -7
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
- data/lib/rubocop/cop/style/optional_boolean_parameter.rb +11 -3
- data/lib/rubocop/cop/style/raise_args.rb +0 -3
- data/lib/rubocop/cop/style/redundant_begin.rb +36 -8
- data/lib/rubocop/cop/style/redundant_condition.rb +5 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +45 -24
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
- data/lib/rubocop/cop/style/redundant_self.rb +3 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
- data/lib/rubocop/cop/style/semicolon.rb +3 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +14 -2
- data/lib/rubocop/cop/style/swap_values.rb +108 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
- data/lib/rubocop/cop/team.rb +6 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +0 -4
- data/lib/rubocop/ext/regexp_node.rb +29 -10
- data/lib/rubocop/ext/regexp_parser.rb +77 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +12 -5
- data/lib/rubocop/formatter/formatter_set.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/magic_comment.rb +2 -2
- data/lib/rubocop/options.rb +22 -17
- data/lib/rubocop/result_cache.rb +8 -2
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +5 -5
- data/lib/rubocop/rspec/shared_contexts.rb +4 -0
- data/lib/rubocop/runner.rb +9 -5
- data/lib/rubocop/target_finder.rb +27 -26
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +61 -6
- metadata +21 -16
- data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
@@ -0,0 +1,185 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Looks for `reduce` or `inject` blocks where the value returned (implicitly or
|
7
|
+
# explicitly) does not include the accumulator. A block is considered valid as
|
8
|
+
# long as at least one return value includes the accumulator.
|
9
|
+
#
|
10
|
+
# If the accumulator is not included in the return value, then the entire
|
11
|
+
# block will just return a transformation of the last element value, and
|
12
|
+
# could be rewritten as such without a loop.
|
13
|
+
#
|
14
|
+
# Also catches instances where an index of the accumulator is returned, as
|
15
|
+
# this may change the type of object being retained.
|
16
|
+
#
|
17
|
+
# NOTE: For the purpose of reducing false positives, this cop only flags
|
18
|
+
# returns in `reduce` blocks where the element is the only variable in
|
19
|
+
# the expression (since we will not be able to tell what other variables
|
20
|
+
# relate to via static analysis).
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
#
|
24
|
+
# # bad
|
25
|
+
# (1..4).reduce(0) do |acc, el|
|
26
|
+
# el * 2
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# # bad, may raise a NoMethodError after the first iteration
|
30
|
+
# %w(a b c).reduce({}) do |acc, letter|
|
31
|
+
# acc[letter] = true
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# # good
|
35
|
+
# (1..4).reduce(0) do |acc, el|
|
36
|
+
# acc + el * 2
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# # good, element is returned but modified using the accumulator
|
40
|
+
# values.reduce do |acc, el|
|
41
|
+
# el << acc
|
42
|
+
# el
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # good, returns the accumulator instead of the index
|
46
|
+
# %w(a b c).reduce({}) do |acc, letter|
|
47
|
+
# acc[letter] = true
|
48
|
+
# acc
|
49
|
+
# end
|
50
|
+
#
|
51
|
+
# # good, at least one branch returns the accumulator
|
52
|
+
# values.reduce(nil) do |result, value|
|
53
|
+
# break result if something?
|
54
|
+
# value
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# # ignored as the return value cannot be determined
|
58
|
+
# enum.reduce do |acc, el|
|
59
|
+
# x = foo(acc, el)
|
60
|
+
# bar(x)
|
61
|
+
# end
|
62
|
+
class UnmodifiedReduceAccumulator < Base
|
63
|
+
MSG = 'Ensure the accumulator `%<accum>s` will be modified by `%<method>s`.'
|
64
|
+
MSG_INDEX = 'Do not return an element of the accumulator in `%<method>s`.'
|
65
|
+
|
66
|
+
def_node_matcher :reduce_with_block?, <<~PATTERN
|
67
|
+
(block (send _recv {:reduce :inject} ...) (args arg+) ...)
|
68
|
+
PATTERN
|
69
|
+
|
70
|
+
def_node_matcher :accumulator_index?, <<~PATTERN
|
71
|
+
(send (lvar %1) {:[] :[]=} ...)
|
72
|
+
PATTERN
|
73
|
+
|
74
|
+
def_node_search :element_modified?, <<~PATTERN
|
75
|
+
{
|
76
|
+
(send _receiver !{:[] :[]=} <`(lvar %1) `_ ...>) # method(el, ...)
|
77
|
+
(send (lvar %1) _message <{ivar gvar cvar lvar send} ...>) # el.method(...)
|
78
|
+
(lvasgn %1 _) # el = ...
|
79
|
+
(%RuboCop::AST::Node::SHORTHAND_ASSIGNMENTS (lvasgn %1) ... _) # el += ...
|
80
|
+
}
|
81
|
+
PATTERN
|
82
|
+
|
83
|
+
def_node_matcher :lvar_used?, <<~PATTERN
|
84
|
+
{
|
85
|
+
(lvar %1)
|
86
|
+
(lvasgn %1 ...)
|
87
|
+
(send (lvar %1) :<< ...)
|
88
|
+
(dstr (begin (lvar %1)))
|
89
|
+
(%RuboCop::AST::Node::SHORTHAND_ASSIGNMENTS (lvasgn %1))
|
90
|
+
}
|
91
|
+
PATTERN
|
92
|
+
|
93
|
+
def_node_search :expression_values, <<~PATTERN
|
94
|
+
{
|
95
|
+
(%RuboCop::AST::Node::VARIABLES $_)
|
96
|
+
(%RuboCop::AST::Node::EQUALS_ASSIGNMENTS $_ ...)
|
97
|
+
(send (%RuboCop::AST::Node::VARIABLES $_) :<< ...)
|
98
|
+
$(send _ _)
|
99
|
+
(dstr (begin {(%RuboCop::AST::Node::VARIABLES $_)}))
|
100
|
+
(%RuboCop::AST::Node::SHORTHAND_ASSIGNMENTS (%RuboCop::AST::Node::EQUALS_ASSIGNMENTS $_) ...)
|
101
|
+
}
|
102
|
+
PATTERN
|
103
|
+
|
104
|
+
def on_block(node)
|
105
|
+
return unless reduce_with_block?(node)
|
106
|
+
|
107
|
+
check_return_values(node)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
|
112
|
+
# Return values in a block are either the value given to next,
|
113
|
+
# the last line of a multiline block, or the only line of the block
|
114
|
+
def return_values(block_body_node)
|
115
|
+
nodes = [block_body_node.begin_type? ? block_body_node.child_nodes.last : block_body_node]
|
116
|
+
|
117
|
+
block_body_node.each_descendant(:next, :break) do |n|
|
118
|
+
# Ignore `next`/`break` inside an inner block
|
119
|
+
next if n.each_ancestor(:block).first != block_body_node.parent
|
120
|
+
next unless n.first_argument
|
121
|
+
|
122
|
+
nodes << n.first_argument
|
123
|
+
end
|
124
|
+
|
125
|
+
nodes
|
126
|
+
end
|
127
|
+
|
128
|
+
def check_return_values(block_node)
|
129
|
+
return_values = return_values(block_node.body)
|
130
|
+
accumulator_name = block_arg_name(block_node, 0)
|
131
|
+
element_name = block_arg_name(block_node, 1)
|
132
|
+
message_opts = { method: block_node.method_name, accum: accumulator_name }
|
133
|
+
|
134
|
+
if (node = returned_accumulator_index(return_values, accumulator_name))
|
135
|
+
add_offense(node, message: format(MSG_INDEX, message_opts))
|
136
|
+
elsif potential_offense?(return_values, block_node.body, element_name, accumulator_name)
|
137
|
+
return_values.each do |return_val|
|
138
|
+
unless acceptable_return?(return_val, element_name)
|
139
|
+
add_offense(return_val, message: format(MSG, message_opts))
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def block_arg_name(node, index)
|
146
|
+
node.arguments[index].node_parts[0]
|
147
|
+
end
|
148
|
+
|
149
|
+
# Look for an index of the accumulator being returned
|
150
|
+
# This is always an offense, in order to try to catch potential exceptions
|
151
|
+
# due to type mismatches
|
152
|
+
def returned_accumulator_index(return_values, accumulator_name)
|
153
|
+
return_values.detect { |val| accumulator_index?(val, accumulator_name) }
|
154
|
+
end
|
155
|
+
|
156
|
+
def potential_offense?(return_values, block_body, element_name, accumulator_name)
|
157
|
+
!(element_modified?(block_body, element_name) ||
|
158
|
+
returns_accumulator_anywhere?(return_values, accumulator_name))
|
159
|
+
end
|
160
|
+
|
161
|
+
# If the accumulator is used in any return value, the node is acceptable since
|
162
|
+
# the accumulator has a chance to change each iteration
|
163
|
+
def returns_accumulator_anywhere?(return_values, accumulator_name)
|
164
|
+
return_values.any? { |node| lvar_used?(node, accumulator_name) }
|
165
|
+
end
|
166
|
+
|
167
|
+
# Determine if a return value is acceptable for the purposes of this cop
|
168
|
+
# If it is an expression containing the accumulator, it is acceptable
|
169
|
+
# Otherwise, it is only unacceptable if it contains the iterated element, since we
|
170
|
+
# otherwise do not have enough information to prevent false positives.
|
171
|
+
def acceptable_return?(return_val, element_name)
|
172
|
+
vars = expression_values(return_val).uniq
|
173
|
+
return true if vars.none? || (vars - [element_name]).any?
|
174
|
+
|
175
|
+
false
|
176
|
+
end
|
177
|
+
|
178
|
+
# Exclude `begin` nodes inside a `dstr` from being collected by `return_values`
|
179
|
+
def allowed_type?(parent_node)
|
180
|
+
!parent_node.dstr_type?
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
@@ -255,7 +255,7 @@ module RuboCop
|
|
255
255
|
PATTERN
|
256
256
|
end
|
257
257
|
|
258
|
-
|
258
|
+
public_send(matcher_name, child)
|
259
259
|
end
|
260
260
|
end
|
261
261
|
|
@@ -279,7 +279,7 @@ module RuboCop
|
|
279
279
|
PATTERN
|
280
280
|
end
|
281
281
|
|
282
|
-
|
282
|
+
public_send(matcher_name, child)
|
283
283
|
end
|
284
284
|
end
|
285
285
|
end
|
@@ -29,6 +29,8 @@ module RuboCop
|
|
29
29
|
# content.
|
30
30
|
# HEREDOC
|
31
31
|
# end # 5 points
|
32
|
+
#
|
33
|
+
# NOTE: This cop does not apply for `Struct` definitions.
|
32
34
|
class BlockLength < Base
|
33
35
|
include CodeLength
|
34
36
|
|
@@ -36,7 +38,7 @@ module RuboCop
|
|
36
38
|
|
37
39
|
def on_block(node)
|
38
40
|
return if excluded_method?(node)
|
39
|
-
return if node.class_constructor?
|
41
|
+
return if node.class_constructor? || node.struct_constructor?
|
40
42
|
|
41
43
|
check_code_length(node)
|
42
44
|
end
|
@@ -29,6 +29,8 @@ module RuboCop
|
|
29
29
|
# HEREDOC
|
30
30
|
# end # 5 points
|
31
31
|
#
|
32
|
+
#
|
33
|
+
# NOTE: This cop also applies for `Struct` definitions.
|
32
34
|
class ClassLength < Base
|
33
35
|
include CodeLength
|
34
36
|
|
@@ -37,17 +39,23 @@ module RuboCop
|
|
37
39
|
end
|
38
40
|
|
39
41
|
def on_casgn(node)
|
40
|
-
|
41
|
-
|
42
|
+
parent = node.parent
|
43
|
+
|
44
|
+
if parent&.assignment?
|
45
|
+
block_node = parent.children[1]
|
46
|
+
elsif parent&.parent&.masgn_type?
|
47
|
+
block_node = parent.parent.children[1]
|
48
|
+
else
|
49
|
+
_scope, _name, block_node = *node
|
42
50
|
end
|
51
|
+
|
52
|
+
return unless block_node.respond_to?(:class_definition?) && block_node.class_definition?
|
53
|
+
|
54
|
+
check_code_length(block_node)
|
43
55
|
end
|
44
56
|
|
45
57
|
private
|
46
58
|
|
47
|
-
def_node_matcher :class_definition?, <<~PATTERN
|
48
|
-
(casgn nil? _ (block (send (const {nil? cbase} :Class) :new) ...))
|
49
|
-
PATTERN
|
50
|
-
|
51
59
|
def message(length, max_length)
|
52
60
|
format('Class has too many lines. [%<length>d/%<max>d]',
|
53
61
|
length: length,
|
@@ -12,6 +12,9 @@ module RuboCop
|
|
12
12
|
MSG = 'Avoid parameter lists longer than %<max>d parameters. ' \
|
13
13
|
'[%<count>d/%<max>d]'
|
14
14
|
|
15
|
+
NAMED_KEYWORD_TYPES = %i[kwoptarg kwarg].freeze
|
16
|
+
private_constant :NAMED_KEYWORD_TYPES
|
17
|
+
|
15
18
|
def on_args(node)
|
16
19
|
count = args_count(node)
|
17
20
|
return unless count > max_params
|
@@ -33,7 +36,7 @@ module RuboCop
|
|
33
36
|
if count_keyword_args?
|
34
37
|
node.children.size
|
35
38
|
else
|
36
|
-
node.children.count { |a|
|
39
|
+
node.children.count { |a| !NAMED_KEYWORD_TYPES.include?(a.type) }
|
37
40
|
end
|
38
41
|
end
|
39
42
|
|
@@ -137,7 +137,7 @@ module RuboCop
|
|
137
137
|
end
|
138
138
|
|
139
139
|
# Internal helper class to hold autocorrect data
|
140
|
-
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
140
|
+
Autocorrection = Struct.new(:match, :block_node, :leading, :trailing) do
|
141
141
|
def self.from_each_with_object(node, match)
|
142
142
|
new(match, node, 0, 0)
|
143
143
|
end
|
@@ -18,7 +18,7 @@ module RuboCop
|
|
18
18
|
'name its argument `other`.'
|
19
19
|
|
20
20
|
OP_LIKE_METHODS = %i[eql? equal?].freeze
|
21
|
-
EXCLUDED = %i[+@ -@ [] []= << === `].freeze
|
21
|
+
EXCLUDED = %i[+@ -@ [] []= << === ` =~].freeze
|
22
22
|
|
23
23
|
def_node_matcher :op_method_candidate?, <<~PATTERN
|
24
24
|
(def [#op_method? $_] (args $(arg [!:other !:_other])) _)
|
@@ -67,7 +67,8 @@ module RuboCop
|
|
67
67
|
private
|
68
68
|
|
69
69
|
def allowed_method_name?(method_name, prefix)
|
70
|
-
!method_name.
|
70
|
+
!(method_name.start_with?(prefix) && # cheap check to avoid allocating Regexp
|
71
|
+
method_name.match?(/^#{prefix}[^0-9]/)) ||
|
71
72
|
method_name == expected_name(method_name, prefix) ||
|
72
73
|
method_name.end_with?('=') ||
|
73
74
|
allowed_method?(method_name)
|
data/lib/rubocop/cop/offense.rb
CHANGED
@@ -63,10 +63,23 @@ module RuboCop
|
|
63
63
|
attr_reader :corrector
|
64
64
|
|
65
65
|
PseudoSourceRange = Struct.new(:line, :column, :source_line, :begin_pos,
|
66
|
-
:end_pos)
|
66
|
+
:end_pos) do
|
67
|
+
alias_method :first_line, :line
|
68
|
+
alias_method :last_line, :line
|
69
|
+
alias_method :last_column, :column
|
70
|
+
|
71
|
+
def column_range
|
72
|
+
column...last_column
|
73
|
+
end
|
74
|
+
|
75
|
+
def size
|
76
|
+
end_pos - begin_pos
|
77
|
+
end
|
78
|
+
alias_method :length, :size
|
79
|
+
end
|
67
80
|
private_constant :PseudoSourceRange
|
68
81
|
|
69
|
-
NO_LOCATION = PseudoSourceRange.new(1, 0, '', 0,
|
82
|
+
NO_LOCATION = PseudoSourceRange.new(1, 0, '', 0, 0).freeze
|
70
83
|
|
71
84
|
# @api private
|
72
85
|
def initialize(severity, location, message, cop_name, # rubocop:disable Metrics/ParameterLists
|
@@ -200,7 +213,7 @@ module RuboCop
|
|
200
213
|
# returns `true` if two offenses contain same attributes
|
201
214
|
def ==(other)
|
202
215
|
COMPARISON_ATTRIBUTES.all? do |attribute|
|
203
|
-
|
216
|
+
public_send(attribute) == other.public_send(attribute)
|
204
217
|
end
|
205
218
|
end
|
206
219
|
|
@@ -208,7 +221,7 @@ module RuboCop
|
|
208
221
|
|
209
222
|
def hash
|
210
223
|
COMPARISON_ATTRIBUTES.reduce(0) do |hash, attribute|
|
211
|
-
hash ^
|
224
|
+
hash ^ public_send(attribute).hash
|
212
225
|
end
|
213
226
|
end
|
214
227
|
|
@@ -221,7 +234,7 @@ module RuboCop
|
|
221
234
|
# comparison result
|
222
235
|
def <=>(other)
|
223
236
|
COMPARISON_ATTRIBUTES.each do |attribute|
|
224
|
-
result =
|
237
|
+
result = public_send(attribute) <=> other.public_send(attribute)
|
225
238
|
return result unless result.zero?
|
226
239
|
end
|
227
240
|
0
|
@@ -3,35 +3,37 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Security
|
6
|
-
# This cop checks for the use of `Kernel#open`.
|
6
|
+
# This cop checks for the use of `Kernel#open` and `URI.open`.
|
7
7
|
#
|
8
|
-
# `Kernel#open`
|
9
|
-
# by prefixing a pipe symbol (e.g., `open("| ls")`).
|
10
|
-
# a serious security risk by using variable input to
|
11
|
-
# `Kernel#open`. It would be better to use
|
12
|
-
# `URI#open` explicitly.
|
8
|
+
# `Kernel#open` and `URI.open` enable not only file access but also process
|
9
|
+
# invocation by prefixing a pipe symbol (e.g., `open("| ls")`).
|
10
|
+
# So, it may lead to a serious security risk by using variable input to
|
11
|
+
# the argument of `Kernel#open` and `URI.open`. It would be better to use
|
12
|
+
# `File.open`, `IO.popen` or `URI.parse#open` explicitly.
|
13
13
|
#
|
14
14
|
# @example
|
15
15
|
# # bad
|
16
16
|
# open(something)
|
17
|
+
# URI.open(something)
|
17
18
|
#
|
18
19
|
# # good
|
19
20
|
# File.open(something)
|
20
21
|
# IO.popen(something)
|
21
22
|
# URI.parse(something).open
|
22
23
|
class Open < Base
|
23
|
-
MSG = 'The use of `
|
24
|
+
MSG = 'The use of `%<receiver>sopen` is a serious security risk.'
|
24
25
|
RESTRICT_ON_SEND = %i[open].freeze
|
25
26
|
|
26
27
|
def_node_matcher :open?, <<~PATTERN
|
27
|
-
(send nil? :open $!str ...)
|
28
|
+
(send ${nil? (const {nil? cbase} :URI)} :open $!str ...)
|
28
29
|
PATTERN
|
29
30
|
|
30
31
|
def on_send(node)
|
31
|
-
open?(node) do |code|
|
32
|
+
open?(node) do |receiver, code|
|
32
33
|
return if safe?(code)
|
33
34
|
|
34
|
-
|
35
|
+
message = format(MSG, receiver: receiver ? "#{receiver.source}." : 'Kernel#')
|
36
|
+
add_offense(node.loc.selector, message: message)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
@@ -83,8 +83,8 @@ module RuboCop
|
|
83
83
|
|
84
84
|
def on_send(node)
|
85
85
|
return unless node.access_modifier?
|
86
|
-
return if node.parent
|
87
|
-
return if
|
86
|
+
return if node.parent&.pair_type?
|
87
|
+
return if allow_modifiers_on_symbols?(node)
|
88
88
|
|
89
89
|
if offense?(node)
|
90
90
|
add_offense(node.loc.selector) if opposite_style_detected
|
@@ -95,6 +95,10 @@ module RuboCop
|
|
95
95
|
|
96
96
|
private
|
97
97
|
|
98
|
+
def allow_modifiers_on_symbols?(node)
|
99
|
+
cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node)
|
100
|
+
end
|
101
|
+
|
98
102
|
def offense?(node)
|
99
103
|
(group_style? && access_modifier_is_inlined?(node)) ||
|
100
104
|
(inline_style? && access_modifier_is_not_inlined?(node))
|