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
|
@@ -181,11 +181,11 @@ module RuboCop
|
|
|
181
181
|
def autocorrect_modifier(corrector, node)
|
|
182
182
|
body = node.if_branch || node.else_branch
|
|
183
183
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
"#{' ' * node.source_range.column}#{body.source}"
|
|
184
|
+
next_code = "next #{node.inverse_keyword} #{node.condition.source}\n" \
|
|
185
|
+
"#{' ' * node.source_range.column}"
|
|
187
186
|
|
|
188
|
-
corrector.
|
|
187
|
+
corrector.insert_before(node, next_code)
|
|
188
|
+
corrector.remove(range_between(body.source_range.end_pos, node.source_range.end_pos))
|
|
189
189
|
end
|
|
190
190
|
|
|
191
191
|
def autocorrect_block(corrector, node)
|
|
@@ -231,7 +231,7 @@ module RuboCop
|
|
|
231
231
|
|
|
232
232
|
# end_range starts with the final newline of the if body
|
|
233
233
|
lines = (node.source_range.line + 1)...node.loc.end.line
|
|
234
|
-
lines = lines.to_a -
|
|
234
|
+
lines = lines.to_a - string_content_lines(node)
|
|
235
235
|
# Skip blank lines
|
|
236
236
|
lines.reject { |lineno| /\A\s*\z/.match?(buffer.source_line(lineno)) }
|
|
237
237
|
end
|
|
@@ -250,11 +250,25 @@ module RuboCop
|
|
|
250
250
|
lines.map { |lineno| buffer.source_line(lineno) =~ /\S/ }.min
|
|
251
251
|
end
|
|
252
252
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
253
|
+
# Lines that start inside a string literal or a heredoc body, whose
|
|
254
|
+
# leading whitespace is part of the string value.
|
|
255
|
+
def string_content_lines(node)
|
|
256
|
+
buffer = node.source_range.source_buffer
|
|
257
|
+
ranges = node.each_node(:any_str).filter_map { |str| string_content_range(str) }
|
|
258
|
+
|
|
259
|
+
ranges.flat_map do |range|
|
|
260
|
+
(range.line..range.last_line).select do |lineno|
|
|
261
|
+
(range.begin_pos...range.end_pos).cover?(buffer.line_range(lineno).begin_pos)
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def string_content_range(node)
|
|
267
|
+
if node.heredoc?
|
|
268
|
+
node.loc.heredoc_body
|
|
269
|
+
elsif node.loc?(:begin) && node.loc?(:end)
|
|
270
|
+
node.loc.begin.end.join(node.loc.end.begin)
|
|
271
|
+
end
|
|
258
272
|
end
|
|
259
273
|
|
|
260
274
|
def reindent_line(corrector, lineno, delta, buffer)
|
|
@@ -44,6 +44,7 @@ module RuboCop
|
|
|
44
44
|
|
|
45
45
|
def on_send(node)
|
|
46
46
|
return unless node.receiver
|
|
47
|
+
return if prefer_comparison? && comment_before_dot?(node)
|
|
47
48
|
|
|
48
49
|
style_check?(node) do
|
|
49
50
|
add_offense(node.loc.selector) do |corrector|
|
|
@@ -58,12 +59,19 @@ module RuboCop
|
|
|
58
59
|
|
|
59
60
|
private
|
|
60
61
|
|
|
62
|
+
def comment_before_dot?(node)
|
|
63
|
+
return false unless node.loc.dot
|
|
64
|
+
|
|
65
|
+
processed_source.contains_comment?(node.receiver.source_range.end.join(node.loc.dot))
|
|
66
|
+
end
|
|
67
|
+
|
|
61
68
|
def autocorrect_to_comparison(corrector, node)
|
|
62
|
-
range = node.
|
|
69
|
+
range = node.receiver.source_range.end.join(node.loc.selector.end)
|
|
63
70
|
corrector.replace(range, ' == nil')
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
|
|
72
|
+
return if !operator_expression?(node.parent) && !receiver_of_parent?(node)
|
|
73
|
+
|
|
74
|
+
corrector.wrap(node, '(', ')')
|
|
67
75
|
end
|
|
68
76
|
|
|
69
77
|
def autocorrect_to_predicate(corrector, node)
|
|
@@ -88,6 +96,10 @@ module RuboCop
|
|
|
88
96
|
node.assignment?
|
|
89
97
|
end
|
|
90
98
|
|
|
99
|
+
def receiver_of_parent?(node)
|
|
100
|
+
node.parent&.call_type? && node.parent.receiver.equal?(node)
|
|
101
|
+
end
|
|
102
|
+
|
|
91
103
|
def operator_send?(node)
|
|
92
104
|
node.send_type? && node.operator_method? && !node.method?(:[]) && !node.method?(:[]=)
|
|
93
105
|
end
|
|
@@ -130,7 +130,7 @@ module RuboCop
|
|
|
130
130
|
|
|
131
131
|
def operator_expression?(node)
|
|
132
132
|
node.operator_keyword? ||
|
|
133
|
-
(node.send_type? && node.
|
|
133
|
+
(node.send_type? && node.operator_method?) ||
|
|
134
134
|
(node.if_type? && node.ternary?) ||
|
|
135
135
|
node.type?(:range, :iflipflop, :eflipflop) ||
|
|
136
136
|
node.assignment?
|
|
@@ -54,11 +54,10 @@ module RuboCop
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
def requires_parens?(child)
|
|
57
|
-
child.operator_keyword? ||
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
child.assignment?
|
|
57
|
+
return true if child.operator_keyword? || operator_method_requiring_parens?(child)
|
|
58
|
+
return true if child.if_type? && child.ternary?
|
|
59
|
+
|
|
60
|
+
child.type?(:range, :iflipflop, :eflipflop) || child.assignment?
|
|
62
61
|
end
|
|
63
62
|
|
|
64
63
|
def correct_opposite_method(corrector, range, child)
|
|
@@ -74,6 +73,12 @@ module RuboCop
|
|
|
74
73
|
def correct_without_parens(corrector, range)
|
|
75
74
|
corrector.replace(range, '!')
|
|
76
75
|
end
|
|
76
|
+
|
|
77
|
+
def operator_method_requiring_parens?(child)
|
|
78
|
+
return false unless child.send_type?
|
|
79
|
+
|
|
80
|
+
child.binary_operation? || (child.unary_operation? && child.method?(:~))
|
|
81
|
+
end
|
|
77
82
|
end
|
|
78
83
|
end
|
|
79
84
|
end
|
|
@@ -90,6 +90,7 @@ module RuboCop
|
|
|
90
90
|
def on_send(node)
|
|
91
91
|
numeric, replacement = check(node)
|
|
92
92
|
return unless numeric
|
|
93
|
+
return if handled_by_bitwise_predicate?(node)
|
|
93
94
|
|
|
94
95
|
return if allowed_method_name?(node.method_name) ||
|
|
95
96
|
node.each_ancestor(:send, :any_block).any? do |ancestor|
|
|
@@ -108,6 +109,12 @@ module RuboCop
|
|
|
108
109
|
allowed_method?(name) || matches_allowed_pattern?(name)
|
|
109
110
|
end
|
|
110
111
|
|
|
112
|
+
def handled_by_bitwise_predicate?(node)
|
|
113
|
+
bitwise_predicate_candidate?(node) &&
|
|
114
|
+
config.for_cop('Style/BitwisePredicate').fetch('Enabled') &&
|
|
115
|
+
BitwisePredicate.support_target_ruby_version?(target_ruby_version)
|
|
116
|
+
end
|
|
117
|
+
|
|
111
118
|
def check(node)
|
|
112
119
|
numeric, operator =
|
|
113
120
|
if style == :predicate
|
|
@@ -124,7 +131,7 @@ module RuboCop
|
|
|
124
131
|
def replacement(node, numeric, operation)
|
|
125
132
|
if style == :predicate
|
|
126
133
|
[parenthesized_source(numeric), REPLACEMENTS.invert[operation.to_s]].join('.')
|
|
127
|
-
elsif
|
|
134
|
+
elsif comparison_requires_parentheses?(node)
|
|
128
135
|
"(#{numeric.source} #{REPLACEMENTS[operation.to_s]} 0)"
|
|
129
136
|
else
|
|
130
137
|
[numeric.source, REPLACEMENTS[operation.to_s], 0].join(' ')
|
|
@@ -140,7 +147,7 @@ module RuboCop
|
|
|
140
147
|
end
|
|
141
148
|
|
|
142
149
|
def require_parentheses?(node)
|
|
143
|
-
node.send_type? && node.
|
|
150
|
+
node.send_type? && node.operator_method? && !node.parenthesized?
|
|
144
151
|
end
|
|
145
152
|
|
|
146
153
|
def replacement_supported?(operator)
|
|
@@ -159,10 +166,11 @@ module RuboCop
|
|
|
159
166
|
end
|
|
160
167
|
end
|
|
161
168
|
|
|
162
|
-
def
|
|
163
|
-
return false unless (parent = node.parent)
|
|
169
|
+
def comparison_requires_parentheses?(node)
|
|
170
|
+
return false unless (parent = node.parent)&.call_type?
|
|
171
|
+
return true if parent.receiver.equal?(node)
|
|
164
172
|
|
|
165
|
-
parent.
|
|
173
|
+
parent.operator_method? && !parent.method?(:[]) && !parent.method?(:[]=)
|
|
166
174
|
end
|
|
167
175
|
|
|
168
176
|
# @!method predicate(node)
|
|
@@ -179,6 +187,14 @@ module RuboCop
|
|
|
179
187
|
def_node_matcher :inverted_comparison, <<~PATTERN
|
|
180
188
|
(send (int 0) ${:== :> :<} [$(...) !gvar_type?])
|
|
181
189
|
PATTERN
|
|
190
|
+
|
|
191
|
+
# @!method bitwise_predicate_candidate?(node)
|
|
192
|
+
def_node_matcher :bitwise_predicate_candidate?, <<~PATTERN
|
|
193
|
+
{
|
|
194
|
+
(send {(begin (send _ :& _)) (send _ :& _)} {:positive? :zero?})
|
|
195
|
+
(send {(begin (send _ :& _)) (send _ :& _)} {:> :==} (int 0))
|
|
196
|
+
}
|
|
197
|
+
PATTERN
|
|
182
198
|
end
|
|
183
199
|
end
|
|
184
200
|
end
|
|
@@ -102,6 +102,7 @@ module RuboCop
|
|
|
102
102
|
return replaced_node unless node.parent
|
|
103
103
|
return "(#{replaced_node})" if node.parent.operator_keyword?
|
|
104
104
|
return "(#{replaced_node})" if node.parent.send_type? && node.parent.operator_method?
|
|
105
|
+
return "(#{replaced_node})" if parent_binds_tighter_than_ternary?(node)
|
|
105
106
|
|
|
106
107
|
replaced_node
|
|
107
108
|
end
|
|
@@ -124,6 +125,14 @@ module RuboCop
|
|
|
124
125
|
"#{expr_replacement(else_branch)}"
|
|
125
126
|
end
|
|
126
127
|
|
|
128
|
+
def parent_binds_tighter_than_ternary?(node)
|
|
129
|
+
parent = node.parent
|
|
130
|
+
return parent.receiver.equal?(node) if parent.call_type?
|
|
131
|
+
return parent.namespace.equal?(node) if parent.type?(:const, :casgn)
|
|
132
|
+
|
|
133
|
+
parent.if_type? && parent.ternary? && parent.condition.equal?(node)
|
|
134
|
+
end
|
|
135
|
+
|
|
127
136
|
def expr_replacement(node)
|
|
128
137
|
return 'nil' if node.nil?
|
|
129
138
|
|
|
@@ -131,7 +140,9 @@ module RuboCop
|
|
|
131
140
|
end
|
|
132
141
|
|
|
133
142
|
def requires_parentheses?(node)
|
|
134
|
-
return true if
|
|
143
|
+
return true if node.type?(
|
|
144
|
+
:and, :or, :if, :rescue, :while, :until, :while_post, :until_post, :any_match_pattern
|
|
145
|
+
)
|
|
135
146
|
return true if node.assignment?
|
|
136
147
|
return true if method_call_with_changed_precedence?(node)
|
|
137
148
|
|
|
@@ -139,7 +150,7 @@ module RuboCop
|
|
|
139
150
|
end
|
|
140
151
|
|
|
141
152
|
def method_call_with_changed_precedence?(node)
|
|
142
|
-
return false unless node.
|
|
153
|
+
return false unless node.call_type? && node.arguments?
|
|
143
154
|
return false if node.parenthesized_call?
|
|
144
155
|
|
|
145
156
|
!node.operator_method?
|
|
@@ -83,7 +83,7 @@ module RuboCop
|
|
|
83
83
|
control_op_condition(cond) do |first_child, rest_children|
|
|
84
84
|
return if require_parentheses?(node, first_child)
|
|
85
85
|
return if semicolon_separated_expressions?(first_child, rest_children)
|
|
86
|
-
return if modifier_op?(first_child)
|
|
86
|
+
return if modifier_op?(first_child) || first_child.masgn_type?
|
|
87
87
|
return if parens_allowed?(cond)
|
|
88
88
|
|
|
89
89
|
message = message(cond)
|
|
@@ -86,10 +86,21 @@ module RuboCop
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def include_same_character_as_used_for_delimiter?(node, type)
|
|
89
|
-
return false unless %w[%w %i].include?(type)
|
|
90
|
-
|
|
91
89
|
used_delimiters = matchpairs(begin_source(node)[-1])
|
|
92
|
-
contains_delimiter?(node, used_delimiters)
|
|
90
|
+
return contains_delimiter?(node, used_delimiters) if %w[%w %i].include?(type)
|
|
91
|
+
return false unless %w[%q %s %r].include?(type)
|
|
92
|
+
|
|
93
|
+
contains_escaped_delimiter?(node, used_delimiters)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Without interpolation an escaped delimiter means something different
|
|
97
|
+
# once the delimiters change (`%q!it\!s!` is `"it!s"`, but `%q(it\!s)`
|
|
98
|
+
# is `"it\\!s"`). For a regexp the match stays the same, but its source
|
|
99
|
+
# changes. Interpolating literals read `\!` as `!` with any delimiter.
|
|
100
|
+
def contains_escaped_delimiter?(node, delimiters)
|
|
101
|
+
body = node.loc.begin.end.join(node.loc.end.begin).source
|
|
102
|
+
|
|
103
|
+
body.scan(/\\./m).any? { |escape| delimiters.include?(escape[1]) }
|
|
93
104
|
end
|
|
94
105
|
|
|
95
106
|
def contains_delimiter?(node, delimiters)
|
|
@@ -101,10 +101,7 @@ module RuboCop
|
|
|
101
101
|
return if exception.send_type? && exception.first_argument&.hash_type?
|
|
102
102
|
|
|
103
103
|
add_offense(node, message: format(COMPACT_MSG, method: node.method_name)) do |corrector|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
corrector.replace(node, replacement)
|
|
107
|
-
opposite_style_detected
|
|
104
|
+
replace_raise(corrector, node, correction_exploded_to_compact(node))
|
|
108
105
|
end
|
|
109
106
|
else
|
|
110
107
|
correct_style_detected
|
|
@@ -121,13 +118,22 @@ module RuboCop
|
|
|
121
118
|
return if allowed_non_exploded_type?(first_arg)
|
|
122
119
|
|
|
123
120
|
add_offense(node, message: format(EXPLODED_MSG, method: node.method_name)) do |corrector|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
corrector.replace(node, replacement)
|
|
127
|
-
opposite_style_detected
|
|
121
|
+
replace_raise(corrector, node, correction_compact_to_exploded(node))
|
|
128
122
|
end
|
|
129
123
|
end
|
|
130
124
|
|
|
125
|
+
def replace_raise(corrector, node, replacement)
|
|
126
|
+
opposite_style_detected
|
|
127
|
+
return if inside_corrected_raise?(node)
|
|
128
|
+
|
|
129
|
+
corrector.replace(node, replacement)
|
|
130
|
+
ignore_node(node)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def inside_corrected_raise?(node)
|
|
134
|
+
node.each_ancestor(:send).any? { |ancestor| ignored_node?(ancestor) }
|
|
135
|
+
end
|
|
136
|
+
|
|
131
137
|
def use_new_method?(first_arg)
|
|
132
138
|
first_arg.send_type? && first_arg.receiver && first_arg.method?(:new)
|
|
133
139
|
end
|
|
@@ -152,7 +158,11 @@ module RuboCop
|
|
|
152
158
|
end
|
|
153
159
|
|
|
154
160
|
def requires_parens?(parent)
|
|
155
|
-
|
|
161
|
+
return true if parent.operator_keyword?
|
|
162
|
+
return true if parent.type?(:call, :super, :yield, :array, :pair)
|
|
163
|
+
return true if parent.any_def_type? && parent.endless?
|
|
164
|
+
|
|
165
|
+
parent.if_type? && parent.ternary?
|
|
156
166
|
end
|
|
157
167
|
end
|
|
158
168
|
end
|
|
@@ -183,7 +183,7 @@ module RuboCop
|
|
|
183
183
|
end
|
|
184
184
|
|
|
185
185
|
def adjusted_source(expr_node, block_node)
|
|
186
|
-
source = expr_node
|
|
186
|
+
source = element_source(expr_node)
|
|
187
187
|
return source unless block_node.numblock_type?
|
|
188
188
|
return source if block_node.method?(:each_with_object)
|
|
189
189
|
|
|
@@ -194,6 +194,22 @@ module RuboCop
|
|
|
194
194
|
def indent(node)
|
|
195
195
|
' ' * node.source_range.column
|
|
196
196
|
end
|
|
197
|
+
|
|
198
|
+
def element_source(expr_node)
|
|
199
|
+
if command_call?(expr_node) || expr_node.assignment? || expr_node.rescue_type?
|
|
200
|
+
return "(#{expr_node.source})"
|
|
201
|
+
end
|
|
202
|
+
return "[#{expr_node.source}]" if expr_node.array_type? && !expr_node.bracketed?
|
|
203
|
+
|
|
204
|
+
expr_node.source
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def command_call?(node)
|
|
208
|
+
node = node.send_node if node.any_block_type?
|
|
209
|
+
return false unless node.type?(:call, :super, :yield)
|
|
210
|
+
|
|
211
|
+
node.arguments? && !node.parenthesized? && !node.operator_method? && !node.setter_method?
|
|
212
|
+
end
|
|
197
213
|
end
|
|
198
214
|
end
|
|
199
215
|
end
|
|
@@ -139,7 +139,7 @@ module RuboCop
|
|
|
139
139
|
offense_range = node.loc.begin
|
|
140
140
|
|
|
141
141
|
add_offense(offense_range) do |corrector|
|
|
142
|
-
if node.parent&.assignment?
|
|
142
|
+
if node.parent&.assignment? || node.parent&.type?(:return, :next, :break)
|
|
143
143
|
replace_begin_with_statement(corrector, offense_range, node)
|
|
144
144
|
else
|
|
145
145
|
remove_begin(corrector, offense_range, node)
|
|
@@ -156,7 +156,7 @@ module RuboCop
|
|
|
156
156
|
first_child = node.children.first
|
|
157
157
|
|
|
158
158
|
source = first_child.source
|
|
159
|
-
source = "(#{source})" if
|
|
159
|
+
source = "(#{source})" if low_precedence_statement?(first_child)
|
|
160
160
|
|
|
161
161
|
corrector.replace(offense_range, source)
|
|
162
162
|
corrector.remove(range_between(offense_range.end_pos, first_child.source_range.end_pos))
|
|
@@ -164,6 +164,13 @@ module RuboCop
|
|
|
164
164
|
restore_removed_comments(corrector, offense_range, node, first_child)
|
|
165
165
|
end
|
|
166
166
|
|
|
167
|
+
def low_precedence_statement?(node)
|
|
168
|
+
return node.modifier_form? if node.basic_conditional?
|
|
169
|
+
return node.prefix_not? if node.send_type?
|
|
170
|
+
|
|
171
|
+
node.operator_keyword? && node.semantic_operator?
|
|
172
|
+
end
|
|
173
|
+
|
|
167
174
|
def remove_begin(corrector, offense_range, node)
|
|
168
175
|
if node.parent.respond_to?(:endless?) && node.parent.endless?
|
|
169
176
|
offense_range = range_with_surrounding_space(offense_range, newlines: true)
|
|
@@ -184,7 +191,8 @@ module RuboCop
|
|
|
184
191
|
def use_modifier_form_after_multiline_begin_block?(node)
|
|
185
192
|
return false unless (parent = node.parent)
|
|
186
193
|
|
|
187
|
-
node.multiline? && parent.if_type? && parent.modifier_form?
|
|
194
|
+
node.multiline? && parent.if_type? && parent.modifier_form? &&
|
|
195
|
+
!parent.condition.equal?(node)
|
|
188
196
|
end
|
|
189
197
|
|
|
190
198
|
def correct_modifier_form_after_multiline_begin_block(corrector, node)
|
|
@@ -222,7 +230,17 @@ module RuboCop
|
|
|
222
230
|
end
|
|
223
231
|
|
|
224
232
|
def valid_begin_assignment?(node)
|
|
225
|
-
node.parent&.assignment? && !node.children.one?
|
|
233
|
+
node.parent&.assignment? && (!node.children.one? || too_long_when_joined?(node))
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def too_long_when_joined?(node)
|
|
237
|
+
statement = node.children.first
|
|
238
|
+
max = config.for_enabled_cop('Layout/LineLength')['Max']
|
|
239
|
+
return false unless max && statement.single_line?
|
|
240
|
+
|
|
241
|
+
length = statement.source.length
|
|
242
|
+
length += 2 if low_precedence_statement?(statement)
|
|
243
|
+
node.loc.column + length > max
|
|
226
244
|
end
|
|
227
245
|
|
|
228
246
|
def inspect_branches(node)
|
|
@@ -78,7 +78,10 @@ module RuboCop
|
|
|
78
78
|
].freeze
|
|
79
79
|
|
|
80
80
|
def on_if(node)
|
|
81
|
-
return
|
|
81
|
+
return unless redundant_condition_offense?(node)
|
|
82
|
+
return if node.each_ancestor(:if).any? do |ancestor|
|
|
83
|
+
redundant_condition_offense?(ancestor)
|
|
84
|
+
end
|
|
82
85
|
|
|
83
86
|
message = message(node)
|
|
84
87
|
|
|
@@ -89,6 +92,10 @@ module RuboCop
|
|
|
89
92
|
|
|
90
93
|
private
|
|
91
94
|
|
|
95
|
+
def redundant_condition_offense?(node)
|
|
96
|
+
!node.modifier_form? && !node.elsif_conditional? && offense?(node)
|
|
97
|
+
end
|
|
98
|
+
|
|
92
99
|
def message(node)
|
|
93
100
|
if redundant_condition?(node)
|
|
94
101
|
REDUNDANT_CONDITION
|
|
@@ -240,10 +247,10 @@ module RuboCop
|
|
|
240
247
|
end
|
|
241
248
|
|
|
242
249
|
# rubocop:disable-next Metrics/AbcSize
|
|
243
|
-
def if_source(if_branch,
|
|
250
|
+
def if_source(if_branch, binary_operator)
|
|
244
251
|
if branches_have_method?(if_branch.parent) && if_branch.parenthesized?
|
|
245
252
|
if_branch.source.delete_suffix(')')
|
|
246
|
-
elsif
|
|
253
|
+
elsif binary_operator
|
|
247
254
|
argument_source = if_branch.first_argument.source
|
|
248
255
|
|
|
249
256
|
"#{if_branch.receiver.source} #{if_branch.method_name} (#{argument_source}"
|
|
@@ -257,8 +264,8 @@ module RuboCop
|
|
|
257
264
|
end
|
|
258
265
|
end
|
|
259
266
|
|
|
260
|
-
def else_source(else_branch,
|
|
261
|
-
if
|
|
267
|
+
def else_source(else_branch, binary_operator) # rubocop:disable Metrics/AbcSize
|
|
268
|
+
if binary_operator
|
|
262
269
|
"#{else_branch.first_argument.source})"
|
|
263
270
|
elsif branches_have_method?(else_branch.parent)
|
|
264
271
|
else_source_if_has_method(else_branch)
|
|
@@ -295,11 +302,11 @@ module RuboCop
|
|
|
295
302
|
|
|
296
303
|
def make_ternary_form(node)
|
|
297
304
|
_condition, if_branch, else_branch = *node # rubocop:disable InternalAffairs/NodeDestructuring -- takes all three branches in one step
|
|
298
|
-
|
|
305
|
+
binary_operator = branches_have_method?(node) && binary_operator?(if_branch)
|
|
299
306
|
|
|
300
307
|
ternary_form = [
|
|
301
|
-
if_source(if_branch,
|
|
302
|
-
else_source(else_branch,
|
|
308
|
+
if_source(if_branch, binary_operator),
|
|
309
|
+
else_source(else_branch, binary_operator)
|
|
303
310
|
].join(' || ')
|
|
304
311
|
ternary_form += ')' if branches_have_method?(node) && if_branch.parenthesized?
|
|
305
312
|
|
|
@@ -320,17 +327,27 @@ module RuboCop
|
|
|
320
327
|
|
|
321
328
|
def require_parentheses?(node)
|
|
322
329
|
(node.basic_conditional? && node.modifier_form?) ||
|
|
323
|
-
node.range_type? ||
|
|
324
|
-
node.
|
|
325
|
-
|
|
330
|
+
node.range_type? || node.rescue_type? ||
|
|
331
|
+
(node.respond_to?(:semantic_operator?) && node.semantic_operator?) ||
|
|
332
|
+
low_precedence_keyword?(node)
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
# e.g. `not foo`, `return foo`, and `yield foo`
|
|
336
|
+
def low_precedence_keyword?(node)
|
|
337
|
+
return node.prefix_not? if node.send_type?
|
|
338
|
+
|
|
339
|
+
node.type?(:return, :next, :break, :yield, :super) &&
|
|
340
|
+
node.arguments? && !node.parenthesized?
|
|
326
341
|
end
|
|
327
342
|
|
|
328
343
|
def require_braces?(node)
|
|
329
344
|
node.hash_type? && !node.braces?
|
|
330
345
|
end
|
|
331
346
|
|
|
332
|
-
|
|
333
|
-
|
|
347
|
+
# Any binary operator binds tighter than `||`, so the fallback must be
|
|
348
|
+
# parenthesized as its argument, e.g. `stack << (foo || :new)`.
|
|
349
|
+
def binary_operator?(node)
|
|
350
|
+
node.binary_operation? && !node.dot?
|
|
334
351
|
end
|
|
335
352
|
|
|
336
353
|
def without_argument_parentheses_method?(node)
|
|
@@ -25,6 +25,12 @@ module RuboCop
|
|
|
25
25
|
MSG = 'Remove the redundant double splat and braces, use keyword arguments directly.'
|
|
26
26
|
MERGE_METHODS = %i[merge merge!].freeze
|
|
27
27
|
|
|
28
|
+
# `Style/TrailingCommaInHashLiteral` adds a comma to the hash literal whose braces
|
|
29
|
+
# this cop removes in the same pass, which would leave a dangling comma.
|
|
30
|
+
def self.autocorrect_incompatible_with
|
|
31
|
+
[Style::TrailingCommaInHashLiteral]
|
|
32
|
+
end
|
|
33
|
+
|
|
28
34
|
# rubocop:disable-next Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
29
35
|
def on_hash(node)
|
|
30
36
|
return if node.pairs.empty? || node.pairs.any?(&:hash_rocket?)
|
|
@@ -49,7 +49,7 @@ module RuboCop
|
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
def replaced_exploded(node, command, message)
|
|
52
|
-
arg =
|
|
52
|
+
arg = message_source(message)
|
|
53
53
|
arg = node.parenthesized? ? "(#{arg})" : " #{arg}"
|
|
54
54
|
"#{command}#{arg}"
|
|
55
55
|
end
|
|
@@ -63,19 +63,31 @@ module RuboCop
|
|
|
63
63
|
next if message.nil_type?
|
|
64
64
|
|
|
65
65
|
add_offense(node, message: MSG_2) do |corrector|
|
|
66
|
-
corrector.replace(new_call,
|
|
66
|
+
corrector.replace(new_call, message_source(message))
|
|
67
67
|
end
|
|
68
68
|
end
|
|
69
69
|
end
|
|
70
70
|
|
|
71
|
-
def
|
|
71
|
+
def message_source(message)
|
|
72
72
|
if string_message?(message)
|
|
73
73
|
message.source
|
|
74
|
+
elsif require_parentheses?(message)
|
|
75
|
+
"(#{message.source}).to_s"
|
|
74
76
|
else
|
|
75
77
|
"#{message.source}.to_s"
|
|
76
78
|
end
|
|
77
79
|
end
|
|
78
80
|
|
|
81
|
+
def require_parentheses?(message)
|
|
82
|
+
if message.call_type?
|
|
83
|
+
!message.method?(:[]) &&
|
|
84
|
+
(message.operator_method? || (message.arguments? && !message.parenthesized?))
|
|
85
|
+
else
|
|
86
|
+
!(message.basic_literal? || message.variable? ||
|
|
87
|
+
message.type?(:const, :self, :begin, :array))
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
79
91
|
# @!method exploded?(node)
|
|
80
92
|
def_node_matcher :exploded?, <<~PATTERN
|
|
81
93
|
(send nil? ${:raise :fail} (const {nil? cbase} :RuntimeError) $_)
|
|
@@ -74,7 +74,8 @@ module RuboCop
|
|
|
74
74
|
def should_not_check?(send, body)
|
|
75
75
|
(body&.const_type? && !check_for_constant?) ||
|
|
76
76
|
(body&.str_type? && !check_for_string?) ||
|
|
77
|
-
rails_cache?(send.receiver)
|
|
77
|
+
rails_cache?(send.receiver) ||
|
|
78
|
+
unappendable_argument?(send)
|
|
78
79
|
end
|
|
79
80
|
|
|
80
81
|
# @!method rails_cache?(node)
|
|
@@ -107,6 +108,13 @@ module RuboCop
|
|
|
107
108
|
def check_for_string?
|
|
108
109
|
frozen_string_literals_enabled?
|
|
109
110
|
end
|
|
111
|
+
|
|
112
|
+
def unappendable_argument?(send)
|
|
113
|
+
argument = send.first_argument
|
|
114
|
+
|
|
115
|
+
argument.type?(:splat, :forwarded_restarg) ||
|
|
116
|
+
(argument.hash_type? && !argument.braces?)
|
|
117
|
+
end
|
|
110
118
|
end
|
|
111
119
|
end
|
|
112
120
|
end
|
|
@@ -29,8 +29,7 @@ module RuboCop
|
|
|
29
29
|
operation_produces_immutable_object?(node.receiver))
|
|
30
30
|
|
|
31
31
|
add_offense(node) do |corrector|
|
|
32
|
-
corrector.remove(node.loc.dot)
|
|
33
|
-
corrector.remove(node.loc.selector)
|
|
32
|
+
corrector.remove(node.loc.dot.join(node.loc.selector))
|
|
34
33
|
end
|
|
35
34
|
end
|
|
36
35
|
|
|
@@ -57,12 +56,21 @@ module RuboCop
|
|
|
57
56
|
def_node_matcher :operation_produces_immutable_object?, <<~PATTERN
|
|
58
57
|
{
|
|
59
58
|
(begin (send {float int} {:+ :- :* :** :/ :% :<<} _))
|
|
60
|
-
(begin (send
|
|
59
|
+
(begin (send #numeric_operation? {:+ :- :* :** :/ :%} {float int}))
|
|
61
60
|
(begin (send _ {:== :=== :!= :<= :>= :< :>} _))
|
|
62
61
|
(send _ {:count :length :size} ...)
|
|
63
62
|
(any_block (send _ {:count :length :size} ...) ...)
|
|
64
63
|
}
|
|
65
64
|
PATTERN
|
|
65
|
+
|
|
66
|
+
# @!method numeric_operation?(node)
|
|
67
|
+
def_node_matcher :numeric_operation?, <<~PATTERN
|
|
68
|
+
{
|
|
69
|
+
float int
|
|
70
|
+
(begin #numeric_operation?)
|
|
71
|
+
(send #numeric_operation? {:+ :- :* :** :/ :%} #numeric_operation?)
|
|
72
|
+
}
|
|
73
|
+
PATTERN
|
|
66
74
|
end
|
|
67
75
|
end
|
|
68
76
|
end
|