Skip to content

Commit

Permalink
Fix an error for Lint/MixedRegexpCaptureTypes cop
Browse files Browse the repository at this point in the history
This commit fixes the following error.

```console
% cd repo/to/rubocop-hq/rubocop
% bundle exec rubocop -d --only Lint/MixedRegexpCaptureTypes
lib/rubocop/cop/utils/format_string.rb
For /Users/koic/src/github.com/rubocop-hq/rubocop: configuration from
/Users/koic/src/github.com/rubocop-hq/rubocop/.rubocop.yml
configuration from
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-performance-1.6.0/config/default.yml
configuration from
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-performance-1.6.0/config/default.yml
Default configuration from
/Users/koic/src/github.com/rubocop-hq/rubocop/config/default.yml
configuration from
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-rspec-1.39.0/config/default.yml
configuration from
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/rubocop-rspec-1.39.0/config/default.yml
Inheriting configuration from
/Users/koic/src/github.com/rubocop-hq/rubocop/.rubocop_todo.yml
Inspecting 1 file
Scanning
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/utils/format_string.rb
An error occurred while Lint/MixedRegexpCaptureTypes cop was inspecting
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/utils/format_string.rb:18:19.
No valid target found for '*'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/parser.rb:432:in
`quantifier'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/parser.rb:102:in
`parse_token'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/parser.rb:39:in
`block in parse'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/lexer.rb:55:in
`block in lex'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/lexer.rb:55:in
`map'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/lexer.rb:55:in
`lex'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/lexer.rb:15:in
`lex'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/parser.rb:38:in
`parse'
/Users/koic/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/regexp_parser-1.7.0/lib/regexp_parser/parser.rb:22:in
`parse'
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/lint/mixed_regexp_capture_types.rb:28:in
`on_regexp'
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/commissioner.rb:56:in
`block (2 levels) in trigger_responding_cops'
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/commissioner.rb:115:in
`with_cop_error_handling'
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/commissioner.rb:55:in
`block in trigger_responding_cops'
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/commissioner.rb:54:in
`each'
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/commissioner.rb:54:in
`trigger_responding_cops'
/Users/koic/src/github.com/rubocop-hq/rubocop/lib/rubocop/cop/commissioner.rb:32:in
`block (2 levels) in <class:Commissioner>'
```

RuboCop does not know a value of variables that it will contain in the regexp literal.
For example, `/(?<foo>#{var}*)` is interpreted as `/(?<foo>*)`.
So it does not offense when variables are used in regexp literals.

Also this PR fixes regexps that is causing an error in `regexp_parser` gem.
  • Loading branch information
koic authored and bbatsov committed Jun 1, 2020
1 parent 2bd7fe4 commit 348da8e
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 2 deletions.
11 changes: 11 additions & 0 deletions lib/rubocop/cop/lint/mixed_regexp_capture_types.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class MixedRegexpCaptureTypes < Cop
'in a Regexp literal.'

def on_regexp(node)
return if contain_non_literal?(node)

tree = Regexp::Parser.parse(node.content)
return unless named_capture?(tree)
return unless numbered_capture?(tree)
Expand All @@ -34,6 +36,15 @@ def on_regexp(node)

private

def contain_non_literal?(node)
if node.respond_to?(:type) && (node.variable? || node.send_type? || node.const_type?)
return true
end
return false unless node.respond_to?(:children)

node.children.any? { |child| contain_non_literal?(child) }
end

def named_capture?(tree)
tree.each_expression.any? do |e|
e.instance_of?(Regexp::Expression::Group::Capture)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/style/redundant_percent_q.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class RedundantPercentQ < Cop
EMPTY = ''
PERCENT_Q = '%q'
PERCENT_CAPITAL_Q = '%Q'
STRING_INTERPOLATION_REGEXP = /#\{.+}/.freeze
STRING_INTERPOLATION_REGEXP = /#\{.+\}/.freeze
ESCAPED_NON_BACKSLASH = /\\[^\\]/.freeze

def on_dstr(node)
Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/cop/util.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def to_string_literal(string)
end

def trim_string_interporation_escape_character(str)
str.gsub(/\\\#{(.*?)\}/) { "\#{#{Regexp.last_match(1)}}" }
str.gsub(/\\\#\{(.*?)\}/) { "\#{#{Regexp.last_match(1)}}" }
end

def interpret_string_escapes(string)
Expand Down
3 changes: 3 additions & 0 deletions lib/rubocop/target_ruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@ def find_version
file = ruby_version_file
return unless file && File.file?(file)

# rubocop:disable Lint/MixedRegexpCaptureTypes
# `(ruby-)` is not a capture type.
File.read(file).match(/\A(ruby-)?(?<version>\d+\.\d+)/) do |md|
# rubocop:enable Lint/MixedRegexpCaptureTypes
md[:version].to_f
end
end
Expand Down
42 changes: 42 additions & 0 deletions spec/rubocop/cop/lint/mixed_regexp_capture_types_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,46 @@
/(?<foo>bar)(?:bar)/
RUBY
end

# RuboCop does not know a value of variables that it will contain in the regexp literal.
# For example, `/(?<foo>#{var}*)` is interpreted as `/(?<foo>*)`.
# So it does not offense when variables are used in regexp literals.
context 'when containing a non-regexp literal' do
it 'does not register an offence when containing a lvar' do
expect_no_offenses(<<~'RUBY')
var = '(\d+)'
/(?<foo>#{var}*)/
RUBY
end

it 'does not register an offence when containing a ivar' do
expect_no_offenses(<<~'RUBY')
/(?<foo>#{@var}*)/
RUBY
end

it 'does not register an offence when containing a cvar' do
expect_no_offenses(<<~'RUBY')
/(?<foo>#{@@var}*)/
RUBY
end

it 'does not register an offence when containing a gvar' do
expect_no_offenses(<<~'RUBY')
/(?<foo>#{$var}*)/
RUBY
end

it 'does not register an offence when containing a method' do
expect_no_offenses(<<~'RUBY')
/(?<foo>#{do_something}*)/
RUBY
end

it 'does not register an offence when containing a constant' do
expect_no_offenses(<<~'RUBY')
/(?<foo>#{CONST}*)/
RUBY
end
end
end

0 comments on commit 348da8e

Please sign in to comment.