rubocop 1.90.0 → 1.92.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/README.md +1 -1
- data/config/default.yml +241 -11
- data/config/obsoletion.yml +9 -0
- data/lib/rubocop/cached_data.rb +47 -7
- data/lib/rubocop/changed_files.rb +134 -0
- data/lib/rubocop/cli/command/cop_names.rb +57 -0
- data/lib/rubocop/cli/command/execute_runner.rb +23 -3
- data/lib/rubocop/cli/command/explain.rb +34 -0
- data/lib/rubocop/cli/command/show_cops.rb +6 -0
- data/lib/rubocop/cli/command/show_docs_url.rb +6 -4
- data/lib/rubocop/cli.rb +11 -4
- data/lib/rubocop/comment_config/directive_range.rb +3 -1
- data/lib/rubocop/comment_config/disable_next.rb +49 -3
- data/lib/rubocop/comment_config/push_pop.rb +55 -0
- data/lib/rubocop/comment_config.rb +32 -53
- data/lib/rubocop/config.rb +10 -0
- data/lib/rubocop/config_loader.rb +18 -7
- data/lib/rubocop/config_loader_resolver.rb +79 -12
- data/lib/rubocop/config_obsoletion/cop_rule.rb +2 -1
- data/lib/rubocop/config_obsoletion/removed_cop.rb +9 -1
- data/lib/rubocop/config_obsoletion.rb +1 -1
- data/lib/rubocop/config_validator.rb +29 -3
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/base.rb +57 -24
- data/lib/rubocop/cop/bundler/gem_comment.rb +0 -1
- data/lib/rubocop/cop/bundler/ordered_gems.rb +0 -8
- data/lib/rubocop/cop/cop_documentation.rb +81 -0
- data/lib/rubocop/cop/cop_explanation.rb +140 -0
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +13 -1
- data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +22 -7
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +23 -2
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
- data/lib/rubocop/cop/correctors.rb +2 -2
- data/lib/rubocop/cop/documentation.rb +1 -1
- data/lib/rubocop/cop/gemspec/dependency_version.rb +0 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +0 -6
- data/lib/rubocop/cop/gemspec/require_mfa.rb +1 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -5
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +0 -7
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +1 -7
- data/lib/rubocop/cop/internal_affairs/style_detected_api_use.rb +1 -7
- data/lib/rubocop/cop/layout/argument_alignment.rb +2 -0
- data/lib/rubocop/cop/layout/block_alignment.rb +27 -0
- data/lib/rubocop/cop/layout/case_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/class_structure.rb +9 -1
- data/lib/rubocop/cop/layout/comment_indentation.rb +8 -5
- data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/else_alignment.rb +1 -0
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +14 -5
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +16 -10
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -0
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -0
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +17 -4
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +5 -3
- data/lib/rubocop/cop/layout/first_method_argument_line_break.rb +6 -0
- data/lib/rubocop/cop/layout/first_method_parameter_line_break.rb +4 -0
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +11 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +15 -10
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -0
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
- data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +4 -4
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +8 -1
- data/lib/rubocop/cop/layout/line_end_string_concatenation_indentation.rb +25 -9
- data/lib/rubocop/cop/layout/line_length.rb +71 -19
- data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +12 -0
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +8 -1
- data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +7 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +14 -0
- data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +4 -0
- data/lib/rubocop/cop/layout/redundant_line_break.rb +22 -1
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +15 -2
- data/lib/rubocop/cop/layout/single_line_block_chain.rb +10 -2
- data/lib/rubocop/cop/layout/space_after_not.rb +5 -0
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +10 -4
- data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
- data/lib/rubocop/cop/layout/space_around_operators.rb +5 -1
- data/lib/rubocop/cop/layout/space_before_block_braces.rb +4 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +15 -2
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +31 -8
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +1 -1
- data/lib/rubocop/cop/lint/ambiguous_operator_precedence.rb +2 -1
- data/lib/rubocop/cop/lint/argument_mismatch.rb +14 -4
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +2 -0
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +88 -14
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_block.rb +1 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
- data/lib/rubocop/cop/lint/literal_as_condition.rb +23 -2
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +63 -19
- data/lib/rubocop/cop/lint/loop.rb +24 -2
- data/lib/rubocop/cop/lint/misplaced_magic_comment.rb +245 -0
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +19 -4
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +1 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +17 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +42 -17
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
- data/lib/rubocop/cop/lint/unescaped_bracket_in_regexp.rb +18 -1
- data/lib/rubocop/cop/lint/useless_assignment.rb +14 -7
- data/lib/rubocop/cop/lint/void.rb +8 -1
- data/lib/rubocop/cop/lint.rb +1 -0
- data/lib/rubocop/cop/metrics/class_length.rb +4 -2
- data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -4
- data/lib/rubocop/cop/metrics/module_length.rb +4 -2
- data/lib/rubocop/cop/migration/department_name.rb +1 -1
- data/lib/rubocop/cop/mixin/alignment.rb +5 -1
- data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +17 -14
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +5 -1
- data/lib/rubocop/cop/mixin/code_length.rb +10 -2
- data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +12 -1
- data/lib/rubocop/cop/mixin/endless_method_body_help.rb +69 -0
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +26 -2
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +31 -3
- data/lib/rubocop/cop/mixin/hash_transform_method.rb +1 -1
- data/lib/rubocop/cop/mixin/min_branches_count.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_element_line_breaks.rb +11 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +9 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/pattern_matching_help.rb +35 -0
- data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +29 -3
- data/lib/rubocop/cop/mixin/project_index_help.rb +15 -0
- data/lib/rubocop/cop/mixin/reparsed_equivalence.rb +13 -3
- data/lib/rubocop/cop/mixin/statement_modifier.rb +22 -2
- data/lib/rubocop/cop/mixin.rb +4 -2
- data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
- data/lib/rubocop/cop/naming/block_forwarding.rb +4 -1
- data/lib/rubocop/cop/naming/block_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/heredoc_delimiter_case.rb +9 -2
- data/lib/rubocop/cop/naming/heredoc_delimiter_naming.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_prefix.rb +7 -22
- data/lib/rubocop/cop/offense.rb +59 -3
- data/lib/rubocop/cop/registry.rb +10 -2
- data/lib/rubocop/cop/security/json_load.rb +16 -4
- data/lib/rubocop/cop/severity.rb +12 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +10 -2
- data/lib/rubocop/cop/style/alias.rb +18 -5
- data/lib/rubocop/cop/style/ambiguous_endless_method_definition.rb +4 -3
- data/lib/rubocop/cop/style/and_or.rb +4 -0
- data/lib/rubocop/cop/style/arguments_forwarding.rb +6 -3
- data/lib/rubocop/cop/style/attr.rb +3 -4
- data/lib/rubocop/cop/style/bitwise_predicate.rb +6 -4
- data/lib/rubocop/cop/style/block_delimiters.rb +29 -3
- data/lib/rubocop/cop/style/case_like_if.rb +9 -6
- data/lib/rubocop/cop/style/class_and_module_children.rb +54 -16
- data/lib/rubocop/cop/style/class_methods_definitions.rb +8 -0
- data/lib/rubocop/cop/style/combinable_loops.rb +85 -11
- data/lib/rubocop/cop/style/concat_array_literals.rb +46 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
- data/lib/rubocop/cop/style/constant_visibility.rb +6 -2
- data/lib/rubocop/cop/style/data_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/directive_scope.rb +154 -21
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +118 -18
- data/lib/rubocop/cop/style/documentation_method.rb +1 -9
- data/lib/rubocop/cop/style/double_negation.rb +11 -0
- data/lib/rubocop/cop/style/each_for_simple_loop.rb +1 -1
- data/lib/rubocop/cop/style/empty_block_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_lambda_parameter.rb +1 -1
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +15 -3
- data/lib/rubocop/cop/style/endless_method.rb +91 -11
- data/lib/rubocop/cop/style/exact_regexp_match.rb +45 -8
- data/lib/rubocop/cop/style/explicit_block_argument.rb +50 -10
- data/lib/rubocop/cop/style/file_null.rb +2 -2
- data/lib/rubocop/cop/style/float_division.rb +28 -14
- data/lib/rubocop/cop/style/for.rb +44 -1
- data/lib/rubocop/cop/style/format_string.rb +28 -6
- data/lib/rubocop/cop/style/format_string_token.rb +1 -1
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
- data/lib/rubocop/cop/style/guard_clause.rb +13 -1
- data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
- data/lib/rubocop/cop/style/hash_lookup_method.rb +35 -9
- data/lib/rubocop/cop/style/hash_syntax.rb +16 -3
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +22 -3
- data/lib/rubocop/cop/style/if_inside_else.rb +21 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +19 -20
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -0
- data/lib/rubocop/cop/style/if_with_semicolon.rb +47 -4
- data/lib/rubocop/cop/style/inverse_methods.rb +24 -2
- data/lib/rubocop/cop/style/it_block_parameter.rb +32 -3
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
- data/lib/rubocop/cop/style/lambda.rb +18 -0
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/magic_comment_format.rb +1 -1
- data/lib/rubocop/cop/style/map_into_array.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +45 -10
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +25 -2
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +26 -3
- data/lib/rubocop/cop/style/method_def_parentheses.rb +29 -3
- data/lib/rubocop/cop/style/missing_else.rb +7 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +45 -5
- data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +7 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -5
- data/lib/rubocop/cop/style/multiline_ternary_operator.rb +7 -3
- data/lib/rubocop/cop/style/multiline_when_then.rb +7 -0
- data/lib/rubocop/cop/style/mutable_constant.rb +28 -1
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +2 -1
- data/lib/rubocop/cop/style/negative_array_index.rb +9 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +36 -12
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +26 -8
- data/lib/rubocop/cop/style/next.rb +24 -10
- data/lib/rubocop/cop/style/nil_comparison.rb +48 -8
- data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
- data/lib/rubocop/cop/style/non_nil_check.rb +18 -2
- data/lib/rubocop/cop/style/not.rb +10 -3
- data/lib/rubocop/cop/style/numeric_literal_prefix.rb +11 -1
- data/lib/rubocop/cop/style/numeric_predicate.rb +21 -5
- data/lib/rubocop/cop/style/one_line_conditional.rb +14 -3
- data/lib/rubocop/cop/style/parallel_assignment.rb +1 -1
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +6 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
- data/lib/rubocop/cop/style/reduce_to_hash.rb +17 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +20 -3
- data/lib/rubocop/cop/style/redundant_condition.rb +34 -17
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +15 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +10 -2
- data/lib/rubocop/cop/style/redundant_freeze.rb +10 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +23 -2
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +6 -5
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +25 -5
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
- data/lib/rubocop/cop/style/require_order.rb +9 -0
- data/lib/rubocop/cop/style/rescue_modifier.rb +5 -9
- data/lib/rubocop/cop/style/return_nil.rb +17 -2
- data/lib/rubocop/cop/style/return_nil_in_predicate_method_definition.rb +11 -1
- data/lib/rubocop/cop/style/sample.rb +9 -8
- data/lib/rubocop/cop/style/self_assignment.rb +12 -15
- data/lib/rubocop/cop/style/semicolon.rb +16 -5
- data/lib/rubocop/cop/style/single_line_block_params.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +16 -4
- data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +29 -5
- data/lib/rubocop/cop/style/string_concatenation.rb +9 -3
- data/lib/rubocop/cop/style/struct_inheritance.rb +14 -0
- data/lib/rubocop/cop/style/super_arguments.rb +3 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +23 -5
- data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +23 -19
- data/lib/rubocop/cop/style/while_until_modifier.rb +1 -1
- data/lib/rubocop/cop/style/yoda_condition.rb +24 -9
- data/lib/rubocop/cop/style/yoda_expression.rb +10 -1
- data/lib/rubocop/cop/style.rb +0 -1
- data/lib/rubocop/cop/team.rb +10 -5
- data/lib/rubocop/cop/util.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +14 -1
- data/lib/rubocop/cops_documentation_generator.rb +23 -2
- data/lib/rubocop/directive_comment.rb +37 -8
- data/lib/rubocop/formatter/base_formatter.rb +22 -0
- data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -1
- data/lib/rubocop/formatter/formatter_set.rb +6 -1
- data/lib/rubocop/formatter/github_actions_formatter.rb +6 -5
- data/lib/rubocop/formatter/html_formatter.rb +2 -2
- data/lib/rubocop/formatter/json_formatter.rb +71 -1
- data/lib/rubocop/formatter/junit_formatter.rb +1 -1
- data/lib/rubocop/formatter/offense_count_formatter.rb +3 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +3 -1
- data/lib/rubocop/formatter/sarif_formatter.rb +186 -0
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
- data/lib/rubocop/formatter.rb +1 -0
- data/lib/rubocop/lsp/runtime.rb +47 -11
- data/lib/rubocop/lsp/stdin_runner.rb +11 -5
- data/lib/rubocop/lsp.rb +5 -2
- data/lib/rubocop/magic_comment.rb +27 -0
- data/lib/rubocop/mcp/autocorrection_request.rb +52 -0
- data/lib/rubocop/mcp/explain_tool.rb +68 -0
- data/lib/rubocop/mcp/scope.rb +65 -0
- data/lib/rubocop/mcp/server.rb +184 -76
- data/lib/rubocop/mcp/source_files.rb +35 -0
- data/lib/rubocop/offense_limit.rb +30 -0
- data/lib/rubocop/options.rb +97 -4
- data/lib/rubocop/path_util.rb +1 -1
- data/lib/rubocop/plugin/configuration_integrator.rb +12 -5
- data/lib/rubocop/plugin/loader.rb +1 -1
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +8 -5
- data/lib/rubocop/result_cache.rb +36 -18
- data/lib/rubocop/runner.rb +160 -49
- data/lib/rubocop/server/cache.rb +2 -2
- data/lib/rubocop/unified_diff.rb +257 -0
- data/lib/rubocop/util.rb +69 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +9 -1
- metadata +21 -6
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +0 -46
|
@@ -131,7 +131,9 @@ module RuboCop
|
|
|
131
131
|
#
|
|
132
132
|
class EndlessMethod < Base
|
|
133
133
|
include ConfigurableEnforcedStyle
|
|
134
|
+
include LineLengthHelp
|
|
134
135
|
include EndlessMethodRewriter
|
|
136
|
+
include EndlessMethodBodyHelp
|
|
135
137
|
extend TargetRubyVersion
|
|
136
138
|
extend AutoCorrector
|
|
137
139
|
|
|
@@ -143,6 +145,12 @@ module RuboCop
|
|
|
143
145
|
MSG_REQUIRE_SINGLE = 'Use endless method definitions for single line methods.'
|
|
144
146
|
MSG_REQUIRE_ALWAYS = 'Use endless method definitions.'
|
|
145
147
|
|
|
148
|
+
# `Style/MethodDefParentheses` adds the same parentheses a parameter list needs in
|
|
149
|
+
# an endless definition, so letting both correct in the same pass would double them.
|
|
150
|
+
def self.autocorrect_incompatible_with
|
|
151
|
+
[Style::MethodCallWithArgsParentheses, Style::MethodDefParentheses]
|
|
152
|
+
end
|
|
153
|
+
|
|
146
154
|
def on_def(node)
|
|
147
155
|
return if node.assignment_method? || use_heredoc?(node)
|
|
148
156
|
|
|
@@ -166,6 +174,8 @@ module RuboCop
|
|
|
166
174
|
return if node.single_line? || style == :allow_always
|
|
167
175
|
|
|
168
176
|
add_offense(node, message: MSG_MULTI_LINE) do |corrector|
|
|
177
|
+
next if endless_parent?(node)
|
|
178
|
+
|
|
169
179
|
correct_to_multiline(corrector, node)
|
|
170
180
|
end
|
|
171
181
|
end
|
|
@@ -175,11 +185,11 @@ module RuboCop
|
|
|
175
185
|
add_offense(node, message: MSG_MULTI_LINE) do |corrector|
|
|
176
186
|
correct_to_multiline(corrector, node)
|
|
177
187
|
end
|
|
178
|
-
elsif !node.endless? && can_be_made_endless?(node) && node
|
|
188
|
+
elsif !node.endless? && can_be_made_endless?(node) && single_line_when_made_endless?(node)
|
|
179
189
|
return if too_long_when_made_endless?(node)
|
|
180
190
|
|
|
181
191
|
add_offense(node, message: MSG_REQUIRE_SINGLE) do |corrector|
|
|
182
|
-
corrector
|
|
192
|
+
correct_to_endless(corrector, node)
|
|
183
193
|
end
|
|
184
194
|
end
|
|
185
195
|
end
|
|
@@ -189,21 +199,58 @@ module RuboCop
|
|
|
189
199
|
return if too_long_when_made_endless?(node)
|
|
190
200
|
|
|
191
201
|
add_offense(node, message: MSG_REQUIRE_ALWAYS) do |corrector|
|
|
192
|
-
corrector
|
|
202
|
+
correct_to_endless(corrector, node)
|
|
193
203
|
end
|
|
194
204
|
end
|
|
195
205
|
|
|
196
206
|
def handle_disallow_style(node)
|
|
197
207
|
return unless node.endless?
|
|
198
208
|
|
|
199
|
-
add_offense(node)
|
|
209
|
+
add_offense(node) do |corrector|
|
|
210
|
+
next if endless_parent?(node)
|
|
211
|
+
|
|
212
|
+
correct_to_multiline(corrector, node)
|
|
213
|
+
end
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
def endless_parent?(node)
|
|
217
|
+
node.parent&.any_def_type? && node.parent.endless?
|
|
200
218
|
end
|
|
201
219
|
|
|
202
220
|
def use_heredoc?(node)
|
|
203
221
|
return false unless (body = node.body)
|
|
204
222
|
return true if body.any_str_type? && body.heredoc?
|
|
205
223
|
|
|
206
|
-
body.each_descendant(:
|
|
224
|
+
body.each_descendant(:any_str).any?(&:heredoc?)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def correct_to_endless(corrector, node)
|
|
228
|
+
if unparenthesized_arguments?(node)
|
|
229
|
+
corrector.replace(name_to_arguments_range(node), '(')
|
|
230
|
+
corrector.replace(signature_to_body_range(node), ') = ')
|
|
231
|
+
else
|
|
232
|
+
corrector.replace(signature_to_body_range(node), ' = ')
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
corrector.remove(body_to_end_range(node))
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def unparenthesized_arguments?(node)
|
|
239
|
+
node.arguments.any? && !node.arguments.loc.begin
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
def name_to_arguments_range(node)
|
|
243
|
+
node.loc.name.end.join(node.arguments.source_range.begin)
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
def signature_to_body_range(node)
|
|
247
|
+
signature_end = node.arguments.any? ? node.arguments.source_range.end : node.loc.name.end
|
|
248
|
+
|
|
249
|
+
signature_end.join(node.body.source_range.begin)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def body_to_end_range(node)
|
|
253
|
+
node.body.source_range.end.join(node.loc.end.end)
|
|
207
254
|
end
|
|
208
255
|
|
|
209
256
|
def endless_replacement(node)
|
|
@@ -217,23 +264,56 @@ module RuboCop
|
|
|
217
264
|
end
|
|
218
265
|
|
|
219
266
|
def arguments(node, missing = '')
|
|
220
|
-
node.arguments.any?
|
|
267
|
+
return missing unless node.arguments.any?
|
|
268
|
+
return parenthesized_arguments(node) if unparenthesized_arguments?(node)
|
|
269
|
+
|
|
270
|
+
node.arguments.source
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def parenthesized_arguments(node)
|
|
274
|
+
padding = space_inside_parens? ? ' ' : ''
|
|
275
|
+
|
|
276
|
+
"(#{padding}#{node.arguments.source}#{padding})"
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def space_inside_parens?
|
|
280
|
+
return false unless config.cop_enabled?('Layout/SpaceInsideParens')
|
|
281
|
+
|
|
282
|
+
config.for_cop('Layout/SpaceInsideParens')['EnforcedStyle'] != 'no_space'
|
|
221
283
|
end
|
|
222
284
|
|
|
223
285
|
def can_be_made_endless?(node)
|
|
224
|
-
|
|
286
|
+
return false unless node.body
|
|
287
|
+
return false if comment_in_discarded_range?(node)
|
|
288
|
+
|
|
289
|
+
endless_method_body?(node.body)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def single_line_when_made_endless?(node)
|
|
293
|
+
!endless_replacement(node).include?("\n")
|
|
225
294
|
end
|
|
226
295
|
|
|
227
296
|
def too_long_when_made_endless?(node)
|
|
228
297
|
return false unless config.cop_enabled?('Layout/LineLength')
|
|
229
298
|
|
|
230
|
-
|
|
299
|
+
line_length(line_when_made_endless(node)) > max_line_length
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
def comment_in_discarded_range?(node)
|
|
303
|
+
discarded_ranges = [signature_to_body_range(node), body_to_end_range(node)]
|
|
231
304
|
|
|
232
|
-
|
|
305
|
+
processed_source.each_comment_in_lines(node.first_line..node.last_line).any? do |comment|
|
|
306
|
+
discarded_ranges.any? { |range| range.contains?(comment.source_range) }
|
|
307
|
+
end
|
|
233
308
|
end
|
|
234
309
|
|
|
235
|
-
def
|
|
236
|
-
|
|
310
|
+
def line_when_made_endless(node)
|
|
311
|
+
keyword_element = node.loc.keyword
|
|
312
|
+
code_before = keyword_element.source_line[0...keyword_element.column]
|
|
313
|
+
end_element = node.loc.end
|
|
314
|
+
code_after = end_element.source_line[end_element.last_column..]
|
|
315
|
+
|
|
316
|
+
"#{code_before}#{endless_replacement(node)}#{code_after}"
|
|
237
317
|
end
|
|
238
318
|
end
|
|
239
319
|
end
|
|
@@ -5,11 +5,15 @@ module RuboCop
|
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for exact regexp match inside `Regexp` literals.
|
|
7
7
|
#
|
|
8
|
+
# `=~` returns an index and `match` returns `MatchData`, so they are only
|
|
9
|
+
# autocorrected when their value is used as a condition. The same goes for
|
|
10
|
+
# safe navigation calls, which return `nil` for a `nil` receiver.
|
|
11
|
+
#
|
|
8
12
|
# @example
|
|
9
13
|
#
|
|
10
14
|
# # bad
|
|
11
15
|
# string =~ /\Astring\z/
|
|
12
|
-
#
|
|
16
|
+
# /\Astring\z/ === string
|
|
13
17
|
# string.match(/\Astring\z/)
|
|
14
18
|
# string.match?(/\Astring\z/)
|
|
15
19
|
#
|
|
@@ -27,14 +31,15 @@ module RuboCop
|
|
|
27
31
|
|
|
28
32
|
MSG = 'Use `%<prefer>s`.'
|
|
29
33
|
RESTRICT_ON_SEND = %i[=~ === !~ match match?].freeze
|
|
34
|
+
BOOLEAN_METHODS = %i[=== !~ match?].to_set.freeze
|
|
30
35
|
|
|
36
|
+
# `String#===` is plain equality, so `===` only matches with the regexp as its receiver.
|
|
31
37
|
# @!method exact_regexp_match(node)
|
|
32
38
|
def_node_matcher :exact_regexp_match, <<~PATTERN
|
|
33
|
-
|
|
34
|
-
_ {:=~
|
|
35
|
-
(regexp
|
|
36
|
-
|
|
37
|
-
(regopt)))
|
|
39
|
+
{
|
|
40
|
+
(call _ {:=~ :!~ :match :match?} (regexp (str $_) (regopt)))
|
|
41
|
+
(send (regexp (str $_) (regopt)) :=== _)
|
|
42
|
+
}
|
|
38
43
|
PATTERN
|
|
39
44
|
|
|
40
45
|
def on_send(node)
|
|
@@ -44,16 +49,48 @@ module RuboCop
|
|
|
44
49
|
return unless exact_match_pattern?(parsed_regexp)
|
|
45
50
|
|
|
46
51
|
string = escape_single_quotes(parsed_regexp[1].text)
|
|
47
|
-
|
|
52
|
+
subject = node.method?(:===) ? node.first_argument : receiver
|
|
53
|
+
prefer = "#{subject.source} #{new_method(node)} '#{string}'"
|
|
48
54
|
|
|
49
55
|
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
|
50
|
-
corrector
|
|
56
|
+
autocorrect(corrector, node, prefer)
|
|
51
57
|
end
|
|
52
58
|
end
|
|
53
59
|
alias on_csend on_send
|
|
54
60
|
|
|
55
61
|
private
|
|
56
62
|
|
|
63
|
+
def autocorrect(corrector, node, prefer)
|
|
64
|
+
return unless boolean_result?(node) || truthiness_only?(node)
|
|
65
|
+
|
|
66
|
+
corrector.replace(node, parenthesize?(node) ? "(#{prefer})" : prefer)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# `=~` returns an index, `match` returns `MatchData` and `&.` can return `nil`,
|
|
70
|
+
# so replacing them with `==` is only safe where the value is used as a condition.
|
|
71
|
+
def boolean_result?(node)
|
|
72
|
+
node.send_type? && BOOLEAN_METHODS.include?(node.method_name)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def truthiness_only?(node)
|
|
76
|
+
return true unless node.value_used?
|
|
77
|
+
|
|
78
|
+
parent = node.parent
|
|
79
|
+
if parent.type?(:begin, :and, :or)
|
|
80
|
+
truthiness_only?(parent)
|
|
81
|
+
elsif parent.type?(:if, :while, :until)
|
|
82
|
+
parent.condition.equal?(node)
|
|
83
|
+
else
|
|
84
|
+
parent.send_type? && parent.method?(:!)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def parenthesize?(node)
|
|
89
|
+
return false unless (parent = node.parent)&.call_type?
|
|
90
|
+
|
|
91
|
+
parent.receiver.equal?(node) || (parent.operator_method? && !parent.method?(:[]))
|
|
92
|
+
end
|
|
93
|
+
|
|
57
94
|
# Escape characters that are special inside a single-quoted string so the
|
|
58
95
|
# generated literal (e.g. for `/\Afoo'bar\z/`) stays valid Ruby.
|
|
59
96
|
def escape_single_quotes(text)
|
|
@@ -50,8 +50,11 @@ module RuboCop
|
|
|
50
50
|
(block $_ (args $...) (yield $...))
|
|
51
51
|
PATTERN
|
|
52
52
|
|
|
53
|
+
# `Style/LambdaCall` rewrites the `call` that the block argument is appended to, and
|
|
54
|
+
# `Style/TrailingCommaInArguments` changes the trailing comma where it is appended,
|
|
55
|
+
# in the same pass.
|
|
53
56
|
def self.autocorrect_incompatible_with
|
|
54
|
-
[Lint::UnusedMethodArgument]
|
|
57
|
+
[Lint::UnusedMethodArgument, Style::LambdaCall, Style::TrailingCommaInArguments]
|
|
55
58
|
end
|
|
56
59
|
|
|
57
60
|
def initialize(config = nil, options = nil)
|
|
@@ -70,10 +73,13 @@ module RuboCop
|
|
|
70
73
|
# this is not a valid ruby pattern, but can happen in haml or erb,
|
|
71
74
|
# so this can cause crashes in haml_lint
|
|
72
75
|
return unless def_node
|
|
76
|
+
return if argument_forwarding?(def_node)
|
|
73
77
|
|
|
74
78
|
block_name = extract_block_name(def_node)
|
|
75
79
|
|
|
76
80
|
add_offense(block_node) do |corrector|
|
|
81
|
+
next unless can_add_block_argument?(def_node, send_node, block_name)
|
|
82
|
+
|
|
77
83
|
corrector.remove(block_body_range(block_node, send_node))
|
|
78
84
|
|
|
79
85
|
add_block_argument(send_node, corrector, block_name)
|
|
@@ -84,6 +90,11 @@ module RuboCop
|
|
|
84
90
|
|
|
85
91
|
private
|
|
86
92
|
|
|
93
|
+
# A block parameter can't be added next to `...`.
|
|
94
|
+
def argument_forwarding?(def_node)
|
|
95
|
+
def_node.arguments.any?(&:forward_arg_type?)
|
|
96
|
+
end
|
|
97
|
+
|
|
87
98
|
def extract_block_name(def_node)
|
|
88
99
|
if def_node.block_argument?
|
|
89
100
|
def_node.last_argument.name
|
|
@@ -92,6 +103,27 @@ module RuboCop
|
|
|
92
103
|
end
|
|
93
104
|
end
|
|
94
105
|
|
|
106
|
+
def can_add_block_argument?(def_node, send_node, block_name)
|
|
107
|
+
return false if block_name_taken?(def_node, block_name)
|
|
108
|
+
|
|
109
|
+
!send_node.zsuper_type? || zsuper_arguments_forwardable?(def_node)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def block_name_taken?(def_node, block_name)
|
|
113
|
+
return false if def_node.block_argument?
|
|
114
|
+
|
|
115
|
+
def_node.each_descendant(:argument, :lvasgn).any? { |node| node.name.to_s == block_name }
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# A destructuring argument can only be passed on as the original value,
|
|
119
|
+
# and anonymous arguments can only be forwarded since Ruby 3.2.
|
|
120
|
+
def zsuper_arguments_forwardable?(def_node)
|
|
121
|
+
def_node.arguments.none? do |arg|
|
|
122
|
+
arg.mlhs_type? ||
|
|
123
|
+
(arg.type?(:restarg, :kwrestarg) && !arg.name && target_ruby_version < 3.2)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
95
127
|
def yielding_arguments?(block_args, yield_args)
|
|
96
128
|
yield_args = yield_args.dup.fill(
|
|
97
129
|
nil,
|
|
@@ -110,6 +142,8 @@ module RuboCop
|
|
|
110
142
|
insert_argument(node, corrector, block_name)
|
|
111
143
|
elsif empty_arguments?(node)
|
|
112
144
|
corrector.replace(node.arguments, "(&#{block_name})")
|
|
145
|
+
elsif index_call?(node)
|
|
146
|
+
corrector.replace(node.loc.selector, "[&#{block_name}]")
|
|
113
147
|
elsif call_like?(node)
|
|
114
148
|
correct_call_node(node, corrector, block_name)
|
|
115
149
|
else
|
|
@@ -122,6 +156,10 @@ module RuboCop
|
|
|
122
156
|
node.arguments.is_a?(RuboCop::AST::Node) && node.arguments.loc.begin
|
|
123
157
|
end
|
|
124
158
|
|
|
159
|
+
def index_call?(node)
|
|
160
|
+
node.send_type? && node.method?(:[]) && !node.loc?(:dot)
|
|
161
|
+
end
|
|
162
|
+
|
|
125
163
|
def call_like?(node)
|
|
126
164
|
node.type?(:call, :zsuper, :super)
|
|
127
165
|
end
|
|
@@ -141,19 +179,21 @@ module RuboCop
|
|
|
141
179
|
else
|
|
142
180
|
"&#{block_name}"
|
|
143
181
|
end
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
range = range_between(args_begin.begin_pos, args_end.end_pos)
|
|
150
|
-
corrector.remove(range)
|
|
182
|
+
if node.parenthesized?
|
|
183
|
+
corrector.replace(node.loc.begin.join(node.loc.end), "(#{new_arguments})")
|
|
184
|
+
else
|
|
185
|
+
corrector.insert_after(node, "(#{new_arguments})")
|
|
186
|
+
end
|
|
151
187
|
end
|
|
152
188
|
|
|
153
189
|
def build_new_arguments_for_zsuper(node)
|
|
154
190
|
def_node = node.each_ancestor(:any_def).first
|
|
155
|
-
def_node.arguments.
|
|
156
|
-
|
|
191
|
+
def_node.arguments.filter_map do |arg|
|
|
192
|
+
case arg.type
|
|
193
|
+
when :arg, :optarg then arg.name.to_s
|
|
194
|
+
when :kwarg, :kwoptarg then "#{arg.name}: #{arg.name}"
|
|
195
|
+
when :restarg, :kwrestarg then arg.source
|
|
196
|
+
end
|
|
157
197
|
end
|
|
158
198
|
end
|
|
159
199
|
|
|
@@ -54,7 +54,7 @@ module RuboCop
|
|
|
54
54
|
@contain_dev_null_string_in_file = ast.each_descendant(:str).any? do |str|
|
|
55
55
|
content = str.str_content
|
|
56
56
|
|
|
57
|
-
valid_string?(content) && content.downcase == '/dev/null' # rubocop:disable Style/FileNull
|
|
57
|
+
valid_string?(content) && content.downcase == '/dev/null' # rubocop:disable Style/FileNull -- the cop needs the literal it is matching
|
|
58
58
|
end
|
|
59
59
|
end
|
|
60
60
|
|
|
@@ -62,7 +62,7 @@ module RuboCop
|
|
|
62
62
|
value = node.value
|
|
63
63
|
return unless valid_string?(value)
|
|
64
64
|
return if acceptable?(node)
|
|
65
|
-
return if value.downcase == 'nul' && !@contain_dev_null_string_in_file # rubocop:disable Style/FileNull
|
|
65
|
+
return if value.downcase == 'nul' && !@contain_dev_null_string_in_file # rubocop:disable Style/FileNull -- the cop needs the literal it is matching
|
|
66
66
|
return unless REGEXP.match?(value)
|
|
67
67
|
|
|
68
68
|
add_offense(node, message: format(MSG, source: value)) do |corrector|
|
|
@@ -97,6 +97,7 @@ module RuboCop
|
|
|
97
97
|
|
|
98
98
|
def on_send(node)
|
|
99
99
|
return unless offense_condition?(node)
|
|
100
|
+
return if comment_before_to_f?(node)
|
|
100
101
|
|
|
101
102
|
add_offense(node) do |corrector|
|
|
102
103
|
case style
|
|
@@ -107,7 +108,7 @@ module RuboCop
|
|
|
107
108
|
remove_to_f_method(corrector, node.receiver)
|
|
108
109
|
add_to_f_method(corrector, node.first_argument)
|
|
109
110
|
when :fdiv
|
|
110
|
-
correct_from_slash_to_fdiv(corrector, node
|
|
111
|
+
correct_from_slash_to_fdiv(corrector, node.receiver, node.first_argument)
|
|
111
112
|
end
|
|
112
113
|
end
|
|
113
114
|
end
|
|
@@ -141,28 +142,41 @@ module RuboCop
|
|
|
141
142
|
end
|
|
142
143
|
|
|
143
144
|
def remove_to_f_method(corrector, send_node)
|
|
144
|
-
corrector.remove(send_node.loc.
|
|
145
|
-
corrector.remove(send_node.loc.selector)
|
|
145
|
+
corrector.remove(send_node.receiver.source_range.end.join(send_node.loc.selector.end))
|
|
146
146
|
end
|
|
147
147
|
|
|
148
|
-
def
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
def comment_before_to_f?(node)
|
|
149
|
+
operands_losing_to_f(node).any? do |operand|
|
|
150
|
+
next false unless to_f_method?(operand)
|
|
151
151
|
|
|
152
|
-
|
|
153
|
-
|
|
152
|
+
range = operand.receiver.source_range.end.join(operand.loc.selector.begin)
|
|
153
|
+
processed_source.contains_comment?(range)
|
|
154
154
|
end
|
|
155
|
-
|
|
156
|
-
corrector.replace(node, "#{receiver_source}.fdiv#{argument_source}")
|
|
157
155
|
end
|
|
158
156
|
|
|
159
|
-
def
|
|
160
|
-
|
|
161
|
-
|
|
157
|
+
def operands_losing_to_f(node)
|
|
158
|
+
case style
|
|
159
|
+
when :left_coerce, :single_coerce
|
|
160
|
+
[node.first_argument]
|
|
161
|
+
when :right_coerce
|
|
162
|
+
[node.receiver]
|
|
162
163
|
else
|
|
163
|
-
node.
|
|
164
|
+
[node.receiver, node.first_argument]
|
|
164
165
|
end
|
|
165
166
|
end
|
|
167
|
+
|
|
168
|
+
def correct_from_slash_to_fdiv(corrector, receiver, argument)
|
|
169
|
+
remove_to_f_method(corrector, receiver) if to_f_method?(receiver)
|
|
170
|
+
|
|
171
|
+
argument_parenthesized = argument.begin_type?
|
|
172
|
+
corrector.replace(
|
|
173
|
+
receiver.source_range.end.join(argument.source_range.begin),
|
|
174
|
+
argument_parenthesized ? '.fdiv' : '.fdiv('
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
remove_to_f_method(corrector, argument) if to_f_method?(argument)
|
|
178
|
+
corrector.insert_after(argument, ')') unless argument_parenthesized
|
|
179
|
+
end
|
|
166
180
|
end
|
|
167
181
|
end
|
|
168
182
|
end
|
|
@@ -52,12 +52,21 @@ module RuboCop
|
|
|
52
52
|
EACH_LENGTH = 'each'.length
|
|
53
53
|
PREFER_EACH = 'Prefer `each` over `for`.'
|
|
54
54
|
PREFER_FOR = 'Prefer `for` over `each`.'
|
|
55
|
+
IMPLICIT_PARAMETERS = %i[_1 _2 _3 _4 _5 _6 _7 _8 _9 it].to_set.freeze
|
|
56
|
+
|
|
57
|
+
# `Style/RedundantBegin` removes the `begin` of a block body in the same pass,
|
|
58
|
+
# leaving a `rescue` or `ensure` clause directly in the `for` body.
|
|
59
|
+
def self.autocorrect_incompatible_with
|
|
60
|
+
[Style::RedundantBegin]
|
|
61
|
+
end
|
|
55
62
|
|
|
56
63
|
def on_for(node)
|
|
57
64
|
if style == :each
|
|
58
65
|
add_offense(node, message: PREFER_EACH) do |corrector|
|
|
59
|
-
ForToEachCorrector.new(node).call(corrector)
|
|
60
66
|
opposite_style_detected
|
|
67
|
+
next unless convertible_to_each?(node)
|
|
68
|
+
|
|
69
|
+
ForToEachCorrector.new(node).call(corrector)
|
|
61
70
|
end
|
|
62
71
|
else
|
|
63
72
|
correct_style_detected
|
|
@@ -69,6 +78,7 @@ module RuboCop
|
|
|
69
78
|
|
|
70
79
|
if style == :for
|
|
71
80
|
return unless node.receiver
|
|
81
|
+
return if rescue_or_ensure_body?(node) || do_end_block_in_collection?(node)
|
|
72
82
|
|
|
73
83
|
add_offense(node, message: PREFER_FOR) do |corrector|
|
|
74
84
|
EachToForCorrector.new(node).call(corrector)
|
|
@@ -84,9 +94,42 @@ module RuboCop
|
|
|
84
94
|
|
|
85
95
|
private
|
|
86
96
|
|
|
97
|
+
# The loop variable becomes a block parameter, which can only be a local
|
|
98
|
+
# variable, and the body can't refer to an implicit block parameter
|
|
99
|
+
# (`_1` or `it`) once the block has an explicit one.
|
|
100
|
+
def convertible_to_each?(node)
|
|
101
|
+
return false unless node.variable.each_node.all? { |n| n.type?(:lvasgn, :mlhs, :splat) }
|
|
102
|
+
return true unless node.body
|
|
103
|
+
|
|
104
|
+
node.body.each_node(:send, :lvar).none? { |ref| implicit_parameter?(ref, node) }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Inside a numbered or `it` block, `_1` and `it` are local variables
|
|
108
|
+
# rather than method calls.
|
|
109
|
+
def implicit_parameter?(ref, for_node)
|
|
110
|
+
return false unless implicit_parameter_reference?(ref)
|
|
111
|
+
|
|
112
|
+
ref.each_ancestor.take_while { |ancestor| !ancestor.equal?(for_node) }
|
|
113
|
+
.none?(&:any_block_type?)
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def implicit_parameter_reference?(ref)
|
|
117
|
+
return IMPLICIT_PARAMETERS.include?(ref.name) if ref.lvar_type?
|
|
118
|
+
|
|
119
|
+
IMPLICIT_PARAMETERS.include?(ref.method_name) && !ref.receiver && !ref.arguments?
|
|
120
|
+
end
|
|
121
|
+
|
|
87
122
|
def suspect_enumerable?(node)
|
|
88
123
|
node.multiline? && node.method?(:each) && !node.send_node.arguments?
|
|
89
124
|
end
|
|
125
|
+
|
|
126
|
+
def rescue_or_ensure_body?(node)
|
|
127
|
+
node.body&.type?(:rescue, :ensure)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def do_end_block_in_collection?(node)
|
|
131
|
+
node.receiver.each_node(:any_block).any?(&:keywords?)
|
|
132
|
+
end
|
|
90
133
|
end
|
|
91
134
|
end
|
|
92
135
|
end
|
|
@@ -69,9 +69,13 @@ module RuboCop
|
|
|
69
69
|
|
|
70
70
|
# @!method variable_argument?(node)
|
|
71
71
|
def_node_matcher :variable_argument?, <<~PATTERN
|
|
72
|
-
(send {str dstr} :%
|
|
72
|
+
(send {str dstr} :% !#autocorrectable?)
|
|
73
73
|
PATTERN
|
|
74
74
|
|
|
75
|
+
def on_new_investigation
|
|
76
|
+
@corrected_ranges = nil
|
|
77
|
+
end
|
|
78
|
+
|
|
75
79
|
def on_send(node)
|
|
76
80
|
formatter(node) do |selector|
|
|
77
81
|
detected_style = selector == :% ? :percent : selector
|
|
@@ -86,10 +90,12 @@ module RuboCop
|
|
|
86
90
|
|
|
87
91
|
private
|
|
88
92
|
|
|
93
|
+
# Only an argument that is provably not an array can be corrected,
|
|
94
|
+
# because `String#%` spreads an array argument and `format` does not.
|
|
89
95
|
def autocorrectable?(node)
|
|
90
|
-
return true if node.
|
|
96
|
+
return true if node.literal?
|
|
91
97
|
|
|
92
|
-
node.
|
|
98
|
+
node.call_type? && AUTOCORRECTABLE_METHODS.include?(node.method_name)
|
|
93
99
|
end
|
|
94
100
|
|
|
95
101
|
def message(detected_style)
|
|
@@ -101,7 +107,9 @@ module RuboCop
|
|
|
101
107
|
end
|
|
102
108
|
|
|
103
109
|
def autocorrect(corrector, node)
|
|
104
|
-
return if variable_argument?(node)
|
|
110
|
+
return if variable_argument?(node) || within_corrected_range?(node)
|
|
111
|
+
|
|
112
|
+
corrected_ranges << node.source_range
|
|
105
113
|
|
|
106
114
|
case node.method_name
|
|
107
115
|
when :%
|
|
@@ -116,6 +124,14 @@ module RuboCop
|
|
|
116
124
|
end
|
|
117
125
|
end
|
|
118
126
|
|
|
127
|
+
def within_corrected_range?(node)
|
|
128
|
+
corrected_ranges.any? { |range| range.contains?(node.source_range) }
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def corrected_ranges
|
|
132
|
+
@corrected_ranges ||= []
|
|
133
|
+
end
|
|
134
|
+
|
|
119
135
|
def autocorrect_from_percent(corrector, node)
|
|
120
136
|
percent_rhs = node.first_argument
|
|
121
137
|
args = case percent_rhs.type
|
|
@@ -146,14 +162,20 @@ module RuboCop
|
|
|
146
162
|
def format_single_parameter(arg)
|
|
147
163
|
# `format(fmt, *args)` is equivalent to `fmt % args`, so unwrap the splat
|
|
148
164
|
# and render the argument it splats.
|
|
149
|
-
return
|
|
165
|
+
return format_splatted_parameter(arg.children.first) if arg.splat_type?
|
|
150
166
|
|
|
151
167
|
source = arg.source
|
|
152
|
-
return "{ #{source} }" if arg.hash_type?
|
|
168
|
+
return "{ #{source} }" if arg.hash_type? && !arg.braces?
|
|
153
169
|
|
|
154
170
|
requires_parentheses?(arg) ? "(#{source})" : source
|
|
155
171
|
end
|
|
156
172
|
|
|
173
|
+
def format_splatted_parameter(arg)
|
|
174
|
+
return "#{arg.source}.to_a" if arg.hash_type?
|
|
175
|
+
|
|
176
|
+
format_single_parameter(arg)
|
|
177
|
+
end
|
|
178
|
+
|
|
157
179
|
# An argument that binds looser than `%` (a ternary, range, assignment, or
|
|
158
180
|
# operator call) must be parenthesized to keep its meaning.
|
|
159
181
|
def requires_parentheses?(arg)
|
|
@@ -228,7 +228,7 @@ module RuboCop
|
|
|
228
228
|
"Prefer #{message_text(style)} over #{message_text(detected_style)}."
|
|
229
229
|
end
|
|
230
230
|
|
|
231
|
-
# rubocop:disable-next Style/FormatStringToken
|
|
231
|
+
# rubocop:disable-next Style/FormatStringToken -- the cop needs the token style it is matching
|
|
232
232
|
def message_text(style)
|
|
233
233
|
{
|
|
234
234
|
annotated: 'annotated tokens (like `%<foo>s`)',
|
|
@@ -142,7 +142,8 @@ module RuboCop
|
|
|
142
142
|
end
|
|
143
143
|
|
|
144
144
|
next_token = processed_source.tokens[token_number]
|
|
145
|
-
if next_token&.text&.valid_encoding? &&
|
|
145
|
+
if next_token&.text&.valid_encoding? &&
|
|
146
|
+
MagicComment.parse(next_token.text).encoding_specified?
|
|
146
147
|
token = next_token
|
|
147
148
|
end
|
|
148
149
|
|
|
@@ -109,6 +109,10 @@ module RuboCop
|
|
|
109
109
|
MSG = 'Use a guard clause (`%<example>s`) instead of wrapping the ' \
|
|
110
110
|
'code inside a conditional expression.'
|
|
111
111
|
|
|
112
|
+
def self.autocorrect_incompatible_with
|
|
113
|
+
[Style::MissingElse]
|
|
114
|
+
end
|
|
115
|
+
|
|
112
116
|
def on_def(node)
|
|
113
117
|
body = node.body
|
|
114
118
|
|
|
@@ -278,7 +282,15 @@ module RuboCop
|
|
|
278
282
|
end
|
|
279
283
|
|
|
280
284
|
def accepted_form?(node, ending: false)
|
|
281
|
-
accepted_if?(node, ending) || node.condition.multiline? ||
|
|
285
|
+
accepted_if?(node, ending) || node.condition.multiline? ||
|
|
286
|
+
node.parent&.assignment? || endless_method_body?(node)
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# The body of an endless method is a single expression, so there is no
|
|
290
|
+
# room for a guard clause followed by the rest of the code.
|
|
291
|
+
def endless_method_body?(node)
|
|
292
|
+
parent = node.parent
|
|
293
|
+
parent&.any_def_type? && parent.endless?
|
|
282
294
|
end
|
|
283
295
|
|
|
284
296
|
def trivial?(node)
|