From 8329663eeae6d6be1072f98b98fa080584aef0d4 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Wed, 22 Apr 2020 20:04:31 +0900 Subject: [PATCH] [Fix #7899] Fix an infinite loop error for `Layout/SpaceAroundOperators` Fixes #7899. This PR fixes the following infinite loop error for `Layout/SpaceAroundOperators` with `Layout/ExtraSpacing` when using `ForceEqualSignAlignment: true`. ```console % bundle exec rubocop -V 0.82.0 (using Parser 2.7.1.1, running on ruby 2.7.0 x86_64-darwin17) % cat .rubocop.yml Layout/ExtraSpacing: ForceEqualSignAlignment: true % cat example.rb test123456 = nil test1234 = nil test1_test2_test3_test4_12 =nil % bundle exec rubocop -a --only Layout/ExtraSpacing,Layout/SpaceAroundOperators (snip) Infinite loop detected in /Users/koic/src/github.com/koic/rubocop-issues/7899/example.rb. /Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/runner.rb:287:in `check_for_infinite_loop' /Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/runner.rb:270:in `block in iterate_until_no_changes' /Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/runner.rb:269:in `loop' /Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/runner.rb:269:in `iterate_until_no_changes' ``` --- CHANGELOG.md | 1 + .../cop/layout/space_around_operators.rb | 19 ++++++++++++++- spec/rubocop/cli/cli_autocorrect_spec.rb | 24 +++++++++++++++++++ .../cop/layout/space_around_operators_spec.rb | 1 - 4 files changed, 43 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 981b5864727..18121f1b60e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ * [#7635](https://github.com/rubocop-hq/rubocop/issues/7635): Fix a false positive for `Style/MultilineWhenThen` when `then` required for a body of `when` is used. ([@koic][]) * [#7905](https://github.com/rubocop-hq/rubocop/pull/7905): Fix an error when running `rubocop --only` or `rubocop --except` options without cop name argument. ([@koic][]) * [#7903](https://github.com/rubocop-hq/rubocop/pull/7903): Fix an incorrect autocorrect for `Style/HashTransformKeys` and `Style/HashTransformValues` cops when line break before `to_h` method. ([@diogoosorio][], [@koic][]) +* [#7899](https://github.com/rubocop-hq/rubocop/issues/7899): Fix an infinite loop error for `Layout/SpaceAroundOperators` with `Layout/ExtraSpacing` when using `ForceEqualSignAlignment: true`. ([@koic][]) ### Changes diff --git a/lib/rubocop/cop/layout/space_around_operators.rb b/lib/rubocop/cop/layout/space_around_operators.rb index 30d870d8e27..b68cdd87bed 100644 --- a/lib/rubocop/cop/layout/space_around_operators.rb +++ b/lib/rubocop/cop/layout/space_around_operators.rb @@ -139,7 +139,7 @@ def autocorrect(range) elsif range.source.end_with?("\n") corrector.replace(range, " #{range.source.strip}\n") else - corrector.replace(range, " #{range.source.strip} ") + enclose_operator_with_space(corrector, range) end end end @@ -170,6 +170,19 @@ def offense(type, operator, with_space, right_operand) yield msg if msg end + def enclose_operator_with_space(corrector, range) + operator = range.source + + # If `ForceEqualSignAlignment` is true, `Layout/ExtraSpacing` cop + # inserts spaces before operator. If `Layout/SpaceAroundOperators` cop + # inserts a space, it collides and raises the infinite loop error. + if force_equal_sign_alignment? + corrector.insert_after(range, ' ') unless operator.end_with?(' ') + else + corrector.replace(range, " #{operator.strip} ") + end + end + def offense_message(type, operator, with_space, right_operand) if should_not_have_surrounding_space?(operator) return if with_space.is?(operator.source) @@ -216,6 +229,10 @@ def space_around_exponent_operator? cop_config['EnforcedStyleForExponentOperator'] == 'space' end + def force_equal_sign_alignment? + config.for_cop('Layout/ExtraSpacing')['ForceEqualSignAlignment'] + end + def should_not_have_surrounding_space?(operator) operator.is?('**') ? !space_around_exponent_operator? : false end diff --git a/spec/rubocop/cli/cli_autocorrect_spec.rb b/spec/rubocop/cli/cli_autocorrect_spec.rb index 3bafc9a9a0f..cc84d296d15 100644 --- a/spec/rubocop/cli/cli_autocorrect_spec.rb +++ b/spec/rubocop/cli/cli_autocorrect_spec.rb @@ -106,6 +106,30 @@ def batch RUBY end + it 'corrects `Layout/SpaceAroundOperators` and `Layout/ExtraSpacing` ' \ + 'offenses when using `ForceEqualSignAlignment: true`' do + create_file('.rubocop.yml', <<~YAML) + Layout/ExtraSpacing: + ForceEqualSignAlignment: true + YAML + + create_file('example.rb', <<~RUBY) + test123456 = nil + test1234 = nil + test1_test2_test3_test4_12 =nil + RUBY + + expect(cli.run(['--auto-correct'])).to eq(1) + + expect(IO.read('example.rb')).to eq(<<~RUBY) + # frozen_string_literal: true + + test123456 = nil + test1234 = nil + test1_test2_test3_test4_12 = nil + RUBY + end + it 'does not correct SpaceAroundOperators in a hash that would be ' \ 'changed back' do create_file('.rubocop.yml', <<~YAML) diff --git a/spec/rubocop/cop/layout/space_around_operators_spec.rb b/spec/rubocop/cop/layout/space_around_operators_spec.rb index c2c40faf05a..1f8bf308220 100644 --- a/spec/rubocop/cop/layout/space_around_operators_spec.rb +++ b/spec/rubocop/cop/layout/space_around_operators_spec.rb @@ -6,7 +6,6 @@ let(:config) do RuboCop::Config .new( - 'Layout/ExtraSpacing' => { 'ForceEqualSignAlignment' => true }, 'Layout/HashAlignment' => { 'EnforcedHashRocketStyle' => hash_style }, 'Layout/SpaceAroundOperators' => { 'AllowForAlignment' => allow_for_alignment,