rubocop 1.19.1 → 1.22.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 +86 -14
- data/lib/rubocop/config.rb +5 -0
- data/lib/rubocop/config_loader.rb +4 -2
- data/lib/rubocop/config_validator.rb +9 -1
- data/lib/rubocop/cop/base.rb +3 -3
- data/lib/rubocop/cop/bundler/gem_filename.rb +103 -0
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +45 -21
- data/lib/rubocop/cop/bundler/ordered_gems.rb +3 -12
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors/line_break_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +11 -10
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +3 -12
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +1 -1
- data/lib/rubocop/cop/generator.rb +14 -8
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -1
- data/lib/rubocop/cop/layout/dot_position.rb +31 -4
- data/lib/rubocop/cop/layout/end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +8 -6
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_argument_line_breaks.rb +3 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +15 -4
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -0
- data/lib/rubocop/cop/layout/space_around_equals_in_parameter_default.rb +2 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +2 -2
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -0
- data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -24
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +111 -0
- data/lib/rubocop/cop/lint/ambiguous_range.rb +8 -8
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +7 -5
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +18 -5
- data/lib/rubocop/cop/lint/boolean_symbol.rb +5 -0
- data/lib/rubocop/cop/lint/debugger.rb +2 -4
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
- data/lib/rubocop/cop/lint/disjunctive_assignment_in_constructor.rb +24 -1
- data/lib/rubocop/cop/lint/else_layout.rb +9 -5
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -1
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +12 -3
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +67 -0
- data/lib/rubocop/cop/lint/interpolation_check.rb +5 -0
- data/lib/rubocop/cop/lint/loop.rb +4 -3
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +5 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +12 -1
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +4 -2
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +17 -0
- data/lib/rubocop/cop/lint/percent_string_array.rb +10 -0
- data/lib/rubocop/cop/lint/raise_exception.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +5 -4
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +50 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/triple_quotes.rb +1 -1
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +8 -3
- data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -3
- data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -2
- data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
- data/lib/rubocop/cop/lint/useless_times.rb +4 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +6 -0
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +57 -34
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/documentation_comment.rb +5 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +23 -1
- data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +9 -1
- data/lib/rubocop/cop/mixin/percent_array.rb +6 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +9 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +5 -1
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +0 -3
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +1 -1
- data/lib/rubocop/cop/naming/inclusive_language.rb +9 -9
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +5 -4
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +7 -0
- data/lib/rubocop/cop/security/io_methods.rb +49 -0
- data/lib/rubocop/cop/security/json_load.rb +8 -7
- data/lib/rubocop/cop/security/open.rb +4 -0
- data/lib/rubocop/cop/security/yaml_load.rb +4 -0
- data/lib/rubocop/cop/style/accessor_grouping.rb +2 -2
- data/lib/rubocop/cop/style/and_or.rb +5 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +13 -2
- data/lib/rubocop/cop/style/array_coercion.rb +21 -3
- data/lib/rubocop/cop/style/ascii_comments.rb +0 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +23 -6
- data/lib/rubocop/cop/style/case_equality.rb +6 -9
- data/lib/rubocop/cop/style/case_like_if.rb +5 -0
- data/lib/rubocop/cop/style/class_and_module_children.rb +9 -0
- data/lib/rubocop/cop/style/collection_compact.rb +7 -5
- data/lib/rubocop/cop/style/collection_methods.rb +8 -6
- data/lib/rubocop/cop/style/combinable_loops.rb +3 -2
- data/lib/rubocop/cop/style/comment_annotation.rb +25 -39
- data/lib/rubocop/cop/style/commented_keyword.rb +4 -1
- data/lib/rubocop/cop/style/date_time.rb +5 -0
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +23 -8
- data/lib/rubocop/cop/style/double_negation.rb +15 -5
- data/lib/rubocop/cop/style/empty_method.rb +1 -1
- data/lib/rubocop/cop/style/explicit_block_argument.rb +21 -11
- data/lib/rubocop/cop/style/float_division.rb +10 -2
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +7 -2
- data/lib/rubocop/cop/style/global_std_stream.rb +4 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +5 -0
- data/lib/rubocop/cop/style/hash_except.rb +4 -3
- data/lib/rubocop/cop/style/hash_transform_keys.rb +4 -6
- data/lib/rubocop/cop/style/hash_transform_values.rb +4 -6
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +18 -16
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +18 -4
- data/lib/rubocop/cop/style/infinite_loop.rb +4 -3
- data/lib/rubocop/cop/style/inverse_methods.rb +9 -2
- data/lib/rubocop/cop/style/lambda_call.rb +1 -1
- data/lib/rubocop/cop/style/line_end_concatenation.rb +13 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +6 -6
- data/lib/rubocop/cop/style/module_function.rb +8 -9
- data/lib/rubocop/cop/style/mutable_constant.rb +73 -6
- data/lib/rubocop/cop/style/negated_if.rb +1 -1
- data/lib/rubocop/cop/style/negated_unless.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +2 -2
- data/lib/rubocop/cop/style/not.rb +2 -2
- data/lib/rubocop/cop/style/numbered_parameters.rb +46 -0
- data/lib/rubocop/cop/style/numbered_parameters_limit.rb +50 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +7 -8
- data/lib/rubocop/cop/style/numeric_predicate.rb +5 -0
- data/lib/rubocop/cop/style/optional_arguments.rb +4 -0
- data/lib/rubocop/cop/style/optional_boolean_parameter.rb +14 -4
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/percent_q_literals.rb +2 -2
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +9 -4
- data/lib/rubocop/cop/style/quoted_symbols.rb +10 -6
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +19 -9
- data/lib/rubocop/cop/style/redundant_condition.rb +2 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +4 -0
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +12 -3
- data/lib/rubocop/cop/style/redundant_freeze.rb +4 -4
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_percent_q.rb +2 -3
- data/lib/rubocop/cop/style/redundant_self.rb +10 -0
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +4 -3
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +51 -18
- data/lib/rubocop/cop/style/regexp_literal.rb +3 -3
- data/lib/rubocop/cop/style/return_nil.rb +2 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +13 -2
- data/lib/rubocop/cop/style/select_by_regexp.rb +133 -0
- data/lib/rubocop/cop/style/single_argument_dig.rb +5 -0
- data/lib/rubocop/cop/style/slicing_with_range.rb +13 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +4 -0
- data/lib/rubocop/cop/style/static_class.rb +5 -5
- data/lib/rubocop/cop/style/string_chars.rb +4 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +5 -1
- data/lib/rubocop/cop/style/string_hash_keys.rb +4 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +4 -0
- data/lib/rubocop/cop/style/swap_values.rb +4 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +26 -0
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +19 -0
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +24 -7
- data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -0
- data/lib/rubocop/cop/util.rb +4 -3
- data/lib/rubocop/cops_documentation_generator.rb +17 -5
- data/lib/rubocop/options.rb +126 -112
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/result_cache.rb +3 -3
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +6 -2
- data/lib/rubocop/runner.rb +2 -3
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +10 -2
- metadata +17 -9
@@ -5,11 +5,14 @@ module RuboCop
|
|
5
5
|
module Lint
|
6
6
|
# This cop checks for setter call to local variable as the final
|
7
7
|
# expression of a function definition.
|
8
|
-
# Its auto-correction is marked as unsafe because return value will be changed.
|
9
8
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
9
|
+
# @safety
|
10
|
+
# There are edge cases in which the local variable references a
|
11
|
+
# value that is also accessible outside the local scope. This is not
|
12
|
+
# detected by the cop, and it can yield a false positive.
|
13
|
+
#
|
14
|
+
# As well, auto-correction is unsafe because the method's
|
15
|
+
# return value will be changed.
|
13
16
|
#
|
14
17
|
# @example
|
15
18
|
#
|
@@ -7,8 +7,9 @@ module RuboCop
|
|
7
7
|
# (when the integer <= 0) or that will only ever yield once
|
8
8
|
# (`1.times`).
|
9
9
|
#
|
10
|
-
#
|
11
|
-
# is
|
10
|
+
# @safety
|
11
|
+
# This cop is unsafe as `times` returns its receiver, which is
|
12
|
+
# *usually* OK, but might change behavior.
|
12
13
|
#
|
13
14
|
# @example
|
14
15
|
# # bad
|
@@ -65,7 +66,7 @@ module RuboCop
|
|
65
66
|
private
|
66
67
|
|
67
68
|
def never_process?(count, node)
|
68
|
-
count < 1 || node.block_type? && node.body.nil?
|
69
|
+
count < 1 || (node.block_type? && node.body.nil?)
|
69
70
|
end
|
70
71
|
|
71
72
|
def remove_node(corrector, node)
|
@@ -8,6 +8,12 @@ module RuboCop
|
|
8
8
|
# (method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric
|
9
9
|
# and https://en.wikipedia.org/wiki/ABC_Software_Metric.
|
10
10
|
#
|
11
|
+
# Interpreting ABC size:
|
12
|
+
#
|
13
|
+
# * <= 17 satisfactory
|
14
|
+
# * 18..30 unsatisfactory
|
15
|
+
# * > 30 dangerous
|
16
|
+
#
|
11
17
|
# You can have repeated "attributes" calls count as a single "branch".
|
12
18
|
# For this purpose, attributes are any method with no argument; no attempt
|
13
19
|
# is meant to distinguish actual `attr_reader` from other methods.
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
46
46
|
visit_depth_last(@node) { |child| calculate_node(child) }
|
47
47
|
|
48
48
|
[
|
49
|
-
Math.sqrt(@assignment**2 + @branch**2 + @condition**2).round(2),
|
49
|
+
Math.sqrt((@assignment**2) + (@branch**2) + (@condition**2)).round(2),
|
50
50
|
"<#{@assignment}, #{@branch}, #{@condition}>"
|
51
51
|
]
|
52
52
|
end
|
@@ -147,7 +147,7 @@ module RuboCop
|
|
147
147
|
|
148
148
|
# Returns true for lines that shall not be included in the count.
|
149
149
|
def irrelevant_line?(source_line)
|
150
|
-
source_line.blank? || !count_comments? && comment_line?(source_line)
|
150
|
+
source_line.blank? || (!count_comments? && comment_line?(source_line))
|
151
151
|
end
|
152
152
|
|
153
153
|
def count_comments?
|
@@ -2,40 +2,63 @@
|
|
2
2
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
5
|
+
# Representation of an annotation comment in source code (eg. `# TODO: blah blah blah`).
|
6
|
+
class AnnotationComment
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
attr_reader :comment, :margin, :keyword, :colon, :space, :note
|
10
|
+
|
11
|
+
# @param [Parser::Source::Comment] comment
|
12
|
+
# @param [Array<String>] keywords
|
13
|
+
def initialize(comment, keywords)
|
14
|
+
@comment = comment
|
15
|
+
@keywords = keywords
|
16
|
+
@margin, @keyword, @colon, @space, @note = split_comment(comment)
|
17
|
+
end
|
18
|
+
|
19
|
+
def annotation?
|
20
|
+
keyword_appearance? && !just_keyword_of_sentence?
|
21
|
+
end
|
22
|
+
|
23
|
+
def correct?(colon:)
|
24
|
+
return false unless keyword && space && note
|
25
|
+
return false unless keyword == keyword.upcase
|
26
|
+
|
27
|
+
self.colon.nil? == !colon
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns the range bounds for just the annotation
|
31
|
+
def bounds
|
32
|
+
start = comment.loc.expression.begin_pos + margin.length
|
33
|
+
length = [keyword, colon, space].reduce(0) { |len, elem| len + elem.to_s.length }
|
34
|
+
[start, start + length]
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
attr_reader :keywords
|
40
|
+
|
41
|
+
def split_comment(comment)
|
42
|
+
# Sort keywords by reverse length so that if a keyword is in a phrase
|
43
|
+
# but also on its own, both will match properly.
|
44
|
+
keywords_regex = Regexp.new(
|
45
|
+
Regexp.union(keywords.sort_by { |w| -w.length }).source,
|
46
|
+
Regexp::IGNORECASE
|
47
|
+
)
|
48
|
+
regex = /^(# ?)(\b#{keywords_regex}\b)(\s*:)?(\s+)?(\S+)?/i
|
49
|
+
|
50
|
+
match = comment.text.match(regex)
|
51
|
+
return false unless match
|
52
|
+
|
53
|
+
match.captures
|
54
|
+
end
|
55
|
+
|
56
|
+
def keyword_appearance?
|
57
|
+
keyword && (colon || space)
|
58
|
+
end
|
59
|
+
|
60
|
+
def just_keyword_of_sentence?
|
61
|
+
keyword == keyword.capitalize && !colon && space && note
|
39
62
|
end
|
40
63
|
end
|
41
64
|
end
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
|
44
44
|
# Returns true for lines that shall not be included in the count.
|
45
45
|
def irrelevant_line(source_line)
|
46
|
-
source_line.blank? || !count_comments? && comment_line?(source_line)
|
46
|
+
source_line.blank? || (!count_comments? && comment_line?(source_line))
|
47
47
|
end
|
48
48
|
|
49
49
|
def build_code_length_calculator(node)
|
@@ -5,7 +5,6 @@ module RuboCop
|
|
5
5
|
# Common functionality for checking documentation.
|
6
6
|
module DocumentationComment
|
7
7
|
extend NodePattern::Macros
|
8
|
-
include Style::AnnotationComment
|
9
8
|
|
10
9
|
private
|
11
10
|
|
@@ -15,7 +14,7 @@ module RuboCop
|
|
15
14
|
return false unless preceding_comment?(node, preceding_lines.last)
|
16
15
|
|
17
16
|
preceding_lines.any? do |comment|
|
18
|
-
!
|
17
|
+
!AnnotationComment.new(comment, annotation_keywords).annotation? &&
|
19
18
|
!interpreter_directive_comment?(comment) &&
|
20
19
|
!rubocop_directive_comment?(comment)
|
21
20
|
end
|
@@ -44,6 +43,10 @@ module RuboCop
|
|
44
43
|
def rubocop_directive_comment?(comment)
|
45
44
|
!!DirectiveComment.new(comment).match_captures
|
46
45
|
end
|
46
|
+
|
47
|
+
def annotation_keywords
|
48
|
+
config.for_cop('Style/CommentAnnotation')['Keywords']
|
49
|
+
end
|
47
50
|
end
|
48
51
|
end
|
49
52
|
end
|
@@ -8,7 +8,9 @@ module RuboCop
|
|
8
8
|
|
9
9
|
FROZEN_STRING_LITERAL = '# frozen_string_literal:'
|
10
10
|
FROZEN_STRING_LITERAL_ENABLED = '# frozen_string_literal: true'
|
11
|
-
|
11
|
+
FROZEN_STRING_LITERAL_TYPES_RUBY27 = %i[str dstr].freeze
|
12
|
+
|
13
|
+
private_constant :FROZEN_STRING_LITERAL_TYPES_RUBY27
|
12
14
|
|
13
15
|
def frozen_string_literal_comment_exists?
|
14
16
|
leading_comment_lines.any? { |line| MagicComment.parse(line).valid_literal_value? }
|
@@ -16,6 +18,26 @@ module RuboCop
|
|
16
18
|
|
17
19
|
private
|
18
20
|
|
21
|
+
def frozen_string_literal?(node)
|
22
|
+
frozen_string = if target_ruby_version >= 3.0
|
23
|
+
uninterpolated_string?(node) || frozen_heredoc?(node)
|
24
|
+
else
|
25
|
+
FROZEN_STRING_LITERAL_TYPES_RUBY27.include?(node.type)
|
26
|
+
end
|
27
|
+
|
28
|
+
frozen_string && frozen_string_literals_enabled?
|
29
|
+
end
|
30
|
+
|
31
|
+
def uninterpolated_string?(node)
|
32
|
+
node.str_type? || (node.dstr_type? && node.each_descendant(:begin).none?)
|
33
|
+
end
|
34
|
+
|
35
|
+
def frozen_heredoc?(node)
|
36
|
+
return false unless node.dstr_type? && node.heredoc?
|
37
|
+
|
38
|
+
node.children.all?(&:str_type?)
|
39
|
+
end
|
40
|
+
|
19
41
|
def frozen_string_literals_enabled?
|
20
42
|
ruby_version = processed_source.ruby_version
|
21
43
|
return false unless ruby_version
|
@@ -21,9 +21,7 @@ module RuboCop
|
|
21
21
|
private
|
22
22
|
|
23
23
|
def indent_level(str)
|
24
|
-
indentations = str.lines
|
25
|
-
.map { |line| line[/^\s*/] }
|
26
|
-
.reject { |line| line.end_with?("\n") }
|
24
|
+
indentations = str.lines.map { |line| line[/^\s*/] }.reject { |line| line.end_with?("\n") }
|
27
25
|
indentations.empty? ? 0 : indentations.min_by(&:size).size
|
28
26
|
end
|
29
27
|
|
@@ -134,7 +134,7 @@ module RuboCop
|
|
134
134
|
|
135
135
|
next if a.setter_method?
|
136
136
|
next unless kind == :with_or_without_parentheses ||
|
137
|
-
kind == :with_parentheses && parentheses?(a)
|
137
|
+
(kind == :with_parentheses && parentheses?(a))
|
138
138
|
|
139
139
|
a.arguments.any? { |arg| within_node?(node, arg) }
|
140
140
|
end
|
@@ -156,7 +156,7 @@ module RuboCop
|
|
156
156
|
|
157
157
|
def disqualified_rhs?(candidate, ancestor)
|
158
158
|
UNALIGNED_RHS_TYPES.include?(ancestor.type) ||
|
159
|
-
ancestor.block_type? && part_of_block_body?(candidate, ancestor)
|
159
|
+
(ancestor.block_type? && part_of_block_body?(candidate, ancestor))
|
160
160
|
end
|
161
161
|
|
162
162
|
def valid_rhs?(candidate, ancestor)
|
@@ -35,7 +35,15 @@ module RuboCop
|
|
35
35
|
previous: gem_name(current),
|
36
36
|
current: gem_name(previous)
|
37
37
|
)
|
38
|
-
|
38
|
+
|
39
|
+
add_offense(current, message: message) do |corrector|
|
40
|
+
OrderedGemCorrector.correct(
|
41
|
+
processed_source,
|
42
|
+
current,
|
43
|
+
previous_declaration(current),
|
44
|
+
treat_comments_as_separators
|
45
|
+
).call(corrector)
|
46
|
+
end
|
39
47
|
end
|
40
48
|
|
41
49
|
def gem_name(declaration_node)
|
@@ -36,7 +36,12 @@ module RuboCop
|
|
36
36
|
def check_percent_array(node)
|
37
37
|
array_style_detected(:percent, node.values.size)
|
38
38
|
|
39
|
-
|
39
|
+
brackets_required = invalid_percent_array_contents?(node)
|
40
|
+
return unless style == :brackets || brackets_required
|
41
|
+
|
42
|
+
# If in percent style but brackets are required due to
|
43
|
+
# string content, the file should be excluded in auto-gen-config
|
44
|
+
no_acceptable_style! if brackets_required
|
40
45
|
|
41
46
|
bracketed_array = build_bracketed_array(node)
|
42
47
|
message = format(self.class::ARRAY_MSG, prefer: bracketed_array)
|
@@ -93,7 +93,15 @@ module RuboCop
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def aligned_assignment?(range, line)
|
96
|
-
range.source[-1] == '=' && line[range.last_column - 1] == '='
|
96
|
+
(range.source[-1] == '=' && line[range.last_column - 1] == '=') ||
|
97
|
+
aligned_with_append_operator?(range, line)
|
98
|
+
end
|
99
|
+
|
100
|
+
def aligned_with_append_operator?(range, line)
|
101
|
+
last_column = range.last_column
|
102
|
+
|
103
|
+
(range.source == '<<' && line[last_column - 1] == '=') ||
|
104
|
+
(range.source[-1] == '=' && line[(last_column - 2)..(last_column - 1)] == '<<')
|
97
105
|
end
|
98
106
|
|
99
107
|
def aligned_identical?(range, line)
|
@@ -13,7 +13,11 @@ module RuboCop
|
|
13
13
|
if style == :single_quotes
|
14
14
|
!double_quotes_required?(src)
|
15
15
|
else
|
16
|
-
|
16
|
+
# The string needs single quotes if:
|
17
|
+
# 1. It contains a double quote
|
18
|
+
# 2. It contains text that would become an escape sequence with double quotes
|
19
|
+
# 3. It contains text that would become an interpolation with double quotes
|
20
|
+
!/" | (?<!\\)\\[abcefMnrtuUx0-7] | \#[@{$]/x.match?(src)
|
17
21
|
end
|
18
22
|
end
|
19
23
|
end
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
24
24
|
# # With `AllowNamesEndingInNumbers` set to false
|
25
25
|
# foo { |num1, num2| num1 * num2 }
|
26
26
|
#
|
27
|
-
# # With `
|
27
|
+
# # With `MinNameLength` set to number greater than 1
|
28
28
|
# baz { |a, b, c| do_stuff(a, b, c) }
|
29
29
|
#
|
30
30
|
# # good
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
54
54
|
private
|
55
55
|
|
56
56
|
def allowed_assignment?(value)
|
57
|
-
value && %i[block const casgn].include?(value.type) ||
|
57
|
+
(value && %i[block const casgn].include?(value.type)) ||
|
58
58
|
allowed_method_call_on_rhs?(value) ||
|
59
59
|
class_or_struct_return_method?(value) ||
|
60
60
|
allowed_conditional_expression_on_rhs?(value)
|
@@ -70,6 +70,8 @@ module RuboCop
|
|
70
70
|
include RangeHelp
|
71
71
|
|
72
72
|
EMPTY_ARRAY = [].freeze
|
73
|
+
MSG = "Consider replacing '%<term>s'%<suffix>s."
|
74
|
+
MSG_FOR_FILE_PATH = "Consider replacing '%<term>s' in file path%<suffix>s."
|
73
75
|
|
74
76
|
WordLocation = Struct.new(:word, :position)
|
75
77
|
|
@@ -197,12 +199,11 @@ module RuboCop
|
|
197
199
|
end
|
198
200
|
|
199
201
|
def create_single_word_message_for_file(word)
|
200
|
-
create_message(word
|
202
|
+
create_message(word, MSG_FOR_FILE_PATH)
|
201
203
|
end
|
202
204
|
|
203
205
|
def create_multiple_word_message_for_file(words)
|
204
|
-
|
205
|
-
"Consider replacing problematic terms #{quoted_words.join(', ')} in file path."
|
206
|
+
format(MSG_FOR_FILE_PATH, term: words.join("', '"), suffix: ' with other terms')
|
206
207
|
end
|
207
208
|
|
208
209
|
def scan_for_words(input)
|
@@ -223,9 +224,12 @@ module RuboCop
|
|
223
224
|
safe_str.gsub(@allowed_regex) { |match| '*' * match.size }
|
224
225
|
end
|
225
226
|
|
226
|
-
def create_message(word)
|
227
|
+
def create_message(word, message = MSG)
|
227
228
|
flagged_term = find_flagged_term(word)
|
228
|
-
|
229
|
+
suggestions = flagged_term['SuggestionString']
|
230
|
+
suggestions = ' with another term' if suggestions.blank?
|
231
|
+
|
232
|
+
format(message, term: word, suffix: suggestions)
|
229
233
|
end
|
230
234
|
|
231
235
|
def find_flagged_term(word)
|
@@ -235,10 +239,6 @@ module RuboCop
|
|
235
239
|
flagged_term
|
236
240
|
end
|
237
241
|
|
238
|
-
def create_message_for_file(word)
|
239
|
-
create_message(word).sub(/\.$/, ' in file path.')
|
240
|
-
end
|
241
|
-
|
242
242
|
def preprocess_suggestions(suggestions)
|
243
243
|
return '' if suggestions.nil? ||
|
244
244
|
(suggestions.is_a?(String) && suggestions.strip.empty?) || suggestions.empty?
|
@@ -14,6 +14,11 @@ module RuboCop
|
|
14
14
|
# convention that is used to implicitly indicate that an ivar should not
|
15
15
|
# be set or referenced outside of the memoization method.
|
16
16
|
#
|
17
|
+
# @safety
|
18
|
+
# This cop relies on the pattern `@instance_var ||= ...`,
|
19
|
+
# but this is sometimes used for other purposes than memoization
|
20
|
+
# so this cop is considered unsafe.
|
21
|
+
#
|
17
22
|
# @example EnforcedStyleForLeadingUnderscores: disallowed (default)
|
18
23
|
# # bad
|
19
24
|
# # Method foo is memoized using an instance variable that is
|
@@ -139,10 +144,6 @@ module RuboCop
|
|
139
144
|
# define_method(:foo) do
|
140
145
|
# @_foo ||= calculate_expensive_thing
|
141
146
|
# end
|
142
|
-
#
|
143
|
-
# This cop relies on the pattern `@instance_var ||= ...`,
|
144
|
-
# but this is sometimes used for other purposes than memoization
|
145
|
-
# so this cop is considered unsafe.
|
146
147
|
class MemoizedInstanceVariableName < Base
|
147
148
|
include ConfigurableEnforcedStyle
|
148
149
|
|
@@ -75,6 +75,9 @@ module RuboCop
|
|
75
75
|
preferred_name = preferred_name(offending_name)
|
76
76
|
return if preferred_name.to_sym == offending_name
|
77
77
|
|
78
|
+
# check variable shadowing for exception variable
|
79
|
+
return if shadowed_variable_name?(node)
|
80
|
+
|
78
81
|
range = offense_range(node)
|
79
82
|
message = message(node)
|
80
83
|
|
@@ -150,6 +153,10 @@ module RuboCop
|
|
150
153
|
preferred_name = preferred_name(offending_name)
|
151
154
|
format(MSG, preferred: preferred_name, bad: offending_name)
|
152
155
|
end
|
156
|
+
|
157
|
+
def shadowed_variable_name?(node)
|
158
|
+
node.each_descendant(:lvar).any? { |n| n.children.first.to_s == preferred_name(n) }
|
159
|
+
end
|
153
160
|
end
|
154
161
|
end
|
155
162
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Security
|
6
|
+
# Checks for the first argument to `IO.read`, `IO.binread`, `IO.write`, `IO.binwrite`,
|
7
|
+
# `IO.foreach`, and `IO.readlines`.
|
8
|
+
#
|
9
|
+
# If argument starts with a pipe character (`'|'`) and the receiver is the `IO` class,
|
10
|
+
# a subprocess is created in the same way as `Kernel#open`, and its output is returned.
|
11
|
+
# `Kernel#open` may allow unintentional command injection, which is the reason these
|
12
|
+
# `IO` methods are a security risk.
|
13
|
+
# Consider to use `File.read` to disable the behavior of subprocess invocation.
|
14
|
+
#
|
15
|
+
# @safety
|
16
|
+
# This cop is unsafe because false positive will occur if the variable passed as
|
17
|
+
# the first argument is a command that is not a file path.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
#
|
21
|
+
# # bad
|
22
|
+
# IO.read(path)
|
23
|
+
# IO.read('path')
|
24
|
+
#
|
25
|
+
# # good
|
26
|
+
# File.read(path)
|
27
|
+
# File.read('path')
|
28
|
+
# IO.read('| command') # Allow intentional command invocation.
|
29
|
+
#
|
30
|
+
class IoMethods < Base
|
31
|
+
extend AutoCorrector
|
32
|
+
|
33
|
+
MSG = '`File.%<method_name>s` is safer than `IO.%<method_name>s`.'
|
34
|
+
RESTRICT_ON_SEND = %i[read binread write binwrite foreach readlines].freeze
|
35
|
+
|
36
|
+
def on_send(node)
|
37
|
+
return unless (receiver = node.receiver) && receiver.source == 'IO'
|
38
|
+
|
39
|
+
argument = node.first_argument
|
40
|
+
return if argument.respond_to?(:value) && argument.value.strip.start_with?('|')
|
41
|
+
|
42
|
+
add_offense(node, message: format(MSG, method_name: node.method_name)) do |corrector|
|
43
|
+
corrector.replace(receiver, 'File')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -6,13 +6,14 @@ module RuboCop
|
|
6
6
|
# This cop checks for the use of JSON class methods which have potential
|
7
7
|
# security issues.
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
9
|
+
# @safety
|
10
|
+
# Autocorrect is disabled by default because it's potentially dangerous.
|
11
|
+
# If using a stream, like `JSON.load(open('file'))`, it will need to call
|
12
|
+
# `#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
|
+
# Other similar issues may apply.
|
16
17
|
#
|
17
18
|
# @example
|
18
19
|
# # bad
|
@@ -11,6 +11,10 @@ module RuboCop
|
|
11
11
|
# the argument of `Kernel#open` and `URI.open`. It would be better to use
|
12
12
|
# `File.open`, `IO.popen` or `URI.parse#open` explicitly.
|
13
13
|
#
|
14
|
+
# @safety
|
15
|
+
# This cop could register false positives if `open` is redefined
|
16
|
+
# in a class and then used without a receiver in that class.
|
17
|
+
#
|
14
18
|
# @example
|
15
19
|
# # bad
|
16
20
|
# open(something)
|
@@ -7,6 +7,10 @@ module RuboCop
|
|
7
7
|
# potential security issues leading to remote code execution when
|
8
8
|
# loading from an untrusted source.
|
9
9
|
#
|
10
|
+
# @safety
|
11
|
+
# The behaviour of the code might change depending on what was
|
12
|
+
# in the YAML payload, since `YAML.safe_load` is more restrictive.
|
13
|
+
#
|
10
14
|
# @example
|
11
15
|
# # bad
|
12
16
|
# YAML.load("--- foo")
|
@@ -59,8 +59,8 @@ module RuboCop
|
|
59
59
|
|
60
60
|
def check(send_node)
|
61
61
|
return if previous_line_comment?(send_node)
|
62
|
-
return unless grouped_style? && sibling_accessors(send_node).size > 1 ||
|
63
|
-
separated_style? && send_node.arguments.size > 1
|
62
|
+
return unless (grouped_style? && sibling_accessors(send_node).size > 1) ||
|
63
|
+
(separated_style? && send_node.arguments.size > 1)
|
64
64
|
|
65
65
|
message = message(send_node)
|
66
66
|
add_offense(send_node, message: message) do |corrector|
|
@@ -7,6 +7,11 @@ module RuboCop
|
|
7
7
|
# `||` instead. It can be configured to check only in conditions or in
|
8
8
|
# all contexts.
|
9
9
|
#
|
10
|
+
# @safety
|
11
|
+
# Auto-correction is unsafe because there is a different operator precedence
|
12
|
+
# between logical operators (`&&` and `||`) and semantic operators (`and` and `or`),
|
13
|
+
# and that might change the behaviour.
|
14
|
+
#
|
10
15
|
# @example EnforcedStyle: always
|
11
16
|
# # bad
|
12
17
|
# foo.save and return
|
@@ -30,6 +30,10 @@ module RuboCop
|
|
30
30
|
# bar(*args)
|
31
31
|
# end
|
32
32
|
#
|
33
|
+
# def foo(**kwargs)
|
34
|
+
# bar(**kwargs)
|
35
|
+
# end
|
36
|
+
#
|
33
37
|
# @example AllowOnlyRestArgument: false
|
34
38
|
# # bad
|
35
39
|
# # The following code can replace the arguments with `...`,
|
@@ -38,6 +42,10 @@ module RuboCop
|
|
38
42
|
# bar(*args)
|
39
43
|
# end
|
40
44
|
#
|
45
|
+
# def foo(**kwargs)
|
46
|
+
# bar(**kwargs)
|
47
|
+
# end
|
48
|
+
#
|
41
49
|
class ArgumentsForwarding < Base
|
42
50
|
include RangeHelp
|
43
51
|
extend AutoCorrector
|
@@ -49,12 +57,15 @@ module RuboCop
|
|
49
57
|
|
50
58
|
# @!method use_rest_arguments?(node)
|
51
59
|
def_node_matcher :use_rest_arguments?, <<~PATTERN
|
52
|
-
(args (restarg $_) $...)
|
60
|
+
(args ({restarg kwrestarg} $_) $...)
|
53
61
|
PATTERN
|
54
62
|
|
55
63
|
# @!method only_rest_arguments?(node, name)
|
56
64
|
def_node_matcher :only_rest_arguments?, <<~PATTERN
|
57
|
-
|
65
|
+
{
|
66
|
+
(send _ _ (splat (lvar %1)))
|
67
|
+
(send _ _ (hash (kwsplat (lvar %1))))
|
68
|
+
}
|
58
69
|
PATTERN
|
59
70
|
|
60
71
|
# @!method forwarding_method_arguments?(node, rest_name, block_name, kwargs_name)
|