rubocop 1.91.0 → 1.92.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/default.yml +4 -1
- data/lib/rubocop/cached_data.rb +47 -7
- data/lib/rubocop/changed_files.rb +35 -13
- data/lib/rubocop/cli/command/cop_names.rb +57 -0
- data/lib/rubocop/cli/command/execute_runner.rb +2 -2
- 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 +3 -2
- data/lib/rubocop/comment_config.rb +17 -8
- data/lib/rubocop/config_loader.rb +6 -3
- data/lib/rubocop/config_loader_resolver.rb +37 -12
- data/lib/rubocop/config_obsoletion/removed_cop.rb +1 -1
- data/lib/rubocop/config_validator.rb +11 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +10 -5
- data/lib/rubocop/cop/badge.rb +1 -1
- data/lib/rubocop/cop/base.rb +42 -21
- 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 +37 -7
- data/lib/rubocop/cop/correctors/empty_line_corrector.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +25 -4
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +34 -0
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +45 -8
- 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/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/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 +5 -1
- 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 +29 -7
- data/lib/rubocop/cop/layout/def_end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/dot_position.rb +25 -15
- data/lib/rubocop/cop/layout/empty_line_after_multiline_condition.rb +21 -8
- data/lib/rubocop/cop/layout/empty_lines.rb +5 -2
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -0
- data/lib/rubocop/cop/layout/empty_lines_around_block_body.rb +9 -3
- data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +23 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +19 -17
- data/lib/rubocop/cop/layout/extra_spacing.rb +4 -0
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +27 -1
- data/lib/rubocop/cop/layout/first_array_element_line_break.rb +15 -0
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +16 -8
- 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/hash_alignment.rb +16 -12
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +7 -3
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +15 -0
- data/lib/rubocop/cop/layout/indentation_consistency.rb +22 -5
- data/lib/rubocop/cop/layout/indentation_style.rb +4 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +2 -2
- 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 +153 -21
- 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 +9 -0
- data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +6 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +30 -5
- 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 +6 -11
- data/lib/rubocop/cop/layout/space_around_keyword.rb +10 -0
- 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/layout/space_inside_reference_brackets.rb +2 -12
- 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/ambiguous_regexp_literal.rb +6 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +3 -1
- data/lib/rubocop/cop/lint/heredoc_method_call_position.rb +4 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +15 -0
- 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 +71 -11
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +18 -3
- data/lib/rubocop/cop/lint/number_conversion.rb +3 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +12 -1
- data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +13 -2
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +47 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +1 -0
- 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/useless_setter_call.rb +7 -4
- data/lib/rubocop/cop/lint/void.rb +8 -1
- 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/mixin/alignment.rb +4 -0
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +23 -19
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +8 -2
- 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 +105 -0
- data/lib/rubocop/cop/mixin/forbidden_identifiers.rb +2 -2
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +24 -5
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +26 -2
- 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 +17 -2
- 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 +25 -4
- data/lib/rubocop/cop/mixin/visibility_help.rb +2 -1
- data/lib/rubocop/cop/mixin.rb +2 -0
- data/lib/rubocop/cop/naming/accessor_method_name.rb +0 -16
- data/lib/rubocop/cop/naming/block_forwarding.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/naming/rescued_exceptions_variable_name.rb +1 -1
- data/lib/rubocop/cop/offense.rb +59 -3
- data/lib/rubocop/cop/registry.rb +1 -1
- data/lib/rubocop/cop/security/json_load.rb +16 -4
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +37 -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 +6 -2
- data/lib/rubocop/cop/style/arguments_forwarding.rb +32 -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 +35 -3
- data/lib/rubocop/cop/style/case_like_if.rb +6 -3
- data/lib/rubocop/cop/style/class_and_module_children.rb +56 -16
- data/lib/rubocop/cop/style/class_methods_definitions.rb +15 -0
- data/lib/rubocop/cop/style/collection_querying.rb +79 -46
- data/lib/rubocop/cop/style/combinable_loops.rb +89 -11
- data/lib/rubocop/cop/style/concat_array_literals.rb +58 -7
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -0
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +65 -9
- data/lib/rubocop/cop/style/double_negation.rb +11 -0
- data/lib/rubocop/cop/style/empty_literal.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +3 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +53 -11
- data/lib/rubocop/cop/style/endless_method.rb +71 -6
- 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/float_division.rb +22 -2
- data/lib/rubocop/cop/style/for.rb +53 -2
- data/lib/rubocop/cop/style/format_string.rb +28 -6
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -1
- data/lib/rubocop/cop/style/guard_clause.rb +31 -22
- data/lib/rubocop/cop/style/hash_as_last_array_item.rb +4 -0
- data/lib/rubocop/cop/style/hash_conversion.rb +28 -8
- data/lib/rubocop/cop/style/hash_lookup_method.rb +32 -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 +32 -26
- 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 +94 -4
- data/lib/rubocop/cop/style/keyword_parameters_order.rb +3 -1
- data/lib/rubocop/cop/style/lambda.rb +34 -1
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/map_into_array.rb +1 -2
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +80 -13
- 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/mixin_grouping.rb +12 -3
- 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 +52 -7
- 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 +27 -8
- 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 +16 -4
- data/lib/rubocop/cop/style/non_nil_check.rb +1 -1
- data/lib/rubocop/cop/style/not.rb +10 -5
- data/lib/rubocop/cop/style/numeric_predicate.rb +21 -5
- data/lib/rubocop/cop/style/one_line_conditional.rb +13 -2
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +1 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +14 -3
- data/lib/rubocop/cop/style/raise_args.rb +19 -9
- data/lib/rubocop/cop/style/reduce_to_hash.rb +17 -1
- data/lib/rubocop/cop/style/redundant_begin.rb +22 -4
- data/lib/rubocop/cop/style/redundant_condition.rb +30 -13
- data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +6 -0
- data/lib/rubocop/cop/style/redundant_exception.rb +15 -3
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +9 -1
- data/lib/rubocop/cop/style/redundant_freeze.rb +11 -3
- data/lib/rubocop/cop/style/redundant_interpolation_unfreeze.rb +24 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +12 -1
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +7 -0
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +20 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +4 -0
- data/lib/rubocop/cop/style/redundant_self_assignment_branch.rb +28 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +38 -4
- data/lib/rubocop/cop/style/regexp_literal.rb +75 -26
- data/lib/rubocop/cop/style/require_order.rb +25 -8
- data/lib/rubocop/cop/style/rescue_modifier.rb +11 -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/send_with_literal_method_name.rb +4 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +21 -4
- 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 +6 -0
- data/lib/rubocop/cop/style/super_arguments.rb +3 -0
- data/lib/rubocop/cop/style/symbol_proc.rb +24 -6
- data/lib/rubocop/cop/style/ternary_parentheses.rb +23 -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/team.rb +10 -5
- data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
- data/lib/rubocop/cop/variable_force/variable.rb +14 -1
- data/lib/rubocop/formatter/base_formatter.rb +22 -0
- data/lib/rubocop/formatter/formatter_set.rb +4 -0
- data/lib/rubocop/formatter/json_formatter.rb +71 -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 +12 -7
- data/lib/rubocop/formatter/worst_offenders_formatter.rb +3 -1
- data/lib/rubocop/lsp/routes.rb +23 -23
- 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/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 +45 -10
- data/lib/rubocop/plugin/configuration_integrator.rb +12 -5
- data/lib/rubocop/remote_config.rb +4 -1
- data/lib/rubocop/result_cache.rb +20 -13
- data/lib/rubocop/runner.rb +109 -41
- data/lib/rubocop/server/cache.rb +6 -6
- data/lib/rubocop/target_ruby.rb +21 -9
- data/lib/rubocop/util.rb +69 -0
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +5 -0
- metadata +16 -5
|
@@ -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
|
|
|
@@ -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
|
|
@@ -141,8 +142,27 @@ module RuboCop
|
|
|
141
142
|
end
|
|
142
143
|
|
|
143
144
|
def remove_to_f_method(corrector, send_node)
|
|
144
|
-
corrector.remove(send_node.loc.
|
|
145
|
-
|
|
145
|
+
corrector.remove(send_node.receiver.source_range.end.join(send_node.loc.selector.end))
|
|
146
|
+
end
|
|
147
|
+
|
|
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
|
+
|
|
152
|
+
range = operand.receiver.source_range.end.join(operand.loc.selector.begin)
|
|
153
|
+
processed_source.contains_comment?(range)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
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]
|
|
163
|
+
else
|
|
164
|
+
[node.receiver, node.first_argument]
|
|
165
|
+
end
|
|
146
166
|
end
|
|
147
167
|
|
|
148
168
|
def correct_from_slash_to_fdiv(corrector, receiver, argument)
|
|
@@ -52,12 +52,23 @@ 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
|
+
# `Style/ItBlockParameter` replaces block parameter references in the body
|
|
60
|
+
# with `it` in the same pass, while they become `for` loop variables.
|
|
61
|
+
def self.autocorrect_incompatible_with
|
|
62
|
+
[Style::RedundantBegin, Style::ItBlockParameter]
|
|
63
|
+
end
|
|
55
64
|
|
|
56
65
|
def on_for(node)
|
|
57
66
|
if style == :each
|
|
58
67
|
add_offense(node, message: PREFER_EACH) do |corrector|
|
|
59
|
-
ForToEachCorrector.new(node).call(corrector)
|
|
60
68
|
opposite_style_detected
|
|
69
|
+
next unless convertible_to_each?(node)
|
|
70
|
+
|
|
71
|
+
ForToEachCorrector.new(node).call(corrector)
|
|
61
72
|
end
|
|
62
73
|
else
|
|
63
74
|
correct_style_detected
|
|
@@ -69,7 +80,8 @@ module RuboCop
|
|
|
69
80
|
|
|
70
81
|
if style == :for
|
|
71
82
|
return unless node.receiver
|
|
72
|
-
return
|
|
83
|
+
return unless convertible_to_for?(node)
|
|
84
|
+
return if rescue_or_ensure_body?(node) || do_end_block_in_collection?(node)
|
|
73
85
|
|
|
74
86
|
add_offense(node, message: PREFER_FOR) do |corrector|
|
|
75
87
|
EachToForCorrector.new(node).call(corrector)
|
|
@@ -85,13 +97,52 @@ module RuboCop
|
|
|
85
97
|
|
|
86
98
|
private
|
|
87
99
|
|
|
100
|
+
# The loop variable becomes a block parameter, which can only be a local
|
|
101
|
+
# variable, and the body can't refer to an implicit block parameter
|
|
102
|
+
# (`_1` or `it`) once the block has an explicit one.
|
|
103
|
+
def convertible_to_each?(node)
|
|
104
|
+
return false unless node.variable.each_node.all? { |n| n.type?(:lvasgn, :mlhs, :splat) }
|
|
105
|
+
return true unless node.body
|
|
106
|
+
|
|
107
|
+
node.body.each_node(:send, :lvar).none? { |ref| implicit_parameter?(ref, node) }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Inside a numbered or `it` block, `_1` and `it` are local variables
|
|
111
|
+
# rather than method calls.
|
|
112
|
+
def implicit_parameter?(ref, for_node)
|
|
113
|
+
return false unless implicit_parameter_reference?(ref)
|
|
114
|
+
|
|
115
|
+
ref.each_ancestor.take_while { |ancestor| !ancestor.equal?(for_node) }
|
|
116
|
+
.none?(&:any_block_type?)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def implicit_parameter_reference?(ref)
|
|
120
|
+
return IMPLICIT_PARAMETERS.include?(ref.name) if ref.lvar_type?
|
|
121
|
+
|
|
122
|
+
IMPLICIT_PARAMETERS.include?(ref.method_name) && !ref.receiver && !ref.arguments?
|
|
123
|
+
end
|
|
124
|
+
|
|
88
125
|
def suspect_enumerable?(node)
|
|
89
126
|
node.multiline? && node.method?(:each) && !node.send_node.arguments?
|
|
90
127
|
end
|
|
91
128
|
|
|
129
|
+
def convertible_to_for?(node)
|
|
130
|
+
return false if node.type?(:numblock, :itblock)
|
|
131
|
+
return true unless node.arguments?
|
|
132
|
+
|
|
133
|
+
arguments = node.arguments
|
|
134
|
+
return false if arguments.children.one? && arguments.children.first.restarg_type?
|
|
135
|
+
|
|
136
|
+
arguments.each_descendant.all? { |arg| arg.type?(:arg, :restarg, :mlhs) }
|
|
137
|
+
end
|
|
138
|
+
|
|
92
139
|
def rescue_or_ensure_body?(node)
|
|
93
140
|
node.body&.type?(:rescue, :ensure)
|
|
94
141
|
end
|
|
142
|
+
|
|
143
|
+
def do_end_block_in_collection?(node)
|
|
144
|
+
node.receiver.each_node(:any_block).any?(&:keywords?)
|
|
145
|
+
end
|
|
95
146
|
end
|
|
96
147
|
end
|
|
97
148
|
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)
|
|
@@ -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
|
|
|
@@ -186,40 +186,37 @@ module RuboCop
|
|
|
186
186
|
return if trivial?(node)
|
|
187
187
|
|
|
188
188
|
example = "#{conditional_keyword} #{condition.source}; #{scope_exiting_keyword}; end"
|
|
189
|
-
replacement =
|
|
190
|
-
#{conditional_keyword} #{condition.source}
|
|
191
|
-
#{scope_exiting_keyword}
|
|
192
|
-
end
|
|
193
|
-
RUBY
|
|
189
|
+
replacement = "#{conditional_keyword} #{condition.source}\n #{scope_exiting_keyword}"
|
|
194
190
|
end
|
|
195
191
|
|
|
196
192
|
add_offense(node.loc.keyword, message: format(MSG, example: example)) do |corrector|
|
|
197
193
|
next if node.else? && guard.nil?
|
|
198
194
|
|
|
199
|
-
autocorrect(corrector, node,
|
|
195
|
+
autocorrect(corrector, node, example, replacement, guard)
|
|
200
196
|
end
|
|
201
197
|
end
|
|
202
198
|
|
|
203
199
|
# rubocop:disable-next Metrics/AbcSize
|
|
204
|
-
def autocorrect(corrector, node,
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
if_branch = node.if_branch
|
|
208
|
-
else_branch = node.else_branch
|
|
209
|
-
|
|
200
|
+
def autocorrect(corrector, node, example, multiline_replacement, guard)
|
|
201
|
+
range = node.loc.keyword.join(node.condition.source_range)
|
|
202
|
+
corrector.replace(range, multiline_replacement || example)
|
|
210
203
|
corrector.replace(node.loc.begin, "\n") if node.then?
|
|
211
204
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
elsif (else_heredoc = find_heredoc_argument(else_branch))
|
|
215
|
-
autocorrect_heredoc_argument(corrector, node, else_heredoc, if_branch, guard)
|
|
216
|
-
else
|
|
217
|
-
corrector.remove(node.loc.end)
|
|
218
|
-
return unless node.else?
|
|
205
|
+
branches = [node.if_branch, node.else_branch]
|
|
206
|
+
guard_branch, leave_branch = guard == :else ? branches.reverse : branches
|
|
219
207
|
|
|
220
|
-
|
|
221
|
-
|
|
208
|
+
heredoc = find_heredoc_argument(guard_branch)
|
|
209
|
+
close_multiline_guard_clause(corrector, range, heredoc, guard) if multiline_replacement
|
|
210
|
+
|
|
211
|
+
if heredoc
|
|
212
|
+
return autocorrect_heredoc_argument(corrector, node, heredoc, leave_branch, guard)
|
|
222
213
|
end
|
|
214
|
+
|
|
215
|
+
corrector.remove(node.loc.end)
|
|
216
|
+
return unless node.else?
|
|
217
|
+
|
|
218
|
+
corrector.remove(node.loc.else)
|
|
219
|
+
corrector.remove(range_of_branch_to_remove(node, guard))
|
|
223
220
|
end
|
|
224
221
|
|
|
225
222
|
def heredoc?(argument)
|
|
@@ -241,6 +238,10 @@ module RuboCop
|
|
|
241
238
|
find_heredoc_argument(node.receiver)
|
|
242
239
|
end
|
|
243
240
|
|
|
241
|
+
def close_multiline_guard_clause(corrector, range, heredoc, guard)
|
|
242
|
+
corrector.insert_after(guard && heredoc ? heredoc.loc.heredoc_end : range, "\nend")
|
|
243
|
+
end
|
|
244
|
+
|
|
244
245
|
def autocorrect_heredoc_argument(corrector, node, heredoc_node, leave_branch, guard)
|
|
245
246
|
remove_whole_lines(corrector, node.loc.end)
|
|
246
247
|
return unless node.else?
|
|
@@ -282,7 +283,15 @@ module RuboCop
|
|
|
282
283
|
end
|
|
283
284
|
|
|
284
285
|
def accepted_form?(node, ending: false)
|
|
285
|
-
accepted_if?(node, ending) || node.condition.multiline? ||
|
|
286
|
+
accepted_if?(node, ending) || node.condition.multiline? ||
|
|
287
|
+
node.parent&.assignment? || endless_method_body?(node)
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
# The body of an endless method is a single expression, so there is no
|
|
291
|
+
# room for a guard clause followed by the rest of the code.
|
|
292
|
+
def endless_method_body?(node)
|
|
293
|
+
parent = node.parent
|
|
294
|
+
parent&.any_def_type? && parent.endless?
|
|
286
295
|
end
|
|
287
296
|
|
|
288
297
|
def trivial?(node)
|
|
@@ -44,6 +44,10 @@ module RuboCop
|
|
|
44
44
|
include ConfigurableEnforcedStyle
|
|
45
45
|
extend AutoCorrector
|
|
46
46
|
|
|
47
|
+
def self.autocorrect_incompatible_with
|
|
48
|
+
[Style::TrailingCommaInArrayLiteral]
|
|
49
|
+
end
|
|
50
|
+
|
|
47
51
|
def on_hash(node)
|
|
48
52
|
return if node.children.first&.kwsplat_type?
|
|
49
53
|
return unless (array = containing_array(node))
|
|
@@ -53,6 +53,12 @@ module RuboCop
|
|
|
53
53
|
# @!method hash_from_array?(node)
|
|
54
54
|
def_node_matcher :hash_from_array?, '(send (const {nil? cbase} :Hash) :[] ...)'
|
|
55
55
|
|
|
56
|
+
# A hash literal as the first argument needs the parentheses of the call,
|
|
57
|
+
# which `Style/MethodCallWithArgsParentheses` removes in the same pass.
|
|
58
|
+
def self.autocorrect_incompatible_with
|
|
59
|
+
[Style::MethodCallWithArgsParentheses]
|
|
60
|
+
end
|
|
61
|
+
|
|
56
62
|
def on_send(node)
|
|
57
63
|
return if part_of_ignored_node?(node) || !hash_from_array?(node)
|
|
58
64
|
|
|
@@ -95,12 +101,30 @@ module RuboCop
|
|
|
95
101
|
def register_offense_for_hash(node, hash_argument)
|
|
96
102
|
add_offense(node, message: MSG_LITERAL_HASH_ARG) do |corrector|
|
|
97
103
|
corrector.replace(node, "{#{hash_argument.source}}")
|
|
98
|
-
|
|
99
|
-
parent = node.parent
|
|
100
|
-
add_parentheses(parent, corrector) if parent&.send_type? && !parent.parenthesized?
|
|
104
|
+
add_parentheses_to_parent_call(node, corrector)
|
|
101
105
|
end
|
|
102
106
|
end
|
|
103
107
|
|
|
108
|
+
# Without parentheses, a hash literal at the start of the first argument would be
|
|
109
|
+
# parsed as a block. That includes an argument like `Hash[a, b].merge(c)`.
|
|
110
|
+
def add_parentheses_to_parent_call(node, corrector)
|
|
111
|
+
node = node.parent while starts_parent?(node)
|
|
112
|
+
parent = node.parent
|
|
113
|
+
return unless parent&.type?(:call, :super, :yield)
|
|
114
|
+
return if parent.parenthesized? || operator_syntax?(parent)
|
|
115
|
+
|
|
116
|
+
add_parentheses(parent, corrector)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def starts_parent?(node)
|
|
120
|
+
node.parent && node.parent.source_range.begin_pos == node.source_range.begin_pos
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# `foo[x]`, `foo.bar = x` and `foo == x` take a hash literal as it is.
|
|
124
|
+
def operator_syntax?(call)
|
|
125
|
+
call.setter_method? || (call.operator_method? && !call.loc?(:dot))
|
|
126
|
+
end
|
|
127
|
+
|
|
104
128
|
def register_offense_for_zip_method(node, zip_method)
|
|
105
129
|
add_offense(node, message: MSG_TO_H) do |corrector|
|
|
106
130
|
if zip_method.parenthesized?
|
|
@@ -135,11 +159,7 @@ module RuboCop
|
|
|
135
159
|
def correct_multi_argument(node)
|
|
136
160
|
add_offense(node, message: MSG_LITERAL_MULTI_ARG) do |corrector|
|
|
137
161
|
corrector.replace(node, args_to_hash(node.arguments))
|
|
138
|
-
|
|
139
|
-
parent = node.parent
|
|
140
|
-
if parent&.send_type? && !parent.method?(:to_h) && !parent.parenthesized?
|
|
141
|
-
add_parentheses(parent, corrector)
|
|
142
|
-
end
|
|
162
|
+
add_parentheses_to_parent_call(node, corrector)
|
|
143
163
|
end
|
|
144
164
|
end
|
|
145
165
|
|
|
@@ -34,6 +34,9 @@ module RuboCop
|
|
|
34
34
|
# # good - fetch with block is allowed
|
|
35
35
|
# hash.fetch(key) { default }
|
|
36
36
|
#
|
|
37
|
+
# # good - `ENV.fetch` is left to `Style/FetchEnvVar` when it is enabled
|
|
38
|
+
# ENV.fetch(key)
|
|
39
|
+
#
|
|
37
40
|
# @example EnforcedStyle: fetch
|
|
38
41
|
# # bad
|
|
39
42
|
# hash[key]
|
|
@@ -55,6 +58,9 @@ module RuboCop
|
|
|
55
58
|
|
|
56
59
|
RESTRICT_ON_SEND = %i[[] fetch].freeze
|
|
57
60
|
|
|
61
|
+
# @!method env_const?(node)
|
|
62
|
+
def_node_matcher :env_const?, '(const {nil? cbase} :ENV)'
|
|
63
|
+
|
|
58
64
|
def on_send(node)
|
|
59
65
|
return if (receiver = node.receiver) && allowed_receiver?(receiver)
|
|
60
66
|
return if part_of_ignored_node?(node)
|
|
@@ -76,28 +82,45 @@ module RuboCop
|
|
|
76
82
|
private
|
|
77
83
|
|
|
78
84
|
def offense_for_brackets?(node)
|
|
79
|
-
style
|
|
80
|
-
|
|
85
|
+
return false if style != :brackets || !node.receiver
|
|
86
|
+
return false if !node.method?(:fetch) || !node.arguments.one?
|
|
87
|
+
return false if node.block_literal? || node.csend_type?
|
|
88
|
+
|
|
89
|
+
!exempt_from_brackets?(node)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def exempt_from_brackets?(node)
|
|
93
|
+
comment_before_dot?(node) || env_fetch_preferred?(node.receiver)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def comment_before_dot?(node)
|
|
97
|
+
processed_source.contains_comment?(node.receiver.source_range.end.join(node.loc.dot))
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def env_fetch_preferred?(receiver)
|
|
101
|
+
env_const?(receiver) && processed_source.registry.enabled?(Style::FetchEnvVar, config)
|
|
81
102
|
end
|
|
82
103
|
|
|
83
104
|
def offense_for_fetch?(node)
|
|
84
|
-
style == :fetch && node.method?(:[]) && node.arguments.one?
|
|
105
|
+
style == :fetch && node.method?(:[]) && node.arguments.one? &&
|
|
106
|
+
!compound_assignment_target?(node)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def compound_assignment_target?(node)
|
|
110
|
+
node.parent&.type?(:op_asgn, :or_asgn, :and_asgn) && node.parent.children.first == node
|
|
85
111
|
end
|
|
86
112
|
|
|
87
113
|
def correct_fetch_to_brackets(corrector, node)
|
|
88
114
|
key = node.first_argument.source
|
|
89
115
|
|
|
90
|
-
corrector.replace(node.
|
|
116
|
+
corrector.replace(node.receiver.source_range.end.join(node.source_range.end), "[#{key}]")
|
|
91
117
|
end
|
|
92
118
|
|
|
93
119
|
def correct_brackets_to_fetch(corrector, node)
|
|
94
120
|
key = node.first_argument.source
|
|
121
|
+
replacement = node.loc.dot ? "fetch(#{key})" : ".fetch(#{key})"
|
|
95
122
|
|
|
96
|
-
|
|
97
|
-
corrector.replace(node.loc.dot.join(node.source_range.end), "&.fetch(#{key})")
|
|
98
|
-
else
|
|
99
|
-
corrector.replace(node.loc.selector.join(node.source_range.end), ".fetch(#{key})")
|
|
100
|
-
end
|
|
123
|
+
corrector.replace(node.loc.selector.join(node.source_range.end), replacement)
|
|
101
124
|
end
|
|
102
125
|
end
|
|
103
126
|
end
|
|
@@ -142,6 +142,13 @@ module RuboCop
|
|
|
142
142
|
MSG_HASH_ROCKETS = 'Use hash rockets syntax.'
|
|
143
143
|
NO_MIXED_KEYS_STYLES = %i[ruby19_no_mixed_keys no_mixed_keys].freeze
|
|
144
144
|
|
|
145
|
+
# Omitting the last hash value of a call without parentheses adds the parentheses,
|
|
146
|
+
# which `Style/MethodCallWithArgsParentheses` and `Style/SuperWithArgsParentheses`
|
|
147
|
+
# would add again in the same pass.
|
|
148
|
+
def self.autocorrect_incompatible_with
|
|
149
|
+
[Style::MethodCallWithArgsParentheses, Style::SuperWithArgsParentheses]
|
|
150
|
+
end
|
|
151
|
+
|
|
145
152
|
def on_hash(node)
|
|
146
153
|
pairs = node.pairs
|
|
147
154
|
|
|
@@ -241,6 +248,8 @@ module RuboCop
|
|
|
241
248
|
def check(pairs, delim, msg)
|
|
242
249
|
pairs.each do |pair|
|
|
243
250
|
if pair.delimiter == delim
|
|
251
|
+
next if pair.value_omission? && keyword_value?(pair)
|
|
252
|
+
|
|
244
253
|
location = pair.source_range.begin.join(pair.loc.operator)
|
|
245
254
|
add_offense(location, message: msg) do |corrector|
|
|
246
255
|
autocorrect(corrector, pair)
|
|
@@ -283,12 +292,16 @@ module RuboCop
|
|
|
283
292
|
end
|
|
284
293
|
|
|
285
294
|
def autocorrect_hash_rockets(corrector, pair_node)
|
|
286
|
-
op = pair_node.loc.operator
|
|
287
|
-
|
|
288
295
|
key_with_hash_rocket = ":#{pair_node.key.source}#{pair_node.inverse_delimiter(true)}"
|
|
289
296
|
key_with_hash_rocket += pair_node.key.source if pair_node.value_omission?
|
|
290
297
|
corrector.replace(pair_node.key, key_with_hash_rocket)
|
|
291
|
-
corrector.remove(
|
|
298
|
+
corrector.remove(operator_range(pair_node))
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
def operator_range(pair_node)
|
|
302
|
+
op = pair_node.loc.operator
|
|
303
|
+
|
|
304
|
+
range_with_surrounding_space(op, newlines: !pair_node.value_omission?)
|
|
292
305
|
end
|
|
293
306
|
|
|
294
307
|
def autocorrect_no_mixed_keys(corrector, pair_node)
|
|
@@ -188,7 +188,7 @@ module RuboCop
|
|
|
188
188
|
end
|
|
189
189
|
end
|
|
190
190
|
|
|
191
|
-
# rubocop:disable-next Metrics/
|
|
191
|
+
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
192
192
|
def check_expressions(node, expressions, insert_position)
|
|
193
193
|
return if expressions.any?(&:nil?)
|
|
194
194
|
|
|
@@ -198,8 +198,7 @@ module RuboCop
|
|
|
198
198
|
add_offense(expression) do |corrector|
|
|
199
199
|
next if node.if_type? && (node.ternary? || node.then?)
|
|
200
200
|
|
|
201
|
-
|
|
202
|
-
corrector.remove(range)
|
|
201
|
+
corrector.remove(removal_range(expression))
|
|
203
202
|
next if inserted_expression
|
|
204
203
|
|
|
205
204
|
if node.parent&.assignment?
|
|
@@ -213,6 +212,26 @@ module RuboCop
|
|
|
213
212
|
end
|
|
214
213
|
end
|
|
215
214
|
|
|
215
|
+
def removal_range(expression)
|
|
216
|
+
range = expression.source_range
|
|
217
|
+
whole_lines = range_by_whole_lines(range, include_final_newline: true)
|
|
218
|
+
return whole_lines if whole_lines.source.strip == expression.source
|
|
219
|
+
|
|
220
|
+
range_with_separator(range)
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def range_with_separator(range)
|
|
224
|
+
source = range.source_buffer.source
|
|
225
|
+
|
|
226
|
+
if (following = source[range.end_pos..][/\A[ \t]*;[ \t]*/])
|
|
227
|
+
range.adjust(end_pos: following.length)
|
|
228
|
+
elsif (preceding = source[0...range.begin_pos][/[ \t]*;[ \t]*\z/])
|
|
229
|
+
range.adjust(begin_pos: -preceding.length)
|
|
230
|
+
else
|
|
231
|
+
range_with_surrounding_space(range, side: :right, newlines: false)
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
216
235
|
def correct_assignment(corrector, node, expression, insert_position)
|
|
217
236
|
indentation = indentation_of(node.parent)
|
|
218
237
|
|