class RuboCop::Cop::Lint::UnescapedBracketInRegexp
Regexp.compile(‘abc]123’)
Regexp.new(‘abc]123’)
%r{abc]123}
/abc]123/
# good
Regexp.compile(‘abc]123’)
Regexp.new(‘abc]123’)
%r{abc]123}
/abc]123/
# bad
@example
—-
-e:1: warning: regular expression has ‘]’ without escape: /abc]123/
$ ruby -e ‘/abc]123/’
—-
[source,ruby]
It emulates the following Ruby warning:
that contain unescaped ‘]` characters.
Checks for Regexpes (both literals and via `Regexp.new` / `Regexp.compile`)
def detect_offenses(node, expr)
def detect_offenses(node, expr) return unless expr.type?(:literal) expr.text.scan(/(?<!\\)\]/) do pos = Regexp.last_match.begin(0) next if pos.zero? # if the unescaped bracket is the first character, Ruby does not warn location = range_at_index(node, expr.ts, pos) add_offense(location) do |corrector| corrector.replace(location, '\]') end end end
def on_regexp(node)
def on_regexp(node) RuboCop::Util.silence_warnings do node.parsed_tree&.each_expression do |expr| detect_offenses(node, expr) end end end
def on_send(node)
def on_send(node) # Ignore nodes that contain interpolation return if node.each_descendant(:dstr).any? regexp_constructor(node) do |text| Regexp::Parser.parse(text.value)&.each_expression do |expr| detect_offenses(text, expr) end rescue Regexp::Parser::Error # Upon encountering an invalid regular expression, # we aim to proceed and identify any remaining potential offenses. end end
def range_at_index(node, index, offset)
def range_at_index(node, index, offset) adjustment = index + offset node.loc.begin.end.adjust(begin_pos: adjustment, end_pos: adjustment + 1) end