rubocop 0.91.0 → 1.0.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 +1 -1
- data/config/default.yml +100 -54
- data/lib/rubocop.rb +10 -6
- data/lib/rubocop/cached_data.rb +2 -1
- data/lib/rubocop/cli/command/version.rb +1 -1
- data/lib/rubocop/comment_config.rb +9 -5
- 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/commissioner.rb +34 -20
- 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/gemspec/required_ruby_version.rb +10 -10
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +4 -7
- data/lib/rubocop/cop/layout/class_structure.rb +8 -1
- data/lib/rubocop/cop/layout/dot_position.rb +6 -9
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +4 -13
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +13 -8
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +1 -2
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +10 -1
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +4 -13
- data/lib/rubocop/cop/layout/space_around_operators.rb +4 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -7
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +0 -4
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -18
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -2
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +2 -2
- 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/constant_definition_in_block.rb +23 -3
- data/lib/rubocop/cop/lint/duplicate_rescue_exception.rb +2 -4
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +37 -0
- data/lib/rubocop/cop/lint/identity_comparison.rb +5 -3
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +2 -5
- data/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb +1 -0
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +22 -12
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +14 -4
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +78 -0
- data/lib/rubocop/cop/lint/rescue_type.rb +0 -1
- data/lib/rubocop/cop/lint/shadowed_exception.rb +6 -6
- data/lib/rubocop/cop/lint/to_json.rb +1 -1
- data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -5
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +3 -9
- data/lib/rubocop/cop/lint/useless_times.rb +11 -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/metrics/utils/abc_size_calculator.rb +25 -16
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +3 -3
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/rescue_node.rb +1 -0
- data/lib/rubocop/cop/mixin/statement_modifier.rb +9 -3
- data/lib/rubocop/cop/mixin/visibility_help.rb +4 -16
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +15 -2
- 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/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 +13 -11
- data/lib/rubocop/cop/style/comment_annotation.rb +6 -0
- data/lib/rubocop/cop/style/commented_keyword.rb +7 -8
- data/lib/rubocop/cop/style/date_time.rb +12 -1
- 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/hash_as_last_array_item.rb +15 -6
- data/lib/rubocop/cop/style/if_unless_modifier.rb +0 -4
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +1 -6
- 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/multiline_block_chain.rb +2 -2
- data/lib/rubocop/cop/style/multiline_when_then.rb +1 -0
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +3 -1
- data/lib/rubocop/cop/style/optional_boolean_parameter.rb +12 -1
- data/lib/rubocop/cop/style/raise_args.rb +0 -3
- data/lib/rubocop/cop/style/random_with_offset.rb +3 -3
- data/lib/rubocop/cop/style/redundant_assignment.rb +1 -9
- 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_conditional.rb +4 -5
- data/lib/rubocop/cop/style/redundant_interpolation.rb +6 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +6 -3
- data/lib/rubocop/cop/style/redundant_percent_q.rb +9 -11
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +39 -24
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -15
- data/lib/rubocop/cop/style/redundant_return.rb +17 -17
- data/lib/rubocop/cop/style/redundant_self.rb +10 -9
- data/lib/rubocop/cop/style/redundant_sort.rb +13 -24
- data/lib/rubocop/cop/style/redundant_sort_by.rb +5 -9
- data/lib/rubocop/cop/style/rescue_standard_error.rb +20 -16
- data/lib/rubocop/cop/style/safe_navigation.rb +16 -4
- data/lib/rubocop/cop/style/string_concatenation.rb +14 -2
- data/lib/rubocop/cop/style/ternary_parentheses.rb +2 -3
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +4 -3
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +3 -1
- data/lib/rubocop/cop/util.rb +0 -1
- data/lib/rubocop/cop/variable_force/branch.rb +0 -4
- data/lib/rubocop/directive_comment.rb +32 -0
- data/lib/rubocop/ext/regexp_node.rb +20 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +12 -5
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- 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/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 +14 -17
- data/lib/rubocop/cop/mixin/regexp_literal_help.rb +0 -43
- data/lib/rubocop/cop/tokens_util.rb +0 -84
@@ -75,8 +75,7 @@ module RuboCop
|
|
75
75
|
|
76
76
|
def rescued_groups_for(rescues)
|
77
77
|
rescues.map do |group|
|
78
|
-
|
79
|
-
evaluate_exceptions(rescue_group)
|
78
|
+
evaluate_exceptions(group)
|
80
79
|
end
|
81
80
|
end
|
82
81
|
|
@@ -117,14 +116,15 @@ module RuboCop
|
|
117
116
|
$VERBOSE = old_verbose
|
118
117
|
end
|
119
118
|
|
120
|
-
def evaluate_exceptions(
|
121
|
-
|
122
|
-
|
119
|
+
def evaluate_exceptions(group)
|
120
|
+
rescued_exceptions = group.exceptions
|
121
|
+
|
122
|
+
if rescued_exceptions.any?
|
123
123
|
rescued_exceptions.each_with_object([]) do |exception, converted|
|
124
124
|
begin
|
125
125
|
silence_warnings do
|
126
126
|
# Avoid printing deprecation warnings about constants
|
127
|
-
converted << Kernel.const_get(exception)
|
127
|
+
converted << Kernel.const_get(exception.source)
|
128
128
|
end
|
129
129
|
rescue NameError
|
130
130
|
converted << nil
|
@@ -159,16 +159,12 @@ module RuboCop
|
|
159
159
|
end
|
160
160
|
|
161
161
|
def preceded_by_continue_statement?(break_statement)
|
162
|
-
|
162
|
+
break_statement.left_siblings.any? do |sibling|
|
163
163
|
next if sibling.loop_keyword? || loop_method?(sibling)
|
164
164
|
|
165
165
|
sibling.each_descendant(:next, :redo).any?
|
166
166
|
end
|
167
167
|
end
|
168
|
-
|
169
|
-
def left_siblings_of(node)
|
170
|
-
node.parent.children[0, node.sibling_index]
|
171
|
-
end
|
172
168
|
end
|
173
169
|
end
|
174
170
|
end
|
@@ -131,12 +131,10 @@ module RuboCop
|
|
131
131
|
MSG = 'Useless `%<current>s` access modifier.'
|
132
132
|
|
133
133
|
def on_class(node)
|
134
|
-
check_node(node.
|
135
|
-
end
|
136
|
-
|
137
|
-
def on_module(node)
|
138
|
-
check_node(node.children[1]) # module body
|
134
|
+
check_node(node.body)
|
139
135
|
end
|
136
|
+
alias on_module on_class
|
137
|
+
alias on_sclass on_class
|
140
138
|
|
141
139
|
def on_block(node)
|
142
140
|
return unless eval_call?(node)
|
@@ -144,10 +142,6 @@ module RuboCop
|
|
144
142
|
check_node(node.body)
|
145
143
|
end
|
146
144
|
|
147
|
-
def on_sclass(node)
|
148
|
-
check_node(node.children[1]) # singleton class body
|
149
|
-
end
|
150
|
-
|
151
145
|
private
|
152
146
|
|
153
147
|
def autocorrect(corrector, node)
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
49
49
|
add_offense(node, message: format(MSG, count: count)) do |corrector|
|
50
50
|
next unless own_line?(node)
|
51
51
|
|
52
|
-
if count
|
52
|
+
if never_process?(count, node)
|
53
53
|
remove_node(corrector, node)
|
54
54
|
elsif !proc_name.empty?
|
55
55
|
autocorrect_block_pass(corrector, node, proc_name)
|
@@ -61,6 +61,10 @@ module RuboCop
|
|
61
61
|
|
62
62
|
private
|
63
63
|
|
64
|
+
def never_process?(count, node)
|
65
|
+
count < 1 || node.block_type? && node.body.nil?
|
66
|
+
end
|
67
|
+
|
64
68
|
def remove_node(corrector, node)
|
65
69
|
corrector.remove(range_by_whole_lines(node.loc.expression, include_final_newline: true))
|
66
70
|
end
|
@@ -82,7 +86,12 @@ module RuboCop
|
|
82
86
|
def fix_indentation(source, range)
|
83
87
|
# Cleanup indentation in a multiline block
|
84
88
|
source_lines = source.split("\n")
|
85
|
-
|
89
|
+
|
90
|
+
source_lines[1..-1].each do |line|
|
91
|
+
next if line.empty?
|
92
|
+
|
93
|
+
line[range] = ''
|
94
|
+
end
|
86
95
|
source_lines.join("\n")
|
87
96
|
end
|
88
97
|
|
@@ -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
|
|
@@ -81,40 +81,49 @@ module RuboCop
|
|
81
81
|
private
|
82
82
|
|
83
83
|
def assignment?(node)
|
84
|
+
return compound_assignment(node) if node.masgn_type? || node.shorthand_asgn?
|
85
|
+
|
84
86
|
node.for_type? ||
|
85
|
-
node.op_asgn_type? ||
|
86
87
|
(node.respond_to?(:setter_method?) && node.setter_method?) ||
|
87
|
-
|
88
|
+
simple_assignment?(node) ||
|
89
|
+
argument?(node)
|
88
90
|
end
|
89
91
|
|
90
|
-
def
|
91
|
-
|
92
|
+
def compound_assignment(node)
|
93
|
+
# Methods setter can not be detected for multiple assignments
|
94
|
+
# and shorthand assigns, so we'll count them here instead
|
95
|
+
children = node.masgn_type? ? node.children[0].children : node.children
|
92
96
|
|
93
|
-
|
94
|
-
|
95
|
-
|
97
|
+
will_be_miscounted = children.count do |child|
|
98
|
+
child.respond_to?(:setter_method?) &&
|
99
|
+
!child.setter_method?
|
96
100
|
end
|
101
|
+
@assignment += will_be_miscounted
|
97
102
|
|
98
|
-
|
103
|
+
false
|
99
104
|
end
|
100
105
|
|
101
|
-
def
|
102
|
-
|
106
|
+
def simple_assignment?(node)
|
107
|
+
if !node.equals_asgn?
|
108
|
+
false
|
109
|
+
elsif node.lvasgn_type?
|
110
|
+
reset_on_lvasgn(node)
|
111
|
+
capturing_variable?(node.children.first)
|
112
|
+
else
|
113
|
+
true
|
114
|
+
end
|
103
115
|
end
|
104
116
|
|
105
|
-
|
106
|
-
|
107
|
-
def assignment_doubled_in_ast?(node)
|
108
|
-
node.masgn_type? || node.or_asgn_type? || node.and_asgn_type?
|
117
|
+
def capturing_variable?(name)
|
118
|
+
name && !/^_/.match?(name)
|
109
119
|
end
|
110
120
|
|
111
121
|
def branch?(node)
|
112
122
|
BRANCH_NODES.include?(node.type)
|
113
123
|
end
|
114
124
|
|
115
|
-
# TODO: move to rubocop-ast
|
116
125
|
def argument?(node)
|
117
|
-
ARGUMENT_TYPES.include?(node.type)
|
126
|
+
ARGUMENT_TYPES.include?(node.type) && capturing_variable?(node.children.first)
|
118
127
|
end
|
119
128
|
|
120
129
|
def condition?(node)
|
@@ -8,9 +8,9 @@ module RuboCop
|
|
8
8
|
include ConfigurableFormatting
|
9
9
|
|
10
10
|
FORMATS = {
|
11
|
-
snake_case: /(?:[
|
12
|
-
normalcase: /(?:_\D*|[
|
13
|
-
non_integer: /[
|
11
|
+
snake_case: /(?:[[[:lower:]]_]|_\d+)$/,
|
12
|
+
normalcase: /(?:_\D*|[[[:upper:]][[:lower:]]]\d*)$/,
|
13
|
+
non_integer: /[[[:upper:]][[:lower:]]_]$/
|
14
14
|
}.freeze
|
15
15
|
end
|
16
16
|
end
|
@@ -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
|
@@ -57,10 +57,11 @@ module RuboCop
|
|
57
57
|
end
|
58
58
|
|
59
59
|
def first_line_comment(node)
|
60
|
-
comment =
|
61
|
-
|
60
|
+
comment = processed_source.find_comment { |c| c.loc.line == node.loc.line }
|
61
|
+
return unless comment
|
62
62
|
|
63
|
-
|
63
|
+
comment_source = comment.loc.expression.source
|
64
|
+
comment_source unless comment_disables_cop?(comment_source)
|
64
65
|
end
|
65
66
|
|
66
67
|
def parenthesize?(node)
|
@@ -80,6 +81,11 @@ module RuboCop
|
|
80
81
|
|
81
82
|
config.for_cop('Layout/LineLength')['Max']
|
82
83
|
end
|
84
|
+
|
85
|
+
def comment_disables_cop?(comment)
|
86
|
+
regexp_pattern = "# rubocop : (disable|todo) ([^,],)* (all|#{cop_name})"
|
87
|
+
Regexp.new(regexp_pattern.gsub(' ', '\s*')).match?(comment)
|
88
|
+
end
|
83
89
|
end
|
84
90
|
end
|
85
91
|
end
|
@@ -16,32 +16,20 @@ module RuboCop
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def find_visibility_start(node)
|
19
|
-
|
20
|
-
|
21
|
-
|
19
|
+
node.left_siblings
|
20
|
+
.reverse
|
21
|
+
.find(&method(:visibility_block?))
|
22
22
|
end
|
23
23
|
|
24
24
|
# Navigate to find the last protected method
|
25
25
|
def find_visibility_end(node)
|
26
26
|
possible_visibilities = VISIBILITY_SCOPES - [node_visibility(node)]
|
27
|
-
right =
|
27
|
+
right = node.right_siblings
|
28
28
|
right.find do |child_node|
|
29
29
|
possible_visibilities.include?(node_visibility(child_node))
|
30
30
|
end || right.last
|
31
31
|
end
|
32
32
|
|
33
|
-
def left_siblings_of(node)
|
34
|
-
siblings_of(node)[0, node.sibling_index]
|
35
|
-
end
|
36
|
-
|
37
|
-
def right_siblings_of(node)
|
38
|
-
siblings_of(node)[node.sibling_index..-1]
|
39
|
-
end
|
40
|
-
|
41
|
-
def siblings_of(node)
|
42
|
-
node.parent.children
|
43
|
-
end
|
44
|
-
|
45
33
|
def_node_matcher :visibility_block?, <<~PATTERN
|
46
34
|
(send nil? { :private :protected :public })
|
47
35
|
PATTERN
|
@@ -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])) _)
|
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
|
@@ -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
|
|