rubocop 1.79.2 → 1.88.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 +2 -2
- data/config/default.yml +259 -90
- data/config/obsoletion.yml +30 -1
- data/exe/rubocop +1 -8
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +36 -4
- 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 +1 -1
- data/lib/rubocop/cli.rb +35 -9
- data/lib/rubocop/comment_config.rb +59 -17
- data/lib/rubocop/config.rb +14 -10
- data/lib/rubocop/config_finder.rb +1 -1
- data/lib/rubocop/config_loader.rb +37 -23
- data/lib/rubocop/config_loader_resolver.rb +20 -10
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -2
- data/lib/rubocop/config_store.rb +7 -2
- data/lib/rubocop/config_validator.rb +1 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/base.rb +25 -4
- data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
- data/lib/rubocop/cop/bundler/gem_version.rb +28 -28
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +26 -7
- data/lib/rubocop/cop/correctors/condition_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +1 -5
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +33 -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/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
- data/lib/rubocop/cop/gemspec/require_mfa.rb +5 -5
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +12 -7
- 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 +9 -9
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +5 -3
- 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 +2 -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 +41 -4
- data/lib/rubocop/cop/layout/case_indentation.rb +3 -1
- data/lib/rubocop/cop/layout/class_structure.rb +14 -7
- data/lib/rubocop/cop/layout/dot_position.rb +2 -2
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +26 -7
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +31 -13
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +2 -2
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +12 -2
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +16 -2
- data/lib/rubocop/cop/layout/empty_lines_around_module_body.rb +16 -2
- data/lib/rubocop/cop/layout/end_alignment.rb +10 -3
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +34 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +26 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +7 -1
- data/lib/rubocop/cop/layout/first_hash_element_line_break.rb +25 -25
- data/lib/rubocop/cop/layout/hash_alignment.rb +3 -6
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- 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 +123 -7
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +26 -9
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +57 -57
- data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +9 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -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 +229 -39
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
- data/lib/rubocop/cop/layout/parameter_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/redundant_line_break.rb +3 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +4 -2
- 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/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_assignment.rb +1 -11
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +1 -10
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +45 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +4 -3
- data/lib/rubocop/cop/lint/constant_reassignment.rb +93 -11
- data/lib/rubocop/cop/lint/constant_resolution.rb +6 -6
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
- data/lib/rubocop/cop/lint/data_define_override.rb +63 -0
- data/lib/rubocop/cop/lint/debugger.rb +0 -3
- data/lib/rubocop/cop/lint/deprecated_constants.rb +2 -8
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -12
- 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 +6 -1
- data/lib/rubocop/cop/lint/empty_in_pattern.rb +8 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
- 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/incompatible_io_select_with_fiber_scheduler.rb +5 -1
- data/lib/rubocop/cop/lint/interpolation_check.rb +25 -5
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +5 -1
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +11 -1
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +9 -12
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +19 -10
- data/lib/rubocop/cop/lint/multiple_comparison.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 +1 -1
- 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 +3 -0
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +7 -7
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -13
- 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 +27 -10
- data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +6 -12
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +15 -4
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +36 -12
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +12 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +10 -3
- data/lib/rubocop/cop/lint/redundant_with_index.rb +1 -1
- 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_exception.rb +1 -4
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +18 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +7 -1
- 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 +39 -7
- 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 +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/suppressed_exception_in_number_conversion.rb +12 -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 +28 -1
- data/lib/rubocop/cop/lint/to_json.rb +12 -16
- 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 +4 -2
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +7 -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/uri_escape_unescape.rb +2 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +53 -25
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +4 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +2 -0
- data/lib/rubocop/cop/lint/useless_or.rb +15 -2
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +8 -4
- 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 +37 -11
- data/lib/rubocop/cop/lint/void.rb +39 -12
- data/lib/rubocop/cop/message_annotator.rb +1 -1
- 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/collection_literal_length.rb +1 -1
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/metrics/utils/iterating_block.rb +1 -1
- data/lib/rubocop/cop/migration/department_name.rb +12 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +2 -2
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +4 -6
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_max.rb +6 -5
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +5 -5
- data/lib/rubocop/cop/mixin/hash_transform_method/autocorrection.rb +63 -0
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +10 -60
- data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/project_index_help.rb +48 -0
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
- data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
- data/lib/rubocop/cop/mixin.rb +86 -0
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_method.rb +32 -8
- data/lib/rubocop/cop/naming/predicate_prefix.rb +12 -12
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +17 -1
- data/lib/rubocop/cop/registry.rb +62 -38
- data/lib/rubocop/cop/security/eval.rb +15 -2
- data/lib/rubocop/cop/security/io_methods.rb +1 -1
- data/lib/rubocop/cop/security/json_load.rb +33 -11
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +15 -4
- data/lib/rubocop/cop/style/accessor_grouping.rb +4 -2
- 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 +25 -7
- data/lib/rubocop/cop/style/array_first_last.rb +12 -1
- data/lib/rubocop/cop/style/array_intersect.rb +50 -12
- 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 +8 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +39 -32
- data/lib/rubocop/cop/style/case_equality.rb +29 -15
- data/lib/rubocop/cop/style/character_literal.rb +2 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +19 -2
- data/lib/rubocop/cop/style/class_equality_comparison.rb +21 -13
- data/lib/rubocop/cop/style/class_methods_definitions.rb +11 -5
- data/lib/rubocop/cop/style/collection_compact.rb +36 -16
- data/lib/rubocop/cop/style/colon_method_call.rb +16 -7
- data/lib/rubocop/cop/style/combinable_loops.rb +5 -0
- data/lib/rubocop/cop/style/comparable_clamp.rb +12 -1
- data/lib/rubocop/cop/style/concat_array_literals.rb +7 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +14 -19
- data/lib/rubocop/cop/style/constant_visibility.rb +20 -12
- data/lib/rubocop/cop/style/copyright.rb +22 -11
- data/lib/rubocop/cop/style/date_time.rb +4 -4
- data/lib/rubocop/cop/style/dig_chain.rb +5 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +1 -1
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +6 -1
- data/lib/rubocop/cop/style/documentation.rb +6 -6
- data/lib/rubocop/cop/style/documentation_method.rb +8 -8
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- 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_class_definition.rb +119 -0
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +0 -6
- 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 +23 -5
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/fetch_env_var.rb +1 -1
- 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 +15 -1
- data/lib/rubocop/cop/style/for.rb +3 -0
- data/lib/rubocop/cop/style/format_string.rb +4 -3
- data/lib/rubocop/cop/style/format_string_token.rb +49 -5
- data/lib/rubocop/cop/style/global_vars.rb +5 -2
- data/lib/rubocop/cop/style/guard_clause.rb +27 -22
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +27 -9
- data/lib/rubocop/cop/style/hash_conversion.rb +1 -1
- data/lib/rubocop/cop/style/hash_lookup_method.rb +106 -0
- data/lib/rubocop/cop/style/hash_slice.rb +16 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- 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/if_inside_else.rb +16 -7
- data/lib/rubocop/cop/style/if_unless_modifier.rb +58 -18
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -12
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +4 -1
- data/lib/rubocop/cop/style/if_with_semicolon.rb +7 -5
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inline_comment.rb +4 -1
- data/lib/rubocop/cop/style/ip_addresses.rb +1 -2
- data/lib/rubocop/cop/style/lambda_call.rb +8 -8
- data/lib/rubocop/cop/style/magic_comment_format.rb +3 -3
- data/lib/rubocop/cop/style/map_join.rb +123 -0
- 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 +17 -4
- data/lib/rubocop/cop/style/method_def_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/min_max_comparison.rb +1 -1
- data/lib/rubocop/cop/style/module_member_existence_check.rb +110 -0
- data/lib/rubocop/cop/style/multiline_if_then.rb +4 -4
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
- data/lib/rubocop/cop/style/mutable_constant.rb +106 -12
- data/lib/rubocop/cop/style/negative_array_index.rb +220 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +11 -10
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +5 -11
- data/lib/rubocop/cop/style/not.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +3 -2
- data/lib/rubocop/cop/style/one_class_per_file.rb +115 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +21 -12
- data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +14 -3
- data/lib/rubocop/cop/style/partition_instead_of_double_select.rb +270 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +2 -0
- 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 +1 -1
- 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_begin.rb +37 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +6 -3
- data/lib/rubocop/cop/style/redundant_constant_base.rb +5 -5
- data/lib/rubocop/cop/style/redundant_each.rb +3 -3
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +27 -5
- data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +26 -10
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +16 -0
- data/lib/rubocop/cop/style/redundant_min_max_by.rb +93 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +36 -30
- data/lib/rubocop/cop/style/redundant_percent_q.rb +5 -3
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +2 -2
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_return.rb +3 -1
- data/lib/rubocop/cop/style/redundant_self.rb +2 -2
- 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_struct_keyword_init.rb +114 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +31 -2
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -3
- data/lib/rubocop/cop/style/reverse_find.rb +51 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +25 -8
- 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 +51 -21
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +41 -8
- data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +12 -3
- data/lib/rubocop/cop/style/special_global_vars.rb +6 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
- data/lib/rubocop/cop/style/struct_inheritance.rb +13 -0
- data/lib/rubocop/cop/style/super_arguments.rb +2 -2
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +7 -6
- data/lib/rubocop/cop/style/tally_method.rb +181 -0
- data/lib/rubocop/cop/style/top_level_method_definition.rb +2 -2
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
- 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 +11 -11
- 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 -0
- data/lib/rubocop/cop/style/word_array.rb +1 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +1 -1
- 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/team.rb +87 -36
- data/lib/rubocop/cop/util.rb +2 -3
- data/lib/rubocop/cop/utils/format_string.rb +10 -0
- data/lib/rubocop/cop/variable_force/branch.rb +30 -6
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +9 -7
- data/lib/rubocop/cops_documentation_generator.rb +4 -4
- data/lib/rubocop/directive_comment.rb +48 -4
- 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 +38 -14
- data/lib/rubocop/formatter/formatter_set.rb +2 -2
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/simple_text_formatter.rb +0 -2
- data/lib/rubocop/formatter/tap_formatter.rb +5 -2
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +1 -1
- data/lib/rubocop/formatter.rb +22 -21
- data/lib/rubocop/lsp/diagnostic.rb +18 -33
- data/lib/rubocop/lsp/disable_comment_edits.rb +135 -0
- data/lib/rubocop/lsp/routes.rb +43 -7
- data/lib/rubocop/lsp/runtime.rb +13 -4
- data/lib/rubocop/lsp/stdin_runner.rb +8 -17
- data/lib/rubocop/magic_comment.rb +20 -0
- data/lib/rubocop/mcp/server.rb +200 -0
- data/lib/rubocop/options.rb +35 -4
- data/lib/rubocop/path_util.rb +14 -2
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/project_index_loader.rb +66 -0
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +10 -8
- data/lib/rubocop/result_cache.rb +61 -38
- data/lib/rubocop/rspec/cop_helper.rb +8 -0
- data/lib/rubocop/rspec/shared_contexts.rb +39 -5
- data/lib/rubocop/rspec/support.rb +2 -1
- data/lib/rubocop/runner.rb +134 -57
- data/lib/rubocop/server/cache.rb +6 -29
- data/lib/rubocop/server/core.rb +8 -0
- data/lib/rubocop/target_finder.rb +17 -10
- data/lib/rubocop/target_ruby.rb +31 -14
- data/lib/rubocop/version.rb +21 -3
- data/lib/rubocop.rb +28 -96
- data/lib/ruby_lsp/rubocop/addon.rb +23 -8
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
- metadata +38 -9
data/lib/rubocop/result_cache.rb
CHANGED
|
@@ -9,7 +9,7 @@ module RuboCop
|
|
|
9
9
|
# Provides functionality for caching RuboCop runs.
|
|
10
10
|
# @api private
|
|
11
11
|
class ResultCache
|
|
12
|
-
NON_CHANGING = %i[color format formatters out debug fail_level
|
|
12
|
+
NON_CHANGING = %i[color format formatters out debug display_time fail_level
|
|
13
13
|
fix_layout autocorrect safe_autocorrect autocorrect_all
|
|
14
14
|
cache fail_fast stdin parallel].freeze
|
|
15
15
|
|
|
@@ -22,19 +22,22 @@ module RuboCop
|
|
|
22
22
|
# Remove old files so that the cache doesn't grow too big. When the
|
|
23
23
|
# threshold MaxFilesInCache has been exceeded, the oldest 50% of all the
|
|
24
24
|
# files in the cache are removed. The reason for removing so much is that
|
|
25
|
-
#
|
|
25
|
+
# removing should be done relatively seldom, since there is a slight risk
|
|
26
26
|
# that some other RuboCop process was just about to read the file, when
|
|
27
27
|
# there's parallel execution and the cache is shared.
|
|
28
28
|
def self.cleanup(config_store, verbose, cache_root_override = nil)
|
|
29
29
|
return if inhibit_cleanup # OPTIMIZE: For faster testing
|
|
30
|
+
return unless config_store.for_pwd.for_all_cops['MaxFilesInCache']
|
|
30
31
|
|
|
31
32
|
rubocop_cache_dir = cache_root(config_store, cache_root_override)
|
|
32
33
|
return unless File.exist?(rubocop_cache_dir)
|
|
33
34
|
|
|
34
|
-
|
|
35
|
+
# We know the cache entries are 3 level deep, so globing
|
|
36
|
+
# for `*/*/*` only returns files.
|
|
37
|
+
files = Dir[File.join(rubocop_cache_dir, '*/*/*')]
|
|
35
38
|
return unless requires_file_removal?(files.length, config_store)
|
|
36
39
|
|
|
37
|
-
remove_oldest_files(files,
|
|
40
|
+
remove_oldest_files(files, rubocop_cache_dir, verbose)
|
|
38
41
|
end
|
|
39
42
|
|
|
40
43
|
class << self
|
|
@@ -49,39 +52,57 @@ module RuboCop
|
|
|
49
52
|
file_count > 1 && file_count > config_store.for_pwd.for_all_cops['MaxFilesInCache']
|
|
50
53
|
end
|
|
51
54
|
|
|
52
|
-
def remove_oldest_files(files,
|
|
55
|
+
def remove_oldest_files(files, rubocop_cache_dir, verbose)
|
|
53
56
|
# Add 1 to half the number of files, so that we remove the file if
|
|
54
57
|
# there's only 1 left.
|
|
55
58
|
remove_count = (files.length / 2) + 1
|
|
56
59
|
puts "Removing the #{remove_count} oldest files from #{rubocop_cache_dir}" if verbose
|
|
57
60
|
sorted = files.sort_by { |path| File.mtime(path) }
|
|
58
|
-
remove_files(sorted,
|
|
61
|
+
remove_files(sorted, remove_count)
|
|
59
62
|
rescue Errno::ENOENT
|
|
60
63
|
# This can happen if parallel RuboCop invocations try to remove the
|
|
61
64
|
# same files. No problem.
|
|
62
65
|
puts $ERROR_INFO if verbose
|
|
63
66
|
end
|
|
64
67
|
|
|
65
|
-
def remove_files(files,
|
|
68
|
+
def remove_files(files, remove_count)
|
|
66
69
|
# Batch file deletions, deleting over 130,000+ files will crash
|
|
67
70
|
# File.delete.
|
|
68
71
|
files[0, remove_count].each_slice(10_000).each do |files_slice|
|
|
69
72
|
File.delete(*files_slice)
|
|
70
73
|
end
|
|
71
|
-
|
|
74
|
+
|
|
75
|
+
dirs = files.map { |f| File.dirname(f) }.uniq
|
|
76
|
+
until dirs.empty?
|
|
77
|
+
dirs.select! do |dir|
|
|
78
|
+
Dir.rmdir(dir)
|
|
79
|
+
true
|
|
80
|
+
rescue SystemCallError # ENOTEMPTY etc
|
|
81
|
+
false
|
|
82
|
+
end
|
|
83
|
+
dirs = dirs.map { |f| File.dirname(f) }.uniq
|
|
84
|
+
end
|
|
72
85
|
end
|
|
73
86
|
end
|
|
74
87
|
|
|
75
88
|
def self.cache_root(config_store, cache_root_override = nil)
|
|
76
|
-
|
|
89
|
+
return @cache_root if @cache_root && !cache_root_override
|
|
90
|
+
|
|
91
|
+
result = CacheConfig.root_dir do
|
|
77
92
|
cache_root_override || config_store.for_pwd.for_all_cops['CacheRootDirectory']
|
|
78
93
|
end
|
|
94
|
+
@cache_root = result unless cache_root_override
|
|
95
|
+
result
|
|
79
96
|
end
|
|
80
97
|
|
|
81
98
|
def self.allow_symlinks_in_cache_location?(config_store)
|
|
82
99
|
config_store.for_pwd.for_all_cops['AllowSymlinksInCacheRootDirectory']
|
|
83
100
|
end
|
|
84
101
|
|
|
102
|
+
def self.reset_config_cache
|
|
103
|
+
@cache_root = nil
|
|
104
|
+
end
|
|
105
|
+
|
|
85
106
|
attr_reader :path
|
|
86
107
|
|
|
87
108
|
def initialize(file, team, options, config_store, cache_root_override = nil)
|
|
@@ -90,7 +111,7 @@ module RuboCop
|
|
|
90
111
|
@allow_symlinks_in_cache_location =
|
|
91
112
|
ResultCache.allow_symlinks_in_cache_location?(config_store)
|
|
92
113
|
@path = File.join(rubocop_cache_dir,
|
|
93
|
-
|
|
114
|
+
self.class.source_checksum,
|
|
94
115
|
context_checksum(team, options),
|
|
95
116
|
file_checksum(file, config_store))
|
|
96
117
|
@cached_data = CachedData.new(file)
|
|
@@ -167,13 +188,11 @@ module RuboCop
|
|
|
167
188
|
end
|
|
168
189
|
|
|
169
190
|
class << self
|
|
170
|
-
attr_accessor :
|
|
171
|
-
end
|
|
191
|
+
attr_accessor :inhibit_cleanup
|
|
172
192
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
begin
|
|
193
|
+
# The checksum of the RuboCop program running the inspection.
|
|
194
|
+
def source_checksum
|
|
195
|
+
@source_checksum ||= begin
|
|
177
196
|
digest = Digest::SHA1.new
|
|
178
197
|
rubocop_extra_features
|
|
179
198
|
.select { |path| File.file?(path) }
|
|
@@ -184,21 +203,33 @@ module RuboCop
|
|
|
184
203
|
digest << RuboCop::Version::STRING << RuboCop::AST::Version::STRING
|
|
185
204
|
digest.hexdigest
|
|
186
205
|
end
|
|
187
|
-
|
|
206
|
+
end
|
|
188
207
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
208
|
+
# Return a hash of the options given at invocation, minus the ones that have
|
|
209
|
+
# no effect on which offenses and disabled line ranges are found, and thus
|
|
210
|
+
# don't affect caching.
|
|
211
|
+
def relevant_options_digest(options)
|
|
212
|
+
@relevant_options_digest ||= {}
|
|
213
|
+
@relevant_options_digest[options] ||= begin
|
|
214
|
+
options = options.reject { |key, _| NON_CHANGING.include?(key) }
|
|
215
|
+
options.to_s.gsub(/[^a-z]+/i, '_')
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
private
|
|
199
220
|
|
|
200
|
-
|
|
201
|
-
|
|
221
|
+
def digest(path)
|
|
222
|
+
content = if path.end_with?(*DL_EXTENSIONS)
|
|
223
|
+
# Shared libraries often contain timestamps of when
|
|
224
|
+
# they were compiled and other non-stable data.
|
|
225
|
+
File.basename(path)
|
|
226
|
+
else
|
|
227
|
+
File.binread(path) # mtime not reliable
|
|
228
|
+
end
|
|
229
|
+
Zlib.crc32(content).to_s
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def rubocop_extra_features
|
|
202
233
|
lib_root = File.join(File.dirname(__FILE__), '..')
|
|
203
234
|
exe_root = File.join(lib_root, '..', 'exe')
|
|
204
235
|
|
|
@@ -216,20 +247,12 @@ module RuboCop
|
|
|
216
247
|
end
|
|
217
248
|
end
|
|
218
249
|
|
|
219
|
-
# Return a hash of the options given at invocation, minus the ones that have
|
|
220
|
-
# no effect on which offenses and disabled line ranges are found, and thus
|
|
221
|
-
# don't affect caching.
|
|
222
|
-
def relevant_options_digest(options)
|
|
223
|
-
options = options.reject { |key, _| NON_CHANGING.include?(key) }
|
|
224
|
-
options.to_s.gsub(/[^a-z]+/i, '_')
|
|
225
|
-
end
|
|
226
|
-
|
|
227
250
|
# We combine team and options into a single "context" checksum to avoid
|
|
228
251
|
# making file names that are too long for some filesystems to handle.
|
|
229
252
|
# This context is for anything that's not (1) the RuboCop executable
|
|
230
253
|
# checksum or (2) the inspected file checksum.
|
|
231
254
|
def context_checksum(team, options)
|
|
232
|
-
keys = [team.external_dependency_checksum, relevant_options_digest(options)]
|
|
255
|
+
keys = [team.external_dependency_checksum, self.class.relevant_options_digest(options)]
|
|
233
256
|
Digest::SHA1.hexdigest(keys.join)
|
|
234
257
|
end
|
|
235
258
|
end
|
|
@@ -6,6 +6,12 @@ require 'tempfile'
|
|
|
6
6
|
module CopHelper
|
|
7
7
|
extend RSpec::SharedContext
|
|
8
8
|
|
|
9
|
+
@integrated_plugins = false
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
attr_accessor :integrated_plugins
|
|
13
|
+
end
|
|
14
|
+
|
|
9
15
|
let(:ruby_version) do
|
|
10
16
|
# The minimum version Prism can parse is 3.3.
|
|
11
17
|
ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : RuboCop::TargetRuby::DEFAULT_VERSION
|
|
@@ -18,11 +24,13 @@ module CopHelper
|
|
|
18
24
|
|
|
19
25
|
before(:all) do
|
|
20
26
|
next if ENV['RUBOCOP_CORE_DEVELOPMENT']
|
|
27
|
+
next if CopHelper.integrated_plugins
|
|
21
28
|
|
|
22
29
|
plugins = Gem.loaded_specs.filter_map do |feature_name, feature_specification|
|
|
23
30
|
feature_name if feature_specification.metadata['default_lint_roller_plugin']
|
|
24
31
|
end
|
|
25
32
|
RuboCop::Plugin.integrate_plugins(RuboCop::Config.new, plugins)
|
|
33
|
+
CopHelper.integrated_plugins = true
|
|
26
34
|
end
|
|
27
35
|
|
|
28
36
|
def inspect_source(source, file = nil)
|
|
@@ -2,8 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
require 'tmpdir'
|
|
4
4
|
|
|
5
|
+
# Reset cached PathUtil.pwd before each example so that tests using Dir.chdir
|
|
6
|
+
# or stubbing Dir.pwd get a fresh value.
|
|
7
|
+
RSpec.configure { |c| c.before { RuboCop::PathUtil.reset_pwd } }
|
|
8
|
+
|
|
5
9
|
RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLength
|
|
6
|
-
around do |example|
|
|
10
|
+
around do |example| # rubocop:disable Metrics/BlockLength
|
|
7
11
|
Dir.mktmpdir do |tmpdir|
|
|
8
12
|
original_home = Dir.home
|
|
9
13
|
original_xdg_config_home = ENV.fetch('XDG_CONFIG_HOME', nil)
|
|
@@ -26,12 +30,17 @@ RSpec.shared_context 'isolated environment' do # rubocop:disable Metrics/BlockLe
|
|
|
26
30
|
begin
|
|
27
31
|
FileUtils.mkdir_p(working_dir)
|
|
28
32
|
|
|
29
|
-
Dir.chdir(working_dir)
|
|
33
|
+
Dir.chdir(working_dir) do
|
|
34
|
+
RuboCop::PathUtil.reset_pwd
|
|
35
|
+
RuboCop::ResultCache.reset_config_cache
|
|
36
|
+
example.run
|
|
37
|
+
end
|
|
30
38
|
ensure
|
|
31
39
|
ENV['HOME'] = original_home
|
|
32
40
|
ENV['XDG_CONFIG_HOME'] = original_xdg_config_home
|
|
33
41
|
|
|
34
|
-
RuboCop::
|
|
42
|
+
RuboCop::ResultCache.reset_config_cache
|
|
43
|
+
RuboCop::ConfigLoader.clear_options # This also resets RuboCop::FileFinder.root_level
|
|
35
44
|
end
|
|
36
45
|
end
|
|
37
46
|
end
|
|
@@ -203,6 +212,27 @@ RSpec.shared_context 'lsp' do
|
|
|
203
212
|
end
|
|
204
213
|
end
|
|
205
214
|
|
|
215
|
+
RSpec.shared_context 'with exclude limit tracking' do
|
|
216
|
+
around do |example|
|
|
217
|
+
Dir.mktmpdir('rubocop-exclude-limit') do |dir|
|
|
218
|
+
RuboCop::ExcludeLimit.tmp_dir = Pathname.new(dir)
|
|
219
|
+
example.run
|
|
220
|
+
ensure
|
|
221
|
+
RuboCop::ExcludeLimit.tmp_dir = nil
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# Reads exclude_limit values from the tmp files written by ExcludeLimit.
|
|
226
|
+
# Returns a hash like { 'Max' => 81 } or nil if no values were written.
|
|
227
|
+
def read_exclude_limit(cop, parameter_name = nil)
|
|
228
|
+
if parameter_name
|
|
229
|
+
read_exclude_limit(cop)[parameter_name]
|
|
230
|
+
else
|
|
231
|
+
RuboCop::ExcludeLimit.read_limits(cop.class.badge.to_s)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
206
236
|
RSpec.shared_context 'ruby 2.0' do
|
|
207
237
|
# Prism supports parsing Ruby 3.3+.
|
|
208
238
|
let(:ruby_version) { ENV['PARSER_ENGINE'] == 'parser_prism' ? 3.3 : 2.0 }
|
|
@@ -266,6 +296,10 @@ RSpec.shared_context 'ruby 3.4' do
|
|
|
266
296
|
let(:ruby_version) { 3.4 }
|
|
267
297
|
end
|
|
268
298
|
|
|
269
|
-
RSpec.shared_context 'ruby
|
|
270
|
-
let(:ruby_version) {
|
|
299
|
+
RSpec.shared_context 'ruby 4.0' do
|
|
300
|
+
let(:ruby_version) { 4.0 }
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
RSpec.shared_context 'ruby 4.1' do
|
|
304
|
+
let(:ruby_version) { 4.1 }
|
|
271
305
|
end
|
|
@@ -30,5 +30,6 @@ RSpec.configure do |config|
|
|
|
30
30
|
config.include_context 'ruby 3.2', :ruby32
|
|
31
31
|
config.include_context 'ruby 3.3', :ruby33
|
|
32
32
|
config.include_context 'ruby 3.4', :ruby34
|
|
33
|
-
config.include_context 'ruby
|
|
33
|
+
config.include_context 'ruby 4.0', :ruby40
|
|
34
|
+
config.include_context 'ruby 4.1', :ruby41
|
|
34
35
|
end
|
data/lib/rubocop/runner.rb
CHANGED
|
@@ -62,14 +62,21 @@ module RuboCop
|
|
|
62
62
|
@errors = []
|
|
63
63
|
@warnings = []
|
|
64
64
|
@aborting = false
|
|
65
|
+
@inspected_files = []
|
|
66
|
+
@report_queue = {}
|
|
65
67
|
end
|
|
66
68
|
|
|
67
69
|
def run(paths)
|
|
70
|
+
# Compute the cache source checksum once to avoid potential
|
|
71
|
+
# inconsistencies between workers.
|
|
72
|
+
ResultCache.source_checksum
|
|
73
|
+
|
|
68
74
|
target_files = find_target_files(paths)
|
|
75
|
+
@project_index = ProjectIndexLoader.build_index(target_files) if project_index_enabled?
|
|
76
|
+
|
|
69
77
|
if @options[:list_target_files]
|
|
70
78
|
list_files(target_files)
|
|
71
79
|
else
|
|
72
|
-
warm_cache(target_files) if @options[:parallel]
|
|
73
80
|
inspect_files(target_files)
|
|
74
81
|
end
|
|
75
82
|
rescue Interrupt
|
|
@@ -86,21 +93,6 @@ module RuboCop
|
|
|
86
93
|
|
|
87
94
|
private
|
|
88
95
|
|
|
89
|
-
# Warms up the RuboCop cache by forking a suitable number of RuboCop
|
|
90
|
-
# instances that each inspects its allotted group of files.
|
|
91
|
-
def warm_cache(target_files)
|
|
92
|
-
saved_options = @options.dup
|
|
93
|
-
if target_files.length <= 1
|
|
94
|
-
puts 'Skipping parallel inspection: only a single file needs inspection' if @options[:debug]
|
|
95
|
-
return
|
|
96
|
-
end
|
|
97
|
-
puts 'Running parallel inspection' if @options[:debug]
|
|
98
|
-
%i[autocorrect safe_autocorrect].each { |opt| @options[opt] = false }
|
|
99
|
-
Parallel.each(target_files) { |target_file| file_offenses(target_file) }
|
|
100
|
-
ensure
|
|
101
|
-
@options = saved_options
|
|
102
|
-
end
|
|
103
|
-
|
|
104
96
|
def find_target_files(paths)
|
|
105
97
|
target_finder = TargetFinder.new(@config_store, @options)
|
|
106
98
|
mode = if @options[:only_recognized_file_types]
|
|
@@ -112,12 +104,26 @@ module RuboCop
|
|
|
112
104
|
target_files.each(&:freeze).freeze
|
|
113
105
|
end
|
|
114
106
|
|
|
115
|
-
def
|
|
116
|
-
|
|
107
|
+
def project_index_enabled?
|
|
108
|
+
return false unless @config_store.for_pwd.for_all_cops['UseProjectIndex']
|
|
117
109
|
|
|
110
|
+
unless ProjectIndexLoader.available?
|
|
111
|
+
ProjectIndexLoader.warn_unavailable
|
|
112
|
+
return false
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
true
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def inspect_files(files) # rubocop:disable Metrics/AbcSize
|
|
118
119
|
formatter_set.started(files)
|
|
120
|
+
file_iterator(files) do |file|
|
|
121
|
+
offenses = process_file(file)
|
|
122
|
+
succeeded = offenses.none? { |o| considered_failure?(o) && offense_displayed?(o) }
|
|
123
|
+
raise Parallel::Break if @options[:fail_fast] && !succeeded
|
|
119
124
|
|
|
120
|
-
|
|
125
|
+
[offenses, succeeded]
|
|
126
|
+
end
|
|
121
127
|
ensure
|
|
122
128
|
# OPTIMIZE: Calling `ResultCache.cleanup` takes time. This optimization
|
|
123
129
|
# mainly targets editors that integrates RuboCop. When RuboCop is run
|
|
@@ -125,23 +131,88 @@ module RuboCop
|
|
|
125
131
|
if files.size > 1 && cached_run?
|
|
126
132
|
ResultCache.cleanup(@config_store, @options[:debug], @options[:cache_root])
|
|
127
133
|
end
|
|
128
|
-
|
|
129
|
-
formatter_set.finished(inspected_files.freeze)
|
|
134
|
+
formatter_set.finished(@inspected_files.freeze)
|
|
130
135
|
formatter_set.close_output_files
|
|
131
136
|
end
|
|
132
137
|
|
|
133
|
-
def
|
|
134
|
-
|
|
135
|
-
offenses = process_file(file)
|
|
136
|
-
yield file
|
|
138
|
+
def file_iterator(files, &block)
|
|
139
|
+
all_passed = true
|
|
137
140
|
|
|
138
|
-
|
|
139
|
-
|
|
141
|
+
on_start = ->(file, _index) { file_started(file) }
|
|
142
|
+
on_finish = lambda do |file, index, (offenses, passed)|
|
|
143
|
+
all_passed &&= passed
|
|
144
|
+
finished_report(file, index, offenses)
|
|
145
|
+
end
|
|
140
146
|
|
|
141
|
-
|
|
142
|
-
|
|
147
|
+
if run_in_parallel?(files)
|
|
148
|
+
parallel_file_iterator(files, on_start, on_finish, &block)
|
|
149
|
+
else
|
|
150
|
+
serial_file_iterator(files, on_start, on_finish, &block)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
process_remaining_report_queue
|
|
154
|
+
|
|
155
|
+
all_passed
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def finished_report(file, index, offenses)
|
|
159
|
+
@report_queue[index] = [file, offenses]
|
|
160
|
+
@next_index_to_report ||= 0
|
|
161
|
+
while @report_queue.key?(@next_index_to_report)
|
|
162
|
+
process_report_queue_entry(@next_index_to_report)
|
|
163
|
+
@next_index_to_report += 1
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def process_report_queue_entry(index)
|
|
168
|
+
file, offenses = @report_queue.delete(index)
|
|
169
|
+
file_finished(file, offenses)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def process_remaining_report_queue
|
|
173
|
+
@report_queue.keys.sort.each do |index|
|
|
174
|
+
process_report_queue_entry(index)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
143
177
|
|
|
144
|
-
|
|
178
|
+
def run_in_parallel?(files)
|
|
179
|
+
return false if @options[:auto_gen_config]
|
|
180
|
+
return false unless @options[:parallel]
|
|
181
|
+
|
|
182
|
+
if files.size <= 1
|
|
183
|
+
puts 'Skipping parallel inspection: only a single file needs inspection' if @options[:debug]
|
|
184
|
+
return false
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
return false if project_index_disables_parallel?
|
|
188
|
+
|
|
189
|
+
puts 'Running parallel inspection' if @options[:debug]
|
|
190
|
+
|
|
191
|
+
true
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def project_index_disables_parallel?
|
|
195
|
+
return false if @project_index.nil? || !Gem.win_platform?
|
|
196
|
+
|
|
197
|
+
if @options[:debug]
|
|
198
|
+
puts 'Skipping parallel inspection: the project index is enabled and parallel ' \
|
|
199
|
+
'inspection is not yet supported on Windows.'
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
true
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def parallel_file_iterator(files, on_start, on_finish, &block)
|
|
206
|
+
Parallel.each(files, start: on_start, finish: on_finish, &block)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
def serial_file_iterator(files, on_start, on_finish, &block)
|
|
210
|
+
files.each_with_index do |file, index|
|
|
211
|
+
on_start.call(file, index)
|
|
212
|
+
result = yield file
|
|
213
|
+
on_finish.call(file, index, result)
|
|
214
|
+
rescue Parallel::Break
|
|
215
|
+
break
|
|
145
216
|
end
|
|
146
217
|
end
|
|
147
218
|
|
|
@@ -150,16 +221,13 @@ module RuboCop
|
|
|
150
221
|
end
|
|
151
222
|
|
|
152
223
|
def process_file(file)
|
|
153
|
-
|
|
154
|
-
offenses = file_offenses(file)
|
|
224
|
+
file_offenses(file)
|
|
155
225
|
rescue InfiniteCorrectionLoop => e
|
|
156
226
|
raise e if @options[:raise_cop_error]
|
|
157
227
|
|
|
158
228
|
errors << e
|
|
159
229
|
warn Rainbow(e.message).red
|
|
160
|
-
|
|
161
|
-
ensure
|
|
162
|
-
file_finished(file, offenses || [])
|
|
230
|
+
e.offenses.compact.sort.freeze
|
|
163
231
|
end
|
|
164
232
|
|
|
165
233
|
def file_offenses(file)
|
|
@@ -190,7 +258,7 @@ module RuboCop
|
|
|
190
258
|
|
|
191
259
|
if real_run_needed
|
|
192
260
|
offenses = yield
|
|
193
|
-
save_in_cache(cache, offenses)
|
|
261
|
+
save_in_cache(cache, offenses) unless Cop::Registry.global.warnings?(file)
|
|
194
262
|
end
|
|
195
263
|
|
|
196
264
|
offenses
|
|
@@ -246,6 +314,7 @@ module RuboCop
|
|
|
246
314
|
end
|
|
247
315
|
|
|
248
316
|
def file_finished(file, offenses)
|
|
317
|
+
@inspected_files << file
|
|
249
318
|
offenses = offenses_to_report(offenses)
|
|
250
319
|
formatter_set.file_finished(file, offenses)
|
|
251
320
|
end
|
|
@@ -254,10 +323,6 @@ module RuboCop
|
|
|
254
323
|
@cached_run ||=
|
|
255
324
|
(@options[:cache] == 'true' ||
|
|
256
325
|
(@options[:cache] != 'false' && @config_store.for_pwd.for_all_cops['UseCache'])) &&
|
|
257
|
-
# When running --auto-gen-config, there's some processing done in the
|
|
258
|
-
# cops related to calculating the Max parameters for Metrics cops. We
|
|
259
|
-
# need to do that processing and cannot use caching.
|
|
260
|
-
!@options[:auto_gen_config] &&
|
|
261
326
|
# We can't cache results from code which is piped in to stdin
|
|
262
327
|
!@options[:stdin]
|
|
263
328
|
end
|
|
@@ -273,7 +338,8 @@ module RuboCop
|
|
|
273
338
|
end
|
|
274
339
|
|
|
275
340
|
def do_inspection_loop(file)
|
|
276
|
-
|
|
341
|
+
# We can reuse the prism result since the source did not change yet.
|
|
342
|
+
processed_source = get_processed_source(file, @prism_result)
|
|
277
343
|
# This variable is 2d array used to track corrected offenses after each
|
|
278
344
|
# inspection iteration. This is used to output meaningful infinite loop
|
|
279
345
|
# error message.
|
|
@@ -295,7 +361,8 @@ module RuboCop
|
|
|
295
361
|
# loop if we find any.
|
|
296
362
|
break unless updated_source_file
|
|
297
363
|
|
|
298
|
-
|
|
364
|
+
# Autocorrect has happened, don't use the prism result since it is stale.
|
|
365
|
+
processed_source = get_processed_source(file, nil)
|
|
299
366
|
end
|
|
300
367
|
|
|
301
368
|
# Return summary of corrected offenses after all iterations
|
|
@@ -344,16 +411,9 @@ module RuboCop
|
|
|
344
411
|
|
|
345
412
|
def inspect_file(processed_source, team = mobilize_team(processed_source))
|
|
346
413
|
extracted_ruby_sources = extract_ruby_sources(processed_source)
|
|
347
|
-
offenses = extracted_ruby_sources
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
offset: extracted_ruby_source[:offset],
|
|
351
|
-
original: processed_source
|
|
352
|
-
)
|
|
353
|
-
@errors.concat(team.errors)
|
|
354
|
-
@warnings.concat(team.warnings)
|
|
355
|
-
report.offenses
|
|
356
|
-
end
|
|
414
|
+
offenses = team.investigate_fragments(extracted_ruby_sources, original: processed_source)
|
|
415
|
+
@errors.concat(team.errors)
|
|
416
|
+
@warnings.concat(team.warnings)
|
|
357
417
|
[offenses, team.updated_source_file?]
|
|
358
418
|
end
|
|
359
419
|
|
|
@@ -373,7 +433,15 @@ module RuboCop
|
|
|
373
433
|
|
|
374
434
|
def mobilize_team(processed_source)
|
|
375
435
|
config = @config_store.for_file(processed_source.path)
|
|
376
|
-
Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
|
|
436
|
+
team = Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
|
|
437
|
+
|
|
438
|
+
if @project_index
|
|
439
|
+
team.cops.each do |cop|
|
|
440
|
+
cop.project_index = @project_index
|
|
441
|
+
end
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
team
|
|
377
445
|
end
|
|
378
446
|
|
|
379
447
|
def mobilized_cop_classes(config) # rubocop:disable Metrics/AbcSize
|
|
@@ -482,7 +550,7 @@ module RuboCop
|
|
|
482
550
|
end
|
|
483
551
|
|
|
484
552
|
# rubocop:disable Metrics/MethodLength
|
|
485
|
-
def get_processed_source(file)
|
|
553
|
+
def get_processed_source(file, prism_result)
|
|
486
554
|
config = @config_store.for_file(file)
|
|
487
555
|
ruby_version = config.target_ruby_version
|
|
488
556
|
parser_engine = config.parser_engine
|
|
@@ -493,7 +561,7 @@ module RuboCop
|
|
|
493
561
|
ruby_version,
|
|
494
562
|
file,
|
|
495
563
|
parser_engine: parser_engine,
|
|
496
|
-
prism_result:
|
|
564
|
+
prism_result: prism_result
|
|
497
565
|
)
|
|
498
566
|
else
|
|
499
567
|
begin
|
|
@@ -516,8 +584,17 @@ module RuboCop
|
|
|
516
584
|
# level caching in ResultCache.
|
|
517
585
|
def standby_team(config)
|
|
518
586
|
@team_by_config ||= {}.compare_by_identity
|
|
519
|
-
@team_by_config[config] ||=
|
|
520
|
-
Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
|
|
587
|
+
@team_by_config[config] ||= begin
|
|
588
|
+
team = Cop::Team.mobilize(mobilized_cop_classes(config), config, @options)
|
|
589
|
+
|
|
590
|
+
if @project_index
|
|
591
|
+
team.cops.each do |cop|
|
|
592
|
+
cop.project_index = @project_index
|
|
593
|
+
end
|
|
594
|
+
end
|
|
595
|
+
|
|
596
|
+
team
|
|
597
|
+
end
|
|
521
598
|
end
|
|
522
599
|
end
|
|
523
600
|
end
|
data/lib/rubocop/server/cache.rb
CHANGED
|
@@ -73,33 +73,12 @@ module RuboCop
|
|
|
73
73
|
cache_root_dir = if cache_root_path
|
|
74
74
|
File.join(cache_root_path, 'rubocop_cache')
|
|
75
75
|
else
|
|
76
|
-
|
|
76
|
+
CacheConfig.root_dir_from_toplevel_config
|
|
77
77
|
end
|
|
78
78
|
|
|
79
79
|
File.expand_path(File.join(cache_root_dir, 'server'))
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
-
def cache_root_dir_from_config
|
|
83
|
-
CacheConfig.root_dir do
|
|
84
|
-
# `RuboCop::ConfigStore` has heavy dependencies, this is a lightweight implementation
|
|
85
|
-
# so that only the necessary `CacheRootDirectory` can be obtained.
|
|
86
|
-
config_path = ConfigFinder.find_config_path(Dir.pwd)
|
|
87
|
-
file_contents = File.read(config_path)
|
|
88
|
-
|
|
89
|
-
# Returns early if `CacheRootDirectory` is not used before requiring `erb` or `yaml`.
|
|
90
|
-
next unless file_contents.include?('CacheRootDirectory')
|
|
91
|
-
|
|
92
|
-
config_yaml = load_erb_templated_yaml(file_contents)
|
|
93
|
-
|
|
94
|
-
# For compatibility with Ruby 3.0 or lower.
|
|
95
|
-
if Gem::Version.new(Psych::VERSION) < Gem::Version.new('4.0.0')
|
|
96
|
-
config_yaml == false ? nil : config_yaml
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
config_yaml&.dig('AllCops', 'CacheRootDirectory')
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
|
|
103
82
|
def port_path
|
|
104
83
|
dir.join('port')
|
|
105
84
|
end
|
|
@@ -135,13 +114,11 @@ module RuboCop
|
|
|
135
114
|
end
|
|
136
115
|
|
|
137
116
|
def acquire_lock
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
lock_file.flock(File::LOCK_UN)
|
|
144
|
-
lock_file.close
|
|
117
|
+
File.open(lock_path, File::CREAT) do |lock_file|
|
|
118
|
+
# flock returns 0 if successful, and false if not.
|
|
119
|
+
flock_result = lock_file.flock(File::LOCK_EX | File::LOCK_NB)
|
|
120
|
+
yield flock_result != false
|
|
121
|
+
end
|
|
145
122
|
end
|
|
146
123
|
|
|
147
124
|
def write_port_and_token_files(port:, token:)
|
data/lib/rubocop/server/core.rb
CHANGED
|
@@ -45,6 +45,8 @@ module RuboCop
|
|
|
45
45
|
write_port_and_token_files
|
|
46
46
|
|
|
47
47
|
pid = fork do
|
|
48
|
+
# NOTE: As of Ruby 4.0.0, ZJIT is still under development, while YJIT is production-ready,
|
|
49
|
+
# so support for ZJIT is deferred.
|
|
48
50
|
if defined?(RubyVM::YJIT.enable)
|
|
49
51
|
RubyVM::YJIT.enable
|
|
50
52
|
end
|
|
@@ -55,6 +57,12 @@ module RuboCop
|
|
|
55
57
|
end
|
|
56
58
|
|
|
57
59
|
Process.waitpid(pid)
|
|
60
|
+
|
|
61
|
+
# The daemon writes its pid file asynchronously after forking, so wait until
|
|
62
|
+
# the server is actually running before returning. This prevents a race where
|
|
63
|
+
# a subsequent command (e.g. `--restart-server`) observes an inconsistent
|
|
64
|
+
# state right after `--start-server` returns.
|
|
65
|
+
Server.wait_for_running_status!(true)
|
|
58
66
|
end
|
|
59
67
|
|
|
60
68
|
def write_port_and_token_files
|