class RuboCop::Cop::Lint::ShadowedException


end
handle_standard_error
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
something
begin
# the same error code.
# This good case is for ‘Errno::EAGAIN` and `Errno::EWOULDBLOCK` with
# the same error code or different error code depends on environment.
# For example, whether `Errno::EAGAIN` and `Errno::EWOULDBLOCK` are
# System dependent error code depends on runtime environment.
# This is a special case for system call errors.
#
# good, however depending on runtime environment.
end
handle_exception
rescue Exception
handle_standard_error
rescue StandardError
something
begin
# good
end
handle_error
rescue Exception, StandardError
something
begin
# bad
end
handle_standard_error
rescue StandardError
handle_exception
rescue Exception
something
begin
# bad
@example
are rescued by `rescue Exception`).
whether `StandardError` is included or not, because all “StandardError“s
exception. (ie. `rescue Exception, StandardError` has the same behavior
unnecessary because it is covered by rescuing the less specific
same `rescue` statement. In both cases, the more specific rescue is
ancestor is, or if it and its ancestor are both rescued in the
An exception is considered shadowed if it is rescued after its
exception is rescued.
less specific exception being rescued before a more specific
Checks for a rescued exception that get shadowed by a

def compare_exceptions(exception, other_exception)

def compare_exceptions(exception, other_exception)
  if system_call_err?(exception) && system_call_err?(other_exception)
    # This condition logic is for special case.
    # System dependent error code depends on runtime environment.
    # For example, whether `Errno::EAGAIN` and `Errno::EWOULDBLOCK` are
    # the same error code or different error code depends on runtime
    # environment. This checks the error code for that.
    exception.const_get(:Errno) != other_exception.const_get(:Errno) &&
      exception <=> other_exception
  else
    exception && other_exception && exception <=> other_exception
  end
end

def contains_multiple_levels_of_exceptions?(group)

def contains_multiple_levels_of_exceptions?(group)
  # Always treat `Exception` as the highest level exception.
  return true if group.size > 1 && group.include?(Exception)
  group.combination(2).any? { |a, b| compare_exceptions(a, b) }
end

def evaluate_exceptions(group)

def evaluate_exceptions(group)
  rescued_exceptions = group.exceptions
  if rescued_exceptions.any?
    rescued_exceptions.each_with_object([]) do |exception, converted|
      RuboCop::Util.silence_warnings do
        # Avoid printing deprecation warnings about constants
        converted << Kernel.const_get(exception.source)
      end
    rescue NameError
      converted << nil
    end
  else
    # treat an empty `rescue` as `rescue StandardError`
    [StandardError]
  end
end

def find_shadowing_rescue(rescues)

def find_shadowing_rescue(rescues)
  rescued_groups = rescued_groups_for(rescues)
  rescued_groups.zip(rescues).each do |group, res|
    return res if contains_multiple_levels_of_exceptions?(group)
  end
  rescued_groups.each_cons(2).with_index do |group_pair, i|
    return rescues[i] unless sorted?(group_pair)
  end
end

def offense_range(rescues)

def offense_range(rescues)
  shadowing_rescue = find_shadowing_rescue(rescues)
  expression = shadowing_rescue.source_range
  range_between(expression.begin_pos, expression.end_pos)
end

def on_rescue(node)

def on_rescue(node)
  return if rescue_modifier?(node)
  _body, *rescues, _else = *node
  rescued_groups = rescued_groups_for(rescues)
  rescue_group_rescues_multiple_levels = rescued_groups.any? do |group|
    contains_multiple_levels_of_exceptions?(group)
  end
  return if !rescue_group_rescues_multiple_levels && sorted?(rescued_groups)
  add_offense(offense_range(rescues))
end

def rescued_groups_for(rescues)

def rescued_groups_for(rescues)
  rescues.map { |group| evaluate_exceptions(group) }
end

def sorted?(rescued_groups)

def sorted?(rescued_groups)
  rescued_groups.each_cons(2).all? do |x, y|
    if x.include?(Exception)
      false
    elsif y.include?(Exception) ||
          # consider sorted if a group is empty or only contains
          # `nil`s
          x.none? || y.none?
      true
    else
      (x <=> y || 0) <= 0
    end
  end
end

def system_call_err?(error)

def system_call_err?(error)
  error && error.ancestors[1] == SystemCallError
end