class RuboCop::Cop::Naming::RescuedExceptionsVariableName


end
# do something
rescue MyException => _exception
# do something
begin
# good
end
# do something
rescue MyException => exception
# do something
begin
# good
end
# do something
rescue MyException => e
# do something
begin
# bad
@example PreferredName: exception
end
# do something
rescue MyException => _e
# do something
begin
# good
end
# do something
rescue MyException => e
# do something
begin
# good
end
# do something
rescue MyException => exception
# do something
begin
# bad
@example PreferredName: e (default)
shadow the outer variable).
the inner rescue (in which case, changing the inner variable would
guarantee that the variable from the outer rescue is not used within
NOTE: This cop does not consider nested rescues because it cannot
the required name of the variable. Its default is ‘e`.
The `PreferredName` config option takes a `String`. It represents
expected.
Makes sure that rescued exceptions variables are named as

def autocorrect(corrector, node, range, offending_name, preferred_name)

def autocorrect(corrector, node, range, offending_name, preferred_name)
  corrector.replace(range, preferred_name)
  correct_node(corrector, node.body, offending_name, preferred_name)
  return unless (kwbegin_node = node.parent.each_ancestor(:kwbegin).first)
  kwbegin_node.right_siblings.each do |child_node|
    correct_node(corrector, child_node, offending_name, preferred_name)
  end
end

def correct_node(corrector, node, offending_name, preferred_name)

def correct_node(corrector, node, offending_name, preferred_name)
  return unless node
  node.each_node(:lvar, :lvasgn, :masgn) do |child_node|
    next unless variable_name_matches?(child_node, offending_name)
    corrector.replace(child_node, preferred_name) if child_node.lvar_type?
    if child_node.masgn_type? || child_node.lvasgn_type?
      correct_reassignment(corrector, child_node, offending_name, preferred_name)
      break
    end
  end
end

def correct_reassignment(corrector, node, offending_name, preferred_name)

different variable.
Further `lvar` nodes will not be corrected though since they now refer to a
If the exception variable is reassigned, that assignment needs to be corrected.
def correct_reassignment(corrector, node, offending_name, preferred_name)
  if node.lvasgn_type?
    correct_node(corrector, node.child_nodes.first, offending_name, preferred_name)
  elsif node.masgn_type?
    # With multiple assign, the assignments are in an array as the last child
    correct_node(corrector, node.children.last, offending_name, preferred_name)
  end
end

def message(node)

def message(node)
  offending_name = variable_name(node)
  preferred_name = preferred_name(offending_name)
  format(MSG, preferred: preferred_name, bad: offending_name)
end

def offense_range(resbody)

def offense_range(resbody)
  variable = resbody.exception_variable
  variable.source_range
end

def on_resbody(node)

def on_resbody(node)
  offending_name = variable_name(node)
  return unless offending_name
  # Handle nested rescues by only requiring the outer one to use the
  # configured variable name, so that nested rescues don't use the same
  # variable.
  return if node.each_ancestor(:resbody).any?
  preferred_name = preferred_name(offending_name)
  return if preferred_name.to_sym == offending_name
  # check variable shadowing for exception variable
  return if shadowed_variable_name?(node)
  range = offense_range(node)
  message = message(node)
  add_offense(range, message: message) do |corrector|
    autocorrect(corrector, node, range, offending_name, preferred_name)
  end
end

def preferred_name(variable_name)

def preferred_name(variable_name)
  preferred_name = cop_config.fetch('PreferredName', 'e')
  if variable_name.to_s.start_with?('_')
    "_#{preferred_name}"
  else
    preferred_name
  end
end

def shadowed_variable_name?(node)

def shadowed_variable_name?(node)
  node.each_descendant(:lvar).any? { |n| n.children.first.to_s == preferred_name(n) }
end

def variable_name(node)

def variable_name(node)
  asgn_node = node.exception_variable
  return unless asgn_node
  asgn_node.children.last
end

def variable_name_matches?(node, name)

def variable_name_matches?(node, name)
  if node.masgn_type?
    node.each_descendant(:lvasgn).any? do |lvasgn_node|
      variable_name_matches?(lvasgn_node, name)
    end
  else
    node.children.first == name
  end
end