rubocop 1.81.7 → 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 +2 -2
- data/config/default.yml +626 -111
- data/config/obsoletion.yml +39 -1
- data/exe/rubocop +1 -1
- 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 +34 -2
- 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 +1 -1
- data/lib/rubocop/cli.rb +41 -14
- 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 +97 -44
- data/lib/rubocop/config.rb +100 -15
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +49 -27
- data/lib/rubocop/config_loader_resolver.rb +95 -20
- data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_store.rb +2 -2
- data/lib/rubocop/config_validator.rb +69 -7
- data/lib/rubocop/cop/autocorrect_logic.rb +24 -6
- 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 +1 -10
- 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 +87 -9
- 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/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 +70 -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/dependency_version.rb +0 -6
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +14 -4
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -8
- data/lib/rubocop/cop/gemspec/require_mfa.rb +9 -6
- 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_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 +28 -2
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +12 -16
- 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_type_group.rb +0 -7
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
- 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/useless_message_assertion.rb +4 -4
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- 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 +84 -4
- data/lib/rubocop/cop/layout/case_indentation.rb +28 -10
- data/lib/rubocop/cop/layout/class_structure.rb +156 -41
- 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 +4 -0
- data/lib/rubocop/cop/layout/dot_position.rb +26 -16
- data/lib/rubocop/cop/layout/else_alignment.rb +2 -14
- data/lib/rubocop/cop/layout/empty_comment.rb +8 -10
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +25 -7
- 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 +15 -2
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +2 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +21 -5
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- 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 +81 -2
- 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 +16 -11
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +8 -4
- 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 +158 -12
- data/lib/rubocop/cop/layout/leading_comment_space.rb +27 -0
- 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 +265 -29
- 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 +10 -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 +268 -38
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +102 -2
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +19 -5
- 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 +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
- data/lib/rubocop/cop/layout/space_around_keyword.rb +14 -2
- data/lib/rubocop/cop/layout/space_around_operators.rb +18 -3
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +1 -1
- data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +9 -8
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +44 -34
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
- data/lib/rubocop/cop/layout/space_inside_reference_brackets.rb +2 -12
- 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 +1 -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/assignment_in_condition.rb +15 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +45 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- 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 +165 -15
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/debugger.rb +13 -2
- data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
- 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 +405 -28
- 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 +9 -2
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -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 -2
- data/lib/rubocop/cop/lint/float_comparison.rb +2 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
- 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 +36 -9
- 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 +46 -18
- data/lib/rubocop/cop/lint/missing_super.rb +31 -1
- 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 +1 -1
- 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 +1 -1
- 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 +10 -0
- 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 +1 -1
- 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_require_statement.rb +5 -4
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +37 -14
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +13 -4
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +11 -5
- data/lib/rubocop/cop/lint/redundant_with_index.rb +2 -3
- data/lib/rubocop/cop/lint/redundant_with_object.rb +5 -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 +2 -1
- data/lib/rubocop/cop/lint/require_relative_self_path.rb +7 -5
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +24 -0
- 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 +33 -2
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -1
- data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +14 -0
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +3 -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_in_number_conversion.rb +13 -2
- 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 +72 -4
- 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/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +15 -9
- 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/useless_access_modifier.rb +1 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +61 -27
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +40 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
- data/lib/rubocop/cop/lint/useless_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +10 -10
- data/lib/rubocop/cop/lint/useless_or.rb +15 -2
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +10 -4
- 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 +94 -14
- data/lib/rubocop/cop/lint/void.rb +59 -22
- data/lib/rubocop/cop/lint.rb +179 -0
- data/lib/rubocop/cop/metrics/block_length.rb +1 -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 +2 -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 +1 -1
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- 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 +5 -1
- data/lib/rubocop/cop/mixin/allowed_methods.rb +5 -5
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +47 -25
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +12 -8
- data/lib/rubocop/cop/mixin/code_length.rb +10 -2
- data/lib/rubocop/cop/mixin/comments_help.rb +1 -2
- 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/empty_lines_around_body.rb +12 -1
- 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 +2 -2
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +5 -1
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +58 -12
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +37 -10
- data/lib/rubocop/cop/mixin/hash_subset.rb +9 -2
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +14 -60
- data/lib/rubocop/cop/mixin/indexed_method_arity.rb +94 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +28 -3
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -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 +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +10 -1
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +79 -8
- data/lib/rubocop/cop/mixin/project_index_help.rb +203 -0
- data/lib/rubocop/cop/mixin/range_help.rb +1 -2
- 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/trailing_comma.rb +7 -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 +4 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +4 -3
- 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 +12 -5
- data/lib/rubocop/cop/naming/method_name.rb +6 -3
- data/lib/rubocop/cop/naming/predicate_method.rb +13 -2
- data/lib/rubocop/cop/naming/predicate_prefix.rb +30 -17
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +12 -7
- 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 +232 -66
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/security/io_methods.rb +2 -2
- data/lib/rubocop/cop/security/json_load.rb +16 -4
- data/lib/rubocop/cop/security/marshal_load.rb +1 -1
- 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 +55 -8
- data/lib/rubocop/cop/style/accessor_grouping.rb +16 -5
- 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 +61 -17
- data/lib/rubocop/cop/style/array_first_last.rb +13 -3
- data/lib/rubocop/cop/style/array_intersect.rb +28 -5
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +3 -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 +7 -6
- data/lib/rubocop/cop/style/block_delimiters.rb +74 -38
- data/lib/rubocop/cop/style/case_equality.rb +29 -15
- data/lib/rubocop/cop/style/case_like_if.rb +11 -10
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +151 -35
- data/lib/rubocop/cop/style/class_equality_comparison.rb +21 -13
- 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_querying.rb +79 -46
- data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
- data/lib/rubocop/cop/style/combinable_loops.rb +91 -9
- 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 +34 -18
- data/lib/rubocop/cop/style/constant_visibility.rb +13 -7
- data/lib/rubocop/cop/style/copyright.rb +27 -12
- data/lib/rubocop/cop/style/data_inheritance.rb +18 -0
- data/lib/rubocop/cop/style/date_time.rb +4 -4
- data/lib/rubocop/cop/style/def_with_parentheses.rb +6 -2
- data/lib/rubocop/cop/style/dig_chain.rb +5 -0
- 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 +11 -0
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/each_with_object.rb +2 -0
- 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 +8 -3
- data/lib/rubocop/cop/style/empty_method.rb +15 -9
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +74 -22
- 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 +100 -21
- data/lib/rubocop/cop/style/env_home.rb +4 -0
- 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/explicit_block_argument.rb +50 -10
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- 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 +28 -14
- data/lib/rubocop/cop/style/for.rb +60 -1
- data/lib/rubocop/cop/style/format_string.rb +44 -9
- data/lib/rubocop/cop/style/format_string_token.rb +50 -7
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +57 -40
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +31 -9
- data/lib/rubocop/cop/style/hash_conversion.rb +39 -11
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -2
- 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 +19 -5
- data/lib/rubocop/cop/style/hash_transform_keys.rb +17 -7
- data/lib/rubocop/cop/style/hash_transform_values.rb +17 -7
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +38 -10
- data/lib/rubocop/cop/style/if_inside_else.rb +36 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +80 -76
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +17 -14
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +61 -8
- data/lib/rubocop/cop/style/inline_comment.rb +5 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +25 -5
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +94 -4
- data/lib/rubocop/cop/style/keyword_arguments_merging.rb +4 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +10 -4
- data/lib/rubocop/cop/style/lambda.rb +45 -2
- data/lib/rubocop/cop/style/lambda_call.rb +24 -8
- 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 +2 -3
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- data/lib/rubocop/cop/style/map_to_hash.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +102 -20
- 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 +42 -6
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +36 -8
- data/lib/rubocop/cop/style/method_def_parentheses.rb +36 -8
- data/lib/rubocop/cop/style/min_max_comparison.rb +4 -1
- 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_if_modifier.rb +45 -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 +14 -13
- 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 +24 -10
- data/lib/rubocop/cop/style/nil_comparison.rb +50 -12
- 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/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +18 -6
- 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 +26 -7
- 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/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 +3 -2
- data/lib/rubocop/cop/style/raise_args.rb +20 -10
- 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_assignment.rb +12 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +25 -7
- data/lib/rubocop/cop/style/redundant_condition.rb +41 -23
- data/lib/rubocop/cop/style/redundant_constant_base.rb +42 -6
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +13 -1
- 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 +21 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
- 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 +43 -7
- data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
- data/lib/rubocop/cop/style/redundant_heredoc_delimiter_quotes.rb +6 -1
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +49 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +82 -115
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +105 -83
- data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +13 -2
- 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 +12 -4
- data/lib/rubocop/cop/style/redundant_return.rb +4 -3
- data/lib/rubocop/cop/style/redundant_self.rb +11 -2
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -2
- 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_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 +106 -28
- data/lib/rubocop/cop/style/require_order.rb +25 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +15 -14
- data/lib/rubocop/cop/style/return_nil.rb +17 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +18 -9
- 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 +52 -23
- data/lib/rubocop/cop/style/self_assignment.rb +13 -16
- data/lib/rubocop/cop/style/semicolon.rb +39 -13
- 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 +19 -7
- data/lib/rubocop/cop/style/single_line_methods.rb +24 -5
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +25 -7
- data/lib/rubocop/cop/style/special_global_vars.rb +7 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +31 -5
- data/lib/rubocop/cop/style/static_class.rb +21 -0
- data/lib/rubocop/cop/style/string_concatenation.rb +25 -6
- data/lib/rubocop/cop/style/string_hash_keys.rb +1 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +36 -1
- data/lib/rubocop/cop/style/super_arguments.rb +6 -4
- data/lib/rubocop/cop/style/symbol_proc.rb +32 -14
- 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 +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- 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 +1 -1
- 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 -0
- 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 +171 -48
- data/lib/rubocop/cop/util.rb +5 -8
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/branch.rb +30 -6
- data/lib/rubocop/cop/variable_force/variable.rb +33 -9
- data/lib/rubocop/cops_documentation_generator.rb +27 -9
- data/lib/rubocop/directive_comment.rb +116 -7
- 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 +39 -10
- data/lib/rubocop/formatter/emacs_style_formatter.rb +3 -1
- data/lib/rubocop/formatter/formatter_set.rb +7 -2
- data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
- data/lib/rubocop/formatter/html_formatter.rb +2 -4
- data/lib/rubocop/formatter/json_formatter.rb +82 -7
- data/lib/rubocop/formatter/junit_formatter.rb +27 -10
- data/lib/rubocop/formatter/offense_count_formatter.rb +4 -3
- data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
- 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 -42
- data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
- data/lib/rubocop/lsp/routes.rb +130 -83
- data/lib/rubocop/lsp/runtime.rb +64 -15
- data/lib/rubocop/lsp/server.rb +6 -2
- data/lib/rubocop/lsp/stdin_runner.rb +35 -2
- data/lib/rubocop/lsp.rb +5 -2
- data/lib/rubocop/magic_comment.rb +47 -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 +141 -13
- data/lib/rubocop/path_util.rb +16 -5
- data/lib/rubocop/pending_cops_reporter.rb +1 -6
- data/lib/rubocop/plugin/configuration_integrator.rb +13 -3
- data/lib/rubocop/plugin/loader.rb +2 -2
- data/lib/rubocop/project_index_loader.rb +82 -0
- data/lib/rubocop/rake_task.rb +2 -3
- data/lib/rubocop/remote_config.rb +18 -13
- data/lib/rubocop/result_cache.rb +102 -59
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/expect_offense.rb +2 -4
- data/lib/rubocop/rspec/shared_contexts.rb +53 -5
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +362 -106
- data/lib/rubocop/server/cache.rb +21 -40
- data/lib/rubocop/server/cli.rb +2 -4
- data/lib/rubocop/server/core.rb +8 -0
- data/lib/rubocop/server.rb +14 -0
- data/lib/rubocop/target_finder.rb +18 -8
- data/lib/rubocop/target_ruby.rb +42 -22
- 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 +23 -7
- data/lib/rubocop.rb +34 -701
- data/lib/ruby_lsp/rubocop/addon.rb +1 -2
- metadata +80 -14
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
|
@@ -6,6 +6,14 @@ module RuboCop
|
|
|
6
6
|
# Checks whether some constant value isn't a
|
|
7
7
|
# mutable literal (e.g. array or hash).
|
|
8
8
|
#
|
|
9
|
+
# When the `Recursive` option is enabled, mutable literals nested inside
|
|
10
|
+
# arrays and hashes are also frozen, so an offense on the outermost
|
|
11
|
+
# unfrozen literal will autocorrect every nested mutable literal as well.
|
|
12
|
+
# When the outer literal already has `.freeze` appended, the cop descends
|
|
13
|
+
# into it and reports each outermost unfrozen literal underneath. The
|
|
14
|
+
# option is disabled by default to preserve existing behavior; opt in to
|
|
15
|
+
# get strict nested freezing.
|
|
16
|
+
#
|
|
9
17
|
# Strict mode can be used to freeze all constants, rather than
|
|
10
18
|
# just literals.
|
|
11
19
|
# Strict mode is considered an experimental feature. It has not been
|
|
@@ -49,6 +57,17 @@ module RuboCop
|
|
|
49
57
|
# CONST = Something.new
|
|
50
58
|
#
|
|
51
59
|
#
|
|
60
|
+
# @example Recursive: false (default)
|
|
61
|
+
# # good - only the outer container needs to be frozen
|
|
62
|
+
# CONST = [{ a: [], b: 'foo' }].freeze
|
|
63
|
+
#
|
|
64
|
+
# @example Recursive: true
|
|
65
|
+
# # bad - nested mutable literals must be frozen too
|
|
66
|
+
# CONST = [{ a: [], b: 'foo' }].freeze
|
|
67
|
+
#
|
|
68
|
+
# # good
|
|
69
|
+
# CONST = [{ a: [].freeze, b: 'foo'.freeze }.freeze].freeze
|
|
70
|
+
#
|
|
52
71
|
# @example EnforcedStyle: strict
|
|
53
72
|
# # bad
|
|
54
73
|
# CONST = Something.new
|
|
@@ -70,6 +89,9 @@ module RuboCop
|
|
|
70
89
|
# end
|
|
71
90
|
# end.freeze
|
|
72
91
|
#
|
|
92
|
+
# # good - `Data.define` declares an immutable value type
|
|
93
|
+
# CONST = Data.define(:foo, :bar)
|
|
94
|
+
#
|
|
73
95
|
# @example
|
|
74
96
|
# # Magic comment - shareable_constant_value: literal
|
|
75
97
|
#
|
|
@@ -124,8 +146,15 @@ module RuboCop
|
|
|
124
146
|
|
|
125
147
|
MSG = 'Freeze mutable objects assigned to constants.'
|
|
126
148
|
|
|
149
|
+
# With `Recursive: true`, `.freeze` is appended to a nested literal. When the literal
|
|
150
|
+
# is the last element and spans multiple lines, the trailing comma lands between the literal
|
|
151
|
+
# and the `.freeze` appended in the same pass.
|
|
152
|
+
def self.autocorrect_incompatible_with
|
|
153
|
+
[Style::HashAsLastArrayItem, Style::TrailingCommaInArrayLiteral, Style::TrailingCommaInHashLiteral]
|
|
154
|
+
end
|
|
155
|
+
|
|
127
156
|
def on_casgn(node)
|
|
128
|
-
if node.expression.nil? # This is only the case for `CONST += ...` or
|
|
157
|
+
if node.expression.nil? # This is only the case for `CONST += ...` or similar
|
|
129
158
|
parent = node.parent
|
|
130
159
|
return unless parent.or_asgn_type? # We only care about `CONST ||= ...`
|
|
131
160
|
|
|
@@ -138,31 +167,55 @@ module RuboCop
|
|
|
138
167
|
private
|
|
139
168
|
|
|
140
169
|
def on_assignment(value)
|
|
141
|
-
|
|
142
|
-
|
|
170
|
+
nodes = mutable_nodes(value) do |node|
|
|
171
|
+
if style == :strict
|
|
172
|
+
strict_check(node)
|
|
173
|
+
else
|
|
174
|
+
literal_check(node)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
nodes.each do |node|
|
|
179
|
+
add_offense(node) { |corrector| autocorrect(corrector, node) }
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def mutable_nodes(value, &block)
|
|
184
|
+
if recursive? && explicitly_frozen_literal?(value)
|
|
185
|
+
literal_children(value.receiver).flat_map { |c| mutable_nodes(c, &block) }
|
|
143
186
|
else
|
|
144
|
-
|
|
187
|
+
node_offending = yield(value)
|
|
188
|
+
|
|
189
|
+
if node_offending
|
|
190
|
+
[value]
|
|
191
|
+
else
|
|
192
|
+
[]
|
|
193
|
+
end
|
|
145
194
|
end
|
|
146
195
|
end
|
|
147
196
|
|
|
148
197
|
def strict_check(value)
|
|
198
|
+
return if value.assignment?
|
|
149
199
|
return if immutable_literal?(value)
|
|
150
200
|
return if operation_produces_immutable_object?(value)
|
|
151
201
|
return if frozen_string_literal?(value)
|
|
152
202
|
return if shareable_constant_value?(value)
|
|
203
|
+
return if parenthesized_immutable_value?(value)
|
|
153
204
|
|
|
154
|
-
|
|
205
|
+
true
|
|
155
206
|
end
|
|
156
207
|
|
|
157
|
-
def
|
|
158
|
-
|
|
159
|
-
return unless mutable_literal?(value) ||
|
|
160
|
-
(target_ruby_version <= 2.7 && range_enclosed_in_parentheses)
|
|
161
|
-
|
|
208
|
+
def literal_check(value)
|
|
209
|
+
return unless mutable_or_unfrozen_range?(value)
|
|
162
210
|
return if frozen_string_literal?(value)
|
|
163
211
|
return if shareable_constant_value?(value)
|
|
164
212
|
|
|
165
|
-
|
|
213
|
+
true
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def mutable_or_unfrozen_range?(value)
|
|
217
|
+
mutable_literal?(value) ||
|
|
218
|
+
(target_ruby_version <= 2.7 && range_enclosed_in_parentheses?(value))
|
|
166
219
|
end
|
|
167
220
|
|
|
168
221
|
def autocorrect(corrector, node)
|
|
@@ -171,13 +224,84 @@ module RuboCop
|
|
|
171
224
|
splat_value = splat_value(node)
|
|
172
225
|
if splat_value
|
|
173
226
|
correct_splat_expansion(corrector, expr, splat_value)
|
|
174
|
-
|
|
227
|
+
corrector.insert_after(expr, '.freeze')
|
|
228
|
+
return
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
return expand_omitted_hash_value(corrector, node.parent) if omitted_hash_value?(node)
|
|
232
|
+
|
|
233
|
+
wrap_for_freeze(corrector, node, expr)
|
|
234
|
+
corrector.insert_after(expr, '.freeze')
|
|
235
|
+
|
|
236
|
+
freeze_nested_literals(corrector, node) if recursive?
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def omitted_hash_value?(node)
|
|
240
|
+
node.parent&.pair_type? && node.parent.value_omission?
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def expand_omitted_hash_value(corrector, pair)
|
|
244
|
+
key = pair.key.value
|
|
245
|
+
|
|
246
|
+
corrector.replace(pair, "#{key}: #{key}.freeze")
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def wrap_for_freeze(corrector, node, expr)
|
|
250
|
+
if node.array_type? && !node.bracketed?
|
|
175
251
|
corrector.wrap(expr, '[', ']')
|
|
252
|
+
elsif node.hash_type? && !node.braces?
|
|
253
|
+
corrector.wrap(expr, '{ ', ' }')
|
|
176
254
|
elsif requires_parentheses?(node)
|
|
177
255
|
corrector.wrap(expr, '(', ')')
|
|
178
256
|
end
|
|
257
|
+
end
|
|
179
258
|
|
|
180
|
-
|
|
259
|
+
# Recursively freezes every nested mutable literal inside an array or
|
|
260
|
+
# hash literal. Already-frozen subtrees are not re-frozen, but their
|
|
261
|
+
# children are still inspected for unfrozen literals deeper down.
|
|
262
|
+
def freeze_nested_literals(corrector, node)
|
|
263
|
+
literal_children(node).each do |child|
|
|
264
|
+
if explicitly_frozen_literal?(child)
|
|
265
|
+
freeze_nested_literals(corrector, child.receiver)
|
|
266
|
+
elsif freezable_nested_literal?(child)
|
|
267
|
+
autocorrect(corrector, child)
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def freezable_nested_literal?(node)
|
|
273
|
+
return false if frozen_string_literal?(node)
|
|
274
|
+
return false if shareable_constant_value?(node)
|
|
275
|
+
|
|
276
|
+
mutable_literal?(node)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Returns the child literals of an array or hash node that may
|
|
280
|
+
# themselves need freezing. For hashes, both keys and values are
|
|
281
|
+
# included. Percent-literal arrays (e.g. `%w(a b)`) are skipped because
|
|
282
|
+
# `.freeze` cannot be appended to their contents. Splat elements are
|
|
283
|
+
# skipped because the splatted object is not stored in the array.
|
|
284
|
+
def literal_children(node)
|
|
285
|
+
case node.type
|
|
286
|
+
when :array
|
|
287
|
+
return [] if node.percent_literal?
|
|
288
|
+
|
|
289
|
+
node.children.reject(&:splat_type?)
|
|
290
|
+
when :hash
|
|
291
|
+
node.children.flat_map { |child| child.pair_type? ? child.children : [] }
|
|
292
|
+
else
|
|
293
|
+
[]
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def explicitly_frozen_literal?(node)
|
|
298
|
+
return false unless node.send_type? && node.method?(:freeze)
|
|
299
|
+
|
|
300
|
+
node.receiver && mutable_literal?(node.receiver)
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
def recursive?
|
|
304
|
+
cop_config.fetch('Recursive', false)
|
|
181
305
|
end
|
|
182
306
|
|
|
183
307
|
def mutable_literal?(value)
|
|
@@ -196,12 +320,30 @@ module RuboCop
|
|
|
196
320
|
recent_shareable_value? node
|
|
197
321
|
end
|
|
198
322
|
|
|
323
|
+
def parenthesized_immutable_value?(value)
|
|
324
|
+
return false if !value.begin_type? || !value.children.one?
|
|
325
|
+
|
|
326
|
+
inner = value.children.first
|
|
327
|
+
|
|
328
|
+
!inner.assignment? && !strict_check(inner)
|
|
329
|
+
end
|
|
330
|
+
|
|
199
331
|
def frozen_regexp_or_range_literals?(node)
|
|
200
332
|
target_ruby_version >= 3.0 && node.type?(:regexp, :range)
|
|
201
333
|
end
|
|
202
334
|
|
|
203
335
|
def requires_parentheses?(node)
|
|
204
|
-
node.range_type? ||
|
|
336
|
+
if node.range_type? || node.operator_keyword? || unparenthesized_method_call?(node)
|
|
337
|
+
return true
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
node.if_type? && node.ternary?
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
def unparenthesized_method_call?(node)
|
|
344
|
+
return false unless node.call_type?
|
|
345
|
+
|
|
346
|
+
node.loc.dot.nil? || (node.arguments.any? && !node.parenthesized?)
|
|
205
347
|
end
|
|
206
348
|
|
|
207
349
|
def correct_splat_expansion(corrector, expr, splat_value)
|
|
@@ -225,6 +367,8 @@ module RuboCop
|
|
|
225
367
|
(const _ _)
|
|
226
368
|
(send (const {nil? cbase} :Struct) :new ...)
|
|
227
369
|
(block (send (const {nil? cbase} :Struct) :new ...) ...)
|
|
370
|
+
(send (const {nil? cbase} :Data) :define ...)
|
|
371
|
+
(block (send (const {nil? cbase} :Data) :define ...) ...)
|
|
228
372
|
(send _ :freeze)
|
|
229
373
|
(send {float int} {:+ :- :* :** :/ :% :<<} _)
|
|
230
374
|
(send _ {:+ :- :* :** :/ :%} {float int})
|
|
@@ -46,7 +46,7 @@ module RuboCop
|
|
|
46
46
|
@corrected_nodes = nil
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
# rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity
|
|
49
|
+
# rubocop:disable-next Metrics/AbcSize,Metrics/CyclomaticComplexity
|
|
50
50
|
def on_if(node)
|
|
51
51
|
return unless if_else?(node)
|
|
52
52
|
return unless (condition = unwrap_begin_nodes(node.condition))
|
|
@@ -64,7 +64,6 @@ module RuboCop
|
|
|
64
64
|
end
|
|
65
65
|
end
|
|
66
66
|
end
|
|
67
|
-
# rubocop:enable Metrics/AbcSize,Metrics/CyclomaticComplexity
|
|
68
67
|
|
|
69
68
|
private
|
|
70
69
|
|
|
@@ -119,7 +118,8 @@ module RuboCop
|
|
|
119
118
|
if node.ternary?
|
|
120
119
|
node.if_branch
|
|
121
120
|
else
|
|
122
|
-
|
|
121
|
+
if_start = node.loc.begin || node.condition.source_range
|
|
122
|
+
range_between(if_start.end_pos, node.loc.else.begin_pos)
|
|
123
123
|
end
|
|
124
124
|
end
|
|
125
125
|
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Identifies usages of `arr[arr.length - n]`, `arr[arr.size - n]`, or
|
|
7
|
+
# `arr[arr.count - n]` and suggests to change them to use `arr[-n]` instead.
|
|
8
|
+
# Also handles range patterns like `arr[0..(arr.length - n)]`.
|
|
9
|
+
#
|
|
10
|
+
# The cop recognizes preserving methods (`sort`, `reverse`, `shuffle`, `rotate`)
|
|
11
|
+
# and their combinations, allowing safe replacement when the receiver matches.
|
|
12
|
+
# It works with variables, instance variables, class variables, and constants.
|
|
13
|
+
#
|
|
14
|
+
# @safety
|
|
15
|
+
# This cop is unsafe because the receiver may not be an Array. For a Hash,
|
|
16
|
+
# `hash[hash.size - 1]` looks up the key `hash.size - 1`, which `hash[-1]`
|
|
17
|
+
# does not. Even for an Array, `arr[arr.length - n]` wraps around to an
|
|
18
|
+
# element from the end when `n` exceeds the length, while `arr[-n]`
|
|
19
|
+
# returns `nil`.
|
|
20
|
+
#
|
|
21
|
+
# @example
|
|
22
|
+
# # bad
|
|
23
|
+
# arr[arr.count - 2]
|
|
24
|
+
# arr[0..(arr.length - 2)]
|
|
25
|
+
# arr[0...(arr.length - 4)]
|
|
26
|
+
# arr.sort[arr.reverse.length - 2]
|
|
27
|
+
# arr.sort.reverse[arr.sort.size - 2]
|
|
28
|
+
#
|
|
29
|
+
# # good
|
|
30
|
+
# arr[-2]
|
|
31
|
+
# arr[0..-2]
|
|
32
|
+
# arr[0...-4]
|
|
33
|
+
# arr.sort[-2]
|
|
34
|
+
# arr.sort.reverse[-2]
|
|
35
|
+
#
|
|
36
|
+
class NegativeArrayIndex < Base
|
|
37
|
+
extend AutoCorrector
|
|
38
|
+
include RangeHelp
|
|
39
|
+
|
|
40
|
+
MSG = 'Use `%<receiver>s[-%<index>s]` instead of `%<current>s`.'
|
|
41
|
+
MSG_RANGE = 'Use `%<receiver>s[%<start>s%<range_op>s-%<index>s]` instead of `%<current>s`.'
|
|
42
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
|
43
|
+
|
|
44
|
+
LENGTH_METHODS = %i[length size count].freeze
|
|
45
|
+
|
|
46
|
+
PRESERVING_METHODS = %i[sort reverse shuffle rotate].freeze
|
|
47
|
+
|
|
48
|
+
# @!method length_subtraction?(node)
|
|
49
|
+
def_node_matcher :length_subtraction?, <<~PATTERN
|
|
50
|
+
(send
|
|
51
|
+
(send $_ {:length :size :count}) :-
|
|
52
|
+
(int $_))
|
|
53
|
+
PATTERN
|
|
54
|
+
|
|
55
|
+
def on_send(node)
|
|
56
|
+
return if node.arguments.empty?
|
|
57
|
+
|
|
58
|
+
index_arg = node.first_argument
|
|
59
|
+
range_node = extract_range_from_begin(index_arg)
|
|
60
|
+
if range_with_length_subtraction?(range_node, node.receiver)
|
|
61
|
+
receiver = node.receiver.source
|
|
62
|
+
return handle_range_pattern(receiver, range_node, index_arg)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
handle_simple_index_pattern(node, index_arg)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
alias on_csend on_send
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def handle_simple_index_pattern(node, index_arg)
|
|
73
|
+
length_receiver, negative_index = length_subtraction?(index_arg)
|
|
74
|
+
|
|
75
|
+
return unless negative_index&.positive?
|
|
76
|
+
return unless receivers_match?(length_receiver, node.receiver)
|
|
77
|
+
|
|
78
|
+
add_offense_for_subtraction(node, index_arg, negative_index)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def extract_range_from_begin(node)
|
|
82
|
+
node.begin_type? ? node.children.first : node
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def extract_inner_end(node)
|
|
86
|
+
node.children.size == 1 ? node.children.first : node
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def add_offense_for_subtraction(node, index_arg, negative_index)
|
|
90
|
+
receiver = node.receiver.source
|
|
91
|
+
offense_range = index_arg.source_range
|
|
92
|
+
current = "#{receiver}[#{index_arg.source}]"
|
|
93
|
+
|
|
94
|
+
message = format(MSG, receiver: receiver, index: negative_index, current: current)
|
|
95
|
+
|
|
96
|
+
add_offense(offense_range, message: message) do |corrector|
|
|
97
|
+
corrector.replace(offense_range, "-#{negative_index}")
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity
|
|
102
|
+
def range_with_length_subtraction?(range_node, array_receiver)
|
|
103
|
+
return false unless range_node&.range_type?
|
|
104
|
+
|
|
105
|
+
range_end = range_node.end
|
|
106
|
+
range_start = range_node.begin
|
|
107
|
+
return false unless range_end && range_start
|
|
108
|
+
|
|
109
|
+
return false unless preserving_method?(range_start)
|
|
110
|
+
|
|
111
|
+
inner_end = extract_inner_end(range_end)
|
|
112
|
+
length_receiver, negative_index = length_subtraction?(inner_end)
|
|
113
|
+
|
|
114
|
+
return false unless negative_index&.positive?
|
|
115
|
+
|
|
116
|
+
receivers_match_strict?(length_receiver, array_receiver)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def handle_range_pattern(receiver, range_node, index_arg)
|
|
120
|
+
range_end = range_node.end
|
|
121
|
+
inner_end = extract_inner_end(range_end)
|
|
122
|
+
_length_receiver, negative_index = length_subtraction?(inner_end)
|
|
123
|
+
|
|
124
|
+
message, replacement = build_range_offense_data(
|
|
125
|
+
receiver, range_node, range_end, inner_end, negative_index, index_arg
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
add_offense(range_end, message: message) do |corrector|
|
|
129
|
+
corrector.replace(index_arg, replacement)
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# rubocop:disable-next Metrics/ParameterLists
|
|
134
|
+
def build_range_offense_data(receiver, range_node, range_end, inner_end, negative_index,
|
|
135
|
+
index_arg)
|
|
136
|
+
range_op = range_node.erange_type? ? '...' : '..'
|
|
137
|
+
range_start = range_node.begin.source
|
|
138
|
+
|
|
139
|
+
range_without_parens =
|
|
140
|
+
build_range_without_parens(range_start, range_op, range_end, inner_end)
|
|
141
|
+
current_source = build_current_source(receiver, range_without_parens, index_arg)
|
|
142
|
+
start, index = format_range_message_parts(range_start, negative_index, index_arg)
|
|
143
|
+
|
|
144
|
+
message = build_message_for_range(receiver, start, range_op, index, current_source)
|
|
145
|
+
replacement = build_replacement_string(range_start, range_op, negative_index, index_arg)
|
|
146
|
+
|
|
147
|
+
[message, replacement]
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def format_range_message_parts(range_start, negative_index, index_arg)
|
|
151
|
+
has_parentheses = index_arg.begin_type?
|
|
152
|
+
start = has_parentheses ? "(#{range_start}" : range_start
|
|
153
|
+
index = has_parentheses ? "#{negative_index})" : negative_index
|
|
154
|
+
|
|
155
|
+
[start, index]
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def build_message_for_range(receiver, start, range_op, index, current)
|
|
159
|
+
format(
|
|
160
|
+
MSG_RANGE,
|
|
161
|
+
receiver: receiver, start: start, range_op: range_op, index: index, current: current
|
|
162
|
+
)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def build_replacement_string(range_start, range_op, negative_index, index_arg)
|
|
166
|
+
has_parentheses = index_arg.begin_type?
|
|
167
|
+
|
|
168
|
+
if has_parentheses
|
|
169
|
+
"(#{range_start}#{range_op}-#{negative_index})"
|
|
170
|
+
else
|
|
171
|
+
"#{range_start}#{range_op}-#{negative_index}"
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def build_current_source(receiver, range_without_parens, index_arg)
|
|
176
|
+
has_parentheses = index_arg.begin_type?
|
|
177
|
+
|
|
178
|
+
if has_parentheses
|
|
179
|
+
"#{receiver}[(#{range_without_parens})]"
|
|
180
|
+
else
|
|
181
|
+
"#{receiver}[#{range_without_parens}]"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def build_range_without_parens(range_start, range_op, range_end, inner_end)
|
|
186
|
+
end_expression = range_end.begin_type? ? range_end.source : inner_end.source
|
|
187
|
+
|
|
188
|
+
"#{range_start}#{range_op}#{end_expression}"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def receivers_match?(length_receiver, array_receiver)
|
|
192
|
+
return array_receiver.self_type? unless length_receiver
|
|
193
|
+
|
|
194
|
+
unless preserving_method?(array_receiver) && preserving_method?(length_receiver)
|
|
195
|
+
return false
|
|
196
|
+
end
|
|
197
|
+
return true if length_receiver.source == array_receiver.source
|
|
198
|
+
return false unless (base_receiver = extract_base_receiver(array_receiver))
|
|
199
|
+
|
|
200
|
+
base_receiver.source == (extract_base_receiver(length_receiver) || length_receiver).source
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def receivers_match_strict?(length_receiver, array_receiver)
|
|
204
|
+
preserving_method?(array_receiver) &&
|
|
205
|
+
length_receiver.source == array_receiver.source
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def extract_base_receiver(node)
|
|
209
|
+
receiver = node.receiver
|
|
210
|
+
|
|
211
|
+
return nil unless receiver
|
|
212
|
+
return receiver unless receiver.receiver
|
|
213
|
+
|
|
214
|
+
extract_base_receiver(receiver)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def preserving_method?(node)
|
|
218
|
+
return true if node.receiver.nil?
|
|
219
|
+
|
|
220
|
+
method_name = node.method_name
|
|
221
|
+
return false unless PRESERVING_METHODS.include?(method_name)
|
|
222
|
+
|
|
223
|
+
preserving_method?(node.receiver)
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
end
|
|
@@ -19,6 +19,19 @@ module RuboCop
|
|
|
19
19
|
|
|
20
20
|
MSG = 'Avoid using nested modifiers.'
|
|
21
21
|
|
|
22
|
+
# Operands that would otherwise bind differently next to `&&`/`||`, or
|
|
23
|
+
# not parse at all.
|
|
24
|
+
# @!method low_precedence?(node)
|
|
25
|
+
def_node_matcher :low_precedence?, <<~PATTERN
|
|
26
|
+
{
|
|
27
|
+
[{and or} semantic_operator?]
|
|
28
|
+
[send prefix_not?]
|
|
29
|
+
[if ternary?]
|
|
30
|
+
assignment?
|
|
31
|
+
[{csend yield super} arguments? !parenthesized? !operator_method?]
|
|
32
|
+
}
|
|
33
|
+
PATTERN
|
|
34
|
+
|
|
22
35
|
def on_while(node)
|
|
23
36
|
check(node)
|
|
24
37
|
end
|
|
@@ -63,25 +76,31 @@ module RuboCop
|
|
|
63
76
|
end
|
|
64
77
|
|
|
65
78
|
def left_hand_operand(node, operator)
|
|
66
|
-
expr = node.condition
|
|
67
|
-
|
|
79
|
+
expr = operand_source(node.condition)
|
|
80
|
+
if (node.condition.or_type? && operator == '&&') || low_precedence?(node.condition)
|
|
81
|
+
expr = "(#{expr})"
|
|
82
|
+
end
|
|
68
83
|
expr
|
|
69
84
|
end
|
|
70
85
|
|
|
71
86
|
def right_hand_operand(node, left_hand_keyword)
|
|
72
87
|
condition = node.condition
|
|
88
|
+
negated = left_hand_keyword != node.keyword
|
|
73
89
|
|
|
74
|
-
expr =
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
else
|
|
78
|
-
condition.source
|
|
79
|
-
end
|
|
80
|
-
expr = "(#{expr})" if requires_parens?(condition)
|
|
81
|
-
expr = "!#{expr}" unless left_hand_keyword == node.keyword
|
|
90
|
+
expr = operand_source(condition)
|
|
91
|
+
expr = "(#{expr})" if requires_parens?(condition, negated)
|
|
92
|
+
expr = "!#{expr}" if negated
|
|
82
93
|
expr
|
|
83
94
|
end
|
|
84
95
|
|
|
96
|
+
def operand_source(condition)
|
|
97
|
+
if condition.send_type? && !condition.arguments.empty? && !condition.operator_method?
|
|
98
|
+
add_parentheses_to_method_arguments(condition)
|
|
99
|
+
else
|
|
100
|
+
condition.source
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
85
104
|
def add_parentheses_to_method_arguments(send_node)
|
|
86
105
|
expr = +''
|
|
87
106
|
expr << "#{send_node.receiver.source}." if send_node.receiver
|
|
@@ -91,8 +110,13 @@ module RuboCop
|
|
|
91
110
|
expr
|
|
92
111
|
end
|
|
93
112
|
|
|
94
|
-
def requires_parens?(node)
|
|
95
|
-
|
|
113
|
+
def requires_parens?(node, negated)
|
|
114
|
+
# A negated `&&`/`||` operand must be wrapped so the `!` applies to the
|
|
115
|
+
# whole expression (e.g. `!(a && b)`, not `!a && b`).
|
|
116
|
+
(negated && node.operator_keyword?) ||
|
|
117
|
+
node.or_type? ||
|
|
118
|
+
low_precedence?(node) ||
|
|
119
|
+
!(RuboCop::AST::Node::COMPARISON_OPERATORS & node.children).empty?
|
|
96
120
|
end
|
|
97
121
|
end
|
|
98
122
|
end
|
|
@@ -26,7 +26,7 @@ module RuboCop
|
|
|
26
26
|
|
|
27
27
|
node.each_descendant(:if).select(&:ternary?).each do |nested_ternary|
|
|
28
28
|
add_offense(nested_ternary) do |corrector|
|
|
29
|
-
next if part_of_ignored_node?(node)
|
|
29
|
+
next if part_of_ignored_node?(node) || contains_heredoc?(node)
|
|
30
30
|
|
|
31
31
|
autocorrect(corrector, node)
|
|
32
32
|
ignore_node(node)
|
|
@@ -36,21 +36,39 @@ module RuboCop
|
|
|
36
36
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
|
+
def contains_heredoc?(node)
|
|
40
|
+
node.each_descendant(:any_str).any?(&:heredoc?)
|
|
41
|
+
end
|
|
42
|
+
|
|
39
43
|
def autocorrect(corrector, if_node)
|
|
40
44
|
replace_loc_and_whitespace(corrector, if_node.loc.question, "\n")
|
|
41
45
|
replace_loc_and_whitespace(corrector, if_node.loc.colon, "\nelse\n")
|
|
42
|
-
corrector
|
|
43
|
-
corrector.wrap(if_node, 'if ', "\nend")
|
|
44
|
-
end
|
|
46
|
+
remove_parentheses(corrector, if_node.if_branch)
|
|
45
47
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
source.delete_prefix('(').delete_suffix(')')
|
|
48
|
+
if modifier_position?(if_node)
|
|
49
|
+
corrector.wrap(if_node, '(if ', "\nend)")
|
|
49
50
|
else
|
|
50
|
-
|
|
51
|
+
corrector.wrap(if_node, 'if ', "\nend")
|
|
51
52
|
end
|
|
52
53
|
end
|
|
53
54
|
|
|
55
|
+
def remove_parentheses(corrector, node)
|
|
56
|
+
return unless node.begin_type? && node.parenthesized_call?
|
|
57
|
+
|
|
58
|
+
corrector.remove(node.loc.begin)
|
|
59
|
+
corrector.remove(node.loc.end)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# An `if` right after `return`, as the operand of `not` or `defined?`, or as
|
|
63
|
+
# the first argument of a call without parentheses would be parsed as a modifier.
|
|
64
|
+
def modifier_position?(node)
|
|
65
|
+
return false unless (parent = node.parent)
|
|
66
|
+
return true if parent.type?(:return, :break, :next)
|
|
67
|
+
return false if !parent.type?(:call, :super, :yield, :defined?) || parent.parenthesized?
|
|
68
|
+
|
|
69
|
+
parent.prefix_not? || parent.first_argument.equal?(node)
|
|
70
|
+
end
|
|
71
|
+
|
|
54
72
|
def replace_loc_and_whitespace(corrector, range, replacement)
|
|
55
73
|
corrector.replace(
|
|
56
74
|
range_with_surrounding_space(range: range, whitespace: true),
|