rubocop 1.71.1 → 1.91.0
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 +883 -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 +7 -2
- data/lib/rubocop/changed_files.rb +112 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +36 -4
- data/lib/rubocop/cli/command/execute_runner.rb +52 -1
- 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 +2 -2
- data/lib/rubocop/cli/command/show_docs_url.rb +4 -8
- data/lib/rubocop/cli/command/suggest_extensions.rb +8 -2
- data/lib/rubocop/cli.rb +58 -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 +92 -48
- data/lib/rubocop/config.rb +137 -19
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +72 -49
- data/lib/rubocop/config_loader_resolver.rb +94 -28
- 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 +8 -0
- 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 +64 -12
- data/lib/rubocop/cop/autocorrect_logic.rb +35 -14
- data/lib/rubocop/cop/badge.rb +9 -1
- data/lib/rubocop/cop/base.rb +93 -21
- data/lib/rubocop/cop/bundler/gem_comment.rb +5 -3
- data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
- data/lib/rubocop/cop/bundler/ordered_gems.rb +2 -3
- data/lib/rubocop/cop/bundler.rb +19 -0
- data/lib/rubocop/cop/commissioner.rb +13 -11
- data/lib/rubocop/cop/corrector.rb +4 -4
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +79 -10
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/each_to_for_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 +7 -1
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +8 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +36 -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 +2 -3
- data/lib/rubocop/cop/exclude_limit.rb +31 -5
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- 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 -3
- 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 +14 -15
- 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 +92 -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_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/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 +4 -2
- 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 +59 -4
- data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +163 -35
- 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 +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +2 -2
- 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_between_defs.rb +46 -21
- 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 +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +13 -2
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +17 -3
- 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 +9 -3
- data/lib/rubocop/cop/layout/extra_spacing.rb +105 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +56 -3
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +18 -5
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +20 -15
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +11 -13
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +3 -3
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +33 -3
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +157 -10
- data/lib/rubocop/cop/layout/leading_comment_space.rb +40 -1
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +2 -3
- data/lib/rubocop/cop/layout/line_length.rb +160 -23
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +8 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +3 -0
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +56 -56
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +245 -40
- 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 +89 -6
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +14 -7
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +11 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +14 -3
- data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -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 +1 -0
- 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 +42 -36
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
- 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_precedence.rb +1 -10
- data/lib/rubocop/cop/lint/ambiguous_range.rb +6 -2
- 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 +20 -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/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 +137 -11
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +13 -19
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +185 -0
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +44 -22
- 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 +19 -10
- 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 +149 -39
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +53 -19
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +15 -4
- 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 +9 -5
- 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 +21 -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 +36 -10
- 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 +56 -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 +4 -1
- 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 +60 -21
- 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/collection_literal_length.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +3 -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 +3 -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 +27 -9
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -7
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- 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 +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- 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 +44 -16
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +29 -26
- 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/multiline_expression_indentation.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +62 -6
- data/lib/rubocop/cop/mixin/project_index_help.rb +188 -0
- data/lib/rubocop/cop/mixin/range_help.rb +16 -5
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +171 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +47 -11
- 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.rb +91 -0
- data/lib/rubocop/cop/naming/accessor_method_name.rb +24 -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/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} +80 -8
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -6
- 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 +52 -9
- data/lib/rubocop/cop/registry.rb +233 -64
- 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 +33 -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 +47 -13
- data/lib/rubocop/cop/style/accessor_grouping.rb +47 -10
- data/lib/rubocop/cop/style/alias.rb +15 -3
- data/lib/rubocop/cop/style/and_or.rb +2 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +49 -37
- 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 +5 -2
- 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 +7 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +43 -38
- data/lib/rubocop/cop/style/case_equality.rb +29 -15
- data/lib/rubocop/cop/style/case_like_if.rb +6 -8
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +135 -21
- data/lib/rubocop/cop/style/class_equality_comparison.rb +22 -14
- data/lib/rubocop/cop/style/class_methods_definitions.rb +11 -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 +167 -0
- data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
- data/lib/rubocop/cop/style/combinable_loops.rb +7 -2
- 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 +8 -3
- data/lib/rubocop/cop/style/conditional_assignment.rb +54 -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 +122 -14
- 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 +3 -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 +11 -2
- data/lib/rubocop/cop/style/empty_method.rb +12 -8
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +110 -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 +191 -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 +8 -1
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
- data/lib/rubocop/cop/style/explicit_block_argument.rb +16 -3
- 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 +25 -17
- data/lib/rubocop/cop/style/for.rb +9 -0
- data/lib/rubocop/cop/style/format_string.rb +17 -4
- data/lib/rubocop/cop/style/format_string_token.rb +86 -16
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
- 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 +32 -23
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
- data/lib/rubocop/cop/style/hash_conversion.rb +28 -12
- 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 +105 -0
- data/lib/rubocop/cop/style/hash_slice.rb +16 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +7 -3
- 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 +18 -9
- data/lib/rubocop/cop/style/if_inside_else.rb +25 -20
- data/lib/rubocop/cop/style/if_unless_modifier.rb +71 -46
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +15 -19
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +5 -2
- data/lib/rubocop/cop/style/if_with_semicolon.rb +16 -6
- 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 +10 -6
- 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 +121 -0
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +20 -10
- data/lib/rubocop/cop/style/lambda.rb +12 -1
- data/lib/rubocop/cop/style/lambda_call.rb +26 -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 +5 -2
- 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 +31 -15
- 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 +34 -5
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +12 -7
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
- data/lib/rubocop/cop/style/method_def_parentheses.rb +7 -5
- data/lib/rubocop/cop/style/min_max_comparison.rb +17 -6
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +40 -7
- 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 +2 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +10 -4
- data/lib/rubocop/cop/style/multiline_memoization.rb +7 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +14 -18
- data/lib/rubocop/cop/style/multiple_comparison.rb +33 -22
- data/lib/rubocop/cop/style/mutable_constant.rb +111 -12
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -2
- data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
- data/lib/rubocop/cop/style/nested_modifier.rb +9 -4
- data/lib/rubocop/cop/style/next.rb +44 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +41 -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 +5 -1
- 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 +1 -1
- 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 +22 -13
- 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 +6 -1
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +4 -0
- 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 +9 -9
- data/lib/rubocop/cop/style/reduce_to_hash.rb +200 -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 +38 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +63 -5
- 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 +11 -3
- data/lib/rubocop/cop/style/redundant_each.rb +4 -5
- data/lib/rubocop/cop/style/redundant_exception.rb +7 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +2 -10
- 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 +2 -2
- 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 +26 -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 +164 -82
- data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +8 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +8 -8
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -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 +0 -5
- data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
- 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 +32 -3
- data/lib/rubocop/cop/style/rescue_modifier.rb +5 -3
- data/lib/rubocop/cop/style/return_nil.rb +2 -2
- 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 +11 -6
- 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 +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +45 -14
- 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 +13 -8
- 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 +3 -1
- data/lib/rubocop/cop/style/static_class.rb +21 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +31 -15
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +38 -2
- data/lib/rubocop/cop/style/super_arguments.rb +4 -6
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +11 -9
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/ternary_parentheses.rb +11 -0
- 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 +18 -19
- 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 +2 -3
- data/lib/rubocop/cop/style/yoda_expression.rb +1 -1
- 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 +163 -45
- 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 +7 -3
- 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 +28 -10
- 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/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 +3 -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 +11 -6
- 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 +2 -3
- data/lib/rubocop/formatter/pacman_formatter.rb +2 -1
- data/lib/rubocop/formatter/sarif_formatter.rb +181 -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 +2 -3
- 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 +136 -33
- data/lib/rubocop/lsp/runtime.rb +23 -8
- data/lib/rubocop/lsp/server.rb +4 -2
- data/lib/rubocop/lsp/stdin_runner.rb +31 -18
- data/lib/rubocop/magic_comment.rb +55 -0
- data/lib/rubocop/mcp/server.rb +199 -0
- data/lib/rubocop/options.rb +129 -21
- data/lib/rubocop/path_util.rb +20 -5
- data/lib/rubocop/pending_cops_reporter.rb +51 -0
- data/lib/rubocop/plugin/configuration_integrator.rb +146 -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 +14 -12
- data/lib/rubocop/result_cache.rb +90 -52
- 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 +294 -100
- 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 +31 -14
- data/lib/rubocop/todo_audit.rb +111 -0
- data/lib/rubocop/unified_diff.rb +257 -0
- data/lib/rubocop/version.rb +48 -10
- data/lib/rubocop.rb +30 -682
- data/lib/ruby_lsp/rubocop/addon.rb +28 -17
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +99 -0
- metadata +116 -19
- 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
|
@@ -23,6 +23,22 @@ module RuboCop
|
|
|
23
23
|
# # good (method calls possibly can return different results)
|
|
24
24
|
# hash[foo] = hash[foo]
|
|
25
25
|
#
|
|
26
|
+
# @example AllowRBSInlineAnnotation: false (default)
|
|
27
|
+
# # bad
|
|
28
|
+
# foo = foo #: Integer
|
|
29
|
+
# foo, bar = foo, bar #: Integer
|
|
30
|
+
# Foo = Foo #: Integer
|
|
31
|
+
# hash['foo'] = hash['foo'] #: Integer
|
|
32
|
+
# obj.attr = obj.attr #: Integer
|
|
33
|
+
#
|
|
34
|
+
# @example AllowRBSInlineAnnotation: true
|
|
35
|
+
# # good
|
|
36
|
+
# foo = foo #: Integer
|
|
37
|
+
# foo, bar = foo, bar #: Integer
|
|
38
|
+
# Foo = Foo #: Integer
|
|
39
|
+
# hash['foo'] = hash['foo'] #: Integer
|
|
40
|
+
# obj.attr = obj.attr #: Integer
|
|
41
|
+
#
|
|
26
42
|
class SelfAssignment < Base
|
|
27
43
|
MSG = 'Self-assignment detected.'
|
|
28
44
|
|
|
@@ -34,8 +50,10 @@ module RuboCop
|
|
|
34
50
|
}.freeze
|
|
35
51
|
|
|
36
52
|
def on_send(node)
|
|
53
|
+
return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.receiver)
|
|
54
|
+
|
|
37
55
|
if node.method?(:[]=)
|
|
38
|
-
handle_key_assignment(node)
|
|
56
|
+
handle_key_assignment(node)
|
|
39
57
|
elsif node.assignment_method?
|
|
40
58
|
handle_attribute_assignment(node) if node.arguments.size == 1
|
|
41
59
|
end
|
|
@@ -44,6 +62,7 @@ module RuboCop
|
|
|
44
62
|
|
|
45
63
|
def on_lvasgn(node)
|
|
46
64
|
return unless node.rhs
|
|
65
|
+
return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.rhs)
|
|
47
66
|
|
|
48
67
|
rhs_type = ASSIGNMENT_TYPE_TO_RHS_TYPE[node.type]
|
|
49
68
|
|
|
@@ -55,22 +74,51 @@ module RuboCop
|
|
|
55
74
|
|
|
56
75
|
def on_casgn(node)
|
|
57
76
|
return unless node.rhs&.const_type?
|
|
77
|
+
return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.rhs)
|
|
58
78
|
|
|
59
79
|
add_offense(node) if node.namespace == node.rhs.namespace &&
|
|
60
80
|
node.short_name == node.rhs.short_name
|
|
61
81
|
end
|
|
62
82
|
|
|
63
83
|
def on_masgn(node)
|
|
84
|
+
first_lhs = node.lhs.assignments.first
|
|
85
|
+
return if allow_rbs_inline_annotation? && rbs_inline_annotation?(first_lhs)
|
|
86
|
+
|
|
64
87
|
add_offense(node) if multiple_self_assignment?(node)
|
|
65
88
|
end
|
|
66
89
|
|
|
67
90
|
def on_or_asgn(node)
|
|
68
|
-
|
|
91
|
+
return if allow_rbs_inline_annotation? && rbs_inline_annotation?(node.lhs)
|
|
92
|
+
|
|
93
|
+
add_offense(node) if or_and_asgn_self_assignment?(node.lhs, node.rhs)
|
|
69
94
|
end
|
|
70
95
|
alias on_and_asgn on_or_asgn
|
|
71
96
|
|
|
72
97
|
private
|
|
73
98
|
|
|
99
|
+
def or_and_asgn_self_assignment?(lhs, rhs)
|
|
100
|
+
case lhs.type
|
|
101
|
+
when :casgn
|
|
102
|
+
rhs.const_type? && lhs.namespace == rhs.namespace && lhs.short_name == rhs.short_name
|
|
103
|
+
when :send, :csend
|
|
104
|
+
reader_self_assignment?(lhs, rhs)
|
|
105
|
+
else
|
|
106
|
+
rhs_matches_lhs?(rhs, lhs)
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Compares two reader calls (attribute `foo.bar` or key `hash['foo']`).
|
|
111
|
+
def reader_self_assignment?(lhs, rhs)
|
|
112
|
+
return false unless rhs.type == lhs.type
|
|
113
|
+
return false unless lhs.method?(rhs.method_name)
|
|
114
|
+
return false unless lhs.receiver == rhs.receiver
|
|
115
|
+
return false unless lhs.arguments == rhs.arguments
|
|
116
|
+
|
|
117
|
+
# `hash[foo] ||= hash[foo]` is intentionally allowed because a method-call key may
|
|
118
|
+
# return different results on each call.
|
|
119
|
+
lhs.arguments.none?(&:call_type?)
|
|
120
|
+
end
|
|
121
|
+
|
|
74
122
|
def multiple_self_assignment?(node)
|
|
75
123
|
lhs = node.lhs
|
|
76
124
|
rhs = node.rhs
|
|
@@ -88,12 +136,13 @@ module RuboCop
|
|
|
88
136
|
end
|
|
89
137
|
|
|
90
138
|
def handle_key_assignment(node)
|
|
91
|
-
value_node = node.
|
|
139
|
+
value_node = node.last_argument
|
|
140
|
+
node_arguments = node.arguments[0...-1]
|
|
92
141
|
|
|
93
|
-
if value_node.
|
|
142
|
+
if value_node.respond_to?(:method?) && value_node.method?(:[]) &&
|
|
94
143
|
node.receiver == value_node.receiver &&
|
|
95
|
-
|
|
96
|
-
|
|
144
|
+
node_arguments.none?(&:call_type?) &&
|
|
145
|
+
node_arguments == value_node.arguments
|
|
97
146
|
add_offense(node)
|
|
98
147
|
end
|
|
99
148
|
end
|
|
@@ -108,6 +157,14 @@ module RuboCop
|
|
|
108
157
|
add_offense(node)
|
|
109
158
|
end
|
|
110
159
|
end
|
|
160
|
+
|
|
161
|
+
def rbs_inline_annotation?(node)
|
|
162
|
+
processed_source.ast_with_comments[node].any? { |comment| comment.text.start_with?('#:') }
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def allow_rbs_inline_annotation?
|
|
166
|
+
cop_config['AllowRBSInlineAnnotation']
|
|
167
|
+
end
|
|
111
168
|
end
|
|
112
169
|
end
|
|
113
170
|
end
|
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
|
45
45
|
# @!method send_with_mixin_argument?(node)
|
|
46
46
|
def_node_matcher :send_with_mixin_argument?, <<~PATTERN
|
|
47
47
|
(send
|
|
48
|
-
(const _ _) {:#{SEND_METHODS.join(' :')}}
|
|
48
|
+
{nil? self (const _ _)} {:#{SEND_METHODS.join(' :')}}
|
|
49
49
|
({sym str} $#mixin_method?)
|
|
50
50
|
$(const _ _)+)
|
|
51
51
|
PATTERN
|
|
@@ -125,13 +125,13 @@ module RuboCop
|
|
|
125
125
|
next false if assignment_node.shorthand_asgn?
|
|
126
126
|
next false unless assignment_node.parent
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
conditional_assignment =
|
|
129
|
+
conditional_assignment?(assignment_node.parent, argument.scope.node)
|
|
130
130
|
|
|
131
131
|
unless uses_var?(assignment_node, argument.name)
|
|
132
132
|
# It's impossible to decide whether a branch or block is executed,
|
|
133
133
|
# so the precise reassignment location is undecidable.
|
|
134
|
-
next false if
|
|
134
|
+
next false if conditional_assignment
|
|
135
135
|
|
|
136
136
|
yield(assignment.node, location_known)
|
|
137
137
|
break
|
|
@@ -147,13 +147,13 @@ module RuboCop
|
|
|
147
147
|
node.source_range.begin_pos
|
|
148
148
|
end
|
|
149
149
|
|
|
150
|
-
# Check whether the given node is
|
|
150
|
+
# Check whether the given node is always executed or not
|
|
151
151
|
#
|
|
152
|
-
def
|
|
152
|
+
def conditional_assignment?(node, stop_search_node)
|
|
153
153
|
return false if node == stop_search_node
|
|
154
154
|
|
|
155
|
-
node.conditional? || node.
|
|
156
|
-
|
|
155
|
+
node.conditional? || node.type?(:block, :rescue) ||
|
|
156
|
+
conditional_assignment?(node.parent, stop_search_node)
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
# Get argument references without assignments' references
|
|
@@ -8,6 +8,11 @@ module RuboCop
|
|
|
8
8
|
# given by `ruby -cw` prior to Ruby 2.6:
|
|
9
9
|
# "shadowing outer local variable - foo".
|
|
10
10
|
#
|
|
11
|
+
# The cop is now disabled by default to match the upstream Ruby behavior.
|
|
12
|
+
# It's useful, however, if you'd like to avoid shadowing variables from outer
|
|
13
|
+
# scopes, which some people consider an anti-pattern that makes it harder
|
|
14
|
+
# to keep track of what's going on in a program.
|
|
15
|
+
#
|
|
11
16
|
# NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
|
|
12
17
|
# because `Ractor` should not access outer variables.
|
|
13
18
|
# eg. following style is encouraged:
|
|
@@ -56,19 +61,28 @@ module RuboCop
|
|
|
56
61
|
|
|
57
62
|
outer_local_variable = variable_table.find_variable(variable.name)
|
|
58
63
|
return unless outer_local_variable
|
|
64
|
+
return if variable_used_in_declaration_of_outer?(variable, outer_local_variable)
|
|
59
65
|
return if same_conditions_node_different_branch?(variable, outer_local_variable)
|
|
60
66
|
|
|
61
67
|
message = format(MSG, variable: variable.name)
|
|
62
68
|
add_offense(variable.declaration_node, message: message)
|
|
63
69
|
end
|
|
64
70
|
|
|
71
|
+
private
|
|
72
|
+
|
|
73
|
+
def variable_used_in_declaration_of_outer?(variable, outer_local_variable)
|
|
74
|
+
variable.scope.node.each_ancestor.any?(outer_local_variable.declaration_node)
|
|
75
|
+
end
|
|
76
|
+
|
|
65
77
|
def same_conditions_node_different_branch?(variable, outer_local_variable)
|
|
78
|
+
return true if different_case_in_branch?(variable, outer_local_variable)
|
|
79
|
+
|
|
66
80
|
variable_node = variable_node(variable)
|
|
67
81
|
return false unless node_or_its_ascendant_conditional?(variable_node)
|
|
68
82
|
|
|
69
83
|
outer_local_variable_node =
|
|
70
84
|
find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
|
|
71
|
-
return
|
|
85
|
+
return false unless outer_local_variable_node
|
|
72
86
|
return false unless outer_local_variable_node.conditional?
|
|
73
87
|
return true if variable_node == outer_local_variable_node
|
|
74
88
|
|
|
@@ -76,6 +90,18 @@ module RuboCop
|
|
|
76
90
|
variable_node == outer_local_variable_node.else_branch
|
|
77
91
|
end
|
|
78
92
|
|
|
93
|
+
# `case ... in` binds variables in the pattern itself, so a block argument in one
|
|
94
|
+
# `in` branch does not shadow a pattern variable from a different `in` branch of the
|
|
95
|
+
# same `case` (the branches are mutually exclusive).
|
|
96
|
+
def different_case_in_branch?(variable, outer_local_variable)
|
|
97
|
+
inner_branch = variable.scope.node.each_ancestor(:in_pattern).first
|
|
98
|
+
outer_branch = outer_local_variable.declaration_node.each_ancestor(:in_pattern).first
|
|
99
|
+
|
|
100
|
+
return false unless inner_branch && outer_branch
|
|
101
|
+
|
|
102
|
+
inner_branch != outer_branch && inner_branch.parent == outer_branch.parent
|
|
103
|
+
end
|
|
104
|
+
|
|
79
105
|
def variable_node(variable)
|
|
80
106
|
parent_node = variable.scope.node.parent
|
|
81
107
|
|
|
@@ -51,7 +51,20 @@ module RuboCop
|
|
|
51
51
|
|
|
52
52
|
# @!method hash_initialized_with_mutable_shared_object?(node)
|
|
53
53
|
def_node_matcher :hash_initialized_with_mutable_shared_object?, <<~PATTERN
|
|
54
|
-
|
|
54
|
+
{
|
|
55
|
+
(send (const {nil? cbase} :Hash) :new [
|
|
56
|
+
{array hash (send (const {nil? cbase} {:Array :Hash}) :new)}
|
|
57
|
+
!#capacity_keyword_argument?
|
|
58
|
+
])
|
|
59
|
+
(send (const {nil? cbase} :Hash) :new
|
|
60
|
+
{array hash (send (const {nil? cbase} {:Array :Hash}) :new)}
|
|
61
|
+
#capacity_keyword_argument?)
|
|
62
|
+
}
|
|
63
|
+
PATTERN
|
|
64
|
+
|
|
65
|
+
# @!method capacity_keyword_argument?(node)
|
|
66
|
+
def_node_matcher :capacity_keyword_argument?, <<~PATTERN
|
|
67
|
+
(hash (pair (sym :capacity) _))
|
|
55
68
|
PATTERN
|
|
56
69
|
|
|
57
70
|
def on_send(node)
|
|
@@ -26,7 +26,23 @@ module RuboCop
|
|
|
26
26
|
'and it may be unexpected.'
|
|
27
27
|
RESTRICT_ON_SEND = %i[new].freeze
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
# This is based on `Struct.instance_methods.sort` in Ruby 4.0.0.
|
|
30
|
+
STRUCT_METHOD_NAMES = %i[
|
|
31
|
+
! != !~ <=> == === [] []= __id__ __send__ all? any? chain chunk chunk_while class clone
|
|
32
|
+
collect collect_concat compact count cycle deconstruct deconstruct_keys
|
|
33
|
+
define_singleton_method detect dig display drop drop_while dup each each_cons each_entry
|
|
34
|
+
each_pair each_slice each_with_index each_with_object entries enum_for eql? equal? extend
|
|
35
|
+
filter filter_map find find_all find_index first flat_map freeze frozen? grep grep_v
|
|
36
|
+
group_by hash include? inject inspect instance_eval instance_exec instance_of?
|
|
37
|
+
instance_variable_defined? instance_variable_get instance_variable_set instance_variables
|
|
38
|
+
is_a? itself kind_of? lazy length map max max_by member? members method methods
|
|
39
|
+
min min_by minmax minmax_by nil? none? object_id one? partition private_methods
|
|
40
|
+
protected_methods public_method public_methods public_send reduce reject
|
|
41
|
+
remove_instance_variable respond_to? reverse_each select send singleton_class
|
|
42
|
+
singleton_method singleton_methods size slice_after slice_before slice_when sort sort_by
|
|
43
|
+
sum take take_while tally tap then to_a to_enum to_h to_s to_set uniq values values_at
|
|
44
|
+
yield_self zip
|
|
45
|
+
].freeze
|
|
30
46
|
STRUCT_MEMBER_NAME_TYPES = %i[sym str].freeze
|
|
31
47
|
|
|
32
48
|
# @!method struct_new(node)
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks for `super` calls with explicit arguments that pass the wrong
|
|
7
|
+
# number of positional arguments to the overridden implementation, using
|
|
8
|
+
# the project index.
|
|
9
|
+
#
|
|
10
|
+
# The check is powered by the project-wide index, so it only runs when
|
|
11
|
+
# `AllCops/UseProjectIndex` is enabled and the `rubydex` gem is installed.
|
|
12
|
+
# Without the index the cop does nothing.
|
|
13
|
+
#
|
|
14
|
+
# Only `super` inside a plain instance method defined directly in a class
|
|
15
|
+
# body is considered, and only when the enclosing class resolves in the
|
|
16
|
+
# index and its entire ancestry is resolved, so a superclass method coming
|
|
17
|
+
# from a gem, the standard library, or a dynamic definition never produces
|
|
18
|
+
# an offense. The overridden implementation is the first ancestor after
|
|
19
|
+
# the enclosing class in the index's method resolution order that defines
|
|
20
|
+
# the method; when it is not a plain method definition (an `attr_*` or an
|
|
21
|
+
# alias) or its definitions disagree on arity, the call is not checked.
|
|
22
|
+
# Calls that forward arguments (`*`, `**`, `...`) are skipped, and bare
|
|
23
|
+
# `super` (which forwards the current method's parameters) is not checked.
|
|
24
|
+
# Methods the index attributes to `Object`, `Kernel`, or `BasicObject`
|
|
25
|
+
# are never used as the overridden implementation, since a `def` inside
|
|
26
|
+
# a block at the top level (`Struct.new do ... end`) is indexed under
|
|
27
|
+
# `Object` even though it defines a method somewhere else entirely.
|
|
28
|
+
#
|
|
29
|
+
# @example
|
|
30
|
+
# # Given the project defines:
|
|
31
|
+
# # class Base
|
|
32
|
+
# # def initialize(name, size); end
|
|
33
|
+
# # end
|
|
34
|
+
#
|
|
35
|
+
# # bad
|
|
36
|
+
# class Widget < Base
|
|
37
|
+
# def initialize(name)
|
|
38
|
+
# super(name)
|
|
39
|
+
# end
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# # good
|
|
43
|
+
# class Widget < Base
|
|
44
|
+
# def initialize(name)
|
|
45
|
+
# super(name, 0)
|
|
46
|
+
# end
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
class SuperArgumentMismatch < Base
|
|
50
|
+
include ProjectIndexHelp
|
|
51
|
+
include IndexedMethodArity
|
|
52
|
+
|
|
53
|
+
MSG = 'Wrong number of arguments to `super` ' \
|
|
54
|
+
'(given %<given>d, expected %<expected>s for `%<parent>s#%<method>s`).'
|
|
55
|
+
|
|
56
|
+
# Blocks that change what method (or scope) `super` refers to, or in
|
|
57
|
+
# which `super` is not statically resolvable.
|
|
58
|
+
CONTEXT_CHANGING_BLOCKS = %i[
|
|
59
|
+
define_method define_singleton_method class_eval class_exec
|
|
60
|
+
module_eval module_exec instance_eval instance_exec refine
|
|
61
|
+
].freeze
|
|
62
|
+
|
|
63
|
+
# Methods the index attributes to the root namespaces are not
|
|
64
|
+
# trustworthy super targets: a `def` inside a block at the top level
|
|
65
|
+
# (`Struct.new do ... end`, `Class.new do ... end`) is indexed under
|
|
66
|
+
# `Object` even though it defines a method somewhere else entirely.
|
|
67
|
+
BUILTIN_ROOTS = %w[Object Kernel BasicObject].freeze
|
|
68
|
+
|
|
69
|
+
def on_super(node)
|
|
70
|
+
return unless project_index
|
|
71
|
+
|
|
72
|
+
def_node = enclosing_instance_method(node)
|
|
73
|
+
return unless def_node
|
|
74
|
+
|
|
75
|
+
shape, parent = resolved_super_shape(def_node)
|
|
76
|
+
return unless shape
|
|
77
|
+
|
|
78
|
+
min, max, has_keywords = shape
|
|
79
|
+
given = positional_argument_count(node, has_keywords)
|
|
80
|
+
return if given.nil? || arity_satisfied?(given, min, max)
|
|
81
|
+
|
|
82
|
+
add_offense(node.loc.keyword,
|
|
83
|
+
message: message(def_node.method_name, parent, given, min, max))
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
private
|
|
87
|
+
|
|
88
|
+
def message(method_name, parent, given, min, max)
|
|
89
|
+
format(MSG, given: given, expected: expected_range(min, max),
|
|
90
|
+
parent: parent.name, method: method_name)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The `def` node whose method the `super` call re-dispatches, or nil
|
|
94
|
+
# when the context is not statically known: `super` inside a
|
|
95
|
+
# singleton method, inside `define_method` or an eval/refine block,
|
|
96
|
+
# or outside any method.
|
|
97
|
+
def enclosing_instance_method(node)
|
|
98
|
+
node.each_ancestor(:any_def, :any_block, :sclass).each do |ancestor|
|
|
99
|
+
case ancestor.type
|
|
100
|
+
when :def then return ancestor
|
|
101
|
+
when :defs, :sclass then return nil
|
|
102
|
+
else
|
|
103
|
+
return nil if CONTEXT_CHANGING_BLOCKS.include?(ancestor.method_name)
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
nil
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# `[[min, max, has_keywords], parent]` for the implementation `super`
|
|
111
|
+
# dispatches to, or nil when the enclosing class or the overridden
|
|
112
|
+
# method is not statically known.
|
|
113
|
+
def resolved_super_shape(def_node)
|
|
114
|
+
declaration = enclosing_class_declaration(def_node)
|
|
115
|
+
return nil unless declaration
|
|
116
|
+
return nil unless fully_resolved_index_ancestry?(declaration, ignore_extend: true)
|
|
117
|
+
|
|
118
|
+
super_method_shape(declaration, def_node.method_name)
|
|
119
|
+
rescue StandardError
|
|
120
|
+
nil
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# The index declaration of the class whose body directly contains
|
|
124
|
+
# `def_node`, or nil when the method is not defined directly in a
|
|
125
|
+
# class body (module methods are excluded because their `super`
|
|
126
|
+
# target depends on where the module is mixed in) or the class does
|
|
127
|
+
# not resolve in the index.
|
|
128
|
+
def enclosing_class_declaration(def_node)
|
|
129
|
+
class_node = def_node.each_ancestor(:class, :module, :sclass, :any_block).first
|
|
130
|
+
return nil unless class_node&.class_type?
|
|
131
|
+
|
|
132
|
+
declaration = project_index[lexical_nesting_of(def_node).join('::')]
|
|
133
|
+
return nil unless declaration.is_a?(Rubydex::Namespace)
|
|
134
|
+
return nil unless declared_at?(declaration, class_node)
|
|
135
|
+
|
|
136
|
+
declaration
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Whether one of the declaration's definitions is the given class
|
|
140
|
+
# node, anchoring the name-based lookup to the source being
|
|
141
|
+
# inspected (a qualified identifier like `class Foo::Bar` can
|
|
142
|
+
# resolve to a namespace other than the joined nesting names).
|
|
143
|
+
def declared_at?(declaration, class_node)
|
|
144
|
+
declaration.definitions.any? do |definition|
|
|
145
|
+
location = definition.location
|
|
146
|
+
location.uri.start_with?(FILE_URI_PREFIX) &&
|
|
147
|
+
location.to_display.start_line == class_node.first_line &&
|
|
148
|
+
same_file?(location.to_file_path, processed_source.file_path)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# The shape of the first implementation of `method_name` after the
|
|
153
|
+
# enclosing class in the index's method resolution order, or nil
|
|
154
|
+
# when no indexed ancestor defines it (e.g. it comes from a gem or
|
|
155
|
+
# the standard library, which are not indexed).
|
|
156
|
+
def super_method_shape(declaration, method_name)
|
|
157
|
+
ancestors = declaration.ancestors.to_a
|
|
158
|
+
position = ancestors.index { |ancestor| ancestor.name == declaration.name }
|
|
159
|
+
return nil unless position
|
|
160
|
+
|
|
161
|
+
ancestors.drop(position + 1).each do |ancestor|
|
|
162
|
+
return nil if BUILTIN_ROOTS.include?(ancestor.name)
|
|
163
|
+
|
|
164
|
+
member = ancestor.member("#{method_name}()")
|
|
165
|
+
next unless member
|
|
166
|
+
|
|
167
|
+
# The first definer along the chain is the receiving
|
|
168
|
+
# implementation; when its shape is unknown there is nothing
|
|
169
|
+
# further to check.
|
|
170
|
+
shape = indexed_member_shape(member)
|
|
171
|
+
return shape && [shape, ancestor]
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
nil
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
179
|
+
end
|
|
@@ -116,7 +116,7 @@ module RuboCop
|
|
|
116
116
|
private
|
|
117
117
|
|
|
118
118
|
def comment_between_rescue_and_end?(node)
|
|
119
|
-
ancestor = node.each_ancestor(:kwbegin, :
|
|
119
|
+
ancestor = node.each_ancestor(:kwbegin, :any_def, :any_block).first
|
|
120
120
|
return false unless ancestor
|
|
121
121
|
|
|
122
122
|
end_line = ancestor.loc.end&.line || ancestor.loc.last_line
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Lint
|
|
6
|
+
# Checks for cases where exceptions unrelated to the numeric constructors `Integer()`,
|
|
7
|
+
# `Float()`, `BigDecimal()`, `Complex()`, and `Rational()` may be unintentionally swallowed.
|
|
8
|
+
#
|
|
9
|
+
# @safety
|
|
10
|
+
# The cop is unsafe for autocorrection because unexpected errors occurring in the argument
|
|
11
|
+
# passed to numeric constructor (e.g., `Integer()`) can lead to incompatible behavior.
|
|
12
|
+
# For example, changing it to `Integer(potential_exception_method_call, exception: false)`
|
|
13
|
+
# ensures that exceptions raised by `potential_exception_method_call` are not ignored.
|
|
14
|
+
#
|
|
15
|
+
# [source,ruby]
|
|
16
|
+
# ----
|
|
17
|
+
# Integer(potential_exception_method_call) rescue nil
|
|
18
|
+
# ----
|
|
19
|
+
#
|
|
20
|
+
# @example
|
|
21
|
+
#
|
|
22
|
+
# # bad
|
|
23
|
+
# Integer(arg) rescue nil
|
|
24
|
+
#
|
|
25
|
+
# # bad
|
|
26
|
+
# begin
|
|
27
|
+
# Integer(arg)
|
|
28
|
+
# rescue
|
|
29
|
+
# nil
|
|
30
|
+
# end
|
|
31
|
+
#
|
|
32
|
+
# # bad
|
|
33
|
+
# begin
|
|
34
|
+
# Integer(arg)
|
|
35
|
+
# rescue
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# # good
|
|
39
|
+
# Integer(arg, exception: false)
|
|
40
|
+
#
|
|
41
|
+
class SuppressedExceptionInNumberConversion < Base
|
|
42
|
+
extend AutoCorrector
|
|
43
|
+
extend TargetRubyVersion
|
|
44
|
+
|
|
45
|
+
MSG = 'Use `%<prefer>s` instead.'
|
|
46
|
+
EXPECTED_EXCEPTION_CLASSES = %w[ArgumentError TypeError ::ArgumentError ::TypeError].freeze
|
|
47
|
+
|
|
48
|
+
# @!method numeric_constructor_rescue_nil(node)
|
|
49
|
+
def_node_matcher :numeric_constructor_rescue_nil, <<~PATTERN
|
|
50
|
+
(rescue
|
|
51
|
+
$#numeric_method?
|
|
52
|
+
(resbody nil? nil? (nil)) nil?)
|
|
53
|
+
PATTERN
|
|
54
|
+
|
|
55
|
+
# @!method begin_numeric_constructor_rescue_nil(node)
|
|
56
|
+
def_node_matcher :begin_numeric_constructor_rescue_nil, <<~PATTERN
|
|
57
|
+
(kwbegin
|
|
58
|
+
(rescue
|
|
59
|
+
$#numeric_method?
|
|
60
|
+
(resbody $_? nil?
|
|
61
|
+
{(nil) nil?}) nil?))
|
|
62
|
+
PATTERN
|
|
63
|
+
|
|
64
|
+
# @!method numeric_method?(node)
|
|
65
|
+
def_node_matcher :numeric_method?, <<~PATTERN
|
|
66
|
+
{
|
|
67
|
+
(call #constructor_receiver? {:Integer :BigDecimal :Complex :Rational}
|
|
68
|
+
_ _?)
|
|
69
|
+
(call #constructor_receiver? :Float
|
|
70
|
+
_)
|
|
71
|
+
}
|
|
72
|
+
PATTERN
|
|
73
|
+
|
|
74
|
+
# @!method constructor_receiver?(node)
|
|
75
|
+
def_node_matcher :constructor_receiver?, <<~PATTERN
|
|
76
|
+
{nil? (const {nil? cbase} :Kernel)}
|
|
77
|
+
PATTERN
|
|
78
|
+
|
|
79
|
+
minimum_target_ruby_version 2.6
|
|
80
|
+
|
|
81
|
+
# rubocop:disable-next Metrics/AbcSize
|
|
82
|
+
def on_rescue(node)
|
|
83
|
+
if (method, exception_classes = begin_numeric_constructor_rescue_nil(node.parent))
|
|
84
|
+
return unless expected_exception_classes_only?(exception_classes)
|
|
85
|
+
|
|
86
|
+
node = node.parent
|
|
87
|
+
else
|
|
88
|
+
return unless (method = numeric_constructor_rescue_nil(node))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# `Integer(arg, exception: false)` already suppresses the conversion error, so there
|
|
92
|
+
# is nothing unintentionally swallowed; adding another `exception: false` is wrong.
|
|
93
|
+
return if exception_keyword_argument?(method)
|
|
94
|
+
|
|
95
|
+
arguments = method.arguments.map(&:source) << 'exception: false'
|
|
96
|
+
prefer = "#{method.method_name}(#{arguments.join(', ')})"
|
|
97
|
+
prefer = "#{method.receiver.source}#{method.loc.dot.source}#{prefer}" if method.receiver
|
|
98
|
+
|
|
99
|
+
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
|
100
|
+
corrector.replace(node, prefer)
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
private
|
|
105
|
+
|
|
106
|
+
def exception_keyword_argument?(method)
|
|
107
|
+
method.arguments.any? do |argument|
|
|
108
|
+
argument.hash_type? && argument.pairs.any? do |pair|
|
|
109
|
+
pair.key.sym_type? && pair.key.value == :exception
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def expected_exception_classes_only?(exception_classes)
|
|
115
|
+
return true unless (arguments = exception_classes.first)
|
|
116
|
+
|
|
117
|
+
(arguments.values.map(&:source) - EXPECTED_EXCEPTION_CLASSES).none?
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -77,11 +77,28 @@ module RuboCop
|
|
|
77
77
|
|
|
78
78
|
def on_send(node)
|
|
79
79
|
return unless node.receiver
|
|
80
|
+
return unless (correction = symbol_conversion_correction(node.receiver))
|
|
80
81
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
register_offense(node, correction: correction)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def symbol_conversion_correction(receiver)
|
|
86
|
+
if receiver.type?(:str, :sym)
|
|
87
|
+
receiver.value.to_sym.inspect
|
|
88
|
+
elsif receiver.dstr_type? && !receiver.heredoc?
|
|
89
|
+
dstr_correction(receiver)
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# Reuse the already-escaped inner source for a plain `"..."` string so embedded
|
|
94
|
+
# quotes stay escaped. Percent literals (`%{}`, `%Q{}`, ...) and adjacent string
|
|
95
|
+
# concatenation have multi-character or no delimiters, so slicing the source would
|
|
96
|
+
# corrupt them; fall back to the node's value there.
|
|
97
|
+
def dstr_correction(receiver)
|
|
98
|
+
if receiver.loc.begin&.source == '"'
|
|
99
|
+
":\"#{receiver.source[1..-2]}\""
|
|
100
|
+
else
|
|
101
|
+
":\"#{receiver.value.to_sym}\""
|
|
85
102
|
end
|
|
86
103
|
end
|
|
87
104
|
|
|
@@ -26,7 +26,31 @@ module RuboCop
|
|
|
26
26
|
"#{diagnostic.message}\n(Using Ruby #{ruby_version} parser; " \
|
|
27
27
|
'configure using `TargetRubyVersion` parameter, under `AllCops`)'
|
|
28
28
|
end
|
|
29
|
-
|
|
29
|
+
location = diagnostic_location(diagnostic.location)
|
|
30
|
+
add_offense(location, message: message, severity: diagnostic.level)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Expand zero-length diagnostic ranges so that editors and formatters
|
|
34
|
+
# can display them. This typically occurs when the parser reports
|
|
35
|
+
# `unexpected token $end` at EOF.
|
|
36
|
+
def diagnostic_location(location)
|
|
37
|
+
return location if location.size.positive?
|
|
38
|
+
|
|
39
|
+
source_buffer = location.source_buffer
|
|
40
|
+
if location.end_pos < source_buffer.source.size
|
|
41
|
+
location.resize(1)
|
|
42
|
+
elsif location.begin_pos.positive?
|
|
43
|
+
location.adjust(begin_pos: -1)
|
|
44
|
+
else
|
|
45
|
+
location
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Override to skip multiline_ranges check which requires AST.
|
|
50
|
+
# Syntax errors mean the AST is nil, so we go directly to
|
|
51
|
+
# the EOL comment insertion path.
|
|
52
|
+
def disable_offense(offense_range)
|
|
53
|
+
disable_offense_with_eol_or_surround_comment(offense_range)
|
|
30
54
|
end
|
|
31
55
|
|
|
32
56
|
def add_offense_from_error(error)
|