rubocop 1.91.0 → 1.92.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 +4 -1
- data/lib/rubocop/cached_data.rb +47 -7
- data/lib/rubocop/changed_files.rb +35 -13
- data/lib/rubocop/cli/command/cop_names.rb +57 -0
- data/lib/rubocop/cli/command/execute_runner.rb +2 -2
- data/lib/rubocop/cli/command/explain.rb +34 -0
- data/lib/rubocop/cli/command/show_cops.rb +6 -0
- data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
- data/lib/rubocop/cli.rb +3 -2
- data/lib/rubocop/comment_config.rb +17 -8
- data/lib/rubocop/config.rb +0 -4
- data/lib/rubocop/config_loader.rb +6 -3
- data/lib/rubocop/config_loader_resolver.rb +37 -12
- data/lib/rubocop/config_obsoletion/removed_cop.rb +1 -1
- data/lib/rubocop/config_obsoletion.rb +9 -0
- data/lib/rubocop/config_validator.rb +11 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/base.rb +42 -21
- data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
- data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
- data/lib/rubocop/cop/cop_documentation.rb +81 -0
- data/lib/rubocop/cop/cop_explanation.rb +140 -0
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +37 -7
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +25 -4
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
- data/lib/rubocop/cop/documentation.rb +1 -1
- data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
- data/lib/rubocop/cop/layout/argument_alignment.rb +5 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/class_structure.rb +29 -7
- data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/dot_position.rb +25 -15
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +21 -25
- data/lib/rubocop/cop/layout/extra_spacing.rb +21 -6
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +27 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +16 -8
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +16 -12
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +7 -3
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
- data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
- data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/line_length.rb +176 -26
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +9 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +30 -5
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
- data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +6 -11
- data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +31 -4
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +16 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +32 -9
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +29 -11
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
- data/lib/rubocop/cop/lint/interpolation_check.rb +20 -17
- data/lib/rubocop/cop/lint/literal_as_condition.rb +15 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
- data/lib/rubocop/cop/lint/loop.rb +24 -2
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +71 -11
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
- data/lib/rubocop/cop/lint/nested_percent_literal.rb +3 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +3 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +22 -1
- data/lib/rubocop/cop/lint/percent_string_array.rb +75 -9
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +39 -9
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +11 -4
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
- data/lib/rubocop/cop/lint/useless_setter_call.rb +7 -4
- data/lib/rubocop/cop/lint/void.rb +8 -1
- data/lib/rubocop/cop/metrics/class_length.rb +4 -2
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
- data/lib/rubocop/cop/metrics/module_length.rb +4 -2
- data/lib/rubocop/cop/mixin/alignment.rb +4 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +23 -19
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +8 -2
- data/lib/rubocop/cop/mixin/code_length.rb +10 -2
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +41 -6
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +26 -2
- data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +17 -2
- data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +39 -5
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
- data/lib/rubocop/cop/mixin.rb +2 -0
- data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
- data/lib/rubocop/cop/naming/block_forwarding.rb +1 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +59 -3
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/security/json_load.rb +16 -4
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +37 -2
- data/lib/rubocop/cop/style/alias.rb +18 -5
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
- data/lib/rubocop/cop/style/and_or.rb +37 -10
- data/lib/rubocop/cop/style/arguments_forwarding.rb +32 -3
- data/lib/rubocop/cop/style/attr.rb +3 -4
- data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
- data/lib/rubocop/cop/style/block_delimiters.rb +35 -3
- data/lib/rubocop/cop/style/case_equality.rb +14 -3
- data/lib/rubocop/cop/style/case_like_if.rb +6 -3
- data/lib/rubocop/cop/style/class_and_module_children.rb +57 -16
- data/lib/rubocop/cop/style/class_methods_definitions.rb +15 -0
- data/lib/rubocop/cop/style/collection_querying.rb +79 -46
- data/lib/rubocop/cop/style/combinable_loops.rb +89 -11
- data/lib/rubocop/cop/style/concat_array_literals.rb +58 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +65 -9
- data/lib/rubocop/cop/style/double_negation.rb +11 -0
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +3 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
- data/lib/rubocop/cop/style/endless_method.rb +104 -11
- data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
- data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
- data/lib/rubocop/cop/style/float_division.rb +37 -2
- data/lib/rubocop/cop/style/for.rb +53 -2
- data/lib/rubocop/cop/style/format_string.rb +28 -6
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
- data/lib/rubocop/cop/style/guard_clause.rb +31 -22
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
- data/lib/rubocop/cop/style/hash_lookup_method.rb +42 -9
- data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
- data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +32 -26
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
- data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
- data/lib/rubocop/cop/style/lambda.rb +34 -1
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/map_into_array.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +80 -13
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +26 -2
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
- data/lib/rubocop/cop/style/method_def_parentheses.rb +38 -4
- data/lib/rubocop/cop/style/missing_else.rb +7 -1
- data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
- data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
- data/lib/rubocop/cop/style/mutable_constant.rb +52 -7
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
- data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +27 -8
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
- data/lib/rubocop/cop/style/next.rb +24 -10
- data/lib/rubocop/cop/style/nil_comparison.rb +16 -4
- data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
- data/lib/rubocop/cop/style/not.rb +10 -5
- data/lib/rubocop/cop/style/numeric_predicate.rb +28 -5
- data/lib/rubocop/cop/style/one_line_conditional.rb +13 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +19 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
- data/lib/rubocop/cop/style/quoted_symbols.rb +5 -7
- data/lib/rubocop/cop/style/raise_args.rb +80 -11
- data/lib/rubocop/cop/style/reduce_to_hash.rb +47 -33
- data/lib/rubocop/cop/style/redundant_begin.rb +45 -5
- data/lib/rubocop/cop/style/redundant_condition.rb +30 -13
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -0
- data/lib/rubocop/cop/style/redundant_exception.rb +27 -11
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +9 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +12 -1
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +20 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
- data/lib/rubocop/cop/style/redundant_self.rb +9 -1
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
- data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
- data/lib/rubocop/cop/style/require_order.rb +25 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +11 -9
- data/lib/rubocop/cop/style/return_nil.rb +17 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
- data/lib/rubocop/cop/style/sample.rb +9 -8
- data/lib/rubocop/cop/style/self_assignment.rb +12 -15
- data/lib/rubocop/cop/style/semicolon.rb +16 -5
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +42 -4
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
- data/lib/rubocop/cop/style/string_concatenation.rb +21 -4
- data/lib/rubocop/cop/style/struct_inheritance.rb +6 -0
- data/lib/rubocop/cop/style/super_arguments.rb +3 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +24 -6
- data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
- data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
- data/lib/rubocop/cop/team.rb +10 -5
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +14 -1
- data/lib/rubocop/formatter/base_formatter.rb +22 -0
- data/lib/rubocop/formatter/formatter_set.rb +4 -0
- data/lib/rubocop/formatter/json_formatter.rb +71 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
- data/lib/rubocop/formatter/sarif_formatter.rb +12 -7
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
- data/lib/rubocop/lsp/routes.rb +23 -23
- data/lib/rubocop/lsp/runtime.rb +47 -11
- data/lib/rubocop/lsp/stdin_runner.rb +11 -5
- data/lib/rubocop/lsp.rb +5 -2
- data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
- data/lib/rubocop/mcp/explain_tool.rb +68 -0
- data/lib/rubocop/mcp/scope.rb +65 -0
- data/lib/rubocop/mcp/server.rb +184 -76
- data/lib/rubocop/mcp/source_files.rb +35 -0
- data/lib/rubocop/offense_limit.rb +30 -0
- data/lib/rubocop/options.rb +45 -10
- data/lib/rubocop/plugin/configuration_integrator.rb +36 -8
- data/lib/rubocop/remote_config.rb +4 -1
- data/lib/rubocop/result_cache.rb +20 -13
- data/lib/rubocop/runner.rb +110 -42
- data/lib/rubocop/server/cache.rb +6 -6
- data/lib/rubocop/target_ruby.rb +21 -9
- data/lib/rubocop/util.rb +69 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -0
- metadata +16 -5
|
@@ -15,31 +15,24 @@ module RuboCop
|
|
|
15
15
|
# would yield false positives. For example, `String` implements `length`
|
|
16
16
|
# and `size`, but it doesn't include `Enumerable`.
|
|
17
17
|
#
|
|
18
|
+
# When `count` is used without a block, it measures the collection's
|
|
19
|
+
# size, so the offense is corrected to `empty?` or `!empty?`. The
|
|
20
|
+
# predicate methods `any?`, `none?` and `one?` test element truthiness
|
|
21
|
+
# instead and would return different results for collections with falsey
|
|
22
|
+
# elements (e.g. `[false].count.zero?` is `false`, but `[false].none?`
|
|
23
|
+
# is `true`). For the same reason, `count == 1` and `count > 1` without
|
|
24
|
+
# a block are not flagged.
|
|
25
|
+
#
|
|
18
26
|
# @safety
|
|
19
27
|
# The cop is unsafe because receiver might not include `Enumerable`, or
|
|
20
28
|
# it has nonstandard implementation of `count` or any replacement
|
|
21
29
|
# methods.
|
|
22
30
|
#
|
|
23
|
-
#
|
|
24
|
-
#
|
|
25
|
-
# `
|
|
26
|
-
#
|
|
27
|
-
#
|
|
28
|
-
# ----
|
|
29
|
-
# [nil, false].count.positive?
|
|
30
|
-
# [nil].count == 1
|
|
31
|
-
# # => true
|
|
32
|
-
#
|
|
33
|
-
# [nil, false].any?
|
|
34
|
-
# [nil].one?
|
|
35
|
-
# # => false
|
|
36
|
-
#
|
|
37
|
-
# [nil].count == 0
|
|
38
|
-
# # => false
|
|
39
|
-
#
|
|
40
|
-
# [nil].none?
|
|
41
|
-
# # => true
|
|
42
|
-
# ----
|
|
31
|
+
# Blockless `count` is corrected to `empty?`, which `Enumerable` doesn't
|
|
32
|
+
# define. `Range`, `Enumerator` (including lazy ones), `Struct`, `StringIO`
|
|
33
|
+
# and any class that just includes `Enumerable` respond to `count` but not
|
|
34
|
+
# to `empty?`, so `(1...1).count.zero?` is `true` while `(1...1).empty?`
|
|
35
|
+
# raises `NoMethodError`.
|
|
43
36
|
#
|
|
44
37
|
# Autocorrection is unsafe when replacement methods don't iterate over
|
|
45
38
|
# every element in collection and the given block runs side effects:
|
|
@@ -60,12 +53,14 @@ module RuboCop
|
|
|
60
53
|
# x.count > 0
|
|
61
54
|
# x.count != 0
|
|
62
55
|
#
|
|
56
|
+
# # good
|
|
57
|
+
# !x.empty?
|
|
58
|
+
#
|
|
59
|
+
# # bad
|
|
63
60
|
# x.count(&:foo?).positive?
|
|
64
61
|
# x.count { |item| item.foo? }.positive?
|
|
65
62
|
#
|
|
66
63
|
# # good
|
|
67
|
-
# x.any?
|
|
68
|
-
#
|
|
69
64
|
# x.any?(&:foo?)
|
|
70
65
|
# x.any? { |item| item.foo? }
|
|
71
66
|
#
|
|
@@ -74,24 +69,33 @@ module RuboCop
|
|
|
74
69
|
# x.count == 0
|
|
75
70
|
#
|
|
76
71
|
# # good
|
|
77
|
-
# x.
|
|
72
|
+
# x.empty?
|
|
78
73
|
#
|
|
79
74
|
# # bad
|
|
80
|
-
# x.count
|
|
81
|
-
# x.
|
|
75
|
+
# x.count(&:foo?).zero?
|
|
76
|
+
# x.count(&:foo?) == 0
|
|
77
|
+
#
|
|
78
|
+
# # good
|
|
79
|
+
# x.none?(&:foo?)
|
|
80
|
+
#
|
|
81
|
+
# # bad
|
|
82
|
+
# x.count(&:foo?) == 1
|
|
83
|
+
#
|
|
84
|
+
# # good
|
|
85
|
+
# x.one?(&:foo?)
|
|
82
86
|
#
|
|
83
87
|
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
|
84
88
|
#
|
|
85
89
|
# # good
|
|
86
|
-
# x.count > 1
|
|
90
|
+
# x.count(&:foo?) > 1
|
|
87
91
|
#
|
|
88
92
|
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
|
89
93
|
#
|
|
90
94
|
# # bad
|
|
91
|
-
# x.count > 1
|
|
95
|
+
# x.count(&:foo?) > 1
|
|
92
96
|
#
|
|
93
97
|
# # good
|
|
94
|
-
# x.many?
|
|
98
|
+
# x.many?(&:foo?)
|
|
95
99
|
#
|
|
96
100
|
class CollectionQuerying < Base
|
|
97
101
|
include RangeHelp
|
|
@@ -102,13 +106,21 @@ module RuboCop
|
|
|
102
106
|
RESTRICT_ON_SEND = %i[positive? > != zero? ==].freeze
|
|
103
107
|
|
|
104
108
|
REPLACEMENTS = {
|
|
105
|
-
[:positive?, nil] =>
|
|
106
|
-
[:>, 0] =>
|
|
107
|
-
[:!=, 0] =>
|
|
108
|
-
[:zero?, nil] =>
|
|
109
|
-
[:==, 0] =>
|
|
110
|
-
[:==, 1] =>
|
|
111
|
-
[:>, 1] =>
|
|
109
|
+
[:positive?, nil] => 'any?',
|
|
110
|
+
[:>, 0] => 'any?',
|
|
111
|
+
[:!=, 0] => 'any?',
|
|
112
|
+
[:zero?, nil] => 'none?',
|
|
113
|
+
[:==, 0] => 'none?',
|
|
114
|
+
[:==, 1] => 'one?',
|
|
115
|
+
[:>, 1] => 'many?'
|
|
116
|
+
}.freeze
|
|
117
|
+
|
|
118
|
+
NO_BLOCK_REPLACEMENTS = {
|
|
119
|
+
[:positive?, nil] => '!empty?',
|
|
120
|
+
[:>, 0] => '!empty?',
|
|
121
|
+
[:!=, 0] => '!empty?',
|
|
122
|
+
[:zero?, nil] => 'empty?',
|
|
123
|
+
[:==, 0] => 'empty?'
|
|
112
124
|
}.freeze
|
|
113
125
|
|
|
114
126
|
# @!method count_predicate(node)
|
|
@@ -132,28 +144,49 @@ module RuboCop
|
|
|
132
144
|
def on_send(node)
|
|
133
145
|
return unless (count_node = count_predicate(node))
|
|
134
146
|
|
|
135
|
-
|
|
147
|
+
replacement = replacement_method(node, count_node)
|
|
136
148
|
|
|
137
|
-
return unless replacement_supported?(
|
|
149
|
+
return unless replacement_supported?(node, replacement)
|
|
138
150
|
|
|
139
151
|
offense_range = count_node.loc.selector.join(node.source_range.end)
|
|
140
|
-
add_offense(offense_range,
|
|
141
|
-
|
|
142
|
-
corrector.replace(count_node.loc.selector, replacement_method)
|
|
143
|
-
corrector.remove(removal_range(node))
|
|
152
|
+
add_offense(offense_range, message: format(MSG, prefer: replacement)) do |corrector|
|
|
153
|
+
autocorrect(corrector, node, count_node, replacement)
|
|
144
154
|
end
|
|
145
155
|
end
|
|
146
156
|
|
|
147
157
|
private
|
|
148
158
|
|
|
149
|
-
def replacement_method(node)
|
|
150
|
-
|
|
159
|
+
def replacement_method(node, count_node)
|
|
160
|
+
key = [node.method_name, node.first_argument&.value]
|
|
161
|
+
return REPLACEMENTS.fetch(key) if block_given_to_count?(count_node)
|
|
162
|
+
|
|
163
|
+
NO_BLOCK_REPLACEMENTS[key]
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def block_given_to_count?(count_node)
|
|
167
|
+
count_node.parent&.any_block_type? || count_node.last_argument&.block_pass_type?
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def replacement_supported?(node, replacement)
|
|
171
|
+
return false unless replacement
|
|
172
|
+
return false if replacement == 'many?' && !active_support_extensions_enabled?
|
|
173
|
+
|
|
174
|
+
!(replacement.start_with?('!') && receiver_of_call?(node))
|
|
151
175
|
end
|
|
152
176
|
|
|
153
|
-
def
|
|
154
|
-
|
|
177
|
+
def receiver_of_call?(node)
|
|
178
|
+
node.parent&.call_type? && node.parent.receiver == node && node.parent.loc.dot
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def autocorrect(corrector, node, count_node, replacement)
|
|
182
|
+
if replacement.start_with?('!')
|
|
183
|
+
corrector.insert_before(count_node, '!')
|
|
184
|
+
corrector.replace(count_node.loc.selector, 'empty?')
|
|
185
|
+
else
|
|
186
|
+
corrector.replace(count_node.loc.selector, replacement)
|
|
187
|
+
end
|
|
155
188
|
|
|
156
|
-
|
|
189
|
+
corrector.remove(removal_range(node))
|
|
157
190
|
end
|
|
158
191
|
|
|
159
192
|
def removal_range(node)
|
|
@@ -60,19 +60,22 @@ module RuboCop
|
|
|
60
60
|
# end
|
|
61
61
|
#
|
|
62
62
|
class CombinableLoops < Base
|
|
63
|
+
include RangeHelp
|
|
63
64
|
extend AutoCorrector
|
|
64
65
|
|
|
65
66
|
MSG = 'Combine this loop with the previous loop.'
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
def self.autocorrect_incompatible_with
|
|
69
|
+
[Layout::BlockEndNewline, Layout::RedundantLineBreak]
|
|
70
|
+
end
|
|
71
|
+
|
|
68
72
|
def on_block(node)
|
|
69
73
|
return unless node.parent&.begin_type?
|
|
70
74
|
return unless collection_looping_method?(node)
|
|
71
|
-
return unless
|
|
72
|
-
return unless node.body && node.left_sibling.body
|
|
75
|
+
return unless combinable_looping_blocks?(node, node.left_sibling)
|
|
73
76
|
|
|
74
77
|
add_offense(node) do |corrector|
|
|
75
|
-
next unless node
|
|
78
|
+
next unless combinable_blocks?(node, node.left_sibling)
|
|
76
79
|
|
|
77
80
|
combine_with_left_sibling(corrector, node)
|
|
78
81
|
end
|
|
@@ -87,9 +90,7 @@ module RuboCop
|
|
|
87
90
|
return unless node.body && node.left_sibling.body
|
|
88
91
|
|
|
89
92
|
add_offense(node) do |corrector|
|
|
90
|
-
|
|
91
|
-
# body referencing an undefined variable, so only autocorrect when they match.
|
|
92
|
-
next unless node.variable == node.left_sibling.variable
|
|
93
|
+
next unless combinable_fors?(node, node.left_sibling)
|
|
93
94
|
|
|
94
95
|
combine_with_left_sibling(corrector, node)
|
|
95
96
|
end
|
|
@@ -110,25 +111,102 @@ module RuboCop
|
|
|
110
111
|
sibling.send_node.arguments == node.send_node.arguments
|
|
111
112
|
end
|
|
112
113
|
|
|
114
|
+
def combinable_looping_blocks?(node, sibling)
|
|
115
|
+
same_collection_looping_block?(node, sibling) && node.body && sibling.body
|
|
116
|
+
end
|
|
117
|
+
|
|
113
118
|
def same_collection_looping_for?(node, sibling)
|
|
114
119
|
sibling&.for_type? && node.collection == sibling.collection
|
|
115
120
|
end
|
|
116
121
|
|
|
122
|
+
def combinable_blocks?(node, sibling)
|
|
123
|
+
return false unless node.arguments == sibling.arguments
|
|
124
|
+
# Numbered and `it` parameters are implicit, so `arguments` is empty for both.
|
|
125
|
+
return false unless node.argument_list == sibling.argument_list
|
|
126
|
+
return false if directive_after_opening?(node)
|
|
127
|
+
|
|
128
|
+
!node.body.type?(:rescue, :ensure) && !sibling.body.type?(:rescue, :ensure)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Combining loops with different iteration variables would leave the second
|
|
132
|
+
# body referencing an undefined variable, so only autocorrect when they match.
|
|
133
|
+
def combinable_fors?(node, sibling)
|
|
134
|
+
node.variable == sibling.variable && !directive_after_opening?(node)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# The opening is removed, so a directive after it would end up on a line of
|
|
138
|
+
# its own, where it covers the rest of the file instead of a single line.
|
|
139
|
+
def directive_after_opening?(node)
|
|
140
|
+
opening_line = loop_opening(node).line
|
|
141
|
+
return false if opening_line == node.body.first_line
|
|
142
|
+
|
|
143
|
+
comment = processed_source.comment_at_line(opening_line)
|
|
144
|
+
comment && DirectiveComment.new(comment).start_with_marker?
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# The block arguments or `{`/`do` of a block, or the `do` or collection of a `for` loop.
|
|
148
|
+
def loop_opening(node)
|
|
149
|
+
if node.for_type?
|
|
150
|
+
node.loc.begin || node.collection.source_range
|
|
151
|
+
else
|
|
152
|
+
(node.block_type? && node.arguments.source_range) || node.loc.begin
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
117
156
|
def combine_with_left_sibling(corrector, node)
|
|
118
|
-
corrector.remove(node.left_sibling
|
|
119
|
-
corrector.remove(
|
|
157
|
+
corrector.remove(closing_with_preceding_space(node.left_sibling, node))
|
|
158
|
+
corrector.remove(opening_with_following_space(node))
|
|
120
159
|
|
|
121
160
|
correct_end_of_block(corrector, node)
|
|
122
161
|
end
|
|
123
162
|
|
|
163
|
+
# Comments and heredoc bodies before the closing delimiter are kept. When
|
|
164
|
+
# the next loop starts on the delimiter's line, the line break before the
|
|
165
|
+
# delimiter is kept too, so that a comment doesn't swallow the next loop.
|
|
166
|
+
def closing_with_preceding_space(loop, next_loop)
|
|
167
|
+
separate_lines = !same_line?(loop.loc.end, next_loop)
|
|
168
|
+
|
|
169
|
+
range_with_surrounding_space(
|
|
170
|
+
loop.loc.end, side: :left, newlines: separate_lines, whitespace: separate_lines
|
|
171
|
+
)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Comments between the opening and the body are kept.
|
|
175
|
+
def opening_with_following_space(node)
|
|
176
|
+
opening = node.source_range.begin.join(loop_opening(node))
|
|
177
|
+
|
|
178
|
+
range_with_surrounding_space(opening, side: :right, whitespace: true)
|
|
179
|
+
end
|
|
180
|
+
|
|
124
181
|
def correct_end_of_block(corrector, node)
|
|
125
182
|
return unless node.left_sibling.respond_to?(:braces?)
|
|
126
|
-
return if node
|
|
183
|
+
return if combined_with_right_sibling?(node)
|
|
127
184
|
|
|
128
|
-
end_of_block = node.
|
|
185
|
+
end_of_block = first_combined_block(node).braces? ? '}' : ' end'
|
|
129
186
|
corrector.remove(node.loc.end)
|
|
130
187
|
corrector.insert_before(node.source_range.end, end_of_block)
|
|
131
188
|
end
|
|
189
|
+
|
|
190
|
+
def combined_with_right_sibling?(node)
|
|
191
|
+
sibling = node.right_sibling
|
|
192
|
+
return false unless sibling&.any_block_type?
|
|
193
|
+
# A disabled loop isn't corrected, so it doesn't get merged into this one.
|
|
194
|
+
return false unless enabled_lines?(sibling.source_range)
|
|
195
|
+
|
|
196
|
+
same_collection_looping_block?(sibling, node) && sibling.body &&
|
|
197
|
+
combinable_blocks?(sibling, node)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def first_combined_block(node)
|
|
201
|
+
first = node.left_sibling
|
|
202
|
+
|
|
203
|
+
while (previous = first.left_sibling) && enabled_lines?(first.source_range) &&
|
|
204
|
+
combinable_looping_blocks?(first, previous) && combinable_blocks?(first, previous)
|
|
205
|
+
first = previous
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
first
|
|
209
|
+
end
|
|
132
210
|
end
|
|
133
211
|
end
|
|
134
212
|
end
|
|
@@ -23,6 +23,7 @@ module RuboCop
|
|
|
23
23
|
# list.push(qux, quux, corge)
|
|
24
24
|
#
|
|
25
25
|
class ConcatArrayLiterals < Base
|
|
26
|
+
include RangeHelp
|
|
26
27
|
extend AutoCorrector
|
|
27
28
|
|
|
28
29
|
MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
|
|
@@ -30,6 +31,14 @@ module RuboCop
|
|
|
30
31
|
'Use `push` with elements as arguments without array brackets instead of `%<current>s`.'
|
|
31
32
|
RESTRICT_ON_SEND = %i[concat].freeze
|
|
32
33
|
|
|
34
|
+
# `Style/MethodCallWithArgsParentheses` removing the parentheses of the `push(...)`
|
|
35
|
+
# this cop writes in the same pass drops the line continuation a multiline call needs.
|
|
36
|
+
# `Style/TrailingCommaInArguments` adds a comma after the array literal this cop
|
|
37
|
+
# replaces with its elements in the same pass.
|
|
38
|
+
def self.autocorrect_incompatible_with
|
|
39
|
+
[Style::MethodCallWithArgsParentheses, Style::TrailingCommaInArguments]
|
|
40
|
+
end
|
|
41
|
+
|
|
33
42
|
# rubocop:disable-next Metrics
|
|
34
43
|
def on_send(node)
|
|
35
44
|
return if node.arguments.empty?
|
|
@@ -54,17 +63,13 @@ module RuboCop
|
|
|
54
63
|
if use_percent_literal
|
|
55
64
|
next unless prefer
|
|
56
65
|
|
|
57
|
-
corrector
|
|
66
|
+
rebuild_call(corrector, offense, prefer)
|
|
58
67
|
elsif node.arguments.any? { |argument| argument.children.empty? }
|
|
59
68
|
# In-place bracket removal would leave dangling commas (e.g.
|
|
60
69
|
# `concat([], [b])` -> `push(, b)`), so rebuild the call instead.
|
|
61
|
-
corrector
|
|
70
|
+
rebuild_call(corrector, offense, preferred_method(node))
|
|
62
71
|
else
|
|
63
|
-
corrector
|
|
64
|
-
node.arguments.each do |argument|
|
|
65
|
-
corrector.remove(argument.loc.begin)
|
|
66
|
-
corrector.remove(argument.loc.end)
|
|
67
|
-
end
|
|
72
|
+
remove_brackets(corrector, node)
|
|
68
73
|
end
|
|
69
74
|
end
|
|
70
75
|
end
|
|
@@ -94,6 +99,52 @@ module RuboCop
|
|
|
94
99
|
arg.children.all? { |child| child.type?(:str, :sym) }
|
|
95
100
|
end
|
|
96
101
|
end
|
|
102
|
+
|
|
103
|
+
def rebuild_call(corrector, offense, replacement)
|
|
104
|
+
# The comments inside the call would be lost.
|
|
105
|
+
return if comment_in?(offense)
|
|
106
|
+
|
|
107
|
+
corrector.replace(offense, replacement)
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def comment_in?(range)
|
|
111
|
+
processed_source.each_comment_in_lines(range.line..range.last_line).any? do |comment|
|
|
112
|
+
range.contains?(comment.source_range)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def remove_brackets(corrector, node)
|
|
117
|
+
closing_ranges = node.arguments.map { |argument| closing_bracket_range(node, argument) }
|
|
118
|
+
# A comment or a heredoc body there can't be moved out of the way.
|
|
119
|
+
return unless closing_ranges.all? { |range| range.source.match?(/\A[\s,]*\]\z/) }
|
|
120
|
+
|
|
121
|
+
replace_selector(corrector, node)
|
|
122
|
+
|
|
123
|
+
node.arguments.zip(closing_ranges) do |argument, closing_range|
|
|
124
|
+
corrector.remove(argument.loc.begin)
|
|
125
|
+
corrector.remove(closing_range)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# Whatever sits between the last element and the `]` of an array that isn't the
|
|
130
|
+
# last argument would end up before the following comma (a newline before it is a
|
|
131
|
+
# syntax error), so it's removed along with the `]`.
|
|
132
|
+
def closing_bracket_range(node, argument)
|
|
133
|
+
return argument.loc.end if argument.equal?(node.last_argument)
|
|
134
|
+
|
|
135
|
+
range_between(argument.children.last.source_range.end_pos, argument.loc.end.end_pos)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def replace_selector(corrector, node)
|
|
139
|
+
if node.parenthesized? || node.single_line?
|
|
140
|
+
corrector.replace(node.loc.selector, 'push')
|
|
141
|
+
else
|
|
142
|
+
range = node.loc.selector.join(node.first_argument.source_range.begin)
|
|
143
|
+
|
|
144
|
+
corrector.replace(range, 'push(')
|
|
145
|
+
corrector.insert_after(node.last_argument.loc.end, ')')
|
|
146
|
+
end
|
|
147
|
+
end
|
|
97
148
|
end
|
|
98
149
|
end
|
|
99
150
|
end
|
|
@@ -223,6 +223,10 @@ module RuboCop
|
|
|
223
223
|
}
|
|
224
224
|
PATTERN
|
|
225
225
|
|
|
226
|
+
def self.autocorrect_incompatible_with
|
|
227
|
+
[Style::MethodCallWithArgsParentheses]
|
|
228
|
+
end
|
|
229
|
+
|
|
226
230
|
ASSIGNMENT_TYPES.each do |type|
|
|
227
231
|
define_method :"on_#{type}" do |node|
|
|
228
232
|
return if part_of_ignored_node?(node)
|
|
@@ -33,7 +33,8 @@ module RuboCop
|
|
|
33
33
|
# a `--` trailing justification comment is allowed, so a team can require
|
|
34
34
|
# every disable to be documented instead of banning them outright. Enable
|
|
35
35
|
# directives are not checked in this mode, since they end a suppression
|
|
36
|
-
# rather than start one.
|
|
36
|
+
# rather than start one. Offenses in this mode are not autocorrected,
|
|
37
|
+
# since only a human can supply the missing justification.
|
|
37
38
|
#
|
|
38
39
|
# This cop cannot be disabled via directive comments when it is explicitly
|
|
39
40
|
# enabled with `Enabled: true`. This prevents users from bypassing the cop
|
|
@@ -99,6 +100,8 @@ module RuboCop
|
|
|
99
100
|
'comment are not permitted.'
|
|
100
101
|
|
|
101
102
|
def on_new_investigation
|
|
103
|
+
@matching_pops = nil
|
|
104
|
+
|
|
102
105
|
processed_source.comments.each do |comment|
|
|
103
106
|
directive = DirectiveComment.new(comment)
|
|
104
107
|
next if ignored?(directive)
|
|
@@ -108,7 +111,7 @@ module RuboCop
|
|
|
108
111
|
|
|
109
112
|
next unless disallowed_cops.any?
|
|
110
113
|
|
|
111
|
-
register_offense(
|
|
114
|
+
register_offense(directive, directive_cops, disallowed_cops)
|
|
112
115
|
end
|
|
113
116
|
end
|
|
114
117
|
|
|
@@ -126,19 +129,61 @@ module RuboCop
|
|
|
126
129
|
end
|
|
127
130
|
end
|
|
128
131
|
|
|
129
|
-
def register_offense(
|
|
130
|
-
|
|
131
|
-
replacement = ''
|
|
132
|
+
def register_offense(directive, directive_cops, disallowed_cops)
|
|
133
|
+
comment = directive.comment
|
|
132
134
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
add_offense(comment, message: offense_message(disallowed_cops)) do |corrector|
|
|
136
|
+
# The remedy in `AllowWithReason` mode is to write the missing `--` justification,
|
|
137
|
+
# which cannot be autocorrected. Removing the directive would also unsuppress
|
|
138
|
+
# the disabled cops and let their autocorrections rewrite the annotated code.
|
|
139
|
+
next if allow_with_reason?
|
|
140
|
+
|
|
141
|
+
if directive_cops.length == disallowed_cops.length
|
|
142
|
+
remove_directive(corrector, directive)
|
|
143
|
+
elsif signed_args?(directive)
|
|
144
|
+
remove_signed_args(corrector, directive, disallowed_cops)
|
|
145
|
+
else
|
|
146
|
+
remove_cops(corrector, comment, disallowed_cops)
|
|
136
147
|
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# A `push` without its `pop` leaves an orphan `pop` behind, so the pair goes together.
|
|
152
|
+
def remove_directive(corrector, directive)
|
|
153
|
+
corrector.replace(directive.comment, '')
|
|
154
|
+
return unless directive.push? && (pop = matching_pop(directive.comment))
|
|
155
|
+
|
|
156
|
+
corrector.replace(pop, '')
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def matching_pop(push_comment)
|
|
160
|
+
@matching_pops ||= pair_pushes_with_pops
|
|
161
|
+
@matching_pops[push_comment]
|
|
162
|
+
end
|
|
137
163
|
|
|
138
|
-
|
|
164
|
+
def pair_pushes_with_pops
|
|
165
|
+
pushes = []
|
|
166
|
+
processed_source.comments.each_with_object({}) do |comment, pairs|
|
|
167
|
+
directive = DirectiveComment.new(comment)
|
|
168
|
+
if directive.push?
|
|
169
|
+
pushes.push(comment)
|
|
170
|
+
elsif directive.pop? && (push = pushes.pop)
|
|
171
|
+
pairs[push] = comment
|
|
172
|
+
end
|
|
139
173
|
end
|
|
140
174
|
end
|
|
141
175
|
|
|
176
|
+
def remove_signed_args(corrector, directive, disallowed_cops)
|
|
177
|
+
range = directive.range
|
|
178
|
+
names = Regexp.union(disallowed_cops)
|
|
179
|
+
corrector.replace(range, range.source.gsub(/\s+[+-]#{names}(?!\S)/, ''))
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def remove_cops(corrector, comment, disallowed_cops)
|
|
183
|
+
corrector.replace(comment, comment.text.sub(/#{Regexp.union(disallowed_cops)},?\s*/, '')
|
|
184
|
+
.sub(/,\s*$/, ''))
|
|
185
|
+
end
|
|
186
|
+
|
|
142
187
|
def offense_message(disallowed_cops)
|
|
143
188
|
if allow_with_reason?
|
|
144
189
|
MSG_MISSING_REASON
|
|
@@ -150,10 +195,16 @@ module RuboCop
|
|
|
150
195
|
end
|
|
151
196
|
|
|
152
197
|
def directive_cops(directive)
|
|
198
|
+
return directive.signed_args.values.flatten if signed_args?(directive)
|
|
199
|
+
|
|
153
200
|
match_captures = directive.match_captures
|
|
154
201
|
match_captures && match_captures[1] ? match_captures[1].split(',').map(&:strip) : []
|
|
155
202
|
end
|
|
156
203
|
|
|
204
|
+
def signed_args?(directive)
|
|
205
|
+
directive.push? || directive.next?
|
|
206
|
+
end
|
|
207
|
+
|
|
157
208
|
def ignored?(directive)
|
|
158
209
|
return true if exempt_mode?(directive)
|
|
159
210
|
|
|
@@ -169,6 +220,11 @@ module RuboCop
|
|
|
169
220
|
end
|
|
170
221
|
|
|
171
222
|
def allow_with_reason?
|
|
223
|
+
# TODO: The obsolete `AllowTrailingComment` is honored for backward compatibility
|
|
224
|
+
# and will be removed in RuboCop 2.0.
|
|
225
|
+
allow_trailing_comment = cop_config['AllowTrailingComment'] # rubocop:disable InternalAffairs/UndefinedConfig -- obsolete key, gone from default.yml on purpose
|
|
226
|
+
return allow_trailing_comment unless allow_trailing_comment.nil?
|
|
227
|
+
|
|
172
228
|
cop_config['AllowWithReason']
|
|
173
229
|
end
|
|
174
230
|
|
|
@@ -70,6 +70,7 @@ module RuboCop
|
|
|
70
70
|
|
|
71
71
|
def on_send(node)
|
|
72
72
|
return unless double_negative?(node) && node.prefix_bang?
|
|
73
|
+
return if part_of_longer_negation?(node)
|
|
73
74
|
return if style == :allowed_in_returns && allowed_in_returns?(node)
|
|
74
75
|
|
|
75
76
|
location = node.loc.selector
|
|
@@ -81,10 +82,20 @@ module RuboCop
|
|
|
81
82
|
|
|
82
83
|
private
|
|
83
84
|
|
|
85
|
+
def part_of_longer_negation?(node)
|
|
86
|
+
return true if negation?(node.parent) && node.parent.receiver.equal?(node)
|
|
87
|
+
|
|
88
|
+
negation?(node.receiver.receiver)
|
|
89
|
+
end
|
|
90
|
+
|
|
84
91
|
def allowed_in_returns?(node)
|
|
85
92
|
node.parent&.return_type? || end_of_method_definition?(node)
|
|
86
93
|
end
|
|
87
94
|
|
|
95
|
+
def negation?(node)
|
|
96
|
+
node&.send_type? && node.method?(:!)
|
|
97
|
+
end
|
|
98
|
+
|
|
88
99
|
def end_of_method_definition?(node)
|
|
89
100
|
return false unless (def_node = find_def_node_from_ascendant(node))
|
|
90
101
|
|
|
@@ -103,7 +103,7 @@ module RuboCop
|
|
|
103
103
|
end
|
|
104
104
|
|
|
105
105
|
def replacement_range(node)
|
|
106
|
-
if
|
|
106
|
+
if offense_hash_node?(node) && first_argument_unparenthesized?(node)
|
|
107
107
|
# `some_method {}` is not same as `some_method Hash.new`
|
|
108
108
|
# because the braces are interpreted as a block. We will have
|
|
109
109
|
# to rewrite the arguments to wrap them in parenthesis.
|
|
@@ -102,8 +102,10 @@ module RuboCop
|
|
|
102
102
|
compact_style? ? '; ' : "\n#{indent}"
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
+
# A method with an argument spanning multiple lines (e.g. a hash default
|
|
106
|
+
# value) can't be put on a single line, so it's as compact as it gets.
|
|
105
107
|
def compact?(node)
|
|
106
|
-
node.single_line?
|
|
108
|
+
node.single_line? || node.arguments.any?(&:multiline?)
|
|
107
109
|
end
|
|
108
110
|
|
|
109
111
|
def expanded?(node)
|