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
@@ -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
|
+
# This cop's autocorrection is unsafe 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)
|
@@ -5,9 +5,27 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop enforces the use of `Array()` instead of explicit `Array` check or `[*var]`.
|
7
7
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
8
|
+
# The cop is disabled by default due to safety concerns.
|
9
|
+
#
|
10
|
+
# @safety
|
11
|
+
# This cop is unsafe because a false positive may occur if
|
12
|
+
# the argument of `Array()` is (or could be) nil or depending
|
13
|
+
# on how the argument is handled by `Array()` (which can be
|
14
|
+
# different than just wrapping the argument in an array).
|
15
|
+
#
|
16
|
+
# For example:
|
17
|
+
#
|
18
|
+
# [source,ruby]
|
19
|
+
# ----
|
20
|
+
# [nil] #=> [nil]
|
21
|
+
# Array(nil) #=> []
|
22
|
+
#
|
23
|
+
# [{a: 'b'}] #= [{a: 'b'}]
|
24
|
+
# Array({a: 'b'}) #=> [[:a, 'b']]
|
25
|
+
#
|
26
|
+
# [Time.now] #=> [#<Time ...>]
|
27
|
+
# Array(Time.now) #=> [14, 16, 14, 16, 9, 2021, 4, 259, true, "EDT"]
|
28
|
+
# ----
|
11
29
|
#
|
12
30
|
# @example
|
13
31
|
# # bad
|
@@ -5,9 +5,11 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# This cop checks for uses of the case equality operator(===).
|
7
7
|
#
|
8
|
+
# If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
|
9
|
+
# the case equality operator is a constant.
|
10
|
+
#
|
8
11
|
# @example
|
9
12
|
# # bad
|
10
|
-
# Array === something
|
11
13
|
# (1..100) === 7
|
12
14
|
# /something/ === some_string
|
13
15
|
#
|
@@ -16,18 +18,13 @@ module RuboCop
|
|
16
18
|
# (1..100).include?(7)
|
17
19
|
# /something/.match?(some_string)
|
18
20
|
#
|
19
|
-
# @example AllowOnConstant
|
20
|
-
# # Style/CaseEquality:
|
21
|
-
# # AllowOnConstant: true
|
22
|
-
#
|
21
|
+
# @example AllowOnConstant: false (default)
|
23
22
|
# # bad
|
24
|
-
#
|
25
|
-
# /something/ === some_string
|
23
|
+
# Array === something
|
26
24
|
#
|
25
|
+
# @example AllowOnConstant: true
|
27
26
|
# # good
|
28
27
|
# Array === something
|
29
|
-
# (1..100).include?(7)
|
30
|
-
# /something/.match?(some_string)
|
31
28
|
#
|
32
29
|
class CaseEquality < Base
|
33
30
|
extend AutoCorrector
|
@@ -6,6 +6,11 @@ module RuboCop
|
|
6
6
|
# This cop identifies places where `if-elsif` constructions
|
7
7
|
# can be replaced with `case-when`.
|
8
8
|
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe. `case` statements use `===` for equality,
|
11
|
+
# so if the original conditional used a different equality operator, the
|
12
|
+
# behaviour may be different.
|
13
|
+
#
|
9
14
|
# @example
|
10
15
|
# # bad
|
11
16
|
# if status == :active
|
@@ -6,6 +6,15 @@ module RuboCop
|
|
6
6
|
# This cop checks the style of children definitions at classes and
|
7
7
|
# modules. Basically there are two different styles:
|
8
8
|
#
|
9
|
+
# @safety
|
10
|
+
# Autocorrection is unsafe.
|
11
|
+
#
|
12
|
+
# Moving from compact to nested children requires knowledge of whether the
|
13
|
+
# outer parent is a module or a class. Moving from nested to compact requires
|
14
|
+
# verification that the outer parent is defined elsewhere. Rubocop does not
|
15
|
+
# have the knowledge to perform either operation safely and thus requires
|
16
|
+
# manual oversight.
|
17
|
+
#
|
9
18
|
# @example EnforcedStyle: nested (default)
|
10
19
|
# # good
|
11
20
|
# # have each child on its own line
|
@@ -6,11 +6,13 @@ module RuboCop
|
|
6
6
|
# This cop checks for places where custom logic on rejection nils from arrays
|
7
7
|
# and hashes can be replaced with `{Array,Hash}#{compact,compact!}`.
|
8
8
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
9
|
+
# @safety
|
10
|
+
# It is unsafe by default because false positives may occur in the
|
11
|
+
# `nil` check of block arguments to the receiver object.
|
12
|
+
#
|
13
|
+
# For example, `[[1, 2], [3, nil]].reject { |first, second| second.nil? }`
|
14
|
+
# and `[[1, 2], [3, nil]].compact` are not compatible. This will work fine
|
15
|
+
# when the receiver is a hash object.
|
14
16
|
#
|
15
17
|
# @example
|
16
18
|
# # bad
|
@@ -6,10 +6,6 @@ module RuboCop
|
|
6
6
|
# This cop enforces the use of consistent method names
|
7
7
|
# from the Enumerable module.
|
8
8
|
#
|
9
|
-
# Unfortunately we cannot actually know if a method is from
|
10
|
-
# Enumerable or not (static analysis limitation), so this cop
|
11
|
-
# can yield some false positives.
|
12
|
-
#
|
13
9
|
# You can customize the mapping from undesired method to desired method.
|
14
10
|
#
|
15
11
|
# e.g. to use `detect` over `find`:
|
@@ -18,9 +14,14 @@ module RuboCop
|
|
18
14
|
# PreferredMethods:
|
19
15
|
# find: detect
|
20
16
|
#
|
21
|
-
#
|
17
|
+
# @safety
|
18
|
+
# This cop is unsafe because it finds methods by name, without actually
|
19
|
+
# being able to determine if the receiver is an Enumerable or not, so
|
20
|
+
# this cop may register false positives.
|
22
21
|
#
|
23
22
|
# @example
|
23
|
+
# # These examples are based on the default mapping for `PreferredMethods`.
|
24
|
+
#
|
24
25
|
# # bad
|
25
26
|
# items.collect
|
26
27
|
# items.collect!
|
@@ -68,7 +69,8 @@ module RuboCop
|
|
68
69
|
return false unless node.arguments.any?
|
69
70
|
|
70
71
|
node.last_argument.block_pass_type? ||
|
71
|
-
node.last_argument.sym_type? &&
|
72
|
+
(node.last_argument.sym_type? &&
|
73
|
+
methods_accepting_symbol.include?(node.method_name.to_s))
|
72
74
|
end
|
73
75
|
|
74
76
|
def message(node)
|
@@ -7,8 +7,9 @@ module RuboCop
|
|
7
7
|
# can be combined into a single loop. It is very likely that combining them
|
8
8
|
# will make the code more efficient and more concise.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
10
|
+
# @safety
|
11
|
+
# The cop is unsafe, because the first loop might modify state that the
|
12
|
+
# second loop depends on; these two aren't combinable.
|
12
13
|
#
|
13
14
|
# @example
|
14
15
|
# # bad
|
@@ -12,7 +12,10 @@ module RuboCop
|
|
12
12
|
#
|
13
13
|
# Auto-correction removes comments from `end` keyword and keeps comments
|
14
14
|
# for `class`, `module`, `def` and `begin` above the keyword.
|
15
|
-
#
|
15
|
+
#
|
16
|
+
# @safety
|
17
|
+
# Auto-correction is unsafe because it may remove a comment that is
|
18
|
+
# meaningful.
|
16
19
|
#
|
17
20
|
# @example
|
18
21
|
# # bad
|
@@ -49,9 +52,11 @@ module RuboCop
|
|
49
52
|
ALLOWED_COMMENTS = %w[:nodoc: :yields: rubocop:disable rubocop:todo].freeze
|
50
53
|
ALLOWED_COMMENT_REGEXES = ALLOWED_COMMENTS.map { |c| /#\s*#{c}/ }.freeze
|
51
54
|
|
55
|
+
REGEXP = /(?<keyword>\S+).*#/.freeze
|
56
|
+
|
52
57
|
def on_new_investigation
|
53
58
|
processed_source.comments.each do |comment|
|
54
|
-
next unless offensive?(comment) && (match =
|
59
|
+
next unless offensive?(comment) && (match = source_line(comment).match(REGEXP))
|
55
60
|
|
56
61
|
register_offense(comment, match[:keyword])
|
57
62
|
end
|
@@ -73,12 +78,12 @@ module RuboCop
|
|
73
78
|
end
|
74
79
|
|
75
80
|
def offensive?(comment)
|
76
|
-
line =
|
81
|
+
line = source_line(comment)
|
77
82
|
KEYWORD_REGEXES.any? { |r| r.match?(line) } &&
|
78
83
|
ALLOWED_COMMENT_REGEXES.none? { |r| r.match?(line) }
|
79
84
|
end
|
80
85
|
|
81
|
-
def
|
86
|
+
def source_line(comment)
|
82
87
|
comment.location.expression.source_line
|
83
88
|
end
|
84
89
|
end
|
@@ -9,6 +9,11 @@ module RuboCop
|
|
9
9
|
# replaceable in certain situations when dealing with multiple timezones
|
10
10
|
# and/or DST.
|
11
11
|
#
|
12
|
+
# @safety
|
13
|
+
# Autocorrection is not safe, because `DateTime` and `Time` do not have
|
14
|
+
# exactly the same behaviour, although in most cases the autocorrection
|
15
|
+
# will be fine.
|
16
|
+
#
|
12
17
|
# @example
|
13
18
|
#
|
14
19
|
# # bad - uses `DateTime` for current time
|
@@ -86,7 +86,7 @@ module RuboCop
|
|
86
86
|
|
87
87
|
return unless arg_node&.dstr_type? && interpolated?(arg_node)
|
88
88
|
return if inline_comment_docs?(arg_node) ||
|
89
|
-
arg_node.heredoc? && comment_block_docs?(arg_node)
|
89
|
+
(arg_node.heredoc? && comment_block_docs?(arg_node))
|
90
90
|
|
91
91
|
add_offense(node.loc.selector)
|
92
92
|
end
|
@@ -71,8 +71,9 @@ module RuboCop
|
|
71
71
|
#
|
72
72
|
class Documentation < Base
|
73
73
|
include DocumentationComment
|
74
|
+
include RangeHelp
|
74
75
|
|
75
|
-
MSG = 'Missing top-level
|
76
|
+
MSG = 'Missing top-level documentation comment for `%<type>s %<identifier>s`.'
|
76
77
|
|
77
78
|
# @!method constant_definition?(node)
|
78
79
|
def_node_matcher :constant_definition?, '{class module casgn}'
|
@@ -88,33 +89,35 @@ module RuboCop
|
|
88
89
|
def on_class(node)
|
89
90
|
return unless node.body
|
90
91
|
|
91
|
-
check(node, node.body
|
92
|
+
check(node, node.body)
|
92
93
|
end
|
93
94
|
|
94
95
|
def on_module(node)
|
95
|
-
check(node, node.body
|
96
|
+
check(node, node.body)
|
96
97
|
end
|
97
98
|
|
98
99
|
private
|
99
100
|
|
100
|
-
def check(node, body
|
101
|
+
def check(node, body)
|
101
102
|
return if namespace?(body)
|
102
103
|
return if documentation_comment?(node)
|
103
104
|
return if constant_allowed?(node)
|
104
105
|
return if nodoc_self_or_outer_module?(node)
|
105
106
|
return if macro_only?(body)
|
106
107
|
|
107
|
-
|
108
|
+
range = range_between(node.loc.expression.begin_pos, node.loc.name.end_pos)
|
109
|
+
message = format(MSG, type: node.type, identifier: identifier(node))
|
110
|
+
add_offense(range, message: message)
|
108
111
|
end
|
109
112
|
|
110
113
|
def nodoc_self_or_outer_module?(node)
|
111
114
|
nodoc_comment?(node) ||
|
112
|
-
compact_namespace?(node) && nodoc_comment?(outer_module(node).first)
|
115
|
+
(compact_namespace?(node) && nodoc_comment?(outer_module(node).first))
|
113
116
|
end
|
114
117
|
|
115
118
|
def macro_only?(body)
|
116
|
-
body.respond_to?(:macro?) && body.macro? ||
|
117
|
-
body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) }
|
119
|
+
(body.respond_to?(:macro?) && body.macro?) ||
|
120
|
+
(body.respond_to?(:children) && body.children&.all? { |child| macro_only?(child) })
|
118
121
|
end
|
119
122
|
|
120
123
|
def namespace?(node)
|
@@ -165,6 +168,18 @@ module RuboCop
|
|
165
168
|
def allowed_constants
|
166
169
|
@allowed_constants ||= cop_config.fetch('AllowedConstants', []).map(&:intern)
|
167
170
|
end
|
171
|
+
|
172
|
+
def identifier(node)
|
173
|
+
# Get the fully qualified identifier for a class/module
|
174
|
+
nodes = [node, *node.each_ancestor(:class, :module)]
|
175
|
+
nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
|
176
|
+
end
|
177
|
+
|
178
|
+
def qualify_const(node)
|
179
|
+
return if node.nil?
|
180
|
+
|
181
|
+
[qualify_const(node.namespace), node.short_name].compact
|
182
|
+
end
|
168
183
|
end
|
169
184
|
end
|
170
185
|
end
|
@@ -9,6 +9,21 @@ module RuboCop
|
|
9
9
|
# that use boolean as a return value. When using `EnforcedStyle: forbidden`, double negation
|
10
10
|
# should be forbidden always.
|
11
11
|
#
|
12
|
+
# NOTE: when `something` is a boolean value
|
13
|
+
# `!!something` and `!something.nil?` are not the same thing.
|
14
|
+
# As you're unlikely to write code that can accept values of any type
|
15
|
+
# this is rarely a problem in practice.
|
16
|
+
#
|
17
|
+
# @safety
|
18
|
+
# Autocorrection is unsafe when the value is `false`, because the result
|
19
|
+
# of the expression will change.
|
20
|
+
#
|
21
|
+
# [source,ruby]
|
22
|
+
# ----
|
23
|
+
# !!false #=> false
|
24
|
+
# !false.nil? #=> true
|
25
|
+
# ----
|
26
|
+
#
|
12
27
|
# @example
|
13
28
|
# # bad
|
14
29
|
# !!something
|
@@ -27,11 +42,6 @@ module RuboCop
|
|
27
42
|
# def foo?
|
28
43
|
# !!return_value
|
29
44
|
# end
|
30
|
-
#
|
31
|
-
# Please, note that when something is a boolean value
|
32
|
-
# !!something and !something.nil? are not the same thing.
|
33
|
-
# As you're unlikely to write code that can accept values of any type
|
34
|
-
# this is rarely a problem in practice.
|
35
45
|
class DoubleNegation < Base
|
36
46
|
include ConfigurableEnforcedStyle
|
37
47
|
extend AutoCorrector
|