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
|
@@ -75,7 +75,7 @@ module RuboCop
|
|
|
75
75
|
return if comments_between_else_and_if?(node, else_branch)
|
|
76
76
|
|
|
77
77
|
add_offense(else_branch.loc.keyword) do |corrector|
|
|
78
|
-
next if part_of_ignored_node?(node)
|
|
78
|
+
next if part_of_ignored_node?(node) || shares_lines_with_other_code?(else_branch)
|
|
79
79
|
|
|
80
80
|
autocorrect(corrector, else_branch)
|
|
81
81
|
ignore_node(node)
|
|
@@ -84,6 +84,26 @@ module RuboCop
|
|
|
84
84
|
|
|
85
85
|
private
|
|
86
86
|
|
|
87
|
+
# The `elsif` correction moves and removes whole lines, so it can't be applied when
|
|
88
|
+
# the nested `if` condition, its `if` branch or its `end` shares a line with other code.
|
|
89
|
+
# A modifier `if` on the `else` line would leave its body on the `elsif` line.
|
|
90
|
+
def shares_lines_with_other_code?(node)
|
|
91
|
+
return false if node.then?
|
|
92
|
+
return !begins_its_line?(node.source_range) if node.modifier_form?
|
|
93
|
+
|
|
94
|
+
moved_ranges(node).any? { |range| !begins_its_line?(range) || !ends_its_line?(range) }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def moved_ranges(node)
|
|
98
|
+
ranges = [if_condition_range(node, node.condition), find_end_range(node)]
|
|
99
|
+
ranges << range_with_comments(node.if_branch) if node.if_branch
|
|
100
|
+
ranges
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def ends_its_line?(range)
|
|
104
|
+
processed_source.lines[range.last_line - 1][range.last_column..].match?(/\A\s*(#|\z)/)
|
|
105
|
+
end
|
|
106
|
+
|
|
87
107
|
def autocorrect(corrector, node)
|
|
88
108
|
if node.then?
|
|
89
109
|
# If the nested `if` is a then node, correct it first,
|
|
@@ -100,6 +100,7 @@ module RuboCop
|
|
|
100
100
|
pattern_matching_nodes(condition).any?
|
|
101
101
|
|
|
102
102
|
return unless (msg = message(node))
|
|
103
|
+
return if modifier_sharing_line_in_logical_operator?(node)
|
|
103
104
|
|
|
104
105
|
add_offense(node.loc.keyword, message: format(msg, keyword: node.keyword)) do |corrector|
|
|
105
106
|
next if part_of_ignored_node?(node)
|
|
@@ -159,7 +160,7 @@ module RuboCop
|
|
|
159
160
|
corrector.replace(node, replacement)
|
|
160
161
|
end
|
|
161
162
|
|
|
162
|
-
def replacement_for_modifier_form(corrector, node)
|
|
163
|
+
def replacement_for_modifier_form(corrector, node)
|
|
163
164
|
comment = comment_on_node_line(node)
|
|
164
165
|
if comment && too_long_due_to_comment_after_modifier?(node, comment)
|
|
165
166
|
remove_comment(corrector, node, comment)
|
|
@@ -167,12 +168,11 @@ module RuboCop
|
|
|
167
168
|
return to_modifier_form_with_move_comment(node, indent(node), comment)
|
|
168
169
|
end
|
|
169
170
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
remove_heredoc(corrector, heredoc)
|
|
171
|
+
heredoc_ranges = heredoc_ranges_in(node)
|
|
172
|
+
unless heredoc_ranges.empty?
|
|
173
|
+
remove_heredoc(corrector, heredoc_ranges)
|
|
174
174
|
|
|
175
|
-
return to_normal_form_with_heredoc(node, indent(node)
|
|
175
|
+
return to_normal_form_with_heredoc(node, indent(node))
|
|
176
176
|
end
|
|
177
177
|
|
|
178
178
|
to_normal_form(node, indent(node))
|
|
@@ -234,11 +234,18 @@ module RuboCop
|
|
|
234
234
|
end
|
|
235
235
|
|
|
236
236
|
def collection_from_ancestor(node)
|
|
237
|
-
return node if node&.type?(:array, :call)
|
|
237
|
+
return node if node&.type?(:array, :call, :and, :or)
|
|
238
238
|
|
|
239
239
|
node.parent if node&.type?(:pair)
|
|
240
240
|
end
|
|
241
241
|
|
|
242
|
+
def modifier_sharing_line_in_logical_operator?(node)
|
|
243
|
+
collection = find_containing_collection(node)
|
|
244
|
+
return false if !node.modifier_form? || !collection&.operator_keyword?
|
|
245
|
+
|
|
246
|
+
another_modifier_if_on_same_line?(node)
|
|
247
|
+
end
|
|
248
|
+
|
|
242
249
|
def another_modifier_if_on_same_line?(node)
|
|
243
250
|
collection = find_containing_collection(node)
|
|
244
251
|
return false unless collection
|
|
@@ -275,16 +282,20 @@ module RuboCop
|
|
|
275
282
|
RUBY
|
|
276
283
|
end
|
|
277
284
|
|
|
278
|
-
def
|
|
279
|
-
|
|
285
|
+
def remove_heredoc(corrector, heredoc_ranges)
|
|
286
|
+
heredoc_ranges.each do |range|
|
|
287
|
+
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
|
288
|
+
end
|
|
289
|
+
end
|
|
280
290
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
#{
|
|
284
|
-
|
|
285
|
-
#{indentation} #{
|
|
286
|
-
|
|
287
|
-
|
|
291
|
+
def to_normal_form_with_heredoc(node, indentation)
|
|
292
|
+
[
|
|
293
|
+
"#{node.keyword} #{node.condition.source}",
|
|
294
|
+
*heredoc_ranges_in(node.condition).map(&:source),
|
|
295
|
+
"#{indentation} #{node.body.source}",
|
|
296
|
+
*heredoc_ranges_in(node.if_branch).map(&:source),
|
|
297
|
+
"#{indentation}end"
|
|
298
|
+
].join("\n")
|
|
288
299
|
end
|
|
289
300
|
|
|
290
301
|
def to_modifier_form_with_move_comment(node, indentation, comment)
|
|
@@ -294,17 +305,12 @@ module RuboCop
|
|
|
294
305
|
RUBY
|
|
295
306
|
end
|
|
296
307
|
|
|
297
|
-
def
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
[heredoc_body, heredoc_end]
|
|
302
|
-
end
|
|
303
|
-
|
|
304
|
-
def remove_heredoc(corrector, heredoc)
|
|
305
|
-
heredoc.each do |range|
|
|
306
|
-
corrector.remove(range_by_whole_lines(range, include_final_newline: true))
|
|
308
|
+
def heredoc_ranges_in(body)
|
|
309
|
+
ranges = body.each_node(:any_str).select(&:heredoc?).map do |heredoc|
|
|
310
|
+
range_by_whole_lines(heredoc.loc.heredoc_body.join(heredoc.loc.heredoc_end))
|
|
307
311
|
end
|
|
312
|
+
# A heredoc opened in another heredoc's interpolation is moved along with it.
|
|
313
|
+
ranges.reject { |range| ranges.any? { |other| other.contains?(range) } }
|
|
308
314
|
end
|
|
309
315
|
|
|
310
316
|
def comment_on_node_line(node)
|
|
@@ -28,6 +28,10 @@ module RuboCop
|
|
|
28
28
|
|
|
29
29
|
MSG = 'Avoid modifier `%<keyword>s` after another conditional.'
|
|
30
30
|
|
|
31
|
+
def self.autocorrect_incompatible_with
|
|
32
|
+
[Style::SoleNestedConditional]
|
|
33
|
+
end
|
|
34
|
+
|
|
31
35
|
# rubocop:disable-next Metrics/AbcSize
|
|
32
36
|
def on_if(node)
|
|
33
37
|
return unless node.modifier_form? && node.body.if_type?
|
|
@@ -21,6 +21,10 @@ module RuboCop
|
|
|
21
21
|
MSG_NEWLINE = 'Do not use `%<keyword>s %<expr>s;` - use a newline instead.'
|
|
22
22
|
MSG_TERNARY = 'Do not use `%<keyword>s %<expr>s;` - use a ternary operator instead.'
|
|
23
23
|
|
|
24
|
+
LOWER_PRECEDENCE_THAN_TERNARY_TYPES = %i[
|
|
25
|
+
and or if rescue any_match_pattern while until while_post until_post
|
|
26
|
+
].freeze
|
|
27
|
+
|
|
24
28
|
def on_normal_if_unless(node)
|
|
25
29
|
return if node.parent&.if_type?
|
|
26
30
|
return if part_of_ignored_node?(node)
|
|
@@ -77,12 +81,14 @@ module RuboCop
|
|
|
77
81
|
def replacement(node)
|
|
78
82
|
return correct_elsif(node) if node.else_branch&.if_type?
|
|
79
83
|
|
|
80
|
-
then_code = node.if_branch ?
|
|
81
|
-
else_code = node.else_branch ?
|
|
84
|
+
then_code = node.if_branch ? ternary_operand(node.if_branch) : 'nil'
|
|
85
|
+
else_code = node.else_branch ? ternary_operand(node.else_branch) : 'nil'
|
|
82
86
|
|
|
83
87
|
then_code, else_code = else_code, then_code if node.unless?
|
|
84
88
|
|
|
85
|
-
"#{ternary_condition(node)} ? #{then_code} : #{else_code}"
|
|
89
|
+
ternary = "#{ternary_condition(node)} ? #{then_code} : #{else_code}"
|
|
90
|
+
|
|
91
|
+
operand_of_parent?(node) ? "(#{ternary})" : ternary
|
|
86
92
|
end
|
|
87
93
|
|
|
88
94
|
def correct_elsif(node)
|
|
@@ -108,7 +114,34 @@ module RuboCop
|
|
|
108
114
|
# `(a = b) ? c : d`), changing what gets assigned.
|
|
109
115
|
def ternary_condition(node)
|
|
110
116
|
condition = node.condition
|
|
111
|
-
condition.assignment? ? "(#{condition.source})" : condition
|
|
117
|
+
condition.assignment? ? "(#{condition.source})" : ternary_operand(condition)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def ternary_operand(expr)
|
|
121
|
+
lower_precedence_than_ternary?(expr) ? "(#{expr.source})" : build_expression(expr)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Expressions that bind looser than `?:` (or cannot appear unparenthesized
|
|
125
|
+
# inside it) would otherwise absorb or break the ternary.
|
|
126
|
+
def lower_precedence_than_ternary?(node)
|
|
127
|
+
return true if node.type?(*LOWER_PRECEDENCE_THAN_TERNARY_TYPES)
|
|
128
|
+
return true if node.send_type? && (node.prefix_not? || prefix_bang_on_command?(node))
|
|
129
|
+
|
|
130
|
+
node.type?(:yield, :super, :defined?) && node.arguments.any? && !node.parenthesized?
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def operand_of_parent?(node)
|
|
134
|
+
return false unless (parent = node.parent)
|
|
135
|
+
return true if parent.operator_keyword?
|
|
136
|
+
|
|
137
|
+
parent.call_type? && call_operand?(parent, node)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def call_operand?(call, node)
|
|
141
|
+
return false if call.prefix_not?
|
|
142
|
+
return true if call.receiver.equal?(node)
|
|
143
|
+
|
|
144
|
+
call.operator_method? && !call.method?(:[]) && !call.method?(:[]=)
|
|
112
145
|
end
|
|
113
146
|
|
|
114
147
|
def build_else_branch(second_condition)
|
|
@@ -131,6 +164,16 @@ module RuboCop
|
|
|
131
164
|
result
|
|
132
165
|
end
|
|
133
166
|
|
|
167
|
+
# `!foo a` leaves the arguments of `foo` unparenthesized at the end of the operand,
|
|
168
|
+
# where they would absorb the rest of the ternary.
|
|
169
|
+
def prefix_bang_on_command?(node)
|
|
170
|
+
return false unless node.prefix_bang?
|
|
171
|
+
|
|
172
|
+
receiver = node.receiver
|
|
173
|
+
|
|
174
|
+
require_argument_parentheses?(receiver) || lower_precedence_than_ternary?(receiver)
|
|
175
|
+
end
|
|
176
|
+
|
|
134
177
|
def require_argument_parentheses?(node)
|
|
135
178
|
return false if !node.call_type? || node.arithmetic_operation?
|
|
136
179
|
|
|
@@ -114,9 +114,31 @@ module RuboCop
|
|
|
114
114
|
method_call, _lhs, method, _rhs = inverse_candidate?(node)
|
|
115
115
|
return unless method_call && method
|
|
116
116
|
|
|
117
|
-
corrector
|
|
117
|
+
remove_negation(corrector, node, method, method_call)
|
|
118
118
|
corrector.replace(method_call.loc.selector, inverse_methods[method].to_s)
|
|
119
|
-
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def remove_negation(corrector, node, method, method_call)
|
|
122
|
+
if !keep_parentheses?(node, method_call)
|
|
123
|
+
corrector.remove(not_to_receiver(node, method_call))
|
|
124
|
+
remove_end_parenthesis(corrector, node, method, method_call)
|
|
125
|
+
elsif node.parenthesized?
|
|
126
|
+
corrector.remove(node.loc.selector)
|
|
127
|
+
else
|
|
128
|
+
corrector.remove(node.loc.selector.join(node.receiver.source_range.begin))
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def keep_parentheses?(node, method_call)
|
|
133
|
+
return false unless node.receiver.begin_type? || node.parenthesized?
|
|
134
|
+
return false unless method_call.operator_method?
|
|
135
|
+
return false unless (parent = node.parent)&.call_type?
|
|
136
|
+
|
|
137
|
+
binary_operator?(parent) || parent.receiver.equal?(node)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def binary_operator?(node)
|
|
141
|
+
node.operator_method? && !node.loc.dot && !node.method?(:[]) && !node.method?(:[]=)
|
|
120
142
|
end
|
|
121
143
|
|
|
122
144
|
def correct_inverse_block(corrector, node)
|
|
@@ -59,8 +59,20 @@ module RuboCop
|
|
|
59
59
|
MSG_AVOID_IT_PARAMETER = 'Avoid using `it` block parameter.'
|
|
60
60
|
MSG_AVOID_IT_PARAMETER_MULTILINE = 'Avoid using `it` block parameter for multi-line blocks.'
|
|
61
61
|
|
|
62
|
+
SCOPE_TYPES = %i[any_def class module sclass].freeze
|
|
63
|
+
|
|
62
64
|
minimum_target_ruby_version 3.4
|
|
63
65
|
|
|
66
|
+
# `Style/StabbyLambdaParentheses` wraps the parameter this cop removes in the same pass,
|
|
67
|
+
# which would leave an empty parameter list that forbids `it`.
|
|
68
|
+
def self.autocorrect_incompatible_with
|
|
69
|
+
[Style::Lambda, Style::StabbyLambdaParentheses]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def on_new_investigation
|
|
73
|
+
@it_variable_definitions = nil
|
|
74
|
+
end
|
|
75
|
+
|
|
64
76
|
def on_block(node)
|
|
65
77
|
return unless style == :always
|
|
66
78
|
return unless node.arguments.one?
|
|
@@ -68,9 +80,10 @@ module RuboCop
|
|
|
68
80
|
# `restarg`, `kwrestarg`, `blockarg` nodes can return early.
|
|
69
81
|
return unless node.first_argument.arg_type?
|
|
70
82
|
|
|
71
|
-
|
|
83
|
+
block_argument_name = node.first_argument.source
|
|
84
|
+
return if keep_parameter_name?(node.body, block_argument_name)
|
|
72
85
|
|
|
73
|
-
|
|
86
|
+
find_block_variables(node, block_argument_name).each do |variable|
|
|
74
87
|
add_offense(variable, message: MSG_USE_IT_PARAMETER) do |corrector|
|
|
75
88
|
corrector.remove(node.arguments)
|
|
76
89
|
corrector.replace(variable, 'it')
|
|
@@ -109,12 +122,89 @@ module RuboCop
|
|
|
109
122
|
private
|
|
110
123
|
|
|
111
124
|
def find_block_variables(node, block_argument_name)
|
|
112
|
-
return []
|
|
125
|
+
return [] if !node.body || it_variable_in_scope?(node)
|
|
126
|
+
|
|
127
|
+
ranges = inner_block_ranges(node.body)
|
|
128
|
+
|
|
129
|
+
block_variables(node.body, block_argument_name).reject do |variable|
|
|
130
|
+
ranges.any? { |range| range.contains?(variable.source_range) }
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def it_variable_in_scope?(node)
|
|
135
|
+
scope = nearest_scope(node)
|
|
136
|
+
return true if it_argument_in_scope?(node, scope)
|
|
113
137
|
|
|
114
|
-
|
|
138
|
+
it_variable_definitions.any? do |definition|
|
|
139
|
+
nearest_scope(definition).equal?(scope) && visible_in_block?(definition, node)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def it_variable_definitions
|
|
144
|
+
@it_variable_definitions ||=
|
|
145
|
+
variable_definitions(processed_source.ast).filter_map do |name, definition|
|
|
146
|
+
definition if name == 'it'
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def nearest_scope(node)
|
|
151
|
+
node.each_ancestor(*SCOPE_TYPES).first
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def it_argument_in_scope?(node, scope)
|
|
155
|
+
owners = node.each_ancestor(:block).select { |block| nearest_scope(block).equal?(scope) }
|
|
156
|
+
owners << scope if scope&.any_def_type?
|
|
157
|
+
|
|
158
|
+
owners.any? { |owner| owner.arguments.argument_list.any? { |arg| arg.name == :it } }
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def visible_in_block?(definition, node)
|
|
162
|
+
return true if definition.source_range.begin_pos < node.source_range.begin_pos
|
|
163
|
+
|
|
164
|
+
node.source_range.contains?(definition.source_range)
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def inner_block_ranges(body)
|
|
168
|
+
body.each_node(:any_block).map { |block| block.loc.begin.join(block.loc.end) }
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def keep_parameter_name?(body, block_arg_name)
|
|
172
|
+
used_within_inner_block?(body, block_arg_name) || reassigned?(body, block_arg_name)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def used_within_inner_block?(body, block_argument_name)
|
|
176
|
+
return false unless body
|
|
177
|
+
|
|
178
|
+
ranges = inner_block_ranges(body)
|
|
179
|
+
|
|
180
|
+
block_variables(body, block_argument_name).any? do |variable|
|
|
181
|
+
ranges.any? { |range| range.contains?(variable.source_range) }
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def reassigned?(body, block_argument_name)
|
|
186
|
+
return false unless body
|
|
187
|
+
|
|
188
|
+
variable_definitions(body).any? { |name, _definition| name == block_argument_name }
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def block_variables(body, block_argument_name)
|
|
192
|
+
body.each_descendant(:lvar).select do |descendant|
|
|
115
193
|
descendant.source == block_argument_name
|
|
116
194
|
end
|
|
117
195
|
end
|
|
196
|
+
|
|
197
|
+
def variable_definitions(node)
|
|
198
|
+
node.each_node(:lvasgn, :match_var, :match_with_lvasgn).flat_map do |definition|
|
|
199
|
+
names = if definition.match_with_lvasgn_type?
|
|
200
|
+
definition.children.first.each_capture(named: true).map(&:name)
|
|
201
|
+
else
|
|
202
|
+
[definition.children.first.to_s]
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
names.map { |name| [name, definition] }
|
|
206
|
+
end
|
|
207
|
+
end
|
|
118
208
|
end
|
|
119
209
|
end
|
|
120
210
|
end
|
|
@@ -75,7 +75,9 @@ module RuboCop
|
|
|
75
75
|
|
|
76
76
|
def remove_kwargs(kwarg_nodes, corrector)
|
|
77
77
|
kwarg_nodes.each do |kwarg|
|
|
78
|
-
|
|
78
|
+
range = range_with_surrounding_space(kwarg.source_range, side: :left, whitespace: true)
|
|
79
|
+
with_space = range_with_surrounding_space(range, side: :right)
|
|
80
|
+
|
|
79
81
|
corrector.remove(range_with_surrounding_comma(with_space, :left))
|
|
80
82
|
end
|
|
81
83
|
end
|
|
@@ -48,6 +48,8 @@ module RuboCop
|
|
|
48
48
|
# end
|
|
49
49
|
class Lambda < Base
|
|
50
50
|
include ConfigurableEnforcedStyle
|
|
51
|
+
include PatternMatchingHelp
|
|
52
|
+
include RescueNode
|
|
51
53
|
extend AutoCorrector
|
|
52
54
|
|
|
53
55
|
LITERAL_MESSAGE = 'Use the `-> { ... }` lambda literal syntax for %<modifier>s lambdas.'
|
|
@@ -71,6 +73,7 @@ module RuboCop
|
|
|
71
73
|
selector = node.send_node.source
|
|
72
74
|
|
|
73
75
|
return unless offending_selector?(node, selector)
|
|
76
|
+
return if uncorrectable_lambda_literal?(node)
|
|
74
77
|
|
|
75
78
|
add_offense(node.send_node, message: message(node, selector)) do |corrector|
|
|
76
79
|
if node.send_node.lambda_literal?
|
|
@@ -91,6 +94,21 @@ module RuboCop
|
|
|
91
94
|
selector == OFFENDING_SELECTORS[:style][style][lines]
|
|
92
95
|
end
|
|
93
96
|
|
|
97
|
+
def uncorrectable_lambda_literal?(node)
|
|
98
|
+
return false unless node.send_node.lambda_literal?
|
|
99
|
+
return true if in_pattern?(node)
|
|
100
|
+
return false unless rescue_or_ensure_clause?(node.body)
|
|
101
|
+
|
|
102
|
+
LambdaLiteralToMethodCorrector.new(node).replace_delimiters?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def rescue_or_ensure_clause?(body)
|
|
106
|
+
return false unless body
|
|
107
|
+
return true if body.ensure_type?
|
|
108
|
+
|
|
109
|
+
body.rescue_type? && !rescue_modifier?(body.resbody_branches.first)
|
|
110
|
+
end
|
|
111
|
+
|
|
94
112
|
def message(node, selector)
|
|
95
113
|
message = selector == '->' ? METHOD_MESSAGE : LITERAL_MESSAGE
|
|
96
114
|
|
|
@@ -111,12 +129,27 @@ module RuboCop
|
|
|
111
129
|
|
|
112
130
|
return unless node.arguments?
|
|
113
131
|
|
|
114
|
-
arg_str =
|
|
132
|
+
arg_str = lambda_arg_string(node.arguments)
|
|
133
|
+
arg_str = " #{arg_str} " if space_inside_parens?
|
|
134
|
+
arg_str = "(#{arg_str})"
|
|
135
|
+
arg_str = " #{arg_str}" if space_in_lambda_literal_required?
|
|
115
136
|
|
|
116
137
|
corrector.insert_after(node.send_node, arg_str)
|
|
117
138
|
corrector.remove(arguments_with_whitespace(node))
|
|
118
139
|
end
|
|
119
140
|
|
|
141
|
+
def space_inside_parens?
|
|
142
|
+
return false unless config.cop_enabled?('Layout/SpaceInsideParens')
|
|
143
|
+
|
|
144
|
+
%w[space compact].include?(config.for_cop('Layout/SpaceInsideParens')['EnforcedStyle'])
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def space_in_lambda_literal_required?
|
|
148
|
+
return false unless config.cop_enabled?('Layout/SpaceInLambdaLiteral')
|
|
149
|
+
|
|
150
|
+
config.for_cop('Layout/SpaceInLambdaLiteral')['EnforcedStyle'] == 'require_space'
|
|
151
|
+
end
|
|
152
|
+
|
|
120
153
|
def arguments_with_whitespace(node)
|
|
121
154
|
node.loc.begin.end.join(node.arguments.loc.end)
|
|
122
155
|
end
|
|
@@ -28,8 +28,9 @@ module RuboCop
|
|
|
28
28
|
def on_send(node)
|
|
29
29
|
return unless node.receiver
|
|
30
30
|
# Rewriting the call rebuilds it as a single expression, which would drop
|
|
31
|
-
# any comments inside the argument list, so leave it to be
|
|
32
|
-
|
|
31
|
+
# any comments or heredoc bodies inside the argument list, so leave it to be
|
|
32
|
+
# fixed manually.
|
|
33
|
+
return if comments_in_node?(node) || heredoc_argument?(node)
|
|
33
34
|
|
|
34
35
|
if offense?(node)
|
|
35
36
|
prefer = prefer(node)
|
|
@@ -59,6 +60,10 @@ module RuboCop
|
|
|
59
60
|
end
|
|
60
61
|
end
|
|
61
62
|
|
|
63
|
+
def heredoc_argument?(node)
|
|
64
|
+
node.arguments.any? { |argument| argument.each_node(:any_str).any?(&:heredoc?) }
|
|
65
|
+
end
|
|
66
|
+
|
|
62
67
|
def offense?(node)
|
|
63
68
|
(explicit_style? && node.implicit_call?) || (implicit_style? && !node.implicit_call?)
|
|
64
69
|
end
|
|
@@ -112,8 +112,7 @@ module RuboCop
|
|
|
112
112
|
|
|
113
113
|
def on_block(node)
|
|
114
114
|
return unless each_block_with_push?(node)
|
|
115
|
-
|
|
116
|
-
dest_var = find_dest_var(node)
|
|
115
|
+
return unless (dest_var = find_dest_var(node))
|
|
117
116
|
|
|
118
117
|
if offending_empty_array_tap?(node, dest_var)
|
|
119
118
|
asgn = dest_var.declaration_node
|
|
@@ -30,7 +30,7 @@ module RuboCop
|
|
|
30
30
|
|
|
31
31
|
private
|
|
32
32
|
|
|
33
|
-
def omit_parentheses(node) # rubocop:disable Metrics/PerceivedComplexity
|
|
33
|
+
def omit_parentheses(node) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
|
34
34
|
return unless node.parenthesized?
|
|
35
35
|
return if inside_endless_method_def?(node)
|
|
36
36
|
return if require_parentheses_for_hash_value_omission?(node)
|
|
@@ -40,6 +40,9 @@ module RuboCop
|
|
|
40
40
|
return if legitimate_call_with_parentheses?(node)
|
|
41
41
|
return if allowed_camel_case_method_call?(node)
|
|
42
42
|
return if allowed_string_interpolation_method_call?(node)
|
|
43
|
+
return if code_after_closing_parenthesis_on_its_own_line?(node)
|
|
44
|
+
return if comment_before_first_argument?(node)
|
|
45
|
+
return if args_parenthesized?(node)
|
|
43
46
|
|
|
44
47
|
(@pending_omit_offenses ||= []) << node
|
|
45
48
|
end
|
|
@@ -104,14 +107,33 @@ module RuboCop
|
|
|
104
107
|
inside_string_interpolation?(node)
|
|
105
108
|
end
|
|
106
109
|
|
|
110
|
+
def code_after_closing_parenthesis_on_its_own_line?(node)
|
|
111
|
+
closing = node.loc.end
|
|
112
|
+
return false if node.arguments.none? || node.last_argument.last_line == closing.line
|
|
113
|
+
|
|
114
|
+
rest = closing.source_line[(closing.column + 1)..].strip
|
|
115
|
+
|
|
116
|
+
!rest.empty? && !rest.start_with?('#')
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Without the parentheses, a comment before the first argument would end the call there,
|
|
120
|
+
# and a line continuation can't carry the call past a comment.
|
|
121
|
+
def comment_before_first_argument?(node)
|
|
122
|
+
return false unless (first_argument = node.first_argument)
|
|
123
|
+
|
|
124
|
+
lines = node.loc.begin.line...first_argument.first_line
|
|
125
|
+
processed_source.each_comment_in_lines(lines).any?
|
|
126
|
+
end
|
|
127
|
+
|
|
107
128
|
def parentheses_at_the_end_of_multiline_call?(node)
|
|
108
|
-
node.multiline?
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
129
|
+
return false unless node.multiline?
|
|
130
|
+
|
|
131
|
+
opening = node.loc.begin
|
|
132
|
+
|
|
133
|
+
opening.source_line[(opening.column + 1)..].gsub(TRAILING_WHITESPACE_REGEX, '').empty?
|
|
112
134
|
end
|
|
113
135
|
|
|
114
|
-
def legitimate_call_with_parentheses?(node) # rubocop:disable Metrics/PerceivedComplexity
|
|
136
|
+
def legitimate_call_with_parentheses?(node) # rubocop:disable Metrics/AbcSize, Metrics/PerceivedComplexity
|
|
115
137
|
call_in_literals?(node) ||
|
|
116
138
|
node.parent&.when_type? ||
|
|
117
139
|
call_with_ambiguous_arguments?(node) ||
|
|
@@ -121,7 +143,9 @@ module RuboCop
|
|
|
121
143
|
allowed_multiline_call_with_parentheses?(node) ||
|
|
122
144
|
allowed_chained_call_with_parentheses?(node) ||
|
|
123
145
|
assignment_in_condition?(node) ||
|
|
124
|
-
|
|
146
|
+
command_assignment_in_expression?(node) ||
|
|
147
|
+
forwards_anonymous_rest_arguments?(node) ||
|
|
148
|
+
trailing_comma?(node)
|
|
125
149
|
end
|
|
126
150
|
|
|
127
151
|
def call_in_literals?(node)
|
|
@@ -137,9 +161,13 @@ module RuboCop
|
|
|
137
161
|
parent = node.parent&.any_block_type? ? node.parent.parent : node.parent
|
|
138
162
|
return false unless parent
|
|
139
163
|
|
|
140
|
-
logical_operator?(parent) ||
|
|
141
|
-
|
|
142
|
-
|
|
164
|
+
if logical_operator?(parent) || command_assignment_before_keyword_operator?(parent)
|
|
165
|
+
return true
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
parent.send_type? && parent.arguments.any? do |argument|
|
|
169
|
+
logical_operator?(argument)
|
|
170
|
+
end
|
|
143
171
|
end
|
|
144
172
|
|
|
145
173
|
def call_in_optional_arguments?(node)
|
|
@@ -229,6 +257,15 @@ module RuboCop
|
|
|
229
257
|
node.operator_keyword? && node.logical_operator?
|
|
230
258
|
end
|
|
231
259
|
|
|
260
|
+
def command_assignment_before_keyword_operator?(node)
|
|
261
|
+
return false unless node.assignment?
|
|
262
|
+
|
|
263
|
+
node = node.parent while node.parent&.assignment?
|
|
264
|
+
return false unless (operator = node.parent)
|
|
265
|
+
|
|
266
|
+
operator.operator_keyword? && operator.semantic_operator?
|
|
267
|
+
end
|
|
268
|
+
|
|
232
269
|
def hash_literal?(node)
|
|
233
270
|
node.hash_type? && node.braces?
|
|
234
271
|
end
|
|
@@ -244,7 +281,7 @@ module RuboCop
|
|
|
244
281
|
end
|
|
245
282
|
|
|
246
283
|
def assigned_before?(node, target)
|
|
247
|
-
node.assignment? && node.loc.operator.begin < target.
|
|
284
|
+
node.assignment? && node.loc.operator.begin < target.source_range.begin
|
|
248
285
|
end
|
|
249
286
|
|
|
250
287
|
def inside_string_interpolation?(node)
|
|
@@ -261,11 +298,41 @@ module RuboCop
|
|
|
261
298
|
parent.assignment? && (grandparent.conditional? || grandparent.when_type?)
|
|
262
299
|
end
|
|
263
300
|
|
|
301
|
+
# rubocop:disable-next Metrics/PerceivedComplexity
|
|
302
|
+
def command_assignment_in_expression?(node)
|
|
303
|
+
value = node.parent&.type?(:any_block, :rescue) ? node.parent : node
|
|
304
|
+
assignment = outermost_assignment(value)
|
|
305
|
+
return false if assignment.equal?(value)
|
|
306
|
+
|
|
307
|
+
call_in_literals?(assignment) ||
|
|
308
|
+
call_in_logical_operators?(assignment) ||
|
|
309
|
+
call_in_optional_arguments?(assignment) ||
|
|
310
|
+
call_as_argument_or_chain?(assignment) ||
|
|
311
|
+
assignment.parent&.type?(:masgn, :return, :next, :break, :defined?)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def outermost_assignment(value)
|
|
315
|
+
parent = value.parent
|
|
316
|
+
return value if !parent&.assignment? || parent.masgn_type?
|
|
317
|
+
return value unless assigned_before?(parent, value)
|
|
318
|
+
|
|
319
|
+
outermost_assignment(parent)
|
|
320
|
+
end
|
|
321
|
+
|
|
264
322
|
def forwards_anonymous_rest_arguments?(node)
|
|
323
|
+
node.arguments.any? do |argument|
|
|
324
|
+
next true if argument.forwarded_restarg_type?
|
|
325
|
+
|
|
326
|
+
argument.hash_type? && argument.children.any?(&:forwarded_kwrestarg_type?)
|
|
327
|
+
end
|
|
328
|
+
end
|
|
329
|
+
|
|
330
|
+
def trailing_comma?(node)
|
|
265
331
|
return false unless (last_argument = node.last_argument)
|
|
266
|
-
return true if last_argument.forwarded_restarg_type?
|
|
267
332
|
|
|
268
|
-
|
|
333
|
+
range = last_argument.source_range.end.join(node.loc.end.begin)
|
|
334
|
+
|
|
335
|
+
processed_source.tokens_within(range).any?(&:comma?)
|
|
269
336
|
end
|
|
270
337
|
end
|
|
271
338
|
end
|