Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
1 parent
1fc1981
commit a678aba
Showing
7 changed files
with
182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Lint | ||
# This cops looks for references of Regexp captures that are out of range | ||
# and thus always returns nil. | ||
# | ||
# @example | ||
# | ||
# /(foo)bar/ =~ 'foobar' | ||
# | ||
# # bad - always returns nil | ||
# | ||
# puts $2 # => nil | ||
# | ||
# # good | ||
# | ||
# puts $1 # => foo | ||
# | ||
class OutOfRangeRegexpRef < Base | ||
MSG = 'Do not use out of range reference for the Regexp.' | ||
|
||
def on_new_investigation | ||
@valid_ref = 0 | ||
end | ||
|
||
def on_regexp(node) | ||
@valid_ref = nil | ||
return if contain_non_literal?(node) | ||
|
||
tree = Regexp::Parser.parse(node.content) | ||
@valid_ref = regexp_captures(tree) | ||
end | ||
|
||
def on_nth_ref(node) | ||
backref, = *node | ||
return if @valid_ref.nil? | ||
|
||
add_offense(node) if backref > @valid_ref | ||
end | ||
|
||
private | ||
|
||
def contain_non_literal?(node) | ||
node.children.size != 2 || !node.children.first.str_type? | ||
end | ||
|
||
def regexp_captures(tree) | ||
named_capture = numbered_capture = 0 | ||
tree.each_expression do |e| | ||
if e.type?(:group) | ||
e.respond_to?(:name) ? named_capture += 1 : numbered_capture += 1 | ||
end | ||
end | ||
named_capture.positive? ? named_capture : numbered_capture | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::Lint::OutOfRangeRegexpRef do | ||
subject(:cop) { described_class.new(config) } | ||
|
||
let(:config) { RuboCop::Config.new } | ||
|
||
it 'registers an offense when references are used before any Regexp' do | ||
expect_offense(<<~RUBY) | ||
puts $3 | ||
^^ Do not use out of range reference for the Regexp. | ||
RUBY | ||
end | ||
|
||
it 'registers an offense when out of range references are used for named captures' do | ||
expect_offense(<<~RUBY) | ||
/(?<foo>FOO)(?<bar>BAR)/ =~ "FOOBAR" | ||
puts $3 | ||
^^ Do not use out of range reference for the Regexp. | ||
RUBY | ||
end | ||
|
||
it 'registers an offense when out of range references are used for numbered captures' do | ||
expect_offense(<<~RUBY) | ||
/(foo)(bar)/ =~ "foobar" | ||
puts $3 | ||
^^ Do not use out of range reference for the Regexp. | ||
RUBY | ||
end | ||
|
||
it 'registers an offense when out of range references are used for mix of numbered and named captures' do | ||
expect_offense(<<~RUBY) | ||
/(?<foo>FOO)(BAR)/ =~ "FOOBAR" | ||
puts $2 | ||
^^ Do not use out of range reference for the Regexp. | ||
RUBY | ||
end | ||
|
||
it 'registers an offense when out of range references are used for non captures' do | ||
expect_offense(<<~RUBY) | ||
/bar/ =~ 'foo' | ||
puts $1 | ||
^^ Do not use out of range reference for the Regexp. | ||
RUBY | ||
end | ||
|
||
it 'does not register offense to a regexp with valid references for named captures' do | ||
expect_no_offenses(<<~RUBY) | ||
/(?<foo>FOO)(?<bar>BAR)/ =~ "FOOBAR" | ||
puts $1 | ||
puts $2 | ||
RUBY | ||
end | ||
|
||
it 'does not register offense to a regexp with valid references for numbered captures' do | ||
expect_no_offenses(<<~RUBY) | ||
/(foo)(bar)/ =~ "foobar" | ||
puts $1 | ||
puts $2 | ||
RUBY | ||
end | ||
|
||
it 'does not register offense to a regexp with valid references for a mix named and numbered captures' do | ||
expect_no_offenses(<<~RUBY) | ||
/(?<foo>FOO)(BAR)/ =~ "FOOBAR" | ||
puts $1 | ||
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. | ||
it 'does not register an offence Regexp containing non literal' do | ||
expect_no_offenses(<<~'RUBY') | ||
var = '(\d+)' | ||
/(?<foo>#{var}*)/ =~ "12" | ||
puts $1 | ||
puts $2 | ||
RUBY | ||
end | ||
end |