rubocop 1.71.1 → 1.92.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +23 -19
- data/config/default.yml +886 -168
- data/config/internal_affairs.yml +20 -0
- data/config/obsoletion.yml +47 -4
- data/exe/rubocop +2 -9
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cached_data.rb +50 -5
- data/lib/rubocop/changed_files.rb +134 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +36 -4
- data/lib/rubocop/cli/command/cop_names.rb +57 -0
- data/lib/rubocop/cli/command/execute_runner.rb +54 -3
- data/lib/rubocop/cli/command/explain.rb +34 -0
- data/lib/rubocop/cli/command/list_enabled_cops_for.rb +40 -0
- data/lib/rubocop/cli/command/lsp.rb +1 -1
- data/lib/rubocop/cli/command/mcp.rb +19 -0
- data/lib/rubocop/cli/command/show_cops.rb +8 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +8 -10
- data/lib/rubocop/cli/command/suggest_extensions.rb +8 -2
- data/lib/rubocop/cli.rb +59 -17
- data/lib/rubocop/comment_config/directive_range.rb +34 -0
- data/lib/rubocop/comment_config/disable_next.rb +143 -0
- data/lib/rubocop/comment_config/push_pop.rb +55 -0
- data/lib/rubocop/comment_config.rb +98 -45
- data/lib/rubocop/config.rb +137 -19
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +75 -49
- data/lib/rubocop/config_loader_resolver.rb +124 -33
- data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +6 -3
- data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
- data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
- data/lib/rubocop/config_obsoletion.rb +47 -3
- data/lib/rubocop/config_store.rb +7 -2
- data/lib/rubocop/config_validator.rb +75 -12
- data/lib/rubocop/cop/autocorrect_logic.rb +43 -17
- data/lib/rubocop/cop/badge.rb +10 -2
- data/lib/rubocop/cop/base.rb +128 -35
- data/lib/rubocop/cop/bundler/gem_comment.rb +5 -4
- data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
- data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -11
- data/lib/rubocop/cop/bundler.rb +19 -0
- data/lib/rubocop/cop/commissioner.rb +13 -11
- data/lib/rubocop/cop/cop_documentation.rb +81 -0
- data/lib/rubocop/cop/cop_explanation.rb +140 -0
- data/lib/rubocop/cop/corrector.rb +4 -4
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +92 -11
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -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/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +31 -4
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +35 -5
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +73 -2
- data/lib/rubocop/cop/correctors/percent_literal_corrector.rb +2 -2
- data/lib/rubocop/cop/correctors.rb +28 -0
- data/lib/rubocop/cop/documentation.rb +3 -4
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +49 -17
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +2 -9
- data/lib/rubocop/cop/gemspec/require_mfa.rb +22 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
- data/lib/rubocop/cop/gemspec.rb +22 -0
- data/lib/rubocop/cop/generator/registration_injector.rb +188 -0
- data/lib/rubocop/cop/generator.rb +5 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
- data/lib/rubocop/cop/internal_affairs/example_heredoc_delimiter.rb +8 -8
- data/lib/rubocop/cop/internal_affairs/itblock_handler.rb +69 -0
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +142 -0
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +16 -20
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_walker.rb +1 -2
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +85 -0
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +2 -2
- data/lib/rubocop/cop/internal_affairs/plugin.rb +33 -0
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +13 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/internal_affairs.rb +3 -16
- data/lib/rubocop/cop/layout/argument_alignment.rb +9 -3
- data/lib/rubocop/cop/layout/array_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/begin_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +86 -4
- data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +28 -10
- data/lib/rubocop/cop/layout/class_structure.rb +191 -41
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
- data/lib/rubocop/cop/layout/comment_indentation.rb +17 -7
- data/lib/rubocop/cop/layout/condition_position.rb +13 -3
- data/lib/rubocop/cop/layout/def_end_alignment.rb +5 -1
- data/lib/rubocop/cop/layout/dot_position.rb +27 -17
- data/lib/rubocop/cop/layout/else_alignment.rb +3 -15
- data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +27 -9
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +63 -5
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +46 -21
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +22 -5
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +17 -3
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- data/lib/rubocop/cop/layout/empty_lines_around_method_body.rb +22 -2
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +23 -15
- data/lib/rubocop/cop/layout/extra_spacing.rb +109 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +82 -3
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +41 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +36 -23
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
- 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/first_parameter_indentation.rb +11 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +20 -18
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +9 -5
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +48 -3
- data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
- data/lib/rubocop/cop/layout/indentation_style.rb +5 -2
- data/lib/rubocop/cop/layout/indentation_width.rb +159 -12
- data/lib/rubocop/cop/layout/leading_comment_space.rb +40 -1
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +10 -4
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/line_length.rb +300 -31
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +69 -57
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +11 -1
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +65 -56
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +7 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +270 -40
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +111 -7
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +29 -9
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
- data/lib/rubocop/cop/layout/space_around_keyword.rb +20 -3
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +30 -4
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +5 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -39
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +55 -36
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +32 -8
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/layout.rb +114 -0
- data/lib/rubocop/cop/lazy_loader.rb +41 -0
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +9 -17
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +72 -1
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +3 -11
- data/lib/rubocop/cop/lint/ambiguous_range.rb +6 -2
- data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +6 -1
- data/lib/rubocop/cop/lint/argument_mismatch.rb +99 -0
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +15 -1
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -8
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +94 -15
- data/lib/rubocop/cop/lint/constant_resolution.rb +31 -6
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +240 -0
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/debugger.rb +13 -4
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
- data/lib/rubocop/cop/lint/deprecated_reference.rb +194 -0
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/duplicate_methods.rb +506 -41
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
- data/lib/rubocop/cop/lint/else_layout.rb +19 -0
- data/lib/rubocop/cop/lint/empty_block.rb +4 -4
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +22 -65
- data/lib/rubocop/cop/lint/empty_expression.rb +0 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
- data/lib/rubocop/cop/lint/empty_when.rb +8 -1
- data/lib/rubocop/cop/lint/ensure_return.rb +19 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +4 -8
- data/lib/rubocop/cop/lint/float_comparison.rb +33 -10
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +1 -2
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -1
- data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +1 -2
- data/lib/rubocop/cop/lint/inherit_exception.rb +53 -7
- data/lib/rubocop/cop/lint/interpolation_check.rb +25 -6
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +152 -11
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +75 -37
- data/lib/rubocop/cop/lint/loop.rb +24 -2
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +60 -23
- data/lib/rubocop/cop/lint/missing_super.rb +31 -1
- data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
- data/lib/rubocop/cop/lint/multiple_comparison.rb +2 -2
- data/lib/rubocop/cop/lint/name_typo.rb +270 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +2 -0
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +20 -0
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +4 -2
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +4 -4
- data/lib/rubocop/cop/lint/number_conversion.rb +22 -11
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +1 -1
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +11 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +15 -4
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +20 -14
- data/lib/rubocop/cop/lint/raise_exception.rb +30 -11
- data/lib/rubocop/cop/lint/rand_one.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +160 -39
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +28 -6
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +5 -25
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +134 -12
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +267 -0
- data/lib/rubocop/cop/lint/redundant_with_index.rb +5 -3
- data/lib/rubocop/cop/lint/redundant_with_object.rb +8 -0
- data/lib/rubocop/cop/lint/refinement_import_methods.rb +8 -1
- data/lib/rubocop/cop/lint/regexp_as_condition.rb +9 -1
- data/lib/rubocop/cop/lint/require_parentheses.rb +13 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +3 -2
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/rescue_type.rb +2 -2
- data/lib/rubocop/cop/lint/return_in_void_context.rb +9 -11
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +28 -4
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +56 -6
- data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +1 -1
- data/lib/rubocop/cop/lint/script_permission.rb +5 -1
- data/lib/rubocop/cop/lint/self_assignment.rb +63 -6
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +27 -1
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +14 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +17 -1
- data/lib/rubocop/cop/lint/super_argument_mismatch.rb +179 -0
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/suppressed_exception_in_number_conversion.rb +122 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +22 -4
- data/lib/rubocop/cop/lint/syntax.rb +25 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +73 -5
- data/lib/rubocop/cop/lint/to_json.rb +20 -17
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +5 -1
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +54 -11
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -1
- data/lib/rubocop/cop/lint/unreachable_code.rb +16 -9
- data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
- data/lib/rubocop/cop/lint/unreachable_pattern_branch.rb +113 -0
- data/lib/rubocop/cop/lint/unused_method_argument.rb +10 -0
- data/lib/rubocop/cop/lint/unused_private_method.rb +234 -0
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +31 -6
- data/lib/rubocop/cop/lint/useless_assignment.rb +63 -27
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +107 -0
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +92 -0
- data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +11 -10
- data/lib/rubocop/cop/lint/useless_or.rb +111 -0
- data/lib/rubocop/cop/lint/useless_rescue.rb +2 -3
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +13 -7
- data/lib/rubocop/cop/lint/useless_setter_call.rb +11 -5
- data/lib/rubocop/cop/lint/useless_times.rb +22 -1
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +201 -0
- data/lib/rubocop/cop/lint/void.rb +68 -22
- data/lib/rubocop/cop/lint.rb +179 -0
- data/lib/rubocop/cop/message_annotator.rb +7 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +2 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +23 -0
- data/lib/rubocop/cop/metrics/class_length.rb +4 -2
- data/lib/rubocop/cop/metrics/collection_literal_length.rb +1 -1
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
- data/lib/rubocop/cop/metrics/method_length.rb +3 -2
- data/lib/rubocop/cop/metrics/module_length.rb +4 -2
- data/lib/rubocop/cop/metrics/perceived_complexity.rb +37 -7
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +2 -2
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +7 -7
- data/lib/rubocop/cop/metrics.rb +31 -0
- data/lib/rubocop/cop/migration/department_name.rb +11 -5
- data/lib/rubocop/cop/migration.rb +13 -0
- data/lib/rubocop/cop/mixin/alignment.rb +7 -3
- data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -5
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +50 -28
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +13 -9
- data/lib/rubocop/cop/mixin/code_length.rb +10 -2
- data/lib/rubocop/cop/mixin/comments_help.rb +2 -3
- data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +1 -2
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +13 -2
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +105 -0
- data/lib/rubocop/cop/mixin/endless_method_rewriter.rb +13 -5
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +20 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +68 -21
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +52 -25
- data/lib/rubocop/cop/mixin/hash_subset.rb +28 -6
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +32 -78
- data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +52 -11
- data/lib/rubocop/cop/mixin/method_complexity.rb +2 -1
- 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_expression_indentation.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +10 -1
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +2 -2
- data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +79 -8
- data/lib/rubocop/cop/mixin/project_index_help.rb +203 -0
- data/lib/rubocop/cop/mixin/range_help.rb +16 -5
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +181 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +69 -12
- data/lib/rubocop/cop/mixin/string_help.rb +1 -1
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +23 -6
- data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
- data/lib/rubocop/cop/mixin.rb +93 -0
- data/lib/rubocop/cop/naming/accessor_method_name.rb +8 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +17 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +7 -4
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +6 -5
- 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/inclusive_language.rb +8 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +13 -6
- data/lib/rubocop/cop/naming/method_name.rb +190 -15
- data/lib/rubocop/cop/naming/predicate_method.rb +330 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +65 -8
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -7
- data/lib/rubocop/cop/naming/variable_name.rb +51 -6
- data/lib/rubocop/cop/naming/variable_number.rb +3 -1
- data/lib/rubocop/cop/naming.rb +31 -0
- data/lib/rubocop/cop/offense.rb +108 -9
- data/lib/rubocop/cop/registry.rb +234 -65
- data/lib/rubocop/cop/security/eval.rb +17 -3
- data/lib/rubocop/cop/security/io_methods.rb +2 -2
- data/lib/rubocop/cop/security/json_load.rb +45 -11
- data/lib/rubocop/cop/security/marshal_load.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/security.rb +19 -0
- data/lib/rubocop/cop/severity.rb +12 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +83 -14
- data/lib/rubocop/cop/style/accessor_grouping.rb +47 -10
- data/lib/rubocop/cop/style/alias.rb +33 -8
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
- data/lib/rubocop/cop/style/and_or.rb +8 -3
- data/lib/rubocop/cop/style/arguments_forwarding.rb +80 -39
- data/lib/rubocop/cop/style/array_first_last.rb +13 -3
- data/lib/rubocop/cop/style/array_intersect.rb +136 -38
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +50 -0
- data/lib/rubocop/cop/style/array_join.rb +4 -2
- data/lib/rubocop/cop/style/ascii_comments.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +8 -6
- data/lib/rubocop/cop/style/bare_percent_literals.rb +4 -3
- data/lib/rubocop/cop/style/begin_block.rb +3 -1
- data/lib/rubocop/cop/style/bitwise_predicate.rb +13 -5
- data/lib/rubocop/cop/style/block_delimiters.rb +77 -40
- data/lib/rubocop/cop/style/case_equality.rb +29 -15
- data/lib/rubocop/cop/style/case_like_if.rb +12 -11
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +181 -27
- data/lib/rubocop/cop/style/class_equality_comparison.rb +22 -14
- data/lib/rubocop/cop/style/class_methods_definitions.rb +26 -5
- data/lib/rubocop/cop/style/collection_compact.rb +37 -17
- data/lib/rubocop/cop/style/collection_methods.rb +1 -0
- data/lib/rubocop/cop/style/collection_querying.rb +200 -0
- data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
- data/lib/rubocop/cop/style/combinable_loops.rb +92 -9
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
- data/lib/rubocop/cop/style/comparable_between.rb +78 -0
- data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +65 -9
- data/lib/rubocop/cop/style/conditional_assignment.rb +58 -24
- data/lib/rubocop/cop/style/constant_visibility.rb +23 -12
- data/lib/rubocop/cop/style/copyright.rb +27 -12
- data/lib/rubocop/cop/style/data_inheritance.rb +25 -0
- data/lib/rubocop/cop/style/date_time.rb +4 -4
- data/lib/rubocop/cop/style/def_with_parentheses.rb +22 -5
- data/lib/rubocop/cop/style/dig_chain.rb +6 -1
- data/lib/rubocop/cop/style/dir_empty.rb +4 -0
- data/lib/rubocop/cop/style/directive_scope.rb +304 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +184 -20
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/documentation.rb +53 -6
- data/lib/rubocop/cop/style/documentation_method.rb +8 -12
- data/lib/rubocop/cop/style/double_negation.rb +14 -3
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +4 -3
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_case_condition.rb +13 -4
- data/lib/rubocop/cop/style/empty_class_definition.rb +126 -0
- data/lib/rubocop/cop/style/empty_heredoc.rb +4 -0
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +12 -3
- data/lib/rubocop/cop/style/empty_method.rb +15 -9
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +152 -0
- data/lib/rubocop/cop/style/encoding.rb +7 -1
- data/lib/rubocop/cop/style/end_block.rb +3 -1
- data/lib/rubocop/cop/style/endless_method.rb +256 -19
- data/lib/rubocop/cop/style/env_home.rb +4 -0
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
- data/lib/rubocop/cop/style/even_odd.rb +11 -1
- data/lib/rubocop/cop/style/exact_regexp_match.rb +52 -8
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
- data/lib/rubocop/cop/style/explicit_block_argument.rb +62 -9
- data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
- data/lib/rubocop/cop/style/fetch_env_var.rb +33 -7
- data/lib/rubocop/cop/style/file_null.rb +6 -4
- data/lib/rubocop/cop/style/file_open.rb +84 -0
- data/lib/rubocop/cop/style/file_write.rb +21 -16
- data/lib/rubocop/cop/style/float_division.rb +43 -15
- data/lib/rubocop/cop/style/for.rb +61 -1
- data/lib/rubocop/cop/style/format_string.rb +44 -9
- data/lib/rubocop/cop/style/format_string_token.rb +86 -16
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +5 -3
- data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +58 -40
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +31 -9
- data/lib/rubocop/cop/style/hash_conversion.rb +52 -16
- data/lib/rubocop/cop/style/hash_each_methods.rb +4 -4
- data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
- data/lib/rubocop/cop/style/hash_lookup_method.rb +128 -0
- data/lib/rubocop/cop/style/hash_slice.rb +16 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +23 -6
- data/lib/rubocop/cop/style/hash_transform_keys.rb +19 -9
- data/lib/rubocop/cop/style/hash_transform_values.rb +19 -9
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +39 -11
- data/lib/rubocop/cop/style/if_inside_else.rb +46 -21
- data/lib/rubocop/cop/style/if_unless_modifier.rb +101 -70
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +19 -19
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -2
- data/lib/rubocop/cop/style/if_with_semicolon.rb +61 -8
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inline_comment.rb +5 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +34 -8
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +27 -7
- data/lib/rubocop/cop/style/ip_addresses.rb +3 -4
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +211 -0
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +23 -11
- data/lib/rubocop/cop/style/lambda.rb +46 -2
- data/lib/rubocop/cop/style/lambda_call.rb +31 -10
- data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
- data/lib/rubocop/cop/style/magic_comment_format.rb +4 -4
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +11 -0
- data/lib/rubocop/cop/style/map_into_array.rb +6 -4
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/map_to_hash.rb +13 -5
- data/lib/rubocop/cop/style/map_to_set.rb +1 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +110 -27
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +15 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +58 -6
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +36 -8
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +36 -8
- data/lib/rubocop/cop/style/min_max_comparison.rb +17 -6
- data/lib/rubocop/cop/style/missing_else.rb +7 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
- data/lib/rubocop/cop/style/mixin_grouping.rb +12 -3
- data/lib/rubocop/cop/style/mixin_usage.rb +1 -1
- data/lib/rubocop/cop/style/module_function.rb +4 -2
- data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
- data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +47 -5
- data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
- data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +15 -22
- 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/multiple_comparison.rb +33 -22
- data/lib/rubocop/cop/style/mutable_constant.rb +158 -14
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +3 -3
- data/lib/rubocop/cop/style/negative_array_index.rb +228 -0
- data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
- data/lib/rubocop/cop/style/next.rb +68 -10
- data/lib/rubocop/cop/style/nil_comparison.rb +53 -13
- data/lib/rubocop/cop/style/nil_lambda.rb +9 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +21 -11
- data/lib/rubocop/cop/style/not.rb +12 -3
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
- data/lib/rubocop/cop/style/numeric_predicate.rb +22 -6
- data/lib/rubocop/cop/style/object_then.rb +1 -0
- data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +35 -15
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +10 -2
- data/lib/rubocop/cop/style/option_hash.rb +1 -1
- data/lib/rubocop/cop/style/optional_arguments.rb +1 -0
- data/lib/rubocop/cop/style/parallel_assignment.rb +58 -27
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +7 -2
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +18 -3
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/perl_backrefs.rb +5 -3
- data/lib/rubocop/cop/style/predicate_with_kind.rb +84 -0
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +12 -12
- data/lib/rubocop/cop/style/proc.rb +4 -2
- data/lib/rubocop/cop/style/raise_args.rb +28 -18
- data/lib/rubocop/cop/style/reduce_to_hash.rb +216 -0
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_assignment.rb +12 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +60 -7
- data/lib/rubocop/cop/style/redundant_condition.rb +93 -18
- data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +26 -4
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +17 -3
- data/lib/rubocop/cop/style/redundant_each.rb +4 -5
- data/lib/rubocop/cop/style/redundant_exception.rb +22 -4
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +11 -11
- data/lib/rubocop/cop/style/redundant_file_extension_in_require.rb +9 -0
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +319 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +13 -5
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +49 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +83 -119
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +176 -83
- data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +15 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +27 -7
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +16 -0
- data/lib/rubocop/cop/style/redundant_return.rb +4 -3
- data/lib/rubocop/cop/style/redundant_self.rb +20 -7
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +2 -3
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +27 -4
- data/lib/rubocop/cop/style/redundant_sort.rb +45 -11
- data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
- data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -2
- data/lib/rubocop/cop/style/redundant_struct_keyword_init.rb +133 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +107 -29
- data/lib/rubocop/cop/style/require_order.rb +25 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +16 -12
- data/lib/rubocop/cop/style/return_nil.rb +19 -4
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +76 -20
- data/lib/rubocop/cop/style/sample.rb +19 -13
- data/lib/rubocop/cop/style/select_by_kind.rb +158 -0
- data/lib/rubocop/cop/style/select_by_range.rb +197 -0
- data/lib/rubocop/cop/style/select_by_regexp.rb +54 -22
- data/lib/rubocop/cop/style/self_assignment.rb +13 -16
- data/lib/rubocop/cop/style/semicolon.rb +56 -14
- data/lib/rubocop/cop/style/send_with_literal_method_name.rb +4 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +22 -8
- data/lib/rubocop/cop/style/single_line_methods.rb +33 -11
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +96 -104
- data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +32 -6
- data/lib/rubocop/cop/style/static_class.rb +21 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +38 -16
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +44 -2
- data/lib/rubocop/cop/style/super_arguments.rb +7 -6
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +35 -15
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +34 -1
- data/lib/rubocop/cop/style/time_now.rb +41 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +3 -2
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
- data/lib/rubocop/cop/style/trailing_method_end_statement.rb +1 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +35 -32
- data/lib/rubocop/cop/style/trivial_accessors.rb +2 -2
- data/lib/rubocop/cop/style/unless_else.rb +10 -9
- data/lib/rubocop/cop/style/unless_logical_operators.rb +3 -3
- data/lib/rubocop/cop/style/while_until_do.rb +7 -0
- data/lib/rubocop/cop/style/while_until_modifier.rb +16 -1
- data/lib/rubocop/cop/style/word_array.rb +1 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +26 -12
- data/lib/rubocop/cop/style/yoda_expression.rb +11 -2
- data/lib/rubocop/cop/style/zero_length_predicate.rb +6 -3
- data/lib/rubocop/cop/style.rb +311 -0
- data/lib/rubocop/cop/team.rb +172 -49
- data/lib/rubocop/cop/util.rb +7 -10
- data/lib/rubocop/cop/utils/format_string.rb +20 -5
- data/lib/rubocop/cop/variable_force/assignment.rb +8 -4
- data/lib/rubocop/cop/variable_force/branch.rb +30 -6
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +42 -11
- data/lib/rubocop/cop/variable_force.rb +26 -9
- data/lib/rubocop/cops_documentation_generator.rb +49 -15
- data/lib/rubocop/directive_comment.rb +147 -5
- data/lib/rubocop/ext/regexp_node.rb +0 -1
- data/lib/rubocop/feature_loader.rb +0 -6
- data/lib/rubocop/file_patterns.rb +9 -1
- data/lib/rubocop/formatter/base_formatter.rb +22 -0
- data/lib/rubocop/formatter/clang_style_formatter.rb +5 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +57 -14
- data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
- data/lib/rubocop/formatter/formatter_set.rb +7 -2
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
- data/lib/rubocop/formatter/html_formatter.rb +3 -5
- data/lib/rubocop/formatter/json_formatter.rb +82 -7
- data/lib/rubocop/formatter/junit_formatter.rb +27 -10
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +5 -4
- data/lib/rubocop/formatter/pacman_formatter.rb +5 -2
- data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +4 -5
- data/lib/rubocop/formatter/tap_formatter.rb +8 -3
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +5 -4
- data/lib/rubocop/formatter.rb +23 -21
- data/lib/rubocop/lockfile.rb +18 -0
- data/lib/rubocop/lsp/diagnostic.rb +22 -41
- data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
- data/lib/rubocop/lsp/routes.rb +158 -55
- data/lib/rubocop/lsp/runtime.rb +66 -15
- data/lib/rubocop/lsp/server.rb +4 -2
- data/lib/rubocop/lsp/stdin_runner.rb +38 -19
- data/lib/rubocop/lsp.rb +5 -2
- data/lib/rubocop/magic_comment.rb +55 -0
- 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 +307 -0
- data/lib/rubocop/mcp/source_files.rb +35 -0
- data/lib/rubocop/offense_limit.rb +30 -0
- data/lib/rubocop/options.rb +166 -23
- data/lib/rubocop/path_util.rb +20 -5
- data/lib/rubocop/pending_cops_reporter.rb +51 -0
- data/lib/rubocop/plugin/configuration_integrator.rb +153 -0
- data/lib/rubocop/plugin/load_error.rb +26 -0
- data/lib/rubocop/plugin/loader.rb +100 -0
- data/lib/rubocop/plugin/not_supported_error.rb +29 -0
- data/lib/rubocop/plugin.rb +46 -0
- data/lib/rubocop/project_index_loader.rb +82 -0
- data/lib/rubocop/rake_task.rb +6 -4
- data/lib/rubocop/remote_config.rb +18 -13
- data/lib/rubocop/result_cache.rb +110 -65
- data/lib/rubocop/rspec/cop_helper.rb +21 -1
- data/lib/rubocop/rspec/expect_offense.rb +11 -7
- data/lib/rubocop/rspec/shared_contexts.rb +85 -3
- data/lib/rubocop/rspec/support.rb +4 -0
- data/lib/rubocop/runner.rb +368 -106
- data/lib/rubocop/server/cache.rb +67 -48
- data/lib/rubocop/server/cli.rb +2 -4
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/server/core.rb +8 -0
- data/lib/rubocop/server.rb +14 -0
- data/lib/rubocop/target_finder.rb +25 -11
- data/lib/rubocop/target_ruby.rb +52 -23
- data/lib/rubocop/todo_audit.rb +111 -0
- data/lib/rubocop/unified_diff.rb +257 -0
- data/lib/rubocop/util.rb +69 -0
- data/lib/rubocop/version.rb +48 -10
- data/lib/rubocop.rb +35 -682
- data/lib/ruby_lsp/rubocop/addon.rb +28 -17
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
- metadata +129 -21
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
- data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
- data/lib/ruby_lsp/rubocop/wraps_built_in_lsp_runtime.rb +0 -50
|
@@ -3,16 +3,21 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Avoid redundant `::` prefix on constant.
|
|
6
|
+
# Avoid redundant `::` prefix on a constant.
|
|
7
7
|
#
|
|
8
|
-
# How Ruby searches
|
|
8
|
+
# How Ruby searches constants is a bit complicated, and it can often be difficult to
|
|
9
9
|
# understand from the code whether the `::` is intended or not. Where `Module.nesting`
|
|
10
10
|
# is empty, there is no need to prepend `::`, so it would be nice to consistently
|
|
11
11
|
# avoid such meaningless `::` prefix to avoid confusion.
|
|
12
12
|
#
|
|
13
|
-
# NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled
|
|
14
|
-
# conflicting rules.
|
|
15
|
-
# `Lint/ConstantResolution` cop which is disabled by default.
|
|
13
|
+
# NOTE: This cop is disabled if `Lint/ConstantResolution` cop is enabled,
|
|
14
|
+
# to prevent conflicting rules. This is because it respects user configurations
|
|
15
|
+
# that want to enable `Lint/ConstantResolution` cop which is disabled by default.
|
|
16
|
+
#
|
|
17
|
+
# When `AllCops/UseProjectIndex` is enabled and the `rubydex` gem is
|
|
18
|
+
# installed, a leading `::` inside a namespace is also reported when the
|
|
19
|
+
# constant provably resolves to the same declaration with and without
|
|
20
|
+
# the base, i.e. nothing in the surrounding nesting shadows it.
|
|
16
21
|
#
|
|
17
22
|
# @example
|
|
18
23
|
# # bad
|
|
@@ -41,13 +46,14 @@ module RuboCop
|
|
|
41
46
|
# ::Const
|
|
42
47
|
# end
|
|
43
48
|
class RedundantConstantBase < Base
|
|
49
|
+
include ProjectIndexHelp
|
|
44
50
|
extend AutoCorrector
|
|
45
51
|
|
|
46
52
|
MSG = 'Remove redundant `::`.'
|
|
47
53
|
|
|
48
54
|
def on_cbase(node)
|
|
49
55
|
return if lint_constant_resolution_cop_enabled?
|
|
50
|
-
return unless bad?(node)
|
|
56
|
+
return unless bad?(node) || provably_unshadowed?(node)
|
|
51
57
|
|
|
52
58
|
add_offense(node) do |corrector|
|
|
53
59
|
corrector.remove(node)
|
|
@@ -56,6 +62,36 @@ module RuboCop
|
|
|
56
62
|
|
|
57
63
|
private
|
|
58
64
|
|
|
65
|
+
# When `AllCops/UseProjectIndex` is enabled, `::` inside a namespace is
|
|
66
|
+
# also redundant when the first constant segment resolves to the same
|
|
67
|
+
# declaration with and without the base, i.e. nothing in the
|
|
68
|
+
# surrounding nesting shadows it.
|
|
69
|
+
def provably_unshadowed?(node)
|
|
70
|
+
return false unless project_index
|
|
71
|
+
return false unless (segment = first_constant_segment(node))
|
|
72
|
+
|
|
73
|
+
nesting = module_nesting_ancestors_of(node)
|
|
74
|
+
.map { |ancestor| ancestor.identifier.const_name }.reverse
|
|
75
|
+
|
|
76
|
+
!nesting.empty? && same_resolution?(segment, nesting)
|
|
77
|
+
rescue StandardError
|
|
78
|
+
false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def same_resolution?(segment, nesting)
|
|
82
|
+
relative = project_index.resolve_constant(segment, nesting)
|
|
83
|
+
absolute = project_index.resolve_constant(segment, [])
|
|
84
|
+
|
|
85
|
+
!relative.nil? && !absolute.nil? && relative.name == absolute.name
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def first_constant_segment(node)
|
|
89
|
+
parent = node.parent
|
|
90
|
+
return nil unless parent&.const_type?
|
|
91
|
+
|
|
92
|
+
parent.short_name.to_s
|
|
93
|
+
end
|
|
94
|
+
|
|
59
95
|
def lint_constant_resolution_cop_enabled?
|
|
60
96
|
lint_constant_resolution_config.fetch('Enabled', false)
|
|
61
97
|
end
|
|
@@ -20,20 +20,42 @@ module RuboCop
|
|
|
20
20
|
|
|
21
21
|
MSG = 'Remove the redundant current directory path.'
|
|
22
22
|
RESTRICT_ON_SEND = %i[require_relative].freeze
|
|
23
|
-
|
|
23
|
+
CURRENT_DIRECTORY_PREFIX = %r{\./+}.freeze
|
|
24
|
+
REDUNDANT_CURRENT_DIRECTORY_PREFIX = /\A#{CURRENT_DIRECTORY_PREFIX}/.freeze
|
|
24
25
|
|
|
25
26
|
def on_send(node)
|
|
26
27
|
return unless (first_argument = node.first_argument)
|
|
27
|
-
return unless first_argument.
|
|
28
|
-
|
|
28
|
+
return unless (index = first_argument.source.index(CURRENT_DIRECTORY_PREFIX))
|
|
29
|
+
|
|
30
|
+
content = leading_path_content(first_argument)
|
|
31
|
+
return unless (redundant_length = redundant_path_length(content))
|
|
29
32
|
|
|
30
33
|
begin_pos = first_argument.source_range.begin.begin_pos + index
|
|
31
|
-
|
|
34
|
+
end_pos = begin_pos + redundant_length
|
|
35
|
+
range = range_between(begin_pos, end_pos)
|
|
32
36
|
|
|
33
37
|
add_offense(range) do |corrector|
|
|
34
38
|
corrector.remove(range)
|
|
35
39
|
end
|
|
36
40
|
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# The literal text at the start of the path, which is the whole string
|
|
45
|
+
# for a plain string and the leading literal segment for an interpolated
|
|
46
|
+
# one (`nil` when it starts with interpolation).
|
|
47
|
+
def leading_path_content(node)
|
|
48
|
+
return node.str_content if node.str_type?
|
|
49
|
+
return unless node.dstr_type? && (first = node.children.first)&.str_type?
|
|
50
|
+
|
|
51
|
+
first.str_content
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def redundant_path_length(path)
|
|
55
|
+
return unless (match = path&.match(REDUNDANT_CURRENT_DIRECTORY_PREFIX))
|
|
56
|
+
|
|
57
|
+
match[0].length
|
|
58
|
+
end
|
|
37
59
|
end
|
|
38
60
|
end
|
|
39
61
|
end
|
|
@@ -25,7 +25,13 @@ module RuboCop
|
|
|
25
25
|
MSG = 'Remove the redundant double splat and braces, use keyword arguments directly.'
|
|
26
26
|
MERGE_METHODS = %i[merge merge!].freeze
|
|
27
27
|
|
|
28
|
-
#
|
|
28
|
+
# `Style/TrailingCommaInHashLiteral` adds a comma to the hash literal whose braces
|
|
29
|
+
# this cop removes in the same pass, which would leave a dangling comma.
|
|
30
|
+
def self.autocorrect_incompatible_with
|
|
31
|
+
[Style::TrailingCommaInHashLiteral]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
29
35
|
def on_hash(node)
|
|
30
36
|
return if node.pairs.empty? || node.pairs.any?(&:hash_rocket?)
|
|
31
37
|
return unless (parent = node.parent)
|
|
@@ -38,7 +44,6 @@ module RuboCop
|
|
|
38
44
|
autocorrect(corrector, node, kwsplat)
|
|
39
45
|
end
|
|
40
46
|
end
|
|
41
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
42
47
|
|
|
43
48
|
private
|
|
44
49
|
|
|
@@ -109,7 +114,7 @@ module RuboCop
|
|
|
109
114
|
|
|
110
115
|
node.arguments.map do |arg|
|
|
111
116
|
if arg.hash_type?
|
|
112
|
-
arg
|
|
117
|
+
hash_argument_source(arg)
|
|
113
118
|
else
|
|
114
119
|
"**#{arg.source}"
|
|
115
120
|
end
|
|
@@ -123,6 +128,15 @@ module RuboCop
|
|
|
123
128
|
|
|
124
129
|
mergeable?(parent)
|
|
125
130
|
end
|
|
131
|
+
|
|
132
|
+
# A braced hash literal passed to `merge` must have its braces stripped so
|
|
133
|
+
# its pairs join the surrounding keyword arguments. Keeping the braces would
|
|
134
|
+
# produce a positional hash after keyword arguments, which is invalid Ruby.
|
|
135
|
+
def hash_argument_source(hash)
|
|
136
|
+
return hash.source unless hash.braces?
|
|
137
|
+
|
|
138
|
+
hash.pairs.map(&:source).join(', ')
|
|
139
|
+
end
|
|
126
140
|
end
|
|
127
141
|
end
|
|
128
142
|
end
|
|
@@ -60,11 +60,11 @@ module RuboCop
|
|
|
60
60
|
|
|
61
61
|
private
|
|
62
62
|
|
|
63
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
63
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
64
64
|
def redundant_each_method(node)
|
|
65
65
|
return if node.last_argument&.block_pass_type?
|
|
66
66
|
|
|
67
|
-
if node.method?(:each) && !node.parent&.
|
|
67
|
+
if node.method?(:each) && !node.parent&.any_block_type?
|
|
68
68
|
ancestor_node = node.each_ancestor(:call).detect do |ancestor|
|
|
69
69
|
ancestor.receiver == node &&
|
|
70
70
|
(RESTRICT_ON_SEND.include?(ancestor.method_name) || ancestor.method?(:reverse_each))
|
|
@@ -74,14 +74,13 @@ module RuboCop
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
return unless (prev_method = node.children.first)
|
|
77
|
-
return if !prev_method.
|
|
78
|
-
prev_method.
|
|
77
|
+
return if !prev_method.call_type? || prev_method.parent.any_block_type? ||
|
|
78
|
+
prev_method.last_argument&.block_pass_type?
|
|
79
79
|
|
|
80
80
|
detected = prev_method.method_name.to_s.start_with?('each_') unless node.method?(:each)
|
|
81
81
|
|
|
82
82
|
prev_method if detected || prev_method.method?(:reverse_each)
|
|
83
83
|
end
|
|
84
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
85
84
|
|
|
86
85
|
def range(node)
|
|
87
86
|
return node.selector unless node.method?(:each)
|
|
@@ -38,6 +38,10 @@ module RuboCop
|
|
|
38
38
|
|
|
39
39
|
def fix_exploded(node)
|
|
40
40
|
exploded?(node) do |command, message|
|
|
41
|
+
# `raise RuntimeError, nil` uses the class name as the message, so
|
|
42
|
+
# rewriting it to `raise nil.to_s` (an empty message) would change it.
|
|
43
|
+
next if message.nil_type?
|
|
44
|
+
|
|
41
45
|
add_offense(node, message: MSG_1) do |corrector|
|
|
42
46
|
corrector.replace(node, replaced_exploded(node, command, message))
|
|
43
47
|
end
|
|
@@ -45,31 +49,45 @@ module RuboCop
|
|
|
45
49
|
end
|
|
46
50
|
|
|
47
51
|
def replaced_exploded(node, command, message)
|
|
48
|
-
arg =
|
|
52
|
+
arg = message_source(message)
|
|
49
53
|
arg = node.parenthesized? ? "(#{arg})" : " #{arg}"
|
|
50
54
|
"#{command}#{arg}"
|
|
51
55
|
end
|
|
52
56
|
|
|
53
57
|
def string_message?(message)
|
|
54
|
-
message.
|
|
58
|
+
message.any_str_type?
|
|
55
59
|
end
|
|
56
60
|
|
|
57
61
|
def fix_compact(node)
|
|
58
62
|
compact?(node) do |new_call, message|
|
|
63
|
+
next if message.nil_type?
|
|
64
|
+
|
|
59
65
|
add_offense(node, message: MSG_2) do |corrector|
|
|
60
|
-
corrector.replace(new_call,
|
|
66
|
+
corrector.replace(new_call, message_source(message))
|
|
61
67
|
end
|
|
62
68
|
end
|
|
63
69
|
end
|
|
64
70
|
|
|
65
|
-
def
|
|
71
|
+
def message_source(message)
|
|
66
72
|
if string_message?(message)
|
|
67
73
|
message.source
|
|
74
|
+
elsif require_parentheses?(message)
|
|
75
|
+
"(#{message.source}).to_s"
|
|
68
76
|
else
|
|
69
77
|
"#{message.source}.to_s"
|
|
70
78
|
end
|
|
71
79
|
end
|
|
72
80
|
|
|
81
|
+
def require_parentheses?(message)
|
|
82
|
+
if message.call_type?
|
|
83
|
+
!message.method?(:[]) &&
|
|
84
|
+
(message.operator_method? || (message.arguments? && !message.parenthesized?))
|
|
85
|
+
else
|
|
86
|
+
!(message.basic_literal? || message.variable? ||
|
|
87
|
+
message.type?(:const, :self, :begin, :array))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
73
91
|
# @!method exploded?(node)
|
|
74
92
|
def_node_matcher :exploded?, <<~PATTERN
|
|
75
93
|
(send nil? ${:raise :fail} (const {nil? cbase} :RuntimeError) $_)
|
|
@@ -49,10 +49,10 @@ module RuboCop
|
|
|
49
49
|
(block
|
|
50
50
|
$(call _ :fetch _)
|
|
51
51
|
(args)
|
|
52
|
-
${nil?
|
|
52
|
+
${nil? basic_literal? const_type?})
|
|
53
53
|
PATTERN
|
|
54
54
|
|
|
55
|
-
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
|
|
55
|
+
def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler, InternalAffairs/ItblockHandler -- the matched body is a literal or a constant
|
|
56
56
|
redundant_fetch_block_candidate?(node) do |send, body|
|
|
57
57
|
return if should_not_check?(send, body)
|
|
58
58
|
|
|
@@ -71,18 +71,11 @@ module RuboCop
|
|
|
71
71
|
|
|
72
72
|
private
|
|
73
73
|
|
|
74
|
-
def basic_literal?(node)
|
|
75
|
-
node&.basic_literal?
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def const_type?(node)
|
|
79
|
-
node&.const_type?
|
|
80
|
-
end
|
|
81
|
-
|
|
82
74
|
def should_not_check?(send, body)
|
|
83
75
|
(body&.const_type? && !check_for_constant?) ||
|
|
84
76
|
(body&.str_type? && !check_for_string?) ||
|
|
85
|
-
rails_cache?(send.receiver)
|
|
77
|
+
rails_cache?(send.receiver) ||
|
|
78
|
+
unappendable_argument?(send)
|
|
86
79
|
end
|
|
87
80
|
|
|
88
81
|
# @!method rails_cache?(node)
|
|
@@ -115,6 +108,13 @@ module RuboCop
|
|
|
115
108
|
def check_for_string?
|
|
116
109
|
frozen_string_literals_enabled?
|
|
117
110
|
end
|
|
111
|
+
|
|
112
|
+
def unappendable_argument?(send)
|
|
113
|
+
argument = send.first_argument
|
|
114
|
+
|
|
115
|
+
argument.type?(:splat, :forwarded_restarg) ||
|
|
116
|
+
(argument.hash_type? && !argument.braces?)
|
|
117
|
+
end
|
|
118
118
|
end
|
|
119
119
|
end
|
|
120
120
|
end
|
|
@@ -41,6 +41,10 @@ module RuboCop
|
|
|
41
41
|
return unless name_node.value.end_with?('.rb')
|
|
42
42
|
|
|
43
43
|
extension_range = extension_range(name_node)
|
|
44
|
+
# A backslash right before the extension means the path is escaped;
|
|
45
|
+
# dropping the extension would either produce invalid Ruby (a trailing
|
|
46
|
+
# backslash escaping the closing quote) or a confusing path, so skip it.
|
|
47
|
+
return if escaped_extension?(name_node, extension_range)
|
|
44
48
|
|
|
45
49
|
add_offense(extension_range) do |corrector|
|
|
46
50
|
corrector.remove(extension_range)
|
|
@@ -55,6 +59,11 @@ module RuboCop
|
|
|
55
59
|
|
|
56
60
|
range_between(end_of_path_string - 4, end_of_path_string - 1)
|
|
57
61
|
end
|
|
62
|
+
|
|
63
|
+
def escaped_extension?(name_node, extension_range)
|
|
64
|
+
offset = extension_range.begin_pos - name_node.source_range.begin_pos
|
|
65
|
+
name_node.source[0...offset].end_with?('\\')
|
|
66
|
+
end
|
|
58
67
|
end
|
|
59
68
|
end
|
|
60
69
|
end
|
|
@@ -62,7 +62,7 @@ module RuboCop
|
|
|
62
62
|
def_node_matcher :select_predicate?, <<~PATTERN
|
|
63
63
|
(call
|
|
64
64
|
{
|
|
65
|
-
(
|
|
65
|
+
(any_block $(call _ {:select :filter :find_all}) ...)
|
|
66
66
|
$(call _ {:select :filter :find_all} block_pass_type?)
|
|
67
67
|
}
|
|
68
68
|
${:#{RESTRICT_ON_SEND.join(' :')}})
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for calls to `Kernel#format` or `Kernel#sprintf` that are redundant.
|
|
7
|
+
#
|
|
8
|
+
# Calling `format` with only a single string or constant argument is redundant,
|
|
9
|
+
# as it can be replaced by the string or constant itself.
|
|
10
|
+
#
|
|
11
|
+
# Also looks for `format` calls where the arguments are literals that can be
|
|
12
|
+
# inlined into a string easily. This applies to the `%s`, `%d`, `%i`, `%u`, and
|
|
13
|
+
# `%f` format specifiers.
|
|
14
|
+
#
|
|
15
|
+
# @safety
|
|
16
|
+
# This cop's autocorrection is unsafe because string object returned by
|
|
17
|
+
# `format` and `sprintf` are never frozen. If `format('string')` is autocorrected to
|
|
18
|
+
# `'string'`, `FrozenError` may occur when calling a destructive method like `String#<<`.
|
|
19
|
+
# Consider using `'string'.dup` instead of `format('string')`.
|
|
20
|
+
# Additionally, since the necessity of `dup` cannot be determined automatically,
|
|
21
|
+
# this autocorrection is inherently unsafe.
|
|
22
|
+
#
|
|
23
|
+
# [source,ruby]
|
|
24
|
+
# ----
|
|
25
|
+
# # frozen_string_literal: true
|
|
26
|
+
#
|
|
27
|
+
# format('template').frozen? # => false
|
|
28
|
+
# 'template'.frozen? # => true
|
|
29
|
+
# ----
|
|
30
|
+
#
|
|
31
|
+
# @example
|
|
32
|
+
#
|
|
33
|
+
# # bad
|
|
34
|
+
# format('the quick brown fox jumps over the lazy dog.')
|
|
35
|
+
# sprintf('the quick brown fox jumps over the lazy dog.')
|
|
36
|
+
#
|
|
37
|
+
# # good
|
|
38
|
+
# 'the quick brown fox jumps over the lazy dog.'
|
|
39
|
+
#
|
|
40
|
+
# # bad
|
|
41
|
+
# format(MESSAGE)
|
|
42
|
+
# sprintf(MESSAGE)
|
|
43
|
+
#
|
|
44
|
+
# # good
|
|
45
|
+
# MESSAGE
|
|
46
|
+
#
|
|
47
|
+
# # bad
|
|
48
|
+
# format('%s %s', 'foo', 'bar')
|
|
49
|
+
# sprintf('%s %s', 'foo', 'bar')
|
|
50
|
+
#
|
|
51
|
+
# # good
|
|
52
|
+
# 'foo bar'
|
|
53
|
+
#
|
|
54
|
+
class RedundantFormat < Base
|
|
55
|
+
extend AutoCorrector
|
|
56
|
+
|
|
57
|
+
MSG = 'Use `%<prefer>s` directly instead of `%<method_name>s`.'
|
|
58
|
+
|
|
59
|
+
RESTRICT_ON_SEND = %i[format sprintf].to_set.freeze
|
|
60
|
+
ACCEPTABLE_LITERAL_TYPES = %i[str dstr sym dsym numeric boolean nil].freeze
|
|
61
|
+
|
|
62
|
+
# @!method format_without_additional_args?(node)
|
|
63
|
+
def_node_matcher :format_without_additional_args?, <<~PATTERN
|
|
64
|
+
(send {(const {nil? cbase} :Kernel) nil?} %RESTRICT_ON_SEND ${str dstr const})
|
|
65
|
+
PATTERN
|
|
66
|
+
|
|
67
|
+
# @!method rational_number?(node)
|
|
68
|
+
def_node_matcher :rational_number?, <<~PATTERN
|
|
69
|
+
{rational (send int :/ rational) (begin rational) (begin (send int :/ rational))}
|
|
70
|
+
PATTERN
|
|
71
|
+
|
|
72
|
+
# @!method complex_number?(node)
|
|
73
|
+
def_node_matcher :complex_number?, <<~PATTERN
|
|
74
|
+
{complex (send int :+ complex) (begin complex) (begin (send int :+ complex))}
|
|
75
|
+
PATTERN
|
|
76
|
+
|
|
77
|
+
# @!method find_hash_value_node(node, name)
|
|
78
|
+
def_node_search :find_hash_value_node, <<~PATTERN
|
|
79
|
+
(pair (sym %1) $_)
|
|
80
|
+
PATTERN
|
|
81
|
+
|
|
82
|
+
# @!method splatted_arguments?(node)
|
|
83
|
+
def_node_matcher :splatted_arguments?, <<~PATTERN
|
|
84
|
+
(send _ %RESTRICT_ON_SEND <{
|
|
85
|
+
splat
|
|
86
|
+
(hash <kwsplat ...>)
|
|
87
|
+
} ...>)
|
|
88
|
+
PATTERN
|
|
89
|
+
|
|
90
|
+
def on_send(node)
|
|
91
|
+
format_without_additional_args?(node) do |value|
|
|
92
|
+
next if string_with_format_sequence?(value)
|
|
93
|
+
|
|
94
|
+
replacement = escape_control_chars(value.source)
|
|
95
|
+
|
|
96
|
+
add_offense(node, message: message(node, replacement)) do |corrector|
|
|
97
|
+
corrector.replace(node, replacement)
|
|
98
|
+
end
|
|
99
|
+
return
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
detect_unnecessary_fields(node)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
# A single-argument `format` whose string still contains a format sequence is
|
|
108
|
+
# not redundant: `format('%s')` raises at runtime, and `format('%%')` returns
|
|
109
|
+
# `'%'`, so replacing it with the literal would change behavior.
|
|
110
|
+
def string_with_format_sequence?(node)
|
|
111
|
+
string = static_string_value(node)
|
|
112
|
+
return false unless string
|
|
113
|
+
|
|
114
|
+
RuboCop::Cop::Utils::FormatString.new(string).format_sequences.any?
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def static_string_value(node)
|
|
118
|
+
if node.str_type?
|
|
119
|
+
node.value
|
|
120
|
+
elsif node.dstr_type?
|
|
121
|
+
node.children.select(&:str_type?).map(&:value).join
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def message(node, prefer)
|
|
126
|
+
format(MSG, prefer: prefer, method_name: node.method_name)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def detect_unnecessary_fields(node)
|
|
130
|
+
return unless node.first_argument&.str_type?
|
|
131
|
+
return if node.first_argument.heredoc?
|
|
132
|
+
|
|
133
|
+
string = node.first_argument.value
|
|
134
|
+
arguments = node.arguments[1..]
|
|
135
|
+
|
|
136
|
+
return unless string && arguments.any?
|
|
137
|
+
return if splatted_arguments?(node)
|
|
138
|
+
|
|
139
|
+
register_all_fields_literal(node, string, arguments)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def register_all_fields_literal(node, string, arguments)
|
|
143
|
+
return unless all_fields_literal?(string, arguments.dup)
|
|
144
|
+
|
|
145
|
+
format_arguments = argument_values(arguments)
|
|
146
|
+
begin
|
|
147
|
+
formatted_string = format(string, *format_arguments)
|
|
148
|
+
rescue ArgumentError
|
|
149
|
+
return
|
|
150
|
+
end
|
|
151
|
+
replacement = quote(formatted_string, node)
|
|
152
|
+
|
|
153
|
+
add_offense(node, message: message(node, replacement)) do |corrector|
|
|
154
|
+
corrector.replace(node, replacement)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
159
|
+
def all_fields_literal?(string, arguments)
|
|
160
|
+
count = 0
|
|
161
|
+
sequences = RuboCop::Cop::Utils::FormatString.new(string).format_sequences
|
|
162
|
+
return false unless sequences.any?
|
|
163
|
+
|
|
164
|
+
sequences.each do |sequence|
|
|
165
|
+
next if sequence.percent?
|
|
166
|
+
next if unknown_variable_width?(sequence, arguments)
|
|
167
|
+
|
|
168
|
+
hash = arguments.detect(&:hash_type?)
|
|
169
|
+
next unless (argument = find_argument(sequence, arguments, hash))
|
|
170
|
+
next unless matching_argument?(sequence, argument)
|
|
171
|
+
next if (sequence.width || sequence.precision) && argument.dstr_type?
|
|
172
|
+
|
|
173
|
+
count += 1
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
sequences.size == count
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# If the sequence has a variable (`*`) width, it cannot be autocorrected
|
|
180
|
+
# if the width is not given as a numeric literal argument
|
|
181
|
+
def unknown_variable_width?(sequence, arguments)
|
|
182
|
+
return false unless sequence.variable_width?
|
|
183
|
+
|
|
184
|
+
argument = positional_argument(arguments, sequence.variable_width_argument_number)
|
|
185
|
+
argument.nil? || !numeric?(argument)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
189
|
+
def find_argument(sequence, arguments, hash)
|
|
190
|
+
if hash && (sequence.annotated? || sequence.template?)
|
|
191
|
+
find_hash_value_node(hash, sequence.name.to_sym).first
|
|
192
|
+
elsif sequence.variable_width?
|
|
193
|
+
# If the specifier contains `*`, the argument for the width can be ignored.
|
|
194
|
+
arguments.delete_at(sequence.variable_width_argument_number - 1)
|
|
195
|
+
arguments.shift
|
|
196
|
+
elsif sequence.arg_number
|
|
197
|
+
positional_argument(arguments, sequence.arg_number.to_i)
|
|
198
|
+
else
|
|
199
|
+
arguments.shift
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def matching_argument?(sequence, argument)
|
|
204
|
+
# Template specifiers don't give a type, any acceptable literal type is ok.
|
|
205
|
+
return argument.type?(*ACCEPTABLE_LITERAL_TYPES) if sequence.template?
|
|
206
|
+
|
|
207
|
+
# An argument matches a specifier if it can be easily converted
|
|
208
|
+
# to that type.
|
|
209
|
+
case sequence.type
|
|
210
|
+
when 's'
|
|
211
|
+
argument.type?(*ACCEPTABLE_LITERAL_TYPES)
|
|
212
|
+
when 'd', 'i', 'u'
|
|
213
|
+
integer?(argument)
|
|
214
|
+
when 'f'
|
|
215
|
+
float?(argument)
|
|
216
|
+
else
|
|
217
|
+
false
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# `Array#[]` raises `RangeError` for an index beyond the 64-bit range
|
|
222
|
+
# (e.g. `format('%*9999999999999999999999$d', 1)`) instead of returning `nil`,
|
|
223
|
+
# so the index needs to be checked before accessing the array.
|
|
224
|
+
def positional_argument(arguments, number)
|
|
225
|
+
index = number - 1
|
|
226
|
+
|
|
227
|
+
arguments[index] if index < arguments.size
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def numeric?(argument)
|
|
231
|
+
argument.type?(:numeric, :str) ||
|
|
232
|
+
rational_number?(argument) ||
|
|
233
|
+
complex_number?(argument)
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def integer?(argument)
|
|
237
|
+
numeric?(argument) && Integer(argument_value(argument), exception: false)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def float?(argument)
|
|
241
|
+
numeric?(argument) && Float(argument_value(argument), exception: false)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# Add correct quotes to the formatted string, preferring retaining the existing
|
|
245
|
+
# quotes if possible.
|
|
246
|
+
def quote(string, node)
|
|
247
|
+
str_node = node.first_argument
|
|
248
|
+
start_delimiter = str_node.loc.begin.source
|
|
249
|
+
end_delimiter = str_node.loc.end.source
|
|
250
|
+
|
|
251
|
+
# If there is any interpolation, the delimiters need to be changed potentially
|
|
252
|
+
if node.each_descendant(:dstr, :dsym).any?
|
|
253
|
+
case start_delimiter
|
|
254
|
+
when "'"
|
|
255
|
+
start_delimiter = end_delimiter = '"'
|
|
256
|
+
when /\A%q(.)/
|
|
257
|
+
start_delimiter = "%Q#{Regexp.last_match[1]}"
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
"#{start_delimiter}#{escape_control_chars(string)}#{end_delimiter}"
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
# Escape any control characters in the string (eg. `\t` or `\n` become `\\t` or `\\n`)
|
|
265
|
+
def escape_control_chars(string)
|
|
266
|
+
string.gsub(/\p{Cc}/) { |s| s.dump[1..-2] }
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
def argument_values(arguments)
|
|
270
|
+
arguments.map { |argument| argument_value(argument) }
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def argument_value(argument)
|
|
274
|
+
argument = argument.children.first if argument.begin_type?
|
|
275
|
+
|
|
276
|
+
# `nil` formats to an empty string (`format('%s', nil) == ''`), not the
|
|
277
|
+
# literal `'nil'` that `argument.source` would return.
|
|
278
|
+
return if argument.nil_type?
|
|
279
|
+
|
|
280
|
+
typed_argument_value(argument)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def typed_argument_value(argument)
|
|
284
|
+
if argument.dsym_type?
|
|
285
|
+
dsym_value(argument)
|
|
286
|
+
elsif argument.hash_type?
|
|
287
|
+
hash_value(argument)
|
|
288
|
+
elsif rational_number?(argument)
|
|
289
|
+
rational_value(argument)
|
|
290
|
+
elsif complex_number?(argument)
|
|
291
|
+
complex_value(argument)
|
|
292
|
+
elsif argument.respond_to?(:value)
|
|
293
|
+
argument.value
|
|
294
|
+
else
|
|
295
|
+
argument.source
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def dsym_value(dsym_node)
|
|
300
|
+
dsym_node.children.first.source
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def hash_value(hash_node)
|
|
304
|
+
hash_node.each_pair.with_object({}) do |pair, hash|
|
|
305
|
+
hash[pair.key.value] = argument_value(pair.value)
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def rational_value(rational_node)
|
|
310
|
+
rational_node.source.to_r
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def complex_value(complex_node)
|
|
314
|
+
Complex(complex_node.source)
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|