rubocop 1.66.1 → 1.69.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +96 -12
- data/config/internal_affairs.yml +11 -0
- data/lib/rubocop/cached_data.rb +12 -4
- data/lib/rubocop/cli/command/auto_generate_config.rb +6 -7
- data/lib/rubocop/cli/command/execute_runner.rb +1 -1
- data/lib/rubocop/cli/command/lsp.rb +2 -2
- data/lib/rubocop/cli/command/version.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +3 -3
- data/lib/rubocop/config_validator.rb +2 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +22 -2
- data/lib/rubocop/cop/base.rb +7 -3
- data/lib/rubocop/cop/bundler/gem_filename.rb +0 -1
- data/lib/rubocop/cop/bundler/gem_version.rb +1 -0
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +0 -1
- data/lib/rubocop/cop/cop.rb +8 -0
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -12
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +10 -0
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +1 -2
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +0 -2
- data/lib/rubocop/cop/generator.rb +6 -0
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +0 -4
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -4
- data/lib/rubocop/cop/internal_affairs/numblock_handler.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/operator_keyword.rb +46 -0
- data/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +6 -21
- data/lib/rubocop/cop/internal_affairs/redundant_source_range.rb +8 -1
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +0 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +0 -5
- data/lib/rubocop/cop/internal_affairs.rb +17 -0
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +5 -1
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +0 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +2 -3
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +3 -4
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +3 -1
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +8 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +11 -12
- data/lib/rubocop/cop/layout/leading_comment_space.rb +71 -1
- data/lib/rubocop/cop/layout/line_length.rb +118 -4
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +2 -3
- data/lib/rubocop/cop/layout/parameter_alignment.rb +3 -4
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -35
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +3 -2
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +16 -17
- data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -5
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +6 -0
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +4 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +4 -0
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +0 -1
- data/lib/rubocop/cop/lint/ambiguous_range.rb +4 -1
- data/lib/rubocop/cop/lint/big_decimal_new.rb +4 -7
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +10 -12
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +6 -0
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_branch.rb +39 -4
- data/lib/rubocop/cop/lint/duplicate_set_element.rb +74 -0
- data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
- data/lib/rubocop/cop/lint/empty_file.rb +0 -2
- data/lib/rubocop/cop/lint/ensure_return.rb +1 -4
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +15 -7
- data/lib/rubocop/cop/lint/float_out_of_range.rb +1 -3
- data/lib/rubocop/cop/lint/hash_new_with_keyword_arguments_as_default.rb +55 -0
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +10 -4
- data/lib/rubocop/cop/lint/interpolation_check.rb +9 -0
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +8 -14
- data/lib/rubocop/cop/lint/literal_as_condition.rb +1 -0
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +1 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +25 -2
- data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -5
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +2 -2
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +8 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -3
- data/lib/rubocop/cop/lint/number_conversion.rb +0 -1
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -2
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +106 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -2
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -6
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +13 -8
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +8 -7
- data/lib/rubocop/cop/lint/refinement_import_methods.rb +1 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +0 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +3 -7
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +9 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +109 -41
- data/lib/rubocop/cop/lint/self_assignment.rb +8 -10
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +91 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +51 -2
- data/lib/rubocop/cop/lint/unused_method_argument.rb +18 -2
- data/lib/rubocop/cop/lint/uri_regexp.rb +25 -7
- data/lib/rubocop/cop/lint/useless_defined.rb +55 -0
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +4 -0
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -25
- data/lib/rubocop/cop/lint/void.rb +3 -2
- data/lib/rubocop/cop/metrics/class_length.rb +7 -7
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -3
- data/lib/rubocop/cop/mixin/check_assignment.rb +4 -12
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +10 -0
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +49 -0
- data/lib/rubocop/cop/mixin/dig_help.rb +27 -0
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +24 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +5 -9
- data/lib/rubocop/cop/mixin/percent_array.rb +1 -1
- data/lib/rubocop/cop/mixin/range_help.rb +0 -1
- data/lib/rubocop/cop/mixin/statement_modifier.rb +3 -2
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +17 -1
- data/lib/rubocop/cop/naming/accessor_method_name.rb +6 -6
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +6 -7
- data/lib/rubocop/cop/naming/file_name.rb +0 -2
- data/lib/rubocop/cop/naming/inclusive_language.rb +12 -3
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +11 -12
- data/lib/rubocop/cop/naming/predicate_name.rb +1 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +3 -11
- data/lib/rubocop/cop/naming/variable_name.rb +3 -4
- data/lib/rubocop/cop/naming/variable_number.rb +2 -3
- data/lib/rubocop/cop/offense.rb +4 -5
- data/lib/rubocop/cop/security/compound_hash.rb +1 -0
- data/lib/rubocop/cop/security/yaml_load.rb +3 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +64 -25
- data/lib/rubocop/cop/style/accessor_grouping.rb +10 -2
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +79 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +46 -6
- data/lib/rubocop/cop/style/array_intersect.rb +5 -4
- data/lib/rubocop/cop/style/bitwise_predicate.rb +100 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +41 -5
- data/lib/rubocop/cop/style/case_like_if.rb +8 -11
- data/lib/rubocop/cop/style/collection_compact.rb +10 -10
- data/lib/rubocop/cop/style/combinable_defined.rb +115 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +7 -0
- data/lib/rubocop/cop/style/commented_keyword.rb +17 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +20 -22
- data/lib/rubocop/cop/style/constant_visibility.rb +3 -12
- data/lib/rubocop/cop/style/data_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/dig_chain.rb +89 -0
- data/lib/rubocop/cop/style/endless_method.rb +1 -14
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -0
- data/lib/rubocop/cop/style/file_null.rb +73 -0
- data/lib/rubocop/cop/style/file_touch.rb +75 -0
- data/lib/rubocop/cop/style/for.rb +0 -1
- data/lib/rubocop/cop/style/global_vars.rb +1 -3
- data/lib/rubocop/cop/style/guard_clause.rb +16 -3
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -2
- data/lib/rubocop/cop/style/hash_each_methods.rb +6 -0
- data/lib/rubocop/cop/style/hash_except.rb +19 -7
- data/lib/rubocop/cop/style/hash_syntax.rb +2 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +1 -2
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -2
- data/lib/rubocop/cop/style/if_with_semicolon.rb +20 -7
- data/lib/rubocop/cop/style/inverse_methods.rb +0 -1
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +67 -0
- data/lib/rubocop/cop/style/lambda.rb +1 -1
- data/lib/rubocop/cop/style/lambda_call.rb +3 -2
- data/lib/rubocop/cop/style/map_into_array.rb +59 -8
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +13 -8
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +7 -11
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +33 -3
- data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
- data/lib/rubocop/cop/style/multiple_comparison.rb +28 -39
- data/lib/rubocop/cop/style/mutable_constant.rb +4 -5
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +6 -4
- data/lib/rubocop/cop/style/nested_modifier.rb +1 -1
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +1 -1
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -4
- data/lib/rubocop/cop/style/not.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +1 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +29 -4
- data/lib/rubocop/cop/style/operator_method_call.rb +25 -7
- data/lib/rubocop/cop/style/or_assignment.rb +3 -6
- data/lib/rubocop/cop/style/parallel_assignment.rb +8 -13
- data/lib/rubocop/cop/style/raise_args.rb +1 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +3 -1
- data/lib/rubocop/cop/style/redundant_assignment.rb +1 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +4 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +37 -22
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +24 -5
- data/lib/rubocop/cop/style/redundant_parentheses.rb +11 -13
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +1 -0
- data/lib/rubocop/cop/style/redundant_return.rb +2 -2
- data/lib/rubocop/cop/style/redundant_self.rb +8 -15
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +7 -5
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +4 -4
- data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
- data/lib/rubocop/cop/style/require_order.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +15 -4
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +54 -12
- data/lib/rubocop/cop/style/safe_navigation.rb +104 -50
- data/lib/rubocop/cop/style/safe_navigation_chain_length.rb +52 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +10 -7
- data/lib/rubocop/cop/style/self_assignment.rb +11 -17
- data/lib/rubocop/cop/style/semicolon.rb +1 -1
- data/lib/rubocop/cop/style/signal_exception.rb +2 -3
- data/lib/rubocop/cop/style/single_argument_dig.rb +9 -5
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +13 -3
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +2 -3
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +13 -12
- data/lib/rubocop/cop/style/struct_inheritance.rb +1 -1
- data/lib/rubocop/cop/style/swap_values.rb +4 -15
- data/lib/rubocop/cop/style/ternary_parentheses.rb +26 -5
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +4 -4
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/variable_interpolation.rb +1 -2
- data/lib/rubocop/cop/team.rb +8 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +18 -3
- data/lib/rubocop/cop/variable_force/branch.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +5 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +4 -10
- data/lib/rubocop/cops_documentation_generator.rb +90 -41
- data/lib/rubocop/file_finder.rb +9 -4
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/lsp/runtime.rb +2 -0
- data/lib/rubocop/lsp/server.rb +0 -1
- data/lib/rubocop/rspec/expect_offense.rb +1 -0
- data/lib/rubocop/runner.rb +17 -6
- data/lib/rubocop/server/cache.rb +6 -1
- data/lib/rubocop/server/core.rb +1 -0
- data/lib/rubocop/target_ruby.rb +13 -13
- data/lib/rubocop/version.rb +28 -7
- data/lib/rubocop/yaml_duplication_checker.rb +20 -27
- data/lib/rubocop.rb +18 -0
- metadata +32 -14
@@ -31,9 +31,6 @@ module RuboCop
|
|
31
31
|
# @!method allowed_pin_operator?(node)
|
32
32
|
def_node_matcher :allowed_pin_operator?, '^(pin (begin !{lvar ivar cvar gvar}))'
|
33
33
|
|
34
|
-
# @!method arg_in_call_with_block?(node)
|
35
|
-
def_node_matcher :arg_in_call_with_block?, '^^(block (send _ _ equal?(%0) ...) ...)'
|
36
|
-
|
37
34
|
def on_begin(node)
|
38
35
|
return if !parentheses?(node) || parens_allowed?(node) || ignore_syntax?(node)
|
39
36
|
|
@@ -59,7 +56,6 @@ module RuboCop
|
|
59
56
|
|
60
57
|
def allowed_expression?(node)
|
61
58
|
allowed_ancestor?(node) ||
|
62
|
-
allowed_method_call?(node) ||
|
63
59
|
allowed_multiple_expression?(node) ||
|
64
60
|
allowed_ternary?(node) ||
|
65
61
|
node.parent&.range_type?
|
@@ -70,11 +66,6 @@ module RuboCop
|
|
70
66
|
keyword_ancestor?(node) && parens_required?(node)
|
71
67
|
end
|
72
68
|
|
73
|
-
def allowed_method_call?(node)
|
74
|
-
# Don't flag `method (arg) { }`
|
75
|
-
arg_in_call_with_block?(node) && !parentheses?(node.parent)
|
76
|
-
end
|
77
|
-
|
78
69
|
def allowed_multiple_expression?(node)
|
79
70
|
return false if node.children.one?
|
80
71
|
|
@@ -156,11 +147,11 @@ module RuboCop
|
|
156
147
|
|
157
148
|
return if begin_node.chained?
|
158
149
|
|
159
|
-
if node.
|
150
|
+
if node.operator_keyword?
|
160
151
|
return if node.semantic_operator? && begin_node.parent
|
161
152
|
return if node.multiline? && allow_in_multiline_conditions?
|
162
153
|
return if ALLOWED_NODE_TYPES.include?(begin_node.parent&.type)
|
163
|
-
return if begin_node.parent&.if_type? && begin_node.parent
|
154
|
+
return if begin_node.parent&.if_type? && begin_node.parent.ternary?
|
164
155
|
|
165
156
|
'a logical expression'
|
166
157
|
elsif node.respond_to?(:comparison_method?) && node.comparison_method?
|
@@ -185,7 +176,8 @@ module RuboCop
|
|
185
176
|
return check_unary(begin_node, node) if node.unary_operation?
|
186
177
|
|
187
178
|
return unless method_call_with_redundant_parentheses?(node)
|
188
|
-
return if call_chain_starts_with_int?(begin_node, node)
|
179
|
+
return if call_chain_starts_with_int?(begin_node, node) ||
|
180
|
+
do_end_block_in_method_chain?(begin_node, node)
|
189
181
|
|
190
182
|
offense(begin_node, 'a method call')
|
191
183
|
end
|
@@ -252,7 +244,7 @@ module RuboCop
|
|
252
244
|
end
|
253
245
|
|
254
246
|
def only_begin_arg?(args)
|
255
|
-
args.one? && args.first
|
247
|
+
args.one? && args.first&.begin_type?
|
256
248
|
end
|
257
249
|
|
258
250
|
def first_argument?(node)
|
@@ -285,6 +277,12 @@ module RuboCop
|
|
285
277
|
recv&.int_type? && (parent = begin_node.parent) &&
|
286
278
|
parent.send_type? && (parent.method?(:-@) || parent.method?(:+@))
|
287
279
|
end
|
280
|
+
|
281
|
+
def do_end_block_in_method_chain?(begin_node, node)
|
282
|
+
return false unless (block = node.each_descendant(:block, :numblock).first)
|
283
|
+
|
284
|
+
block.keywords? && begin_node.each_ancestor(:send, :csend).any?
|
285
|
+
end
|
288
286
|
end
|
289
287
|
end
|
290
288
|
end
|
@@ -61,9 +61,9 @@ module RuboCop
|
|
61
61
|
RESTRICT_ON_SEND = %i[define_method define_singleton_method lambda].freeze
|
62
62
|
|
63
63
|
def on_send(node)
|
64
|
-
return unless
|
64
|
+
return unless node.block_literal?
|
65
65
|
|
66
|
-
check_branch(parent.body)
|
66
|
+
check_branch(node.parent.body)
|
67
67
|
end
|
68
68
|
|
69
69
|
def on_def(node)
|
@@ -66,14 +66,12 @@ module RuboCop
|
|
66
66
|
# Assignment of self.x
|
67
67
|
|
68
68
|
def on_or_asgn(node)
|
69
|
-
lhs
|
70
|
-
allow_self(lhs)
|
69
|
+
allow_self(node.lhs)
|
71
70
|
end
|
72
71
|
alias on_and_asgn on_or_asgn
|
73
72
|
|
74
73
|
def on_op_asgn(node)
|
75
|
-
lhs
|
76
|
-
allow_self(lhs)
|
74
|
+
allow_self(node.lhs)
|
77
75
|
end
|
78
76
|
|
79
77
|
# Using self.x to distinguish from local variable x
|
@@ -92,13 +90,11 @@ module RuboCop
|
|
92
90
|
end
|
93
91
|
|
94
92
|
def on_masgn(node)
|
95
|
-
|
96
|
-
add_masgn_lhs_variables(rhs, lhs)
|
93
|
+
add_masgn_lhs_variables(node.rhs, node.lhs)
|
97
94
|
end
|
98
95
|
|
99
96
|
def on_lvasgn(node)
|
100
|
-
|
101
|
-
add_lhs_to_local_variables_scopes(rhs, lhs)
|
97
|
+
add_lhs_to_local_variables_scopes(node.rhs, node.lhs)
|
102
98
|
end
|
103
99
|
|
104
100
|
def on_in_pattern(node)
|
@@ -127,12 +123,10 @@ module RuboCop
|
|
127
123
|
# Allow conditional nodes to use `self` in the condition if that variable
|
128
124
|
# name is used in an `lvasgn` or `masgn` within the `if`.
|
129
125
|
node.child_nodes.each do |child_node|
|
130
|
-
lhs, _rhs = *child_node
|
131
|
-
|
132
126
|
if child_node.lvasgn_type?
|
133
|
-
add_lhs_to_local_variables_scopes(node.condition, lhs)
|
127
|
+
add_lhs_to_local_variables_scopes(node.condition, child_node.lhs)
|
134
128
|
elsif child_node.masgn_type?
|
135
|
-
add_masgn_lhs_variables(node.condition, lhs)
|
129
|
+
add_masgn_lhs_variables(node.condition, child_node.lhs)
|
136
130
|
end
|
137
131
|
end
|
138
132
|
end
|
@@ -181,9 +175,8 @@ module RuboCop
|
|
181
175
|
def on_argument(node)
|
182
176
|
if node.mlhs_type?
|
183
177
|
on_args(node)
|
184
|
-
|
185
|
-
|
186
|
-
@local_variables_scopes[node] << name
|
178
|
+
elsif node.respond_to?(:name)
|
179
|
+
@local_variables_scopes[node] << node.name
|
187
180
|
end
|
188
181
|
end
|
189
182
|
|
@@ -49,19 +49,21 @@ module RuboCop
|
|
49
49
|
gvasgn: :gvar
|
50
50
|
}.freeze
|
51
51
|
|
52
|
+
# rubocop:disable Metrics/AbcSize
|
52
53
|
def on_lvasgn(node)
|
53
|
-
|
54
|
-
|
55
|
-
return unless receiver
|
54
|
+
return unless (rhs = node.rhs)
|
55
|
+
return unless rhs.send_type? && method_returning_self?(rhs.method_name)
|
56
|
+
return unless (receiver = rhs.receiver)
|
56
57
|
|
57
58
|
receiver_type = ASSIGNMENT_TYPE_TO_RECEIVER_TYPE[node.type]
|
58
|
-
return unless receiver.type == receiver_type && receiver.children.first == lhs
|
59
|
+
return unless receiver.type == receiver_type && receiver.children.first == node.lhs
|
59
60
|
|
60
|
-
message = format(MSG, method_name: method_name)
|
61
|
+
message = format(MSG, method_name: rhs.method_name)
|
61
62
|
add_offense(node.loc.operator, message: message) do |corrector|
|
62
63
|
corrector.replace(node, rhs.source)
|
63
64
|
end
|
64
65
|
end
|
66
|
+
# rubocop:enable Metrics/AbcSize
|
65
67
|
alias on_ivasgn on_lvasgn
|
66
68
|
alias on_cvasgn on_lvasgn
|
67
69
|
alias on_gvasgn on_lvasgn
|
@@ -23,7 +23,6 @@ module RuboCop
|
|
23
23
|
# foo = bar unless condition
|
24
24
|
#
|
25
25
|
class RedundantSelfAssignmentBranch < Base
|
26
|
-
include RangeHelp
|
27
26
|
extend AutoCorrector
|
28
27
|
|
29
28
|
MSG = 'Remove the self-assignment branch.'
|
@@ -34,16 +33,17 @@ module RuboCop
|
|
34
33
|
PATTERN
|
35
34
|
|
36
35
|
def on_lvasgn(node)
|
37
|
-
|
36
|
+
expression = node.expression
|
37
|
+
|
38
38
|
return unless use_if_and_else_branch?(expression)
|
39
39
|
|
40
40
|
if_branch = expression.if_branch
|
41
41
|
else_branch = expression.else_branch
|
42
42
|
return if inconvertible_to_modifier?(if_branch, else_branch)
|
43
43
|
|
44
|
-
if self_assign?(
|
44
|
+
if self_assign?(node.name, if_branch)
|
45
45
|
register_offense(expression, if_branch, else_branch, 'unless')
|
46
|
-
elsif self_assign?(
|
46
|
+
elsif self_assign?(node.name, else_branch)
|
47
47
|
register_offense(expression, else_branch, if_branch, 'if')
|
48
48
|
end
|
49
49
|
end
|
@@ -103,7 +103,7 @@ module RuboCop
|
|
103
103
|
next unless sibling.is_a?(AST::Node)
|
104
104
|
|
105
105
|
sibling = sibling_node(sibling)
|
106
|
-
break unless sibling&.send_type? && sibling
|
106
|
+
break unless sibling&.send_type? && sibling.method?(node.method_name)
|
107
107
|
break unless sibling.arguments? && !sibling.receiver
|
108
108
|
break unless in_same_section?(sibling, node)
|
109
109
|
break unless node.first_argument.str_type? && sibling.first_argument.str_type?
|
@@ -68,17 +68,16 @@ module RuboCop
|
|
68
68
|
end
|
69
69
|
|
70
70
|
def correct_rescue_block(corrector, node, parenthesized)
|
71
|
-
operation
|
72
|
-
*_, rescue_args = *rescue_modifier
|
71
|
+
operation = node.body
|
73
72
|
|
74
73
|
node_indentation, node_offset = indentation_and_offset(node, parenthesized)
|
75
74
|
|
76
75
|
corrector.remove(range_between(operation.source_range.end_pos, node.source_range.end_pos))
|
77
76
|
corrector.insert_before(operation, "begin\n#{node_indentation}")
|
78
|
-
corrector.insert_after(operation, <<~RESCUE_CLAUSE.chop)
|
77
|
+
corrector.insert_after(heredoc_end(operation) || operation, <<~RESCUE_CLAUSE.chop)
|
79
78
|
|
80
79
|
#{node_offset}rescue
|
81
|
-
#{node_indentation}#{
|
80
|
+
#{node_indentation}#{node.resbody_branches.first.body.source}
|
82
81
|
#{node_offset}end
|
83
82
|
RESCUE_CLAUSE
|
84
83
|
end
|
@@ -92,6 +91,18 @@ module RuboCop
|
|
92
91
|
end
|
93
92
|
[node_indentation, node_offset]
|
94
93
|
end
|
94
|
+
|
95
|
+
def heredoc_end(node)
|
96
|
+
return unless node.call_type?
|
97
|
+
|
98
|
+
heredoc = node.arguments.reverse.find do |argument|
|
99
|
+
argument.respond_to?(:heredoc?) && argument.heredoc?
|
100
|
+
end
|
101
|
+
|
102
|
+
return unless heredoc
|
103
|
+
|
104
|
+
heredoc.loc.heredoc_end
|
105
|
+
end
|
95
106
|
end
|
96
107
|
end
|
97
108
|
end
|
@@ -3,7 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks
|
6
|
+
# Checks for predicate method definitions that return `nil`.
|
7
|
+
# A predicate method should only return a boolean value.
|
7
8
|
#
|
8
9
|
# @safety
|
9
10
|
# Autocorrection is marked as unsafe because the change of the return value
|
@@ -31,6 +32,24 @@ module RuboCop
|
|
31
32
|
# do_something?
|
32
33
|
# end
|
33
34
|
#
|
35
|
+
# # bad
|
36
|
+
# def foo?
|
37
|
+
# if condition
|
38
|
+
# nil
|
39
|
+
# else
|
40
|
+
# true
|
41
|
+
# end
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# # good
|
45
|
+
# def foo?
|
46
|
+
# if condition
|
47
|
+
# false
|
48
|
+
# else
|
49
|
+
# true
|
50
|
+
# end
|
51
|
+
# end
|
52
|
+
#
|
34
53
|
# @example AllowedMethods: ['foo?']
|
35
54
|
# # good
|
36
55
|
# def foo?
|
@@ -64,24 +83,25 @@ module RuboCop
|
|
64
83
|
return if allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name)
|
65
84
|
return unless (body = node.body)
|
66
85
|
|
67
|
-
body.each_descendant(:return)
|
68
|
-
register_offense(return_node, 'return false') if return_nil?(return_node)
|
69
|
-
end
|
70
|
-
|
71
|
-
return unless (nil_node = nil_node_at_the_end_of_method_body(body))
|
86
|
+
body.each_descendant(:return) { |return_node| handle_return(return_node) }
|
72
87
|
|
73
|
-
|
88
|
+
handle_implicit_return_values(body)
|
74
89
|
end
|
75
90
|
alias on_defs on_def
|
76
91
|
|
77
92
|
private
|
78
93
|
|
79
|
-
def
|
80
|
-
return
|
81
|
-
return
|
82
|
-
return unless
|
94
|
+
def last_node_of_type(node, type)
|
95
|
+
return unless node
|
96
|
+
return node if node_type?(node, type)
|
97
|
+
return unless node.begin_type?
|
98
|
+
return unless (last_child = node.children.last)
|
99
|
+
|
100
|
+
last_child if last_child.is_a?(AST::Node) && node_type?(last_child, type)
|
101
|
+
end
|
83
102
|
|
84
|
-
|
103
|
+
def node_type?(node, type)
|
104
|
+
node.type == type.to_sym
|
85
105
|
end
|
86
106
|
|
87
107
|
def register_offense(offense_node, replacement)
|
@@ -89,6 +109,28 @@ module RuboCop
|
|
89
109
|
corrector.replace(offense_node, replacement)
|
90
110
|
end
|
91
111
|
end
|
112
|
+
|
113
|
+
def handle_implicit_return_values(node)
|
114
|
+
handle_if(last_node_of_type(node, :if))
|
115
|
+
handle_nil(last_node_of_type(node, :nil))
|
116
|
+
end
|
117
|
+
|
118
|
+
def handle_return(return_node)
|
119
|
+
register_offense(return_node, 'return false') if return_nil?(return_node)
|
120
|
+
end
|
121
|
+
|
122
|
+
def handle_nil(nil_node)
|
123
|
+
return unless nil_node
|
124
|
+
|
125
|
+
register_offense(nil_node, 'false')
|
126
|
+
end
|
127
|
+
|
128
|
+
def handle_if(if_node)
|
129
|
+
return unless if_node
|
130
|
+
|
131
|
+
handle_implicit_return_values(if_node.if_branch)
|
132
|
+
handle_implicit_return_values(if_node.else_branch)
|
133
|
+
end
|
92
134
|
end
|
93
135
|
end
|
94
136
|
end
|
@@ -21,6 +21,11 @@ module RuboCop
|
|
21
21
|
# We have limited the cop to not register an offense for method chains
|
22
22
|
# that exceed this option's value.
|
23
23
|
#
|
24
|
+
# NOTE: This cop will recognize offenses but not autocorrect code when the
|
25
|
+
# right hand side (RHS) of the `&&` statement is an `||` statement
|
26
|
+
# (eg. `foo && (foo.bar? || foo.baz?)`). It can be corrected
|
27
|
+
# manually by removing the `foo &&` and adding `&.` to each `foo` on the RHS.
|
28
|
+
#
|
24
29
|
# @safety
|
25
30
|
# Autocorrection is unsafe because if a value is `false`, the resulting
|
26
31
|
# code will have different behavior or raise an error.
|
@@ -81,7 +86,7 @@ module RuboCop
|
|
81
86
|
# foo.baz = bar if foo
|
82
87
|
# foo.baz + bar if foo
|
83
88
|
# foo.bar > 2 if foo
|
84
|
-
class SafeNavigation < Base
|
89
|
+
class SafeNavigation < Base # rubocop:disable Metrics/ClassLength
|
85
90
|
include NilMethods
|
86
91
|
include RangeHelp
|
87
92
|
extend AutoCorrector
|
@@ -121,50 +126,122 @@ module RuboCop
|
|
121
126
|
}
|
122
127
|
PATTERN
|
123
128
|
|
129
|
+
# @!method and_with_rhs_or?(node)
|
130
|
+
def_node_matcher :and_with_rhs_or?, '(and _ {or (begin or)})'
|
131
|
+
|
124
132
|
# @!method not_nil_check?(node)
|
125
133
|
def_node_matcher :not_nil_check?, '(send (send $_ :nil?) :!)'
|
126
134
|
|
135
|
+
# @!method and_inside_begin?(node)
|
136
|
+
def_node_matcher :and_inside_begin?, '`(begin and ...)'
|
137
|
+
|
138
|
+
# @!method strip_begin(node)
|
139
|
+
def_node_matcher :strip_begin, '{ (begin $!begin) $!(begin) }'
|
140
|
+
|
127
141
|
def on_if(node)
|
128
142
|
return if allowed_if_condition?(node)
|
129
143
|
|
130
|
-
|
144
|
+
checked_variable, receiver, method_chain, _method = extract_parts_from_if(node)
|
145
|
+
return unless offending_node?(node, checked_variable, method_chain, receiver)
|
146
|
+
|
147
|
+
body = extract_if_body(node)
|
148
|
+
method_call = receiver.parent
|
149
|
+
|
150
|
+
removal_ranges = [begin_range(node, body), end_range(node, body)]
|
151
|
+
|
152
|
+
report_offense(node, method_chain, method_call, *removal_ranges) do |corrector|
|
153
|
+
corrector.insert_before(method_call.loc.dot, '&') unless method_call.safe_navigation?
|
154
|
+
end
|
131
155
|
end
|
132
156
|
|
133
|
-
def on_and(node)
|
134
|
-
|
157
|
+
def on_and(node) # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
|
158
|
+
collect_and_clauses(node).each do |(lhs, lhs_operator_range), (rhs, _rhs_operator_range)|
|
159
|
+
lhs_not_nil_check = not_nil_check?(lhs)
|
160
|
+
lhs_receiver = lhs_not_nil_check || lhs
|
161
|
+
rhs_receiver = find_matching_receiver_invocation(strip_begin(rhs), lhs_receiver)
|
162
|
+
|
163
|
+
next if !cop_config['ConvertCodeThatCanStartToReturnNil'] && lhs_not_nil_check
|
164
|
+
next unless offending_node?(node, lhs_receiver, rhs, rhs_receiver)
|
165
|
+
|
166
|
+
# Since we are evaluating every clause in potentially a complex chain of `and` nodes,
|
167
|
+
# we need to ensure that there isn't an object check happening
|
168
|
+
lhs_method_chain = find_method_chain(lhs_receiver)
|
169
|
+
next unless lhs_method_chain == lhs_receiver || lhs_not_nil_check
|
170
|
+
|
171
|
+
report_offense(
|
172
|
+
node,
|
173
|
+
rhs, rhs_receiver,
|
174
|
+
range_with_surrounding_space(range: lhs.source_range, side: :right),
|
175
|
+
range_with_surrounding_space(range: lhs_operator_range, side: :right),
|
176
|
+
offense_range: range_between(lhs.source_range.begin_pos, rhs.source_range.end_pos)
|
177
|
+
)
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def report_offense(node, rhs, rhs_receiver, *removal_ranges, offense_range: node)
|
182
|
+
add_offense(offense_range) do |corrector|
|
183
|
+
# If the RHS is an `or` we cannot safely autocorrect because in order to remove
|
184
|
+
# the non-nil check we need to add safe-navs to all clauses where the receiver is used
|
185
|
+
next if and_with_rhs_or?(node)
|
186
|
+
|
187
|
+
removal_ranges.each { |range| corrector.remove(range) }
|
188
|
+
yield corrector if block_given?
|
189
|
+
|
190
|
+
handle_comments(corrector, node, rhs)
|
191
|
+
|
192
|
+
add_safe_nav_to_all_methods_in_chain(corrector, rhs_receiver, rhs)
|
193
|
+
end
|
135
194
|
end
|
136
195
|
|
137
196
|
private
|
138
197
|
|
139
|
-
def
|
140
|
-
|
141
|
-
return if receiver != checked_variable || receiver.nil?
|
142
|
-
return if use_var_only_in_unless_modifier?(node, checked_variable)
|
143
|
-
return if chain_length(method_chain, method) > max_chain_length
|
144
|
-
return if unsafe_method_used?(method_chain, method)
|
145
|
-
return if method_chain.method?(:empty?)
|
198
|
+
def find_method_chain(node)
|
199
|
+
return node unless node&.parent&.call_type?
|
146
200
|
|
147
|
-
|
201
|
+
find_method_chain(node.parent)
|
148
202
|
end
|
149
203
|
|
150
|
-
def
|
151
|
-
|
204
|
+
def collect_and_clauses(node)
|
205
|
+
# Collect the lhs, operator and rhs of all `and` nodes
|
206
|
+
# `and` nodes can be nested and can contain `begin` nodes
|
207
|
+
# This gives us a source-ordered list of clauses that is then used to look
|
208
|
+
# for matching receivers as well as operator locations for offense and corrections
|
209
|
+
node.each_descendant(:and)
|
210
|
+
.inject(and_parts(node)) { |nodes, and_node| concat_nodes(nodes, and_node) }
|
211
|
+
.sort_by { |a| a.is_a?(RuboCop::AST::Node) ? a.source_range.begin_pos : a.begin_pos }
|
212
|
+
.each_slice(2)
|
213
|
+
.each_cons(2)
|
152
214
|
end
|
153
215
|
|
154
|
-
def
|
155
|
-
|
156
|
-
method_call = method_call(node)
|
216
|
+
def concat_nodes(nodes, and_node)
|
217
|
+
return nodes if and_node.each_ancestor(:block).any?
|
157
218
|
|
158
|
-
|
159
|
-
|
160
|
-
corrector.insert_before(method_call.loc.dot, '&') unless method_call.safe_navigation?
|
161
|
-
handle_comments(corrector, node, method_call)
|
219
|
+
nodes.concat(and_parts(and_node))
|
220
|
+
end
|
162
221
|
|
163
|
-
|
222
|
+
def and_parts(node)
|
223
|
+
parts = [node.loc.operator]
|
224
|
+
parts << node.rhs unless and_inside_begin?(node.rhs)
|
225
|
+
parts << node.lhs unless node.lhs.and_type? || and_inside_begin?(node.lhs)
|
226
|
+
parts
|
164
227
|
end
|
165
228
|
|
166
|
-
def
|
167
|
-
if
|
229
|
+
def offending_node?(node, lhs_receiver, rhs, rhs_receiver) # rubocop:disable Metrics/CyclomaticComplexity
|
230
|
+
return false if lhs_receiver != rhs_receiver || rhs_receiver.nil?
|
231
|
+
return false if use_var_only_in_unless_modifier?(node, lhs_receiver)
|
232
|
+
return false if chain_length(rhs, rhs_receiver) > max_chain_length
|
233
|
+
return false if unsafe_method_used?(rhs, rhs_receiver.parent)
|
234
|
+
return false if rhs.send_type? && rhs.method?(:empty?)
|
235
|
+
|
236
|
+
true
|
237
|
+
end
|
238
|
+
|
239
|
+
def use_var_only_in_unless_modifier?(node, variable)
|
240
|
+
node.if_type? && node.unless? && !method_called?(variable)
|
241
|
+
end
|
242
|
+
|
243
|
+
def extract_if_body(node)
|
244
|
+
if node.ternary?
|
168
245
|
node.branches.find { |branch| !branch.nil_type? }
|
169
246
|
else
|
170
247
|
node.node_parts[1]
|
@@ -201,20 +278,6 @@ module RuboCop
|
|
201
278
|
node.else? || node.elsif?
|
202
279
|
end
|
203
280
|
|
204
|
-
def method_call(node)
|
205
|
-
_checked_variable, matching_receiver, = extract_parts(node)
|
206
|
-
matching_receiver.parent
|
207
|
-
end
|
208
|
-
|
209
|
-
def extract_parts(node)
|
210
|
-
case node.type
|
211
|
-
when :if
|
212
|
-
extract_parts_from_if(node)
|
213
|
-
when :and
|
214
|
-
extract_parts_from_and(node)
|
215
|
-
end
|
216
|
-
end
|
217
|
-
|
218
281
|
def extract_parts_from_if(node)
|
219
282
|
variable, receiver =
|
220
283
|
if node.ternary?
|
@@ -230,16 +293,6 @@ module RuboCop
|
|
230
293
|
[checked_variable, matching_receiver, receiver, method]
|
231
294
|
end
|
232
295
|
|
233
|
-
def extract_parts_from_and(node)
|
234
|
-
checked_variable, rhs = *node
|
235
|
-
if cop_config['ConvertCodeThatCanStartToReturnNil']
|
236
|
-
checked_variable = not_nil_check?(checked_variable) || checked_variable
|
237
|
-
end
|
238
|
-
|
239
|
-
checked_variable, matching_receiver, method = extract_common_parts(rhs, checked_variable)
|
240
|
-
[checked_variable, matching_receiver, rhs, method]
|
241
|
-
end
|
242
|
-
|
243
296
|
def extract_common_parts(method_chain, checked_variable)
|
244
297
|
matching_receiver = find_matching_receiver_invocation(method_chain, checked_variable)
|
245
298
|
|
@@ -249,7 +302,7 @@ module RuboCop
|
|
249
302
|
end
|
250
303
|
|
251
304
|
def find_matching_receiver_invocation(method_chain, checked_variable)
|
252
|
-
return nil unless method_chain
|
305
|
+
return nil unless method_chain.respond_to?(:receiver)
|
253
306
|
|
254
307
|
receiver = method_chain.receiver
|
255
308
|
|
@@ -259,7 +312,7 @@ module RuboCop
|
|
259
312
|
end
|
260
313
|
|
261
314
|
def chain_length(method_chain, method)
|
262
|
-
method.each_ancestor(:send).inject(
|
315
|
+
method.each_ancestor(:send, :csend).inject(0) do |total, ancestor|
|
263
316
|
break total + 1 if ancestor == method_chain
|
264
317
|
|
265
318
|
total + 1
|
@@ -310,6 +363,7 @@ module RuboCop
|
|
310
363
|
start_method.each_ancestor do |ancestor|
|
311
364
|
break unless %i[send block].include?(ancestor.type)
|
312
365
|
next unless ancestor.send_type?
|
366
|
+
next if ancestor.safe_navigation?
|
313
367
|
|
314
368
|
corrector.insert_before(ancestor.loc.dot, '&')
|
315
369
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Enforces safe navigation chains length to not exceed the configured maximum.
|
7
|
+
# The longer the chain is, the harder it becomes to track what on it could be
|
8
|
+
# returning `nil`.
|
9
|
+
#
|
10
|
+
# There is a potential interplay with `Style/SafeNavigation` - if both are enabled
|
11
|
+
# and their settings are "incompatible", one of the cops will complain about what
|
12
|
+
# the other proposes.
|
13
|
+
#
|
14
|
+
# E.g. if `Style/SafeNavigation` is configured with `MaxChainLength: 2` (default)
|
15
|
+
# and this cop is configured with `Max: 1`, then for `foo.bar.baz if foo` the former
|
16
|
+
# will suggest `foo&.bar&.baz`, which is an offense for the latter.
|
17
|
+
#
|
18
|
+
# @example Max: 2 (default)
|
19
|
+
# # bad
|
20
|
+
# user&.address&.zip&.upcase
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# user&.address&.zip
|
24
|
+
# user.address.zip if user
|
25
|
+
#
|
26
|
+
class SafeNavigationChainLength < Base
|
27
|
+
MSG = 'Avoid safe navigation chains longer than %<max>d calls.'
|
28
|
+
|
29
|
+
def on_csend(node)
|
30
|
+
safe_navigation_chains = safe_navigation_chains(node)
|
31
|
+
return if safe_navigation_chains.size < max
|
32
|
+
|
33
|
+
add_offense(safe_navigation_chains.last, message: format(MSG, max: max))
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def safe_navigation_chains(node)
|
39
|
+
node.each_ancestor.with_object([]) do |parent, chains|
|
40
|
+
break chains unless parent.csend_type?
|
41
|
+
|
42
|
+
chains << parent
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def max
|
47
|
+
cop_config['Max'] || 2
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|