rubocop 1.72.1 → 1.81.7
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/README.md +22 -18
- data/config/default.yml +240 -65
- data/config/internal_affairs.yml +20 -0
- data/config/obsoletion.yml +8 -3
- data/exe/rubocop +1 -8
- data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
- data/lib/rubocop/cli.rb +19 -4
- data/lib/rubocop/config.rb +35 -6
- data/lib/rubocop/config_loader.rb +8 -40
- data/lib/rubocop/config_loader_resolver.rb +9 -7
- data/lib/rubocop/config_obsoletion/extracted_cop.rb +4 -3
- data/lib/rubocop/config_obsoletion/renamed_cop.rb +18 -3
- data/lib/rubocop/config_obsoletion.rb +46 -2
- data/lib/rubocop/config_store.rb +5 -0
- data/lib/rubocop/config_validator.rb +7 -6
- data/lib/rubocop/cop/autocorrect_logic.rb +22 -14
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +7 -4
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +37 -15
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +9 -5
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +6 -2
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +92 -0
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +6 -5
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +6 -1
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/internal_affairs.rb +1 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/block_end_newline.rb +1 -0
- data/lib/rubocop/cop/layout/class_structure.rb +36 -1
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +5 -5
- data/lib/rubocop/cop/layout/def_end_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +32 -14
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +101 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +34 -4
- data/lib/rubocop/cop/layout/empty_lines_around_arguments.rb +8 -29
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_class_body.rb +1 -1
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/hash_alignment.rb +4 -7
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -0
- data/lib/rubocop/cop/layout/leading_comment_space.rb +13 -1
- data/lib/rubocop/cop/layout/line_length.rb +43 -10
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_method_parameter_line_breaks.rb +1 -0
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +9 -5
- data/lib/rubocop/cop/layout/redundant_line_break.rb +9 -5
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +11 -5
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +10 -0
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +12 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +1 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +5 -38
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +12 -3
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +1 -0
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -5
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +13 -7
- data/lib/rubocop/cop/lint/debugger.rb +2 -4
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +5 -2
- data/lib/rubocop/cop/lint/duplicate_methods.rb +111 -23
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +14 -64
- data/lib/rubocop/cop/lint/empty_interpolation.rb +14 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +0 -6
- data/lib/rubocop/cop/lint/float_comparison.rb +32 -10
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +124 -10
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
- data/lib/rubocop/cop/lint/mixed_case_range.rb +2 -2
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +3 -3
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +1 -1
- data/lib/rubocop/cop/lint/raise_exception.rb +29 -10
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +0 -21
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +43 -13
- data/lib/rubocop/cop/lint/redundant_with_index.rb +3 -0
- data/lib/rubocop/cop/lint/redundant_with_object.rb +3 -0
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- 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/return_in_void_context.rb +9 -11
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +31 -5
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +13 -1
- data/lib/rubocop/cop/lint/shared_mutable_default.rb +12 -1
- data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
- data/lib/rubocop/cop/lint/to_enum_arguments.rb +1 -1
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +1 -1
- data/lib/rubocop/cop/lint/unexpected_block_arity.rb +2 -0
- data/lib/rubocop/cop/lint/unreachable_code.rb +1 -0
- data/lib/rubocop/cop/lint/unreachable_loop.rb +5 -5
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +30 -4
- data/lib/rubocop/cop/lint/useless_assignment.rb +2 -0
- data/lib/rubocop/cop/lint/useless_constant_scoping.rb +9 -12
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/lint/void.rb +16 -2
- data/lib/rubocop/cop/message_annotator.rb +7 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +1 -0
- data/lib/rubocop/cop/metrics/method_length.rb +1 -0
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +4 -4
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +3 -3
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -2
- data/lib/rubocop/cop/mixin/def_node.rb +1 -1
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +20 -0
- data/lib/rubocop/cop/mixin/forbidden_pattern.rb +16 -0
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -2
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
- data/lib/rubocop/cop/mixin/hash_subset.rb +19 -4
- data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -0
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/range_help.rb +12 -0
- data/lib/rubocop/cop/mixin/target_ruby_version.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +18 -2
- data/lib/rubocop/cop/naming/block_forwarding.rb +3 -3
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_name.rb +187 -15
- data/lib/rubocop/cop/naming/predicate_method.rb +319 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
- data/lib/rubocop/cop/naming/variable_name.rb +51 -6
- data/lib/rubocop/cop/registry.rb +9 -6
- data/lib/rubocop/cop/security/eval.rb +2 -1
- data/lib/rubocop/cop/security/json_load.rb +33 -11
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +32 -10
- data/lib/rubocop/cop/style/accessor_grouping.rb +32 -6
- data/lib/rubocop/cop/style/arguments_forwarding.rb +21 -24
- data/lib/rubocop/cop/style/array_intersect.rb +113 -38
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
- data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
- data/lib/rubocop/cop/style/block_delimiters.rb +3 -2
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/class_and_module_children.rb +48 -10
- data/lib/rubocop/cop/style/class_equality_comparison.rb +1 -1
- data/lib/rubocop/cop/style/collection_methods.rb +1 -0
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +1 -0
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +12 -5
- data/lib/rubocop/cop/style/comparable_between.rb +78 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +26 -8
- data/lib/rubocop/cop/style/constant_visibility.rb +14 -9
- data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
- data/lib/rubocop/cop/style/def_with_parentheses.rb +18 -5
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/double_negation.rb +3 -3
- data/lib/rubocop/cop/style/empty_literal.rb +4 -0
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/endless_method.rb +176 -18
- data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -7
- data/lib/rubocop/cop/style/explicit_block_argument.rb +3 -3
- data/lib/rubocop/cop/style/exponential_notation.rb +5 -4
- data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
- data/lib/rubocop/cop/style/float_division.rb +15 -1
- data/lib/rubocop/cop/style/for.rb +1 -0
- data/lib/rubocop/cop/style/format_string_token.rb +38 -11
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +3 -2
- data/lib/rubocop/cop/style/global_std_stream.rb +3 -0
- data/lib/rubocop/cop/style/guard_clause.rb +2 -1
- data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
- data/lib/rubocop/cop/style/hash_each_methods.rb +3 -2
- data/lib/rubocop/cop/style/hash_fetch_chain.rb +104 -0
- data/lib/rubocop/cop/style/hash_syntax.rb +4 -1
- 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 +3 -3
- data/lib/rubocop/cop/style/if_inside_else.rb +10 -13
- data/lib/rubocop/cop/style/if_unless_modifier.rb +35 -8
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/inverse_methods.rb +10 -6
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +2 -2
- data/lib/rubocop/cop/style/ip_addresses.rb +2 -2
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +121 -0
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +13 -7
- data/lib/rubocop/cop/style/lambda.rb +1 -0
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/line_end_concatenation.rb +10 -4
- data/lib/rubocop/cop/style/map_into_array.rb +4 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +12 -3
- data/lib/rubocop/cop/style/map_to_set.rb +1 -3
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +9 -8
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +2 -1
- data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
- data/lib/rubocop/cop/style/multiline_block_chain.rb +2 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +1 -9
- data/lib/rubocop/cop/style/next.rb +44 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
- data/lib/rubocop/cop/style/object_then.rb +1 -0
- data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
- data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/proc.rb +1 -0
- data/lib/rubocop/cop/style/raise_args.rb +8 -8
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +35 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +57 -0
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +14 -4
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
- data/lib/rubocop/cop/style/redundant_format.rb +79 -18
- data/lib/rubocop/cop/style/redundant_freeze.rb +2 -2
- data/lib/rubocop/cop/style/redundant_interpolation.rb +12 -3
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -4
- data/lib/rubocop/cop/style/redundant_parentheses.rb +73 -18
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +4 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_self.rb +9 -5
- data/lib/rubocop/cop/style/redundant_self_assignment.rb +1 -1
- data/lib/rubocop/cop/style/redundant_sort_by.rb +17 -1
- data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +3 -0
- data/lib/rubocop/cop/style/return_nil.rb +2 -2
- data/lib/rubocop/cop/style/safe_navigation.rb +61 -14
- data/lib/rubocop/cop/style/select_by_regexp.rb +4 -1
- data/lib/rubocop/cop/style/semicolon.rb +23 -7
- data/lib/rubocop/cop/style/single_line_do_end_block.rb +3 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +10 -7
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +75 -101
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +18 -15
- data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
- data/lib/rubocop/cop/style/super_arguments.rb +1 -2
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +3 -1
- data/lib/rubocop/cop/style/top_level_method_definition.rb +1 -0
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +52 -1
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +47 -6
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +48 -6
- data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
- data/lib/rubocop/cop/style/unless_else.rb +10 -9
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/utils/format_string.rb +15 -2
- data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
- data/lib/rubocop/cop/variable_force/scope.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +3 -8
- data/lib/rubocop/cop/variable_force.rb +26 -9
- data/lib/rubocop/cops_documentation_generator.rb +23 -7
- data/lib/rubocop/directive_comment.rb +1 -1
- data/lib/rubocop/ext/regexp_node.rb +0 -1
- data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -5
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +2 -1
- data/lib/rubocop/lsp/diagnostic.rb +25 -24
- data/lib/rubocop/lsp/routes.rb +65 -9
- data/lib/rubocop/lsp/runtime.rb +5 -5
- data/lib/rubocop/lsp/server.rb +2 -2
- data/lib/rubocop/lsp/stdin_runner.rb +3 -17
- data/lib/rubocop/magic_comment.rb +8 -0
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/plugin/configuration_integrator.rb +2 -0
- data/lib/rubocop/plugin/load_error.rb +1 -1
- data/lib/rubocop/plugin.rb +9 -2
- data/lib/rubocop/result_cache.rb +14 -12
- data/lib/rubocop/rspec/cop_helper.rb +6 -1
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- data/lib/rubocop/rspec/shared_contexts.rb +34 -0
- data/lib/rubocop/rspec/support.rb +3 -0
- data/lib/rubocop/runner.rb +10 -4
- data/lib/rubocop/server/cache.rb +17 -12
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/target_finder.rb +13 -9
- data/lib/rubocop/target_ruby.rb +11 -2
- data/lib/rubocop/version.rb +14 -7
- data/lib/rubocop.rb +17 -2
- data/lib/ruby_lsp/rubocop/addon.rb +25 -10
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +57 -5
- metadata +24 -8
- data/lib/rubocop/cop/utils/regexp_ranges.rb +0 -113
|
@@ -6,6 +6,10 @@ module RuboCop
|
|
|
6
6
|
# Checks for duplicated instance (or singleton) method
|
|
7
7
|
# definitions.
|
|
8
8
|
#
|
|
9
|
+
# NOTE: Aliasing a method to itself is allowed, as it indicates that
|
|
10
|
+
# the developer intends to suppress Ruby's method redefinition warnings.
|
|
11
|
+
# See https://bugs.ruby-lang.org/issues/13574.
|
|
12
|
+
#
|
|
9
13
|
# @example
|
|
10
14
|
#
|
|
11
15
|
# # bad
|
|
@@ -39,10 +43,64 @@ module RuboCop
|
|
|
39
43
|
# end
|
|
40
44
|
#
|
|
41
45
|
# alias bar foo
|
|
46
|
+
#
|
|
47
|
+
# # good
|
|
48
|
+
# alias foo foo
|
|
49
|
+
# def foo
|
|
50
|
+
# 1
|
|
51
|
+
# end
|
|
52
|
+
#
|
|
53
|
+
# # good
|
|
54
|
+
# alias_method :foo, :foo
|
|
55
|
+
# def foo
|
|
56
|
+
# 1
|
|
57
|
+
# end
|
|
58
|
+
#
|
|
59
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
|
60
|
+
#
|
|
61
|
+
# # good
|
|
62
|
+
# def foo
|
|
63
|
+
# 1
|
|
64
|
+
# end
|
|
65
|
+
#
|
|
66
|
+
# delegate :foo, to: :bar
|
|
67
|
+
#
|
|
68
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
|
69
|
+
#
|
|
70
|
+
# # bad
|
|
71
|
+
# def foo
|
|
72
|
+
# 1
|
|
73
|
+
# end
|
|
74
|
+
#
|
|
75
|
+
# delegate :foo, to: :bar
|
|
76
|
+
#
|
|
77
|
+
# # good
|
|
78
|
+
# def foo
|
|
79
|
+
# 1
|
|
80
|
+
# end
|
|
81
|
+
#
|
|
82
|
+
# delegate :baz, to: :bar
|
|
83
|
+
#
|
|
84
|
+
# # good - delegate with splat arguments is ignored
|
|
85
|
+
# def foo
|
|
86
|
+
# 1
|
|
87
|
+
# end
|
|
88
|
+
#
|
|
89
|
+
# delegate :foo, **options
|
|
90
|
+
#
|
|
91
|
+
# # good - delegate inside a condition is ignored
|
|
92
|
+
# def foo
|
|
93
|
+
# 1
|
|
94
|
+
# end
|
|
95
|
+
#
|
|
96
|
+
# if cond
|
|
97
|
+
# delegate :foo, to: :bar
|
|
98
|
+
# end
|
|
99
|
+
#
|
|
42
100
|
class DuplicateMethods < Base
|
|
43
101
|
MSG = 'Method `%<method>s` is defined at both %<defined>s and %<current>s.'
|
|
44
|
-
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr
|
|
45
|
-
|
|
102
|
+
RESTRICT_ON_SEND = %i[alias_method attr_reader attr_writer attr_accessor attr
|
|
103
|
+
delegate].freeze
|
|
46
104
|
|
|
47
105
|
def initialize(config = nil, options = nil)
|
|
48
106
|
super
|
|
@@ -54,14 +112,12 @@ module RuboCop
|
|
|
54
112
|
# if a method definition is inside an if, it is very likely
|
|
55
113
|
# that a different definition is used depending on platform, etc.
|
|
56
114
|
return if node.each_ancestor.any?(&:if_type?)
|
|
57
|
-
return if possible_dsl?(node)
|
|
58
115
|
|
|
59
116
|
found_instance_method(node, node.method_name)
|
|
60
117
|
end
|
|
61
118
|
|
|
62
119
|
def on_defs(node)
|
|
63
120
|
return if node.each_ancestor.any?(&:if_type?)
|
|
64
|
-
return if possible_dsl?(node)
|
|
65
121
|
|
|
66
122
|
if node.receiver.const_type?
|
|
67
123
|
_, const_name = *node.receiver
|
|
@@ -73,32 +129,48 @@ module RuboCop
|
|
|
73
129
|
|
|
74
130
|
# @!method method_alias?(node)
|
|
75
131
|
def_node_matcher :method_alias?, <<~PATTERN
|
|
76
|
-
(alias (sym $_name) sym)
|
|
132
|
+
(alias (sym $_name) (sym $_original_name))
|
|
77
133
|
PATTERN
|
|
78
134
|
|
|
79
135
|
def on_alias(node)
|
|
80
|
-
|
|
136
|
+
name, original_name = method_alias?(node)
|
|
137
|
+
return unless name && original_name
|
|
138
|
+
return if name == original_name
|
|
81
139
|
return if node.ancestors.any?(&:if_type?)
|
|
82
|
-
return if possible_dsl?(node)
|
|
83
140
|
|
|
84
141
|
found_instance_method(node, name)
|
|
85
142
|
end
|
|
86
143
|
|
|
87
144
|
# @!method alias_method?(node)
|
|
88
145
|
def_node_matcher :alias_method?, <<~PATTERN
|
|
89
|
-
(send nil? :alias_method (sym $_name)
|
|
146
|
+
(send nil? :alias_method (sym $_name) (sym $_original_name))
|
|
147
|
+
PATTERN
|
|
148
|
+
|
|
149
|
+
# @!method delegate_method?(node)
|
|
150
|
+
def_node_matcher :delegate_method?, <<~PATTERN
|
|
151
|
+
(send nil? :delegate
|
|
152
|
+
({sym str} $_)+
|
|
153
|
+
(hash <(pair (sym :to) {sym str}) ...>)
|
|
154
|
+
)
|
|
90
155
|
PATTERN
|
|
91
156
|
|
|
92
157
|
# @!method sym_name(node)
|
|
93
158
|
def_node_matcher :sym_name, '(sym $_name)'
|
|
94
|
-
|
|
95
|
-
|
|
159
|
+
|
|
160
|
+
def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
161
|
+
name, original_name = alias_method?(node)
|
|
162
|
+
|
|
163
|
+
if name && original_name
|
|
164
|
+
return if name == original_name
|
|
96
165
|
return if node.ancestors.any?(&:if_type?)
|
|
97
|
-
return if possible_dsl?(node)
|
|
98
166
|
|
|
99
167
|
found_instance_method(node, name)
|
|
100
168
|
elsif (attr = node.attribute_accessor?)
|
|
101
169
|
on_attr(node, *attr)
|
|
170
|
+
elsif active_support_extensions_enabled? && (names = delegate_method?(node))
|
|
171
|
+
return if node.ancestors.any?(&:if_type?)
|
|
172
|
+
|
|
173
|
+
on_delegate(node, names)
|
|
102
174
|
end
|
|
103
175
|
end
|
|
104
176
|
|
|
@@ -123,6 +195,32 @@ module RuboCop
|
|
|
123
195
|
current: source_location(node))
|
|
124
196
|
end
|
|
125
197
|
|
|
198
|
+
def on_delegate(node, method_names)
|
|
199
|
+
name_prefix = delegate_prefix(node)
|
|
200
|
+
|
|
201
|
+
method_names.each do |name|
|
|
202
|
+
name = "#{name_prefix}_#{name}" if name_prefix
|
|
203
|
+
|
|
204
|
+
found_instance_method(node, name)
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def delegate_prefix(node)
|
|
209
|
+
kwargs_node = node.last_argument
|
|
210
|
+
|
|
211
|
+
return unless (prefix = hash_value(kwargs_node, :prefix))
|
|
212
|
+
|
|
213
|
+
if prefix.true_type?
|
|
214
|
+
hash_value(kwargs_node, :to).value
|
|
215
|
+
elsif prefix.type?(:sym, :str)
|
|
216
|
+
prefix.value
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def hash_value(node, key)
|
|
221
|
+
node.pairs.find { |pair| pair.key.value == key }&.value
|
|
222
|
+
end
|
|
223
|
+
|
|
126
224
|
def found_instance_method(node, name)
|
|
127
225
|
return found_sclass_method(node, name) unless (scope = node.parent_module_name)
|
|
128
226
|
|
|
@@ -166,7 +264,7 @@ module RuboCop
|
|
|
166
264
|
end
|
|
167
265
|
|
|
168
266
|
def method_key(node, method_name)
|
|
169
|
-
if (ancestor_def = node.each_ancestor(
|
|
267
|
+
if (ancestor_def = node.each_ancestor(:any_def).first)
|
|
170
268
|
"#{ancestor_def.method_name}.#{method_name}"
|
|
171
269
|
else
|
|
172
270
|
method_name
|
|
@@ -174,7 +272,7 @@ module RuboCop
|
|
|
174
272
|
end
|
|
175
273
|
|
|
176
274
|
def location(node)
|
|
177
|
-
if
|
|
275
|
+
if node.any_def_type?
|
|
178
276
|
node.loc.keyword.join(node.loc.name)
|
|
179
277
|
else
|
|
180
278
|
node.source_range
|
|
@@ -237,16 +335,6 @@ module RuboCop
|
|
|
237
335
|
end
|
|
238
336
|
end
|
|
239
337
|
|
|
240
|
-
def possible_dsl?(node)
|
|
241
|
-
# DSL methods may evaluate a block in the context of a newly created
|
|
242
|
-
# class or module
|
|
243
|
-
# Assume that if a method definition is inside any block call which
|
|
244
|
-
# we can't identify, it could be a DSL
|
|
245
|
-
node.each_ancestor(:block).any? do |ancestor|
|
|
246
|
-
!ancestor.method?(:class_eval) && !ancestor.class_constructor?
|
|
247
|
-
end
|
|
248
|
-
end
|
|
249
|
-
|
|
250
338
|
def source_location(node)
|
|
251
339
|
range = node.source_range
|
|
252
340
|
path = smart_path(range.source_buffer.name)
|
|
@@ -24,8 +24,6 @@ module RuboCop
|
|
|
24
24
|
|
|
25
25
|
MSG_REPEATED_ELEMENT = 'Duplicate element inside regexp character class'
|
|
26
26
|
|
|
27
|
-
OCTAL_DIGITS_AFTER_ESCAPE = 2
|
|
28
|
-
|
|
29
27
|
def on_regexp(node)
|
|
30
28
|
each_repeated_character_class_element_loc(node) do |loc|
|
|
31
29
|
add_offense(loc, message: MSG_REPEATED_ELEMENT) do |corrector|
|
|
@@ -40,9 +38,9 @@ module RuboCop
|
|
|
40
38
|
|
|
41
39
|
seen = Set.new
|
|
42
40
|
group_expressions(node, expr.expressions) do |group|
|
|
43
|
-
group_source = group.
|
|
41
|
+
group_source = group.to_s
|
|
44
42
|
|
|
45
|
-
yield
|
|
43
|
+
yield group.expression if seen.include?(group_source)
|
|
46
44
|
|
|
47
45
|
seen << group_source
|
|
48
46
|
end
|
|
@@ -52,40 +50,13 @@ module RuboCop
|
|
|
52
50
|
private
|
|
53
51
|
|
|
54
52
|
def group_expressions(node, expressions)
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
until expressions.empty?
|
|
59
|
-
# With we may need to compose a group of multiple expressions.
|
|
60
|
-
group = [expressions.shift]
|
|
61
|
-
next if within_interpolation?(node, group.first)
|
|
62
|
-
|
|
63
|
-
# With regexp_parser < 2.7 escaped octal sequences may be up to 3
|
|
64
|
-
# separate expressions ("\\0", "0", "1").
|
|
65
|
-
pop_octal_digits(group, expressions) if escaped_octal?(group.first.to_s)
|
|
66
|
-
|
|
67
|
-
yield(group)
|
|
68
|
-
end
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
def pop_octal_digits(current_child, expressions)
|
|
72
|
-
OCTAL_DIGITS_AFTER_ESCAPE.times do
|
|
73
|
-
next_child = expressions.first
|
|
74
|
-
break unless octal?(next_child.to_s)
|
|
53
|
+
expressions.each do |expression|
|
|
54
|
+
next if within_interpolation?(node, expression)
|
|
75
55
|
|
|
76
|
-
|
|
56
|
+
yield(expression)
|
|
77
57
|
end
|
|
78
58
|
end
|
|
79
59
|
|
|
80
|
-
def source_range(children)
|
|
81
|
-
return children.first.expression if children.size == 1
|
|
82
|
-
|
|
83
|
-
range_between(
|
|
84
|
-
children.first.expression.begin_pos,
|
|
85
|
-
children.last.expression.begin_pos + children.last.to_s.length
|
|
86
|
-
)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
60
|
def skip_expression?(expr)
|
|
90
61
|
expr.type != :set || expr.token == :intersection
|
|
91
62
|
end
|
|
@@ -99,14 +70,6 @@ module RuboCop
|
|
|
99
70
|
interpolation_locs(node).any? { |il| il.overlaps?(parse_tree_child_loc) }
|
|
100
71
|
end
|
|
101
72
|
|
|
102
|
-
def escaped_octal?(string)
|
|
103
|
-
string.length == 2 && string[0] == '\\' && octal?(string[1])
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def octal?(char)
|
|
107
|
-
('0'..'7').cover?(char)
|
|
108
|
-
end
|
|
109
|
-
|
|
110
73
|
def interpolation_locs(node)
|
|
111
74
|
@interpolation_locs ||= {}
|
|
112
75
|
|
|
@@ -7,11 +7,6 @@ module RuboCop
|
|
|
7
7
|
#
|
|
8
8
|
# NOTE: empty `else` branches are handled by `Style/EmptyElse`.
|
|
9
9
|
#
|
|
10
|
-
# @safety
|
|
11
|
-
# Autocorrection for this cop is not safe. The conditions for empty branches that
|
|
12
|
-
# the autocorrection removes may have side effects, or the logic in subsequent
|
|
13
|
-
# branches may change due to the removal of a previous condition.
|
|
14
|
-
#
|
|
15
10
|
# @example
|
|
16
11
|
# # bad
|
|
17
12
|
# if condition
|
|
@@ -41,6 +36,13 @@ module RuboCop
|
|
|
41
36
|
# if condition
|
|
42
37
|
# do_something
|
|
43
38
|
# elsif other_condition
|
|
39
|
+
# nil
|
|
40
|
+
# end
|
|
41
|
+
#
|
|
42
|
+
# # good
|
|
43
|
+
# if condition
|
|
44
|
+
# do_something
|
|
45
|
+
# elsif other_condition
|
|
44
46
|
# do_something_else
|
|
45
47
|
# end
|
|
46
48
|
#
|
|
@@ -63,11 +65,9 @@ module RuboCop
|
|
|
63
65
|
class EmptyConditionalBody < Base
|
|
64
66
|
extend AutoCorrector
|
|
65
67
|
include CommentsHelp
|
|
66
|
-
include RangeHelp
|
|
67
68
|
|
|
68
69
|
MSG = 'Avoid `%<keyword>s` branches without a body.'
|
|
69
70
|
|
|
70
|
-
# rubocop:disable Metrics/AbcSize
|
|
71
71
|
def on_if(node)
|
|
72
72
|
return if node.body || same_line?(node.loc.begin, node.loc.end)
|
|
73
73
|
return if cop_config['AllowComments'] && contains_comments?(node)
|
|
@@ -75,12 +75,11 @@ module RuboCop
|
|
|
75
75
|
range = offense_range(node)
|
|
76
76
|
|
|
77
77
|
add_offense(range, message: format(MSG, keyword: node.keyword)) do |corrector|
|
|
78
|
-
next
|
|
78
|
+
next unless can_simplify_conditional?(node)
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
flip_orphaned_else(corrector, node)
|
|
81
81
|
end
|
|
82
82
|
end
|
|
83
|
-
# rubocop:enable Metrics/AbcSize
|
|
84
83
|
|
|
85
84
|
private
|
|
86
85
|
|
|
@@ -92,53 +91,23 @@ module RuboCop
|
|
|
92
91
|
end
|
|
93
92
|
end
|
|
94
93
|
|
|
95
|
-
def
|
|
96
|
-
|
|
97
|
-
remove_empty_branch(corrector, node)
|
|
98
|
-
correct_other_branches(corrector, node)
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def remove_comments(corrector, node)
|
|
102
|
-
comments_in_range(node).each do |comment|
|
|
103
|
-
range = range_by_whole_lines(comment.source_range, include_final_newline: true)
|
|
104
|
-
corrector.remove(range)
|
|
105
|
-
end
|
|
94
|
+
def can_simplify_conditional?(node)
|
|
95
|
+
node.else_branch && node.loc.else.source == 'else'
|
|
106
96
|
end
|
|
107
97
|
|
|
108
|
-
# rubocop:disable Metrics/AbcSize
|
|
109
98
|
def remove_empty_branch(corrector, node)
|
|
110
99
|
range = if empty_if_branch?(node) && else_branch?(node)
|
|
111
100
|
branch_range(node)
|
|
112
|
-
elsif same_line?(node, else_kw_loc = node.loc.else)
|
|
113
|
-
node.source_range.begin.join(else_kw_loc.begin)
|
|
114
|
-
elsif node.parent&.loc.respond_to?(:end) &&
|
|
115
|
-
same_line?(node, end_loc = node.parent.loc.end)
|
|
116
|
-
node.source_range.begin.join(end_loc.begin)
|
|
117
101
|
else
|
|
118
102
|
deletion_range(branch_range(node))
|
|
119
103
|
end
|
|
120
104
|
|
|
121
105
|
corrector.remove(range)
|
|
122
106
|
end
|
|
123
|
-
# rubocop:enable Metrics/AbcSize
|
|
124
|
-
|
|
125
|
-
def correct_other_branches(corrector, node)
|
|
126
|
-
return unless require_other_branches_correction?(node)
|
|
127
|
-
|
|
128
|
-
if node.else_branch&.if_type? && !node.else_branch.modifier_form?
|
|
129
|
-
# Replace an orphaned `elsif` with `if`
|
|
130
|
-
corrector.replace(node.else_branch.loc.keyword, 'if')
|
|
131
|
-
else
|
|
132
|
-
# Flip orphaned `else`
|
|
133
|
-
corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
|
|
137
|
-
def require_other_branches_correction?(node)
|
|
138
|
-
return false unless node.if_type? && node.else?
|
|
139
|
-
return false if !empty_if_branch?(node) && node.elsif?
|
|
140
107
|
|
|
141
|
-
|
|
108
|
+
def flip_orphaned_else(corrector, node)
|
|
109
|
+
corrector.replace(node.loc.else, "#{node.inverse_keyword} #{node.condition.source}")
|
|
110
|
+
remove_empty_branch(corrector, node)
|
|
142
111
|
end
|
|
143
112
|
|
|
144
113
|
def empty_if_branch?(node)
|
|
@@ -149,36 +118,17 @@ module RuboCop
|
|
|
149
118
|
if_branch.if_type? && !if_branch.body
|
|
150
119
|
end
|
|
151
120
|
|
|
152
|
-
def empty_elsif_branch?(node)
|
|
153
|
-
return false unless (else_branch = node.else_branch)
|
|
154
|
-
|
|
155
|
-
else_branch.if_type? && !else_branch.body
|
|
156
|
-
end
|
|
157
|
-
|
|
158
121
|
def else_branch?(node)
|
|
159
122
|
node.else_branch && !node.else_branch.if_type?
|
|
160
123
|
end
|
|
161
124
|
|
|
162
|
-
# rubocop:disable Metrics/AbcSize
|
|
163
125
|
def branch_range(node)
|
|
164
126
|
if empty_if_branch?(node) && else_branch?(node)
|
|
165
127
|
node.source_range.with(end_pos: node.loc.else.begin_pos)
|
|
166
128
|
elsif node.loc.else
|
|
167
129
|
node.source_range.with(end_pos: node.condition.source_range.end_pos)
|
|
168
|
-
elsif all_branches_body_missing?(node)
|
|
169
|
-
if_node = node.ancestors.detect(&:if?)
|
|
170
|
-
node.source_range.join(if_node.loc.end.end)
|
|
171
|
-
else
|
|
172
|
-
node.source_range
|
|
173
130
|
end
|
|
174
131
|
end
|
|
175
|
-
# rubocop:enable Metrics/AbcSize
|
|
176
|
-
|
|
177
|
-
def all_branches_body_missing?(node)
|
|
178
|
-
return false unless node.parent&.if_type?
|
|
179
|
-
|
|
180
|
-
node.parent.branches.compact.empty?
|
|
181
|
-
end
|
|
182
132
|
|
|
183
133
|
def deletion_range(range)
|
|
184
134
|
# Collect a range between the start of the `if` node and the next relevant node,
|
|
@@ -19,10 +19,23 @@ module RuboCop
|
|
|
19
19
|
MSG = 'Empty interpolation detected.'
|
|
20
20
|
|
|
21
21
|
def on_interpolation(begin_node)
|
|
22
|
-
return
|
|
22
|
+
return if in_percent_literal_array?(begin_node)
|
|
23
|
+
|
|
24
|
+
node_children = begin_node.children.dup
|
|
25
|
+
node_children.delete_if { |e| e.nil_type? || (e.basic_literal? && e.str_content&.empty?) }
|
|
26
|
+
return unless node_children.empty?
|
|
23
27
|
|
|
24
28
|
add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
|
|
25
29
|
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def in_percent_literal_array?(begin_node)
|
|
34
|
+
array_node = begin_node.each_ancestor(:array).first
|
|
35
|
+
return false unless array_node
|
|
36
|
+
|
|
37
|
+
array_node.percent_literal?
|
|
38
|
+
end
|
|
26
39
|
end
|
|
27
40
|
end
|
|
28
41
|
end
|
|
@@ -156,12 +156,6 @@ module RuboCop
|
|
|
156
156
|
|
|
157
157
|
overridden_kwargs
|
|
158
158
|
end
|
|
159
|
-
|
|
160
|
-
def arguments_range(node)
|
|
161
|
-
arguments = node.arguments
|
|
162
|
-
|
|
163
|
-
range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
|
|
164
|
-
end
|
|
165
159
|
end
|
|
166
160
|
end
|
|
167
161
|
end
|
|
@@ -15,6 +15,14 @@ module RuboCop
|
|
|
15
15
|
# x == 0.1
|
|
16
16
|
# x != 0.1
|
|
17
17
|
#
|
|
18
|
+
# # bad
|
|
19
|
+
# case value
|
|
20
|
+
# when 1.0
|
|
21
|
+
# foo
|
|
22
|
+
# when 2.0
|
|
23
|
+
# bar
|
|
24
|
+
# end
|
|
25
|
+
#
|
|
18
26
|
# # good - using BigDecimal
|
|
19
27
|
# x.to_d == 0.1.to_d
|
|
20
28
|
#
|
|
@@ -32,12 +40,21 @@ module RuboCop
|
|
|
32
40
|
# # good - comparing against nil
|
|
33
41
|
# Float(x, exception: false) == nil
|
|
34
42
|
#
|
|
43
|
+
# # good - using epsilon comparison in case expression
|
|
44
|
+
# case
|
|
45
|
+
# when (value - 1.0).abs < Float::EPSILON
|
|
46
|
+
# foo
|
|
47
|
+
# when (value - 2.0).abs < Float::EPSILON
|
|
48
|
+
# bar
|
|
49
|
+
# end
|
|
50
|
+
#
|
|
35
51
|
# # Or some other epsilon based type of comparison:
|
|
36
52
|
# # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
|
|
37
53
|
#
|
|
38
54
|
class FloatComparison < Base
|
|
39
55
|
MSG_EQUALITY = 'Avoid equality comparisons of floats as they are unreliable.'
|
|
40
56
|
MSG_INEQUALITY = 'Avoid inequality comparisons of floats as they are unreliable.'
|
|
57
|
+
MSG_CASE = 'Avoid float literal comparisons in case statements as they are unreliable.'
|
|
41
58
|
|
|
42
59
|
EQUALITY_METHODS = %i[== != eql? equal?].freeze
|
|
43
60
|
FLOAT_RETURNING_METHODS = %i[to_f Float fdiv].freeze
|
|
@@ -58,6 +75,16 @@ module RuboCop
|
|
|
58
75
|
end
|
|
59
76
|
alias on_csend on_send
|
|
60
77
|
|
|
78
|
+
def on_case(node)
|
|
79
|
+
node.when_branches.each do |when_branch|
|
|
80
|
+
when_branch.each_condition do |condition|
|
|
81
|
+
next if !float?(condition) || literal_safe?(condition)
|
|
82
|
+
|
|
83
|
+
add_offense(condition, message: MSG_CASE)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
61
88
|
private
|
|
62
89
|
|
|
63
90
|
def float?(node)
|
|
@@ -67,7 +94,7 @@ module RuboCop
|
|
|
67
94
|
when :float
|
|
68
95
|
true
|
|
69
96
|
when :send
|
|
70
|
-
|
|
97
|
+
float_send?(node)
|
|
71
98
|
when :begin
|
|
72
99
|
float?(node.children.first)
|
|
73
100
|
else
|
|
@@ -81,23 +108,18 @@ module RuboCop
|
|
|
81
108
|
(node.numeric_type? && node.value.zero?) || node.nil_type?
|
|
82
109
|
end
|
|
83
110
|
|
|
84
|
-
|
|
85
|
-
def check_send(node)
|
|
111
|
+
def float_send?(node)
|
|
86
112
|
if node.arithmetic_operation?
|
|
87
113
|
float?(node.receiver) || float?(node.first_argument)
|
|
88
114
|
elsif FLOAT_RETURNING_METHODS.include?(node.method_name)
|
|
89
115
|
true
|
|
90
116
|
elsif node.receiver&.float_type?
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
else
|
|
94
|
-
check_numeric_returning_method(node)
|
|
95
|
-
end
|
|
117
|
+
FLOAT_INSTANCE_METHODS.include?(node.method_name) ||
|
|
118
|
+
numeric_returning_method?(node)
|
|
96
119
|
end
|
|
97
120
|
end
|
|
98
|
-
# rubocop:enable Metrics/PerceivedComplexity
|
|
99
121
|
|
|
100
|
-
def
|
|
122
|
+
def numeric_returning_method?(node)
|
|
101
123
|
return false unless node.receiver
|
|
102
124
|
|
|
103
125
|
case node.method_name
|
|
@@ -11,39 +11,43 @@ module RuboCop
|
|
|
11
11
|
# @example
|
|
12
12
|
# # bad
|
|
13
13
|
# foo.object_id == bar.object_id
|
|
14
|
+
# foo.object_id != baz.object_id
|
|
14
15
|
#
|
|
15
16
|
# # good
|
|
16
17
|
# foo.equal?(bar)
|
|
18
|
+
# !foo.equal?(baz)
|
|
17
19
|
#
|
|
18
20
|
class IdentityComparison < Base
|
|
19
21
|
extend AutoCorrector
|
|
20
22
|
|
|
21
|
-
MSG = 'Use
|
|
22
|
-
RESTRICT_ON_SEND = %i[==].freeze
|
|
23
|
+
MSG = 'Use `%<bang>sequal?` instead of `%<comparison_method>s` when comparing `object_id`.'
|
|
24
|
+
RESTRICT_ON_SEND = %i[== !=].freeze
|
|
25
|
+
|
|
26
|
+
# @!method object_id_comparison(node)
|
|
27
|
+
def_node_matcher :object_id_comparison, <<~PATTERN
|
|
28
|
+
(send
|
|
29
|
+
(send
|
|
30
|
+
_lhs_receiver :object_id) ${:== :!=}
|
|
31
|
+
(send
|
|
32
|
+
_rhs_receiver :object_id))
|
|
33
|
+
PATTERN
|
|
23
34
|
|
|
24
35
|
def on_send(node)
|
|
25
|
-
return unless
|
|
36
|
+
return unless (comparison_method = object_id_comparison(node))
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
bang = comparison_method == :== ? '' : '!'
|
|
39
|
+
add_offense(node,
|
|
40
|
+
message: format(MSG, comparison_method: comparison_method,
|
|
41
|
+
bang: bang)) do |corrector|
|
|
28
42
|
receiver = node.receiver.receiver
|
|
29
43
|
argument = node.first_argument.receiver
|
|
30
44
|
return unless receiver && argument
|
|
31
45
|
|
|
32
|
-
replacement = "#{receiver.source}.equal?(#{argument.source})"
|
|
46
|
+
replacement = "#{bang}#{receiver.source}.equal?(#{argument.source})"
|
|
33
47
|
|
|
34
48
|
corrector.replace(node, replacement)
|
|
35
49
|
end
|
|
36
50
|
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def compare_between_object_id_by_double_equal?(node)
|
|
41
|
-
object_id_method?(node.receiver) && object_id_method?(node.first_argument)
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
def object_id_method?(node)
|
|
45
|
-
node.send_type? && node.method?(:object_id)
|
|
46
|
-
end
|
|
47
51
|
end
|
|
48
52
|
end
|
|
49
53
|
end
|