Skip to content

Autocorrect clobbering with nested if/unless/if and Style/SoleNestedConditional #14298

@5hun-s

Description

@5hun-s

Expected behavior

RuboCop should autocorrect a nested if -> unless -> if structure into a single if statement with combined conditions, converting unless to ! as needed.

      if foo
        unless bar
        ^^^^^^ Consider merging nested conditions into outer `if` conditions.
          if baz
          ^^ Consider merging nested conditions into outer `unless` conditions.
            do_something
          end
        end
      end

Should be autocorrected to:

      if foo && !bar && baz
            do_something
          end

Actual behavior

Although the autocorrection works correctly as expected, the following clobbering error is output:

An error occurred while Style/SoleNestedConditional cop was inspecting /app/app/forms/sample_form.rb:1:1.
Parser::Source::TreeRewriter detected clobbering
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter.rb:427:in `trigger_policy'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter.rb:414:in `enforce_policy'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:234:in `call'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:234:in `swallow'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:98:in `with'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:125:in `place_in_hierarchy'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:107:in `do_combine'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:118:in `place_in_hierarchy'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:132:in `block in combine_children'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:131:in `each'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:131:in `inject'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:131:in `combine_children'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:222:in `merge'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:105:in `do_combine'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter/action.rb:31:in `combine'
/app/vendor/bundle/ruby/3.2.0/gems/parser-3.3.8.0/lib/parser/source/tree_rewriter.rb:143:in `merge!'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/base.rb:374:in `apply_correction'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/base.rb:453:in `attempt_correction'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/base.rb:434:in `use_corrector'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/base.rb:428:in `correct'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/base.rb:210:in `add_offense'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/style/sole_nested_conditional.rb:67:in `on_if'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:107:in `public_send'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:107:in `block (2 levels) in trigger_responding_cops'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:171:in `with_cop_error_handling'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:106:in `block in trigger_responding_cops'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:105:in `each'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:105:in `trigger_responding_cops'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:69:in `on_if'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:164:in `on_if'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:71:in `on_if'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `block in on_dstr'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `each'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `on_dstr'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:71:in `on_begin'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:164:in `on_if'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:71:in `on_if'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `block in on_dstr'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `each'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `on_dstr'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:71:in `on_begin'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:163:in `on_def'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:71:in `on_def'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `block in on_dstr'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `each'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:146:in `on_dstr'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:71:in `on_begin'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:163:in `on_class'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:71:in `on_class'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:147:in `on_while'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:71:in `on_module'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-ast-1.45.0/lib/rubocop/ast/traversal.rb:20:in `walk'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/commissioner.rb:87:in `investigate'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/team.rb:174:in `investigate_partial'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cop/team.rb:101:in `investigate'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:349:in `block in inspect_file'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:348:in `each'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:348:in `flat_map'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:348:in `inspect_file'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:291:in `block in do_inspection_loop'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:325:in `block in iterate_until_no_changes'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:318:in `loop'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:318:in `iterate_until_no_changes'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:287:in `do_inspection_loop'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:168:in `block in file_offenses'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:193:in `file_offense_cache'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:167:in `file_offenses'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:158:in `process_file'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:139:in `block in each_inspected_file'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:138:in `each'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:138:in `reduce'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:138:in `each_inspected_file'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:124:in `inspect_files'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/runner.rb:77:in `run'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli/command/execute_runner.rb:26:in `block in execute_runner'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli/command/execute_runner.rb:52:in `with_redirect'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli/command/execute_runner.rb:25:in `execute_runner'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli/command/execute_runner.rb:17:in `run'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli/command.rb:11:in `run'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli/environment.rb:18:in `run'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli.rb:122:in `run_command'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli.rb:129:in `execute_runners'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli.rb:51:in `block in run'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli.rb:81:in `profile_if_needed'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/lib/rubocop/cli.rb:43:in `run'
/app/vendor/bundle/ruby/3.2.0/gems/rubocop-1.69.2/exe/rubocop:19:in `<top (required)>'
/app/vendor/bundle/ruby/3.2.0/bin/rubocop:25:in `load'
/app/vendor/bundle/ruby/3.2.0/bin/rubocop:25:in `<top (required)>'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/cli/exec.rb:58:in `load'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/cli/exec.rb:58:in `kernel_load'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/cli/exec.rb:23:in `run'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/cli.rb:492:in `exec'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/vendor/thor/lib/thor/invocation.rb:127:in `invoke_command'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/cli.rb:34:in `dispatch'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/cli.rb:28:in `start'
/usr/local/bundle/gems/bundler-2.4.16/exe/bundle:37:in `block in <top (required)>'
/usr/local/bundle/gems/bundler-2.4.16/lib/bundler/friendly_errors.rb:117:in `with_friendly_errors'
/usr/local/bundle/gems/bundler-2.4.16/exe/bundle:29:in `<top (required)>'
/usr/local/bundle/bin/bundle:25:in `load'
/usr/local/bundle/bin/bundle:25:in `<main>'
W

Steps to reproduce the problem

This issue occurs with three-level nested conditionals structured as if -> unless -> if.(It does not occur with three nested if statements.)

      if foo
        unless bar
          if baz
            do_something
          end
        end
      end

RuboCop version

Include the output of rubocop -V or bundle exec rubocop -V if using Bundler.
If you see extension cop versions (e.g. rubocop-performance, rubocop-rspec, and others)
output by rubocop -V, include them as well. Here's an example:

/app # bundle exec rubocop -V
1.69.2 (using Parser 3.3.8.0, rubocop-ast 1.45.0, analyzing as Ruby 3.2, running on ruby 3.2.2) [aarch64-linux-musl]
  - rubocop-performance 1.23.1
  - rubocop-rails 2.27.0
  - rubocop-rspec 3.3.0

I investigated the error.

The Style/SoleNestedConditional cop converts unless statements into if ! form before attempting to merge them.

Correction A: tries to combine the outer if and the middle unless.
Correction B: Attempts to combine the middle unless with the inner if. This also tries to modify the same range.

Both corrections attempt to modify the same code range that includes the middle unless keyword and its condition, resulting in conflicting changes.

May I try to fix this error?.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      pFad - Phonifier reborn

      Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

      Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


      Alternative Proxies:

      Alternative Proxy

      pFad Proxy

      pFad v3 Proxy

      pFad v4 Proxy