rubocop 1.50.2 → 1.62.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 +7 -5
- data/assets/output.css.erb +159 -0
- data/assets/output.html.erb +1 -160
- data/config/default.yml +196 -28
- data/config/obsoletion.yml +5 -0
- data/lib/rubocop/cli/command/auto_generate_config.rb +22 -8
- data/lib/rubocop/cli/command/lsp.rb +19 -0
- data/lib/rubocop/cli.rb +10 -2
- data/lib/rubocop/config.rb +8 -2
- data/lib/rubocop/config_finder.rb +14 -4
- data/lib/rubocop/config_loader.rb +0 -1
- data/lib/rubocop/config_loader_resolver.rb +4 -3
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +9 -1
- data/lib/rubocop/config_obsoletion.rb +13 -10
- data/lib/rubocop/config_validator.rb +14 -7
- data/lib/rubocop/cop/autocorrect_logic.rb +9 -2
- data/lib/rubocop/cop/base.rb +23 -4
- data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -0
- data/lib/rubocop/cop/bundler/duplicated_group.rb +127 -0
- data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
- data/lib/rubocop/cop/bundler/gem_version.rb +2 -2
- data/lib/rubocop/cop/bundler/ordered_gems.rb +9 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +4 -8
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +5 -13
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +7 -4
- data/lib/rubocop/cop/exclude_limit.rb +1 -1
- data/lib/rubocop/cop/gemspec/dependency_version.rb +2 -2
- data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +9 -1
- data/lib/rubocop/cop/gemspec/required_ruby_version.rb +5 -1
- data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
- data/lib/rubocop/cop/internal_affairs/example_description.rb +45 -24
- data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/method_name_end_with.rb +8 -6
- data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
- data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +127 -33
- data/lib/rubocop/cop/internal_affairs/redundant_expect_offense_arguments.rb +34 -0
- data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +11 -2
- data/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +2 -0
- data/lib/rubocop/cop/internal_affairs.rb +2 -0
- data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +7 -0
- data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +1 -2
- data/lib/rubocop/cop/layout/dot_position.rb +1 -5
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +42 -9
- data/lib/rubocop/cop/layout/empty_line_after_magic_comment.rb +14 -7
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +27 -4
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +2 -0
- data/lib/rubocop/cop/layout/end_alignment.rb +15 -3
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +22 -7
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +4 -4
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +3 -3
- data/lib/rubocop/cop/layout/leading_comment_space.rb +1 -1
- data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +17 -9
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +18 -3
- data/lib/rubocop/cop/layout/redundant_line_break.rb +30 -7
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +5 -0
- data/lib/rubocop/cop/layout/space_after_comma.rb +9 -1
- data/lib/rubocop/cop/layout/space_after_not.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_method_call_operator.rb +2 -2
- data/lib/rubocop/cop/layout/space_around_operators.rb +53 -21
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +19 -10
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_parens.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_range_literal.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_empty_lines.rb +5 -0
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
- data/lib/rubocop/cop/lint/binary_operator_with_identical_operands.rb +2 -2
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/debugger.rb +19 -5
- data/lib/rubocop/cop/lint/duplicate_hash_key.rb +2 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +46 -19
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +6 -7
- data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
- data/lib/rubocop/cop/lint/hash_compare_by_identity.rb +2 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +1 -1
- data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
- data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
- data/lib/rubocop/cop/lint/it_without_arguments_in_block.rb +56 -0
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +85 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +34 -5
- data/lib/rubocop/cop/lint/mixed_case_range.rb +111 -0
- data/lib/rubocop/cop/lint/next_without_accumulator.rb +6 -21
- data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +10 -7
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +14 -4
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +130 -0
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +12 -3
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +72 -8
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -2
- data/lib/rubocop/cop/lint/redundant_with_object.rb +2 -2
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -3
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +14 -8
- data/lib/rubocop/cop/lint/script_permission.rb +3 -3
- data/lib/rubocop/cop/lint/self_assignment.rb +38 -0
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
- data/lib/rubocop/cop/lint/shadowed_argument.rb +1 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +7 -1
- data/lib/rubocop/cop/lint/struct_new_override.rb +12 -12
- data/lib/rubocop/cop/lint/suppressed_exception.rb +2 -2
- data/lib/rubocop/cop/lint/symbol_conversion.rb +8 -3
- data/lib/rubocop/cop/lint/syntax.rb +6 -3
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +12 -5
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
- data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
- data/lib/rubocop/cop/lint/unmodified_reduce_accumulator.rb +2 -2
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
- data/lib/rubocop/cop/lint/useless_assignment.rb +94 -10
- data/lib/rubocop/cop/lint/useless_times.rb +2 -2
- data/lib/rubocop/cop/lint/void.rb +97 -11
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -3
- data/lib/rubocop/cop/metrics/block_length.rb +1 -1
- data/lib/rubocop/cop/metrics/class_length.rb +8 -3
- data/lib/rubocop/cop/metrics/method_length.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +32 -4
- data/lib/rubocop/cop/migration/department_name.rb +2 -2
- data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +19 -11
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -0
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +14 -11
- data/lib/rubocop/cop/mixin/heredoc.rb +6 -2
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
- data/lib/rubocop/cop/mixin/percent_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +6 -8
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
- data/lib/rubocop/cop/mixin/string_help.rb +4 -2
- data/lib/rubocop/cop/mixin/trailing_comma.rb +1 -1
- data/lib/rubocop/cop/naming/block_forwarding.rb +13 -5
- data/lib/rubocop/cop/naming/constant_name.rb +2 -3
- data/lib/rubocop/cop/naming/file_name.rb +1 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +3 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +26 -11
- data/lib/rubocop/cop/naming/predicate_name.rb +2 -2
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
- data/lib/rubocop/cop/naming/variable_name.rb +6 -1
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/security/open.rb +2 -2
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +6 -2
- data/lib/rubocop/cop/style/alias.rb +9 -8
- data/lib/rubocop/cop/style/arguments_forwarding.rb +411 -63
- data/lib/rubocop/cop/style/array_first_last.rb +64 -0
- data/lib/rubocop/cop/style/array_intersect.rb +13 -5
- data/lib/rubocop/cop/style/attr.rb +11 -1
- data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
- data/lib/rubocop/cop/style/begin_block.rb +1 -2
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
- data/lib/rubocop/cop/style/block_comments.rb +1 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +5 -4
- data/lib/rubocop/cop/style/case_like_if.rb +5 -5
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
- data/lib/rubocop/cop/style/class_check.rb +1 -0
- data/lib/rubocop/cop/style/class_equality_comparison.rb +24 -39
- data/lib/rubocop/cop/style/class_vars.rb +3 -3
- data/lib/rubocop/cop/style/collection_compact.rb +32 -12
- data/lib/rubocop/cop/style/collection_methods.rb +2 -0
- data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
- data/lib/rubocop/cop/style/combinable_loops.rb +36 -8
- data/lib/rubocop/cop/style/commented_keyword.rb +5 -2
- data/lib/rubocop/cop/style/concat_array_literals.rb +2 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +11 -10
- data/lib/rubocop/cop/style/copyright.rb +5 -2
- data/lib/rubocop/cop/style/date_time.rb +5 -4
- data/lib/rubocop/cop/style/dir.rb +1 -1
- data/lib/rubocop/cop/style/dir_empty.rb +8 -14
- data/lib/rubocop/cop/style/document_dynamic_eval_definition.rb +1 -1
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +7 -7
- data/lib/rubocop/cop/style/each_with_object.rb +2 -2
- data/lib/rubocop/cop/style/empty_case_condition.rb +6 -1
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +8 -19
- data/lib/rubocop/cop/style/exact_regexp_match.rb +69 -0
- data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
- data/lib/rubocop/cop/style/file_read.rb +2 -2
- data/lib/rubocop/cop/style/for.rb +3 -1
- data/lib/rubocop/cop/style/format_string.rb +24 -3
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -1
- data/lib/rubocop/cop/style/guard_clause.rb +28 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +10 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +106 -33
- data/lib/rubocop/cop/style/hash_except.rb +21 -9
- data/lib/rubocop/cop/style/hash_syntax.rb +6 -2
- data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
- data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +34 -5
- data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -2
- data/lib/rubocop/cop/style/inverse_methods.rb +14 -13
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +54 -8
- data/lib/rubocop/cop/style/lambda.rb +3 -3
- data/lib/rubocop/cop/style/lambda_call.rb +5 -0
- data/lib/rubocop/cop/style/map_compact_with_conditional_block.rb +8 -10
- data/lib/rubocop/cop/style/map_to_hash.rb +17 -7
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +24 -9
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +2 -4
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +20 -0
- data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
- data/lib/rubocop/cop/style/mixin_grouping.rb +1 -1
- data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
- data/lib/rubocop/cop/style/multiline_method_signature.rb +10 -1
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +6 -4
- data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +3 -11
- data/lib/rubocop/cop/style/next.rb +1 -1
- data/lib/rubocop/cop/style/nil_comparison.rb +2 -0
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +1 -1
- data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
- data/lib/rubocop/cop/style/object_then.rb +5 -3
- data/lib/rubocop/cop/style/open_struct_use.rb +1 -1
- data/lib/rubocop/cop/style/operator_method_call.rb +8 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +3 -5
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -0
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/preferred_hash_methods.rb +1 -1
- data/lib/rubocop/cop/style/raise_args.rb +4 -1
- data/lib/rubocop/cop/style/redundant_argument.rb +10 -4
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
- data/lib/rubocop/cop/style/redundant_assignment.rb +10 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +10 -2
- data/lib/rubocop/cop/style/redundant_conditional.rb +2 -10
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +39 -0
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +93 -5
- data/lib/rubocop/cop/style/redundant_each.rb +7 -4
- data/lib/rubocop/cop/style/redundant_exception.rb +32 -12
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +3 -3
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +118 -0
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +32 -8
- data/lib/rubocop/cop/style/redundant_parentheses.rb +72 -23
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +100 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -1
- data/lib/rubocop/cop/style/redundant_return.rb +14 -3
- data/lib/rubocop/cop/style/redundant_self.rb +17 -2
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +8 -1
- data/lib/rubocop/cop/style/redundant_sort.rb +10 -9
- data/lib/rubocop/cop/style/redundant_sort_by.rb +2 -2
- data/lib/rubocop/cop/style/redundant_string_escape.rb +3 -1
- data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
- data/lib/rubocop/cop/style/require_order.rb +11 -5
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
- data/lib/rubocop/cop/style/return_nil.rb +6 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +95 -0
- data/lib/rubocop/cop/style/sample.rb +3 -4
- data/lib/rubocop/cop/style/select_by_regexp.rb +22 -11
- data/lib/rubocop/cop/style/self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/semicolon.rb +20 -4
- data/lib/rubocop/cop/style/signal_exception.rb +1 -1
- data/lib/rubocop/cop/style/single_argument_dig.rb +7 -3
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +67 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
- data/lib/rubocop/cop/style/slicing_with_range.rb +76 -10
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +6 -2
- data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
- data/lib/rubocop/cop/style/string_chars.rb +1 -0
- data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +30 -5
- data/lib/rubocop/cop/style/strip.rb +7 -4
- data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
- data/lib/rubocop/cop/style/symbol_array.rb +35 -15
- data/lib/rubocop/cop/style/symbol_proc.rb +36 -0
- data/lib/rubocop/cop/style/unpack_first.rb +11 -14
- data/lib/rubocop/cop/style/yaml_file_read.rb +66 -0
- data/lib/rubocop/cop/style/yoda_condition.rb +4 -2
- data/lib/rubocop/cop/style/yoda_expression.rb +8 -7
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/utils/regexp_ranges.rb +113 -0
- data/lib/rubocop/cop/variable_force/assignment.rb +45 -4
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +1 -0
- data/lib/rubocop/cops_documentation_generator.rb +16 -4
- data/lib/rubocop/directive_comment.rb +10 -8
- data/lib/rubocop/ext/regexp_node.rb +9 -4
- data/lib/rubocop/ext/regexp_parser.rb +4 -1
- data/lib/rubocop/file_finder.rb +4 -7
- data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
- data/lib/rubocop/formatter/html_formatter.rb +35 -14
- data/lib/rubocop/formatter/json_formatter.rb +0 -1
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +12 -2
- data/lib/rubocop/formatter.rb +1 -1
- data/lib/rubocop/lsp/logger.rb +22 -0
- data/lib/rubocop/lsp/routes.rb +246 -0
- data/lib/rubocop/lsp/runtime.rb +99 -0
- data/lib/rubocop/lsp/server.rb +71 -0
- data/lib/rubocop/lsp/severity.rb +27 -0
- data/lib/rubocop/lsp.rb +29 -0
- data/lib/rubocop/magic_comment.rb +13 -11
- data/lib/rubocop/options.rb +22 -9
- data/lib/rubocop/path_util.rb +6 -2
- data/lib/rubocop/result_cache.rb +5 -2
- data/lib/rubocop/rspec/cop_helper.rb +8 -2
- data/lib/rubocop/rspec/expect_offense.rb +8 -8
- data/lib/rubocop/rspec/shared_contexts.rb +42 -18
- data/lib/rubocop/rspec/support.rb +2 -0
- data/lib/rubocop/runner.rb +15 -6
- data/lib/rubocop/server/cache.rb +1 -1
- data/lib/rubocop/server/client_command/exec.rb +3 -3
- data/lib/rubocop/server/server_command/exec.rb +0 -1
- data/lib/rubocop/string_interpreter.rb +3 -3
- data/lib/rubocop/target_finder.rb +91 -81
- data/lib/rubocop/target_ruby.rb +85 -78
- data/lib/rubocop/version.rb +27 -8
- data/lib/rubocop.rb +19 -0
- metadata +56 -14
- /data/lib/rubocop/formatter/{git_hub_actions_formatter.rb → github_actions_formatter.rb} +0 -0
@@ -8,6 +8,27 @@ module RuboCop
|
|
8
8
|
# This cop identifies places where `do_something(*args, &block)`
|
9
9
|
# can be replaced by `do_something(...)`.
|
10
10
|
#
|
11
|
+
# In Ruby 3.1, anonymous block forwarding has been added.
|
12
|
+
#
|
13
|
+
# This cop identifies places where `do_something(&block)` can be replaced
|
14
|
+
# by `do_something(&)`; if desired, this functionality can be disabled
|
15
|
+
# by setting `UseAnonymousForwarding: false`.
|
16
|
+
#
|
17
|
+
# In Ruby 3.2, anonymous args/kwargs forwarding has been added.
|
18
|
+
#
|
19
|
+
# This cop also identifies places where `use_args(*args)`/`use_kwargs(**kwargs)` can be
|
20
|
+
# replaced by `use_args(*)`/`use_kwargs(**)`; if desired, this functionality can be disabled
|
21
|
+
# by setting `UseAnonymousForwarding: false`.
|
22
|
+
#
|
23
|
+
# And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
|
24
|
+
# and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
|
25
|
+
# that are sufficient for anonymizing meaningless naming.
|
26
|
+
#
|
27
|
+
# Meaningless names that are commonly used can be anonymized by default:
|
28
|
+
# e.g., `*args`, `**options`, `&block`, and so on.
|
29
|
+
#
|
30
|
+
# Names not on this list are likely to be meaningful and are allowed by default.
|
31
|
+
#
|
11
32
|
# @example
|
12
33
|
# # bad
|
13
34
|
# def foo(*args, &block)
|
@@ -24,7 +45,30 @@ module RuboCop
|
|
24
45
|
# bar(...)
|
25
46
|
# end
|
26
47
|
#
|
27
|
-
# @example
|
48
|
+
# @example UseAnonymousForwarding: true (default, only relevant for Ruby >= 3.2)
|
49
|
+
# # bad
|
50
|
+
# def foo(*args, **kwargs, &block)
|
51
|
+
# args_only(*args)
|
52
|
+
# kwargs_only(**kwargs)
|
53
|
+
# block_only(&block)
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# def foo(*, **, &)
|
58
|
+
# args_only(*)
|
59
|
+
# kwargs_only(**)
|
60
|
+
# block_only(&)
|
61
|
+
# end
|
62
|
+
#
|
63
|
+
# @example UseAnonymousForwarding: false (only relevant for Ruby >= 3.2)
|
64
|
+
# # good
|
65
|
+
# def foo(*args, **kwargs, &block)
|
66
|
+
# args_only(*args)
|
67
|
+
# kwargs_only(**kwargs)
|
68
|
+
# block_only(&block)
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# @example AllowOnlyRestArgument: true (default, only relevant for Ruby < 3.2)
|
28
72
|
# # good
|
29
73
|
# def foo(*args)
|
30
74
|
# bar(*args)
|
@@ -34,7 +78,7 @@ module RuboCop
|
|
34
78
|
# bar(**kwargs)
|
35
79
|
# end
|
36
80
|
#
|
37
|
-
# @example AllowOnlyRestArgument: false
|
81
|
+
# @example AllowOnlyRestArgument: false (only relevant for Ruby < 3.2)
|
38
82
|
# # bad
|
39
83
|
# # The following code can replace the arguments with `...`,
|
40
84
|
# # but it will change the behavior. Because `...` forwards block also.
|
@@ -46,6 +90,38 @@ module RuboCop
|
|
46
90
|
# bar(**kwargs)
|
47
91
|
# end
|
48
92
|
#
|
93
|
+
# @example RedundantRestArgumentNames: ['args', 'arguments'] (default)
|
94
|
+
# # bad
|
95
|
+
# def foo(*args)
|
96
|
+
# bar(*args)
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# # good
|
100
|
+
# def foo(*)
|
101
|
+
# bar(*)
|
102
|
+
# end
|
103
|
+
#
|
104
|
+
# @example RedundantKeywordRestArgumentNames: ['kwargs', 'options', 'opts'] (default)
|
105
|
+
# # bad
|
106
|
+
# def foo(**kwargs)
|
107
|
+
# bar(**kwargs)
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# # good
|
111
|
+
# def foo(**)
|
112
|
+
# bar(**)
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# @example RedundantBlockArgumentNames: ['blk', 'block', 'proc'] (default)
|
116
|
+
# # bad - But it is good with `EnforcedStyle: explicit` set for `Naming/BlockForwarding`.
|
117
|
+
# def foo(&block)
|
118
|
+
# bar(&block)
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# # good
|
122
|
+
# def foo(&)
|
123
|
+
# bar(&)
|
124
|
+
# end
|
49
125
|
class ArgumentsForwarding < Base
|
50
126
|
include RangeHelp
|
51
127
|
extend AutoCorrector
|
@@ -53,102 +129,374 @@ module RuboCop
|
|
53
129
|
|
54
130
|
minimum_target_ruby_version 2.7
|
55
131
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
(send _ _ (hash (kwsplat (lvar %1))))
|
68
|
-
}
|
69
|
-
PATTERN
|
70
|
-
|
71
|
-
# @!method forwarding_method_arguments?(node, rest_name, block_name, kwargs_name)
|
72
|
-
def_node_matcher :forwarding_method_arguments?, <<~PATTERN
|
73
|
-
{
|
74
|
-
(send _ _
|
75
|
-
(splat (lvar %1))
|
76
|
-
(block-pass {(lvar %2) nil?}))
|
77
|
-
(send _ _
|
78
|
-
(splat (lvar %1))
|
79
|
-
(hash (kwsplat (lvar %3)))
|
80
|
-
(block-pass {(lvar %2) nil?}))
|
81
|
-
}
|
82
|
-
PATTERN
|
132
|
+
FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
|
133
|
+
ADDITIONAL_ARG_TYPES = %i[lvar arg].freeze
|
134
|
+
|
135
|
+
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
136
|
+
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
137
|
+
KWARGS_MSG = 'Use anonymous keyword arguments forwarding (`**`).'
|
138
|
+
BLOCK_MSG = 'Use anonymous block arguments forwarding (`&`).'
|
139
|
+
|
140
|
+
def self.autocorrect_incompatible_with
|
141
|
+
[Naming::BlockForwarding]
|
142
|
+
end
|
83
143
|
|
84
144
|
def on_def(node)
|
85
145
|
return unless node.body
|
86
|
-
return unless (rest_args_name, args = use_rest_arguments?(node.arguments))
|
87
|
-
return if args.any?(&:default?)
|
88
146
|
|
89
|
-
node.
|
90
|
-
|
147
|
+
restarg, kwrestarg, blockarg = extract_forwardable_args(node.arguments)
|
148
|
+
forwardable_args = redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
149
|
+
send_nodes = node.each_descendant(:send).to_a
|
150
|
+
|
151
|
+
send_classifications = classify_send_nodes(
|
152
|
+
node, send_nodes, non_splat_or_block_pass_lvar_references(node.body), forwardable_args
|
153
|
+
)
|
91
154
|
|
92
|
-
|
93
|
-
all_lvars_as_forwarding_method_arguments?(node, send_node)
|
155
|
+
return if send_classifications.empty?
|
94
156
|
|
95
|
-
|
96
|
-
|
157
|
+
if only_forwards_all?(send_classifications)
|
158
|
+
add_forward_all_offenses(node, send_classifications, forwardable_args)
|
159
|
+
elsif target_ruby_version >= 3.2
|
160
|
+
add_post_ruby_32_offenses(node, send_classifications, forwardable_args)
|
97
161
|
end
|
98
162
|
end
|
163
|
+
|
99
164
|
alias on_defs on_def
|
100
165
|
|
101
166
|
private
|
102
167
|
|
103
|
-
def
|
104
|
-
|
105
|
-
block_arg_name = args.last.source.delete('&') if args.last&.blockarg_type?
|
106
|
-
|
107
|
-
[kwargs_name, block_arg_name].map { |name| name&.to_sym }
|
168
|
+
def extract_forwardable_args(args)
|
169
|
+
[args.find(&:restarg_type?), args.find(&:kwrestarg_type?), args.find(&:blockarg_type?)]
|
108
170
|
end
|
109
171
|
|
110
|
-
def
|
111
|
-
|
172
|
+
def redundant_forwardable_named_args(restarg, kwrestarg, blockarg)
|
173
|
+
restarg_node = redundant_named_arg(restarg, 'RedundantRestArgumentNames', '*')
|
174
|
+
kwrestarg_node = redundant_named_arg(kwrestarg, 'RedundantKeywordRestArgumentNames', '**')
|
175
|
+
blockarg_node = redundant_named_arg(blockarg, 'RedundantBlockArgumentNames', '&')
|
112
176
|
|
113
|
-
|
177
|
+
[restarg_node, kwrestarg_node, blockarg_node]
|
114
178
|
end
|
115
179
|
|
116
|
-
def
|
117
|
-
|
180
|
+
def only_forwards_all?(send_classifications)
|
181
|
+
send_classifications.all? { |_, c, _, _| c == :all }
|
182
|
+
end
|
183
|
+
|
184
|
+
# rubocop:disable Metrics/MethodLength
|
185
|
+
def add_forward_all_offenses(node, send_classifications, forwardable_args)
|
186
|
+
_rest_arg, _kwrest_arg, block_arg = *forwardable_args
|
187
|
+
registered_block_arg_offense = false
|
118
188
|
|
119
|
-
|
120
|
-
|
189
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
190
|
+
if !forward_rest && !forward_kwrest
|
191
|
+
# Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
|
192
|
+
# in Ruby 3.3.0.
|
193
|
+
if outside_block?(forward_block_arg)
|
194
|
+
register_forward_block_arg_offense(!forward_rest, node.arguments, block_arg)
|
195
|
+
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
196
|
+
end
|
197
|
+
registered_block_arg_offense = true
|
198
|
+
break
|
199
|
+
else
|
200
|
+
register_forward_all_offense(send_node, send_node, forward_rest)
|
201
|
+
end
|
202
|
+
end
|
121
203
|
|
122
|
-
|
204
|
+
return if registered_block_arg_offense
|
205
|
+
|
206
|
+
rest_arg, _kwrest_arg, _block_arg = *forwardable_args
|
207
|
+
register_forward_all_offense(node, node.arguments, rest_arg)
|
123
208
|
end
|
209
|
+
# rubocop:enable Metrics/MethodLength
|
210
|
+
|
211
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
212
|
+
def add_post_ruby_32_offenses(def_node, send_classifications, forwardable_args)
|
213
|
+
return unless use_anonymous_forwarding?
|
124
214
|
|
125
|
-
|
126
|
-
add_offense(arguments_range(forwarding_method)) do |corrector|
|
127
|
-
begin_pos = forwarding_method.loc.selector&.end_pos || forwarding_method.loc.dot.end_pos
|
128
|
-
range = range_between(begin_pos, forwarding_method.source_range.end_pos)
|
215
|
+
rest_arg, kwrest_arg, block_arg = *forwardable_args
|
129
216
|
|
130
|
-
|
217
|
+
send_classifications.each do |send_node, _c, forward_rest, forward_kwrest, forward_block_arg| # rubocop:disable Layout/LineLength
|
218
|
+
if outside_block?(forward_rest)
|
219
|
+
register_forward_args_offense(def_node.arguments, rest_arg)
|
220
|
+
register_forward_args_offense(send_node, forward_rest)
|
221
|
+
end
|
222
|
+
|
223
|
+
if outside_block?(forward_kwrest)
|
224
|
+
register_forward_kwargs_offense(!forward_rest, def_node.arguments, kwrest_arg)
|
225
|
+
register_forward_kwargs_offense(!forward_rest, send_node, forward_kwrest)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Prevents `anonymous block parameter is also used within block (SyntaxError)` occurs
|
229
|
+
# in Ruby 3.3.0.
|
230
|
+
if outside_block?(forward_block_arg)
|
231
|
+
register_forward_block_arg_offense(!forward_rest, def_node.arguments, block_arg)
|
232
|
+
register_forward_block_arg_offense(!forward_rest, send_node, forward_block_arg)
|
233
|
+
end
|
131
234
|
end
|
132
235
|
end
|
236
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
237
|
+
|
238
|
+
def non_splat_or_block_pass_lvar_references(body)
|
239
|
+
body.each_descendant(:lvar, :lvasgn).filter_map do |lvar|
|
240
|
+
parent = lvar.parent
|
241
|
+
|
242
|
+
next if lvar.lvar_type? && FORWARDING_LVAR_TYPES.include?(parent.type)
|
243
|
+
|
244
|
+
lvar.children.first
|
245
|
+
end.uniq
|
246
|
+
end
|
133
247
|
|
134
|
-
def
|
135
|
-
|
136
|
-
|
137
|
-
|
248
|
+
def classify_send_nodes(def_node, send_nodes, referenced_lvars, forwardable_args)
|
249
|
+
send_nodes.filter_map do |send_node|
|
250
|
+
classification_and_forwards = classification_and_forwards(
|
251
|
+
def_node,
|
252
|
+
send_node,
|
253
|
+
referenced_lvars,
|
254
|
+
forwardable_args
|
138
255
|
)
|
139
|
-
|
256
|
+
|
257
|
+
next unless classification_and_forwards
|
258
|
+
|
259
|
+
[send_node, *classification_and_forwards]
|
140
260
|
end
|
141
261
|
end
|
142
262
|
|
143
|
-
def
|
144
|
-
|
263
|
+
def classification_and_forwards(def_node, send_node, referenced_lvars, forwardable_args)
|
264
|
+
classifier = SendNodeClassifier.new(
|
265
|
+
def_node, send_node, referenced_lvars, forwardable_args,
|
266
|
+
target_ruby_version: target_ruby_version,
|
267
|
+
allow_only_rest_arguments: allow_only_rest_arguments?
|
268
|
+
)
|
269
|
+
|
270
|
+
classification = classifier.classification
|
271
|
+
|
272
|
+
return unless classification
|
145
273
|
|
146
|
-
|
274
|
+
[
|
275
|
+
classification,
|
276
|
+
classifier.forwarded_rest_arg,
|
277
|
+
classifier.forwarded_kwrest_arg,
|
278
|
+
classifier.forwarded_block_arg
|
279
|
+
]
|
280
|
+
end
|
281
|
+
|
282
|
+
def redundant_named_arg(arg, config_name, keyword)
|
283
|
+
return nil unless arg
|
284
|
+
|
285
|
+
redundant_arg_names = cop_config.fetch(config_name, []).map do |redundant_arg_name|
|
286
|
+
"#{keyword}#{redundant_arg_name}"
|
287
|
+
end << keyword
|
288
|
+
|
289
|
+
redundant_arg_names.include?(arg.source) ? arg : nil
|
290
|
+
end
|
291
|
+
|
292
|
+
def outside_block?(node)
|
293
|
+
return false unless node
|
294
|
+
|
295
|
+
node.each_ancestor(:block, :numblock).none?
|
296
|
+
end
|
297
|
+
|
298
|
+
def register_forward_args_offense(def_arguments_or_send, rest_arg_or_splat)
|
299
|
+
add_offense(rest_arg_or_splat, message: ARGS_MSG) do |corrector|
|
300
|
+
add_parens_if_missing(def_arguments_or_send, corrector)
|
301
|
+
|
302
|
+
corrector.replace(rest_arg_or_splat, '*')
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
def register_forward_kwargs_offense(add_parens, def_arguments_or_send, kwrest_arg_or_splat)
|
307
|
+
add_offense(kwrest_arg_or_splat, message: KWARGS_MSG) do |corrector|
|
308
|
+
add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
|
309
|
+
|
310
|
+
corrector.replace(kwrest_arg_or_splat, '**')
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def register_forward_block_arg_offense(add_parens, def_arguments_or_send, block_arg)
|
315
|
+
return if target_ruby_version <= 3.0 || block_arg.source == '&' || explicit_block_name?
|
316
|
+
|
317
|
+
add_offense(block_arg, message: BLOCK_MSG) do |corrector|
|
318
|
+
add_parens_if_missing(def_arguments_or_send, corrector) if add_parens
|
319
|
+
|
320
|
+
corrector.replace(block_arg, '&')
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def register_forward_all_offense(def_or_send, send_or_arguments, rest_or_splat)
|
325
|
+
arg_range = arguments_range(def_or_send, rest_or_splat)
|
326
|
+
|
327
|
+
add_offense(arg_range, message: FORWARDING_MSG) do |corrector|
|
328
|
+
add_parens_if_missing(send_or_arguments, corrector)
|
329
|
+
|
330
|
+
corrector.replace(arg_range, '...')
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
334
|
+
def arguments_range(node, first_node)
|
335
|
+
arguments = node.arguments.reject { |arg| ADDITIONAL_ARG_TYPES.include?(arg.type) }
|
336
|
+
|
337
|
+
start_node = first_node || arguments.first
|
338
|
+
|
339
|
+
range_between(start_node.source_range.begin_pos, arguments.last.source_range.end_pos)
|
147
340
|
end
|
148
341
|
|
149
342
|
def allow_only_rest_arguments?
|
150
343
|
cop_config.fetch('AllowOnlyRestArgument', true)
|
151
344
|
end
|
345
|
+
|
346
|
+
def use_anonymous_forwarding?
|
347
|
+
cop_config.fetch('UseAnonymousForwarding', false)
|
348
|
+
end
|
349
|
+
|
350
|
+
def add_parens_if_missing(node, corrector)
|
351
|
+
return if parentheses?(node)
|
352
|
+
|
353
|
+
add_parentheses(node, corrector)
|
354
|
+
end
|
355
|
+
|
356
|
+
# Classifies send nodes for possible rest/kwrest/all (including block) forwarding.
|
357
|
+
class SendNodeClassifier
|
358
|
+
extend NodePattern::Macros
|
359
|
+
|
360
|
+
# @!method forwarded_rest_arg?(node, rest_name)
|
361
|
+
def_node_matcher :forwarded_rest_arg?, '(splat (lvar %1))'
|
362
|
+
|
363
|
+
# @!method extract_forwarded_kwrest_arg(node, kwrest_name)
|
364
|
+
def_node_matcher :extract_forwarded_kwrest_arg, '(hash <$(kwsplat (lvar %1)) ...>)'
|
365
|
+
|
366
|
+
# @!method forwarded_block_arg?(node, block_name)
|
367
|
+
def_node_matcher :forwarded_block_arg?, '(block_pass {(lvar %1) nil?})'
|
368
|
+
|
369
|
+
def initialize(def_node, send_node, referenced_lvars, forwardable_args, **config)
|
370
|
+
@def_node = def_node
|
371
|
+
@send_node = send_node
|
372
|
+
@referenced_lvars = referenced_lvars
|
373
|
+
@rest_arg, @kwrest_arg, @block_arg = *forwardable_args
|
374
|
+
@rest_arg_name, @kwrest_arg_name, @block_arg_name =
|
375
|
+
*forwardable_args.map { |a| a&.name }
|
376
|
+
@config = config
|
377
|
+
end
|
378
|
+
|
379
|
+
def forwarded_rest_arg
|
380
|
+
return nil if referenced_rest_arg?
|
381
|
+
|
382
|
+
arguments.find { |arg| forwarded_rest_arg?(arg, @rest_arg_name) }
|
383
|
+
end
|
384
|
+
|
385
|
+
def forwarded_kwrest_arg
|
386
|
+
return nil if referenced_kwrest_arg?
|
387
|
+
|
388
|
+
arguments.filter_map { |arg| extract_forwarded_kwrest_arg(arg, @kwrest_arg_name) }.first
|
389
|
+
end
|
390
|
+
|
391
|
+
def forwarded_block_arg
|
392
|
+
return nil if referenced_block_arg?
|
393
|
+
|
394
|
+
arguments.find { |arg| forwarded_block_arg?(arg, @block_arg_name) }
|
395
|
+
end
|
396
|
+
|
397
|
+
def classification
|
398
|
+
return nil unless forwarded_rest_arg || forwarded_kwrest_arg || forwarded_block_arg
|
399
|
+
|
400
|
+
if can_forward_all?
|
401
|
+
:all
|
402
|
+
else
|
403
|
+
:rest_or_kwrest
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
private
|
408
|
+
|
409
|
+
def can_forward_all?
|
410
|
+
return false if any_arg_referenced?
|
411
|
+
return false if ruby_32_missing_rest_or_kwest?
|
412
|
+
return false unless offensive_block_forwarding?
|
413
|
+
return false if additional_kwargs_or_forwarded_kwargs?
|
414
|
+
|
415
|
+
no_additional_args? || (target_ruby_version >= 3.0 && no_post_splat_args?)
|
416
|
+
end
|
417
|
+
|
418
|
+
def ruby_32_missing_rest_or_kwest?
|
419
|
+
target_ruby_version >= 3.2 && !forwarded_rest_and_kwrest_args
|
420
|
+
end
|
421
|
+
|
422
|
+
def offensive_block_forwarding?
|
423
|
+
@block_arg ? forwarded_block_arg : allow_offense_for_no_block?
|
424
|
+
end
|
425
|
+
|
426
|
+
def forwarded_rest_and_kwrest_args
|
427
|
+
forwarded_rest_arg && forwarded_kwrest_arg
|
428
|
+
end
|
429
|
+
|
430
|
+
def arguments
|
431
|
+
@send_node.arguments
|
432
|
+
end
|
433
|
+
|
434
|
+
def referenced_rest_arg?
|
435
|
+
@referenced_lvars.include?(@rest_arg_name)
|
436
|
+
end
|
437
|
+
|
438
|
+
def referenced_kwrest_arg?
|
439
|
+
@referenced_lvars.include?(@kwrest_arg_name)
|
440
|
+
end
|
441
|
+
|
442
|
+
def referenced_block_arg?
|
443
|
+
@referenced_lvars.include?(@block_arg_name)
|
444
|
+
end
|
445
|
+
|
446
|
+
def any_arg_referenced?
|
447
|
+
referenced_rest_arg? || referenced_kwrest_arg? || referenced_block_arg?
|
448
|
+
end
|
449
|
+
|
450
|
+
def target_ruby_version
|
451
|
+
@config.fetch(:target_ruby_version)
|
452
|
+
end
|
453
|
+
|
454
|
+
def no_post_splat_args?
|
455
|
+
return true unless (splat_index = arguments.index(forwarded_rest_arg))
|
456
|
+
|
457
|
+
arg_after_splat = arguments[splat_index + 1]
|
458
|
+
[nil, :hash, :block_pass].include?(arg_after_splat&.type)
|
459
|
+
end
|
460
|
+
|
461
|
+
def additional_kwargs_or_forwarded_kwargs?
|
462
|
+
additional_kwargs? || forward_additional_kwargs?
|
463
|
+
end
|
464
|
+
|
465
|
+
def additional_kwargs?
|
466
|
+
@def_node.arguments.any? { |a| a.kwarg_type? || a.kwoptarg_type? }
|
467
|
+
end
|
468
|
+
|
469
|
+
def forward_additional_kwargs?
|
470
|
+
return false unless forwarded_kwrest_arg
|
471
|
+
|
472
|
+
!forwarded_kwrest_arg.parent.children.one?
|
473
|
+
end
|
474
|
+
|
475
|
+
def allow_offense_for_no_block?
|
476
|
+
!@config.fetch(:allow_only_rest_arguments)
|
477
|
+
end
|
478
|
+
|
479
|
+
def no_additional_args?
|
480
|
+
forwardable_count = [@rest_arg, @kwrest_arg, @block_arg].compact.size
|
481
|
+
|
482
|
+
return false if missing_rest_arg_or_kwrest_arg?
|
483
|
+
|
484
|
+
@def_node.arguments.size == forwardable_count &&
|
485
|
+
@send_node.arguments.size == forwardable_count
|
486
|
+
end
|
487
|
+
|
488
|
+
def missing_rest_arg_or_kwrest_arg?
|
489
|
+
(@rest_arg_name && !forwarded_rest_arg) ||
|
490
|
+
(@kwrest_arg_name && !forwarded_kwrest_arg)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
def explicit_block_name?
|
495
|
+
block_forwarding_config = config.for_cop('Naming/BlockForwarding')
|
496
|
+
return false unless block_forwarding_config['Enabled']
|
497
|
+
|
498
|
+
block_forwarding_config['EnforcedStyle'] == 'explicit'
|
499
|
+
end
|
152
500
|
end
|
153
501
|
end
|
154
502
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Identifies usages of `arr[0]` and `arr[-1]` and suggests to change
|
7
|
+
# them to use `arr.first` and `arr.last` instead.
|
8
|
+
#
|
9
|
+
# The cop is disabled by default due to safety concerns.
|
10
|
+
#
|
11
|
+
# @safety
|
12
|
+
# This cop is unsafe because `[0]` or `[-1]` can be called on a Hash,
|
13
|
+
# which returns a value for `0` or `-1` key, but changing these to use
|
14
|
+
# `.first` or `.last` will return first/last tuple instead. Also, String
|
15
|
+
# does not implement `first`/`last` methods.
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# # bad
|
19
|
+
# arr[0]
|
20
|
+
# arr[-1]
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# arr.first
|
24
|
+
# arr.last
|
25
|
+
# arr[0] = 2
|
26
|
+
# arr[0][-2]
|
27
|
+
#
|
28
|
+
class ArrayFirstLast < Base
|
29
|
+
extend AutoCorrector
|
30
|
+
|
31
|
+
MSG = 'Use `%<preferred>s`.'
|
32
|
+
RESTRICT_ON_SEND = %i[[]].freeze
|
33
|
+
|
34
|
+
# rubocop:disable Metrics/AbcSize
|
35
|
+
def on_send(node)
|
36
|
+
return unless node.arguments.size == 1 && node.first_argument.int_type?
|
37
|
+
|
38
|
+
value = node.first_argument.value
|
39
|
+
return unless [0, -1].include?(value)
|
40
|
+
|
41
|
+
node = innermost_braces_node(node)
|
42
|
+
return if node.parent && brace_method?(node.parent)
|
43
|
+
|
44
|
+
preferred = (value.zero? ? 'first' : 'last')
|
45
|
+
add_offense(node.loc.selector, message: format(MSG, preferred: preferred)) do |corrector|
|
46
|
+
corrector.replace(node.loc.selector, ".#{preferred}")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
# rubocop:enable Metrics/AbcSize
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def innermost_braces_node(node)
|
54
|
+
node = node.receiver while node.receiver.send_type? && node.receiver.method?(:[])
|
55
|
+
node
|
56
|
+
end
|
57
|
+
|
58
|
+
def brace_method?(node)
|
59
|
+
node.send_type? && (node.method?(:[]) || node.method?(:[]=))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -11,6 +11,15 @@ module RuboCop
|
|
11
11
|
# The `array1.intersect?(array2)` method is faster than
|
12
12
|
# `(array1 & array2).any?` and is more readable.
|
13
13
|
#
|
14
|
+
# In cases like the following, compatibility is not ensured,
|
15
|
+
# so it will not be detected when using block argument.
|
16
|
+
#
|
17
|
+
# [source,ruby]
|
18
|
+
# ----
|
19
|
+
# ([1] & [1,2]).any? { |x| false } # => false
|
20
|
+
# [1].intersect?([1,2]) { |x| false } # => true
|
21
|
+
# ----
|
22
|
+
#
|
14
23
|
# @safety
|
15
24
|
# This cop cannot guarantee that `array1` and `array2` are
|
16
25
|
# actually arrays while method `intersect?` is for arrays only.
|
@@ -68,16 +77,15 @@ module RuboCop
|
|
68
77
|
RESTRICT_ON_SEND = (STRAIGHT_METHODS + NEGATED_METHODS).freeze
|
69
78
|
|
70
79
|
def on_send(node)
|
80
|
+
return if (parent = node.parent) && (parent.block_type? || parent.numblock_type?)
|
71
81
|
return unless (receiver, argument, method_name = bad_intersection_check?(node))
|
72
82
|
|
73
83
|
message = message(receiver.source, argument.source, method_name)
|
74
84
|
|
75
85
|
add_offense(node, message: message) do |corrector|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
corrector.replace(node, "!#{receiver.source}.intersect?(#{argument.source})")
|
80
|
-
end
|
86
|
+
bang = straight?(method_name) ? '' : '!'
|
87
|
+
|
88
|
+
corrector.replace(node, "#{bang}#{receiver.source}.intersect?(#{argument.source})")
|
81
89
|
end
|
82
90
|
end
|
83
91
|
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
24
24
|
def on_send(node)
|
25
25
|
return unless node.command?(:attr) && node.arguments?
|
26
26
|
# check only for method definitions in class/module body
|
27
|
-
return if
|
27
|
+
return if allowed_context?(node)
|
28
28
|
|
29
29
|
message = message(node)
|
30
30
|
add_offense(node.loc.selector, message: message) do |corrector|
|
@@ -34,6 +34,16 @@ module RuboCop
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
+
def allowed_context?(node)
|
38
|
+
return false unless (class_node = node.each_ancestor(:class, :block).first)
|
39
|
+
|
40
|
+
(!class_node.class_type? && !class_eval?(class_node)) || define_attr_method?(class_node)
|
41
|
+
end
|
42
|
+
|
43
|
+
def define_attr_method?(node)
|
44
|
+
node.each_descendant(:def).any? { |def_node| def_node.method?(:attr) }
|
45
|
+
end
|
46
|
+
|
37
47
|
def autocorrect(corrector, node)
|
38
48
|
attr_name, setter = *node.arguments
|
39
49
|
|