diff --git a/CHANGELOG.md b/CHANGELOG.md index 78062cab6b3..ee16d441fda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * [#8324](https://github.com/rubocop-hq/rubocop/issues/8324): Fix crash for `Layout/SpaceAroundMethodCallOperator` when using `Proc#call` shorthand syntax. ([@fatkodima][]) * [#8323](https://github.com/rubocop-hq/rubocop/issues/8323): Fix a false positive for `Style/HashAsLastArrayItem` when hash is not a last array item. ([@fatkodima][]) * [#8299](https://github.com/rubocop-hq/rubocop/issues/8299): Fix an incorrect auto-correct for `Style/RedundantCondition` when using `raise`, `rescue`, or `and` without argument parentheses in `else`. ([@koic][]) +* [#8335](https://github.com/rubocop-hq/rubocop/issues/8335): Fix incorrect character class detection for nested or POSIX bracket character classes in `Style/RedundantRegexpEscape`. ([@owst][]) ## 0.88.0 (2020-07-13) diff --git a/lib/rubocop/cop/style/redundant_regexp_escape.rb b/lib/rubocop/cop/style/redundant_regexp_escape.rb index 4c16887eb3e..4c370fe613f 100644 --- a/lib/rubocop/cop/style/redundant_regexp_escape.rb +++ b/lib/rubocop/cop/style/redundant_regexp_escape.rb @@ -92,18 +92,18 @@ def delimiter?(node, char) def each_escape(node) pattern_source(node).each_char.with_index.reduce( - [nil, false] - ) do |(previous, within_character_class), (current, index)| + [nil, 0] + ) do |(previous, char_class_depth), (current, index)| if previous == '\\' - yield [current, index - 1, within_character_class] + yield [current, index - 1, !char_class_depth.zero?] - [nil, within_character_class] - elsif previous == '[' && current != ':' - [current, true] - elsif previous != ':' && current == ']' - [current, false] + [nil, char_class_depth] + elsif previous == '[' + [current, char_class_depth + 1] + elsif current == ']' + [current, char_class_depth - 1] else - [current, within_character_class] + [current, char_class_depth] end end end diff --git a/spec/rubocop/cop/style/redundant_regexp_escape_spec.rb b/spec/rubocop/cop/style/redundant_regexp_escape_spec.rb index 5a477164401..f7aacb27eb9 100644 --- a/spec/rubocop/cop/style/redundant_regexp_escape_spec.rb +++ b/spec/rubocop/cop/style/redundant_regexp_escape_spec.rb @@ -67,6 +67,19 @@ end end + context 'with an escaped . inside a character class beginning with :' do + it 'registers an offense and corrects' do + expect_offense(<<~'RUBY') + foo = /[:\.]/ + ^^ Redundant escape inside regexp literal + RUBY + + expect_correction(<<~'RUBY') + foo = /[:.]/ + RUBY + end + end + context 'with an escaped character class and following escaped char' do it 'does not register an offense' do expect_no_offenses('foo = /\[\+/') @@ -79,12 +92,44 @@ end end - context 'with a POSIX character class inside a character class' do + context 'with a nested character class then allowed escape' do + it 'does not register an offense' do + expect_no_offenses('foo = /[a-w&&[^c-g]\-]/') + end + end + + context 'with a nested character class containing redundant escape' do + it 'registers an offense and corrects' do + expect_offense(<<~'RUBY') + foo = /[[:punct:]&&[^\.]]/ + ^^ Redundant escape inside regexp literal + RUBY + + expect_correction(<<~'RUBY') + foo = /[[:punct:]&&[^.]]/ + RUBY + end + end + + context 'with a POSIX character class then allowed escape inside a character class' do it 'does not register an offense' do expect_no_offenses('foo = /[[:alnum:]\-_]+/') end end + context 'with a POSIX character class then disallowed escape inside a character class' do + it 'registers an offense and corrects' do + expect_offense(<<~'RUBY') + foo = /[[:alnum:]\.]/ + ^^ Redundant escape inside regexp literal + RUBY + + expect_correction(<<~'RUBY') + foo = /[[:alnum:].]/ + RUBY + end + end + context 'with a backreference' do it 'does not register an offense' do expect_no_offenses('foo = /([a-z])\s*\1/')