rubocop 1.20.0 → 1.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +64 -15
- data/lib/rubocop/config.rb +5 -0
- data/lib/rubocop/config_loader.rb +3 -1
- data/lib/rubocop/config_validator.rb +9 -1
- data/lib/rubocop/cop/base.rb +3 -3
- data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
- 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 +31 -24
- data/lib/rubocop/cop/generator.rb +14 -8
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +1 -1
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +2 -1
- data/lib/rubocop/cop/layout/dot_position.rb +30 -5
- data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
- data/lib/rubocop/cop/layout/end_alignment.rb +2 -3
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +9 -7
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -3
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -0
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
- 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_before_comment.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +74 -28
- 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 +9 -9
- 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 +0 -2
- 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 +10 -6
- 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/parameter_lists.rb +5 -2
- 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/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +15 -6
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
- data/lib/rubocop/cop/mixin/heredoc.rb +1 -3
- data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -2
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- 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/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
- data/lib/rubocop/cop/mixin/string_literals_help.rb +5 -1
- data/lib/rubocop/cop/mixin/trailing_body.rb +1 -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/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/commented_keyword.rb +9 -4
- 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 +6 -1
- 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_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 +14 -1
- 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/multiline_in_pattern_then.rb +1 -1
- data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +13 -8
- 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 +0 -1
- 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 +138 -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 +3 -2
- 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 +15 -4
- 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/rspec/parallel_formatter.rb +90 -0
- data/lib/rubocop/rspec/support.rb +1 -0
- data/lib/rubocop/runner.rb +2 -3
- data/lib/rubocop/target_finder.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +8 -1
- metadata +14 -5
@@ -0,0 +1,138 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop looks for places where an subset of an Enumerable (array,
|
7
|
+
# range, set, etc.; see note below) is calculated based on a `Regexp`
|
8
|
+
# match, and suggests `grep` or `grep_v` instead.
|
9
|
+
#
|
10
|
+
# NOTE: Hashes do not behave as you may expect with `grep`, which
|
11
|
+
# means that `hash.grep` is not equivalent to `hash.select`. Although
|
12
|
+
# RuboCop is limited by static analysis, this cop attempts to avoid
|
13
|
+
# registering an offense when the receiver is a hash (hash literal,
|
14
|
+
# `Hash.new`, `Hash#[]`, or `to_h`/`to_hash`).
|
15
|
+
#
|
16
|
+
# NOTE: `grep` and `grep_v` were optimized when used without a block
|
17
|
+
# in Ruby 3.0, but may be slower in previous versions.
|
18
|
+
# See https://bugs.ruby-lang.org/issues/17030
|
19
|
+
#
|
20
|
+
# @safety
|
21
|
+
# Autocorrection is marked as unsafe because `MatchData` will
|
22
|
+
# not be created by `grep`, but may have previously been relied
|
23
|
+
# upon after the `match?` or `=~` call.
|
24
|
+
#
|
25
|
+
# Additionally, the cop cannot guarantee that the receiver of
|
26
|
+
# `select` or `reject` is actually an array by static analysis,
|
27
|
+
# so the correction may not be actually equivalent.
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# # bad (select or find_all)
|
31
|
+
# array.select { |x| x.match? /regexp/ }
|
32
|
+
# array.select { |x| /regexp/.match?(x) }
|
33
|
+
# array.select { |x| x =~ /regexp/ }
|
34
|
+
# array.select { |x| /regexp/ =~ x }
|
35
|
+
#
|
36
|
+
# # bad (reject)
|
37
|
+
# array.reject { |x| x.match? /regexp/ }
|
38
|
+
# array.reject { |x| /regexp/.match?(x) }
|
39
|
+
# array.reject { |x| x =~ /regexp/ }
|
40
|
+
# array.reject { |x| /regexp/ =~ x }
|
41
|
+
#
|
42
|
+
# # good
|
43
|
+
# array.grep(regexp)
|
44
|
+
# array.grep_v(regexp)
|
45
|
+
class SelectByRegexp < Base
|
46
|
+
extend AutoCorrector
|
47
|
+
include RangeHelp
|
48
|
+
|
49
|
+
MSG = 'Prefer `%<replacement>s` to `%<original_method>s` with a regexp match.'
|
50
|
+
RESTRICT_ON_SEND = %i[select find_all reject].freeze
|
51
|
+
REPLACEMENTS = { select: 'grep', find_all: 'grep', reject: 'grep_v' }.freeze
|
52
|
+
REGEXP_METHODS = %i[match? =~].to_set.freeze
|
53
|
+
|
54
|
+
# @!method regexp_match?(node)
|
55
|
+
def_node_matcher :regexp_match?, <<~PATTERN
|
56
|
+
{
|
57
|
+
(block send (args (arg $_)) ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
|
58
|
+
(numblock send $1 ${(send _ %REGEXP_METHODS _) match-with-lvasgn})
|
59
|
+
}
|
60
|
+
PATTERN
|
61
|
+
|
62
|
+
# Returns true if a node appears to return a hash
|
63
|
+
# @!method creates_hash?(node)
|
64
|
+
def_node_matcher :creates_hash?, <<~PATTERN
|
65
|
+
{
|
66
|
+
(send (const _ :Hash) {:new :[]} ...)
|
67
|
+
(block (send (const _ :Hash) :new ...) ...)
|
68
|
+
(send _ { :to_h :to_hash } ...)
|
69
|
+
}
|
70
|
+
PATTERN
|
71
|
+
|
72
|
+
# @!method calls_lvar?(node, name)
|
73
|
+
def_node_matcher :calls_lvar?, <<~PATTERN
|
74
|
+
{
|
75
|
+
(send (lvar %1) ...)
|
76
|
+
(send ... (lvar %1))
|
77
|
+
(match-with-lvasgn regexp (lvar %1))
|
78
|
+
}
|
79
|
+
PATTERN
|
80
|
+
|
81
|
+
def on_send(node)
|
82
|
+
return unless (block_node = node.block_node)
|
83
|
+
return if block_node.body.begin_type?
|
84
|
+
return if receiver_allowed?(block_node.receiver)
|
85
|
+
return unless (regexp_method_send_node = extract_send_node(block_node))
|
86
|
+
return if match_predicate_without_receiver?(regexp_method_send_node)
|
87
|
+
|
88
|
+
regexp = find_regexp(regexp_method_send_node)
|
89
|
+
register_offense(node, block_node, regexp)
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
def receiver_allowed?(node)
|
95
|
+
return false unless node
|
96
|
+
|
97
|
+
node.hash_type? || creates_hash?(node)
|
98
|
+
end
|
99
|
+
|
100
|
+
def register_offense(node, block_node, regexp)
|
101
|
+
replacement = REPLACEMENTS[node.method_name.to_sym]
|
102
|
+
message = format(MSG, replacement: replacement, original_method: node.method_name)
|
103
|
+
|
104
|
+
add_offense(block_node, message: message) do |corrector|
|
105
|
+
# Only correct if it can be determined what the regexp is
|
106
|
+
if regexp
|
107
|
+
range = range_between(node.loc.selector.begin_pos, block_node.loc.end.end_pos)
|
108
|
+
corrector.replace(range, "#{replacement}(#{regexp.source})")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def extract_send_node(block_node)
|
114
|
+
return unless (block_arg_name, regexp_method_send_node = regexp_match?(block_node))
|
115
|
+
|
116
|
+
block_arg_name = :"_#{block_arg_name}" if block_node.numblock_type?
|
117
|
+
return unless calls_lvar?(regexp_method_send_node, block_arg_name)
|
118
|
+
|
119
|
+
regexp_method_send_node
|
120
|
+
end
|
121
|
+
|
122
|
+
def find_regexp(node)
|
123
|
+
return node.child_nodes.first if node.match_with_lvasgn_type?
|
124
|
+
|
125
|
+
if node.receiver.lvar_type?
|
126
|
+
node.first_argument
|
127
|
+
elsif node.first_argument.lvar_type?
|
128
|
+
node.receiver
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def match_predicate_without_receiver?(node)
|
133
|
+
node.send_type? && node.method?(:match?) && node.receiver.nil?
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
@@ -6,6 +6,11 @@ module RuboCop
|
|
6
6
|
# Sometimes using dig method ends up with just a single
|
7
7
|
# argument. In such cases, dig should be replaced with [].
|
8
8
|
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe because it cannot be guaranteed that the receiver
|
11
|
+
# is an `Enumerable` or does not have a nonstandard implementation
|
12
|
+
# of `dig`.
|
13
|
+
#
|
9
14
|
# @example
|
10
15
|
# # bad
|
11
16
|
# { key: 'value' }.dig(:key)
|
@@ -6,6 +6,19 @@ module RuboCop
|
|
6
6
|
# This cop checks that arrays are sliced with endless ranges instead of
|
7
7
|
# `ary[start..-1]` on Ruby 2.6+.
|
8
8
|
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe because `x..-1` and `x..` are only guaranteed to
|
11
|
+
# be equivalent for `Array#[]`, and the cop cannot determine what class
|
12
|
+
# the receiver is.
|
13
|
+
#
|
14
|
+
# For example:
|
15
|
+
# [source,ruby]
|
16
|
+
# ----
|
17
|
+
# sum = proc { |ary| ary.sum }
|
18
|
+
# sum[-3..-1] # => -6
|
19
|
+
# sum[-3..] # Hangs forever
|
20
|
+
# ----
|
21
|
+
#
|
9
22
|
# @example
|
10
23
|
# # bad
|
11
24
|
# items[1..-1]
|
@@ -9,6 +9,10 @@ module RuboCop
|
|
9
9
|
# will add a require statement to the top of the file if
|
10
10
|
# enabled by RequireEnglish config.
|
11
11
|
#
|
12
|
+
# @safety
|
13
|
+
# Autocorrection is marked as unsafe because if `RequireEnglish` is not
|
14
|
+
# true, replacing perl-style variables with english variables will break.
|
15
|
+
#
|
12
16
|
# @example EnforcedStyle: use_english_names (default)
|
13
17
|
# # good
|
14
18
|
# require 'English' # or this could be in another file.
|
@@ -7,9 +7,10 @@ module RuboCop
|
|
7
7
|
# replaced with a module. Classes should be used only when it makes sense to create
|
8
8
|
# instances out of them.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
10
|
+
# @safety
|
11
|
+
# This cop is unsafe, because it is possible that this class is a parent
|
12
|
+
# for some other subclass, monkey-patched with instance methods or
|
13
|
+
# a dummy instance is instantiated from it somewhere.
|
13
14
|
#
|
14
15
|
# @example
|
15
16
|
# # bad
|
@@ -60,8 +61,7 @@ module RuboCop
|
|
60
61
|
return false if nodes.empty?
|
61
62
|
|
62
63
|
nodes.all? do |node|
|
63
|
-
node_visibility(node) == :public &&
|
64
|
-
node.defs_type? ||
|
64
|
+
(node_visibility(node) == :public && node.defs_type?) ||
|
65
65
|
sclass_convertible_to_module?(node) ||
|
66
66
|
node.equals_asgn? ||
|
67
67
|
extend_call?(node)
|
@@ -5,8 +5,10 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# Checks for uses of `String#split` with empty string or regexp literal argument.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# @safety
|
9
|
+
# This cop is unsafe because it cannot be guaranteed that the receiver
|
10
|
+
# is actually a string. If another class has a `split` method with
|
11
|
+
# different behaviour, it would be registered as a false positive.
|
10
12
|
#
|
11
13
|
# @example
|
12
14
|
# # bad
|
@@ -23,6 +23,10 @@ module RuboCop
|
|
23
23
|
# This is useful when the receiver is some expression that returns string like `Pathname`
|
24
24
|
# instead of a string literal.
|
25
25
|
#
|
26
|
+
# @safety
|
27
|
+
# This cop is unsafe in `aggressive` mode, as it cannot be guaranteed that
|
28
|
+
# the receiver is actually a string, which can result in a false positive.
|
29
|
+
#
|
26
30
|
# @example Mode: aggressive (default)
|
27
31
|
# # bad
|
28
32
|
# email_with_name = user.name + ' <' + user.email + '>'
|
@@ -93,7 +97,7 @@ module RuboCop
|
|
93
97
|
|
94
98
|
def offensive_for_mode?(receiver_node)
|
95
99
|
mode = cop_config['Mode'].to_sym
|
96
|
-
mode == :aggressive || mode == :conservative && receiver_node.str_type?
|
100
|
+
mode == :aggressive || (mode == :conservative && receiver_node.str_type?)
|
97
101
|
end
|
98
102
|
|
99
103
|
def line_end_concatenation?(node)
|
@@ -6,6 +6,10 @@ module RuboCop
|
|
6
6
|
# This cop checks for the use of strings as keys in hashes. The use of
|
7
7
|
# symbols is preferred instead.
|
8
8
|
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe because while symbols are preferred for hash keys,
|
11
|
+
# there are instances when string keys are required.
|
12
|
+
#
|
9
13
|
# @example
|
10
14
|
# # bad
|
11
15
|
# { 'one' => 1, 'two' => 2, 'three' => 3 }
|
@@ -5,8 +5,9 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for inheritance from Struct.new.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
8
|
+
# @safety
|
9
|
+
# Auto-correction is unsafe because it will change the inheritance
|
10
|
+
# tree (e.g. return value of `Module#ancestors`) of the constant.
|
10
11
|
#
|
11
12
|
# @example
|
12
13
|
# # bad
|
@@ -4,8 +4,10 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# This cop enforces the use of shorthand-style swapping of 2 variables.
|
7
|
-
#
|
8
|
-
#
|
7
|
+
#
|
8
|
+
# @safety
|
9
|
+
# Autocorrection is unsafe, because the temporary variable used to
|
10
|
+
# swap variables will be removed, but may be referred to elsewhere.
|
9
11
|
#
|
10
12
|
# @example
|
11
13
|
# # bad
|
@@ -8,6 +8,32 @@ module RuboCop
|
|
8
8
|
# If you prefer a style that allows block for method with arguments,
|
9
9
|
# please set `true` to `AllowMethodsWithArguments`.
|
10
10
|
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because `proc`s and blocks work differently
|
13
|
+
# when additional arguments are passed in. A block will silently
|
14
|
+
# ignore additional arguments, but a `proc` will raise
|
15
|
+
# an `ArgumentError`.
|
16
|
+
#
|
17
|
+
# For example:
|
18
|
+
#
|
19
|
+
# [source,ruby]
|
20
|
+
# ----
|
21
|
+
# class Foo
|
22
|
+
# def bar
|
23
|
+
# :bar
|
24
|
+
# end
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# def call(options = {}, &block)
|
28
|
+
# block.call(Foo.new, options)
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
# call { |x| x.bar }
|
32
|
+
# #=> :bar
|
33
|
+
# call(&:bar)
|
34
|
+
# # ArgumentError: wrong number of arguments (given 1, expected 0)
|
35
|
+
# ----
|
36
|
+
#
|
11
37
|
# @example
|
12
38
|
# # bad
|
13
39
|
# something.map { |s| s.upcase }
|
@@ -8,6 +8,25 @@ module RuboCop
|
|
8
8
|
# that comma to be present. Blocks with more than one argument never
|
9
9
|
# require a trailing comma.
|
10
10
|
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because a trailing comma can indicate there are
|
13
|
+
# more parameters that are not used.
|
14
|
+
#
|
15
|
+
# For example:
|
16
|
+
# [source,ruby]
|
17
|
+
# ----
|
18
|
+
# # with a trailing comma
|
19
|
+
# {foo: 1, bar: 2, baz: 3}.map {|key,| key }
|
20
|
+
# #=> [:foo, :bar, :baz]
|
21
|
+
#
|
22
|
+
# # without a trailing comma
|
23
|
+
# {foo: 1, bar: 2, baz: 3}.map {|key| key }
|
24
|
+
# #=> [[:foo, 1], [:bar, 2], [:baz, 3]]
|
25
|
+
# ----
|
26
|
+
#
|
27
|
+
# This can be fixed by replacing the trailing comma with a placeholder
|
28
|
+
# argument (such as `|key, _value|`).
|
29
|
+
#
|
11
30
|
# @example
|
12
31
|
# # bad
|
13
32
|
# add { |foo, bar,| foo + bar }
|
@@ -7,6 +7,26 @@ module RuboCop
|
|
7
7
|
# i.e. comparison operations where the order of expression is reversed.
|
8
8
|
# eg. `5 == x`
|
9
9
|
#
|
10
|
+
# @safety
|
11
|
+
# This cop is unsafe because comparison operators can be defined
|
12
|
+
# differently on different classes, and are not guaranteed to
|
13
|
+
# have the same result if reversed.
|
14
|
+
#
|
15
|
+
# For example:
|
16
|
+
#
|
17
|
+
# [source,ruby]
|
18
|
+
# ----
|
19
|
+
# class MyKlass
|
20
|
+
# def ==(other)
|
21
|
+
# true
|
22
|
+
# end
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# obj = MyKlass.new
|
26
|
+
# obj == 'string' #=> true
|
27
|
+
# 'string' == obj #=> false
|
28
|
+
# ----
|
29
|
+
#
|
10
30
|
# @example EnforcedStyle: forbid_for_all_comparison_operators (default)
|
11
31
|
# # bad
|
12
32
|
# 99 == foo
|
@@ -58,14 +78,11 @@ module RuboCop
|
|
58
78
|
extend AutoCorrector
|
59
79
|
|
60
80
|
MSG = 'Reverse the order of the operands `%<source>s`.'
|
61
|
-
|
62
81
|
REVERSE_COMPARISON = { '<' => '>', '<=' => '>=', '>' => '<', '>=' => '<=' }.freeze
|
63
|
-
|
64
82
|
EQUALITY_OPERATORS = %i[== !=].freeze
|
65
|
-
|
66
83
|
NONCOMMUTATIVE_OPERATORS = %i[===].freeze
|
67
|
-
|
68
84
|
PROGRAM_NAMES = %i[$0 $PROGRAM_NAME].freeze
|
85
|
+
RESTRICT_ON_SEND = RuboCop::AST::Node::COMPARISON_OPERATORS
|
69
86
|
|
70
87
|
# @!method file_constant_equal_program_name?(node)
|
71
88
|
def_node_matcher :file_constant_equal_program_name?, <<~PATTERN
|
@@ -74,7 +91,7 @@ module RuboCop
|
|
74
91
|
|
75
92
|
def on_send(node)
|
76
93
|
return unless yoda_compatible_condition?(node)
|
77
|
-
return if equality_only? && non_equality_operator?(node) ||
|
94
|
+
return if (equality_only? && non_equality_operator?(node)) ||
|
78
95
|
file_constant_equal_program_name?(node)
|
79
96
|
|
80
97
|
valid_yoda?(node) || add_offense(node) do |corrector|
|
@@ -102,8 +119,8 @@ module RuboCop
|
|
102
119
|
lhs = node.receiver
|
103
120
|
rhs = node.first_argument
|
104
121
|
|
105
|
-
return true if lhs.literal? && rhs.literal? ||
|
106
|
-
!lhs.literal? && !rhs.literal? ||
|
122
|
+
return true if (lhs.literal? && rhs.literal?) ||
|
123
|
+
(!lhs.literal? && !rhs.literal?) ||
|
107
124
|
interpolation?(lhs)
|
108
125
|
|
109
126
|
enforce_yoda? ? lhs.literal? : rhs.literal?
|
@@ -9,6 +9,12 @@ module RuboCop
|
|
9
9
|
# receiver.length < 1 and receiver.size == 0 that can be
|
10
10
|
# replaced by receiver.empty? and !receiver.empty?.
|
11
11
|
#
|
12
|
+
# @safety
|
13
|
+
# This cop is unsafe because it cannot be guaranteed that the receiver
|
14
|
+
# has an `empty?` method that is defined in terms of `length`. If there
|
15
|
+
# is a non-standard class that redefines `length` or `empty?`, the cop
|
16
|
+
# may register a false positive.
|
17
|
+
#
|
12
18
|
# @example
|
13
19
|
# # bad
|
14
20
|
# [1, 2, 3].length == 0
|
data/lib/rubocop/cop/util.rb
CHANGED
@@ -113,7 +113,8 @@ module RuboCop
|
|
113
113
|
if needs_escaping?(string) && compatible_external_encoding_for?(string)
|
114
114
|
string.inspect
|
115
115
|
else
|
116
|
-
|
116
|
+
# In a single-quoted strings, double quotes don't need to be escaped
|
117
|
+
"'#{string.gsub('\"', '"').gsub('\\') { '\\\\' }}'"
|
117
118
|
end
|
118
119
|
end
|
119
120
|
|
@@ -125,12 +126,22 @@ module RuboCop
|
|
125
126
|
StringInterpreter.interpret(string)
|
126
127
|
end
|
127
128
|
|
129
|
+
def line(node_or_range)
|
130
|
+
if node_or_range.respond_to?(:line)
|
131
|
+
node_or_range.line
|
132
|
+
elsif node_or_range.respond_to?(:loc)
|
133
|
+
node_or_range.loc.line
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
128
137
|
def same_line?(node1, node2)
|
129
|
-
|
138
|
+
line1 = line(node1)
|
139
|
+
line2 = line(node2)
|
140
|
+
line1 && line2 && line1 == line2
|
130
141
|
end
|
131
142
|
|
132
|
-
def indent(node)
|
133
|
-
' ' * node.loc.column
|
143
|
+
def indent(node, offset: 0)
|
144
|
+
' ' * (node.loc.column + offset)
|
134
145
|
end
|
135
146
|
|
136
147
|
def to_supported_styles(enforced_style)
|
@@ -33,11 +33,12 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
33
33
|
cops.with_department(department).sort!
|
34
34
|
end
|
35
35
|
|
36
|
-
def cops_body(cop, description, examples_objects, pars)
|
36
|
+
def cops_body(cop, description, examples_objects, safety_objects, pars) # rubocop:disable Metrics/AbcSize
|
37
37
|
content = h2(cop.cop_name)
|
38
38
|
content << required_ruby_version(cop)
|
39
39
|
content << properties(cop)
|
40
40
|
content << "#{description}\n"
|
41
|
+
content << safety_object(safety_objects) if safety_objects.any? { |s| !s.text.blank? }
|
41
42
|
content << examples(examples_objects) if examples_objects.count.positive?
|
42
43
|
content << configurations(pars)
|
43
44
|
content << references(cop)
|
@@ -52,6 +53,16 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
52
53
|
end
|
53
54
|
end
|
54
55
|
|
56
|
+
def safety_object(safety_object_objects)
|
57
|
+
safety_object_objects.each_with_object(h3('Safety').dup) do |safety_object, content|
|
58
|
+
next if safety_object.text.blank?
|
59
|
+
|
60
|
+
content << "\n" unless content.end_with?("\n\n")
|
61
|
+
content << safety_object.text
|
62
|
+
content << "\n"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
55
66
|
def required_ruby_version(cop)
|
56
67
|
return '' unless cop.respond_to?(:required_minimum_ruby_version)
|
57
68
|
|
@@ -61,8 +72,8 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
61
72
|
# rubocop:disable Metrics/MethodLength
|
62
73
|
def properties(cop)
|
63
74
|
header = [
|
64
|
-
'Enabled by default', 'Safe', 'Supports autocorrection', '
|
65
|
-
'
|
75
|
+
'Enabled by default', 'Safe', 'Supports autocorrection', 'Version Added',
|
76
|
+
'Version Changed'
|
66
77
|
]
|
67
78
|
autocorrect = if cop.support_autocorrect?
|
68
79
|
"Yes#{' (Unsafe)' unless cop.new(config).safe_autocorrect?}"
|
@@ -217,12 +228,13 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
|
|
217
228
|
]
|
218
229
|
pars = cop_config.reject { |k| non_display_keys.include? k }
|
219
230
|
description = 'No documentation'
|
220
|
-
examples_object = []
|
231
|
+
examples_object = safety_object = []
|
221
232
|
cop_code(cop) do |code_object|
|
222
233
|
description = code_object.docstring unless code_object.docstring.blank?
|
223
234
|
examples_object = code_object.tags('example')
|
235
|
+
safety_object = code_object.tags('safety')
|
224
236
|
end
|
225
|
-
cops_body(cop, description, examples_object, pars)
|
237
|
+
cops_body(cop, description, examples_object, safety_object, pars)
|
226
238
|
end
|
227
239
|
|
228
240
|
def cop_code(cop)
|