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