class Sorbet::Private::Serialize

def self.header(typed="true", subcommand="update")

def self.header(typed="true", subcommand="update")
  buffer = []
  buffer << "# This file is autogenerated. Do not edit it by hand. Regenerate it with:"
  buffer << "#   srb rbi #{subcommand}"
  if typed
    buffer << ""
    buffer << "# typed: #{typed}"
  end
  buffer << ""
  buffer.join("\n")
end

def alias(base, other_name)

def alias(base, other_name)
  ret = String.new
  ret << "#{other_name} = #{base}"
  ret
end

def ancestor_has_method(method, klass)

def ancestor_has_method(method, klass)
  return false if !Sorbet::Private::RealStdlib.real_is_a?(klass, Class)
  first_ancestor = klass.ancestors.find do |ancestor|
    next if ancestor == klass
    begin
      ancestor.instance_method(method.name)
    rescue NameError
      nil
    end
  end
  return false unless first_ancestor
  first_ancestor.instance_method(method.name).parameters == method.parameters
end

def class_or_module(class_name)

def class_or_module(class_name)
  if !valid_class_name(class_name)
    return " # Skipping serializing #{class_name} because it is an invalid name\n"
  end
  klass = @constant_cache.class_by_name(class_name)
  is_nil = nil.equal?(klass)
  raise "#{class_name} is not a Class or Module. Maybe it was miscategorized?" if is_nil
  ret = String.new
  superclass = Sorbet::Private::RealStdlib.real_is_a?(klass, Class) ? Sorbet::Private::RealStdlib.real_superclass(klass) : nil
  if superclass
    superclass_str = Sorbet::Private::RealStdlib.real_eqeq(superclass, Object) ? '' : @constant_cache.name_by_class(superclass)
  else
    superclass_str = ''
  end
  superclass_str = !superclass_str || superclass_str.empty? ? '' : " < #{superclass_str}"
  ret << (Sorbet::Private::RealStdlib.real_is_a?(klass, Class) ? "class #{class_name}#{superclass_str}\n" : "module #{class_name}\n")
  # We don't use .included_modules since that also has all the aweful things
  # that are mixed into Object. This way we at least have a delimiter before
  # the awefulness starts (the superclass).
  Sorbet::Private::RealStdlib.real_ancestors(klass).each do |ancestor|
    next if Sorbet::Private::RealStdlib.real_eqeq(ancestor, klass)
    break if Sorbet::Private::RealStdlib.real_eqeq(ancestor, superclass)
    ancestor_name = @constant_cache.name_by_class(ancestor)
    next unless ancestor_name
    next if ancestor_name == class_name
    if Sorbet::Private::RealStdlib.real_is_a?(ancestor, Class)
      ret << "  # Skipping `include #{ancestor_name}` because it is a Class\n"
      next
    end
    if !valid_class_name(ancestor_name)
      ret << "  # Skipping `include #{ancestor_name}` because it is an invalid name\n"
      next
    end
    ret << "  include ::#{ancestor_name}\n"
  end
  singleton_class = Sorbet::Private::RealStdlib.real_singleton_class(klass)
  Sorbet::Private::RealStdlib.real_ancestors(singleton_class).each do |ancestor|
    next if ancestor == Sorbet::Private::RealStdlib.real_singleton_class(klass)
    break if superclass && ancestor == Sorbet::Private::RealStdlib.real_singleton_class(superclass)
    break if ancestor == Module
    break if ancestor == Object
    ancestor_name = @constant_cache.name_by_class(ancestor)
    next unless ancestor_name
    if Sorbet::Private::RealStdlib.real_is_a?(ancestor, Class)
      ret << "  # Skipping `extend #{ancestor_name}` because it is a Class\n"
      next
    end
    if !valid_class_name(ancestor_name)
      ret << "  # Skipping `extend #{ancestor_name}` because it is an invalid name\n"
      next
    end
    ret << "  extend ::#{ancestor_name}\n"
  end
  constants = []
  # Declare all the type_members and type_templates
  constants += get_constants(klass).uniq.map do |const_sym|
    # We have to not pass `false` because `klass.constants` intentionally is
    # pulling in all the ancestor constants
    next if Sorbet::Private::ConstantLookupCache::DEPRECATED_CONSTANTS.include?("#{class_name}::#{const_sym}")
    begin
      value = klass.const_get(const_sym)
    rescue LoadError, NameError, RuntimeError, ArgumentError => err
      ret << "# Got #{err.class} when trying to get class constant symbol #{class_name}::#{const_sym}\n"
      next
    end
    # next if !Sorbet::Private::RealStdlib.real_is_a?(value, T::Types::TypeVariable)
    next if Sorbet::Private::RealStdlib.real_is_a?(value, Module)
    next if !comparable?(value)
    [const_sym, value]
  end
  constants += get_constants(klass, false).uniq.map do |const_sym|
    next if DENYLIST_CONSTANTS.include?([class_name, const_sym])
    next if Sorbet::Private::ConstantLookupCache::DEPRECATED_CONSTANTS.include?("#{class_name}::#{const_sym}")
    begin
      value = klass.const_get(const_sym, false)
    rescue LoadError, NameError, RuntimeError, ArgumentError => err
      ret << "# Got #{err.class} when trying to get class constant symbol #{class_name}::#{const_sym}_\n"
      next
    end
    next if Sorbet::Private::RealStdlib.real_is_a?(value, Module)
    next if !comparable?(value)
    [const_sym, value]
  end
  constants_sorted = constants.compact.sort_by do |const_sym, _value|
    const_sym
  end
  constants_uniq = constants_sorted.uniq do |const_sym, _value|
    const_sym.hash
  end
  constants_serialized = constants_uniq.map do |const_sym, value|
    constant(const_sym, value)
  end
  ret << constants_serialized.join("\n")
  ret << "\n\n" if !constants_serialized.empty?
  methods = []
  instance_methods = Sorbet::Private::RealStdlib.real_instance_methods(klass, false)
  begin
    initialize = klass.instance_method(:initialize)
  rescue
    initialize = nil
  end
  if initialize && initialize.owner == klass
    # This method never apears in the reflection list...
    instance_methods += [:initialize]
  end
  Sorbet::Private::RealStdlib.real_ancestors(klass).reject {|ancestor| @constant_cache.name_by_class(ancestor)}.each do |ancestor|
    instance_methods += ancestor.instance_methods(false)
  end
  # uniq here is required because we populate additional methos from anonymous superclasses and there
  # might be duplicates
  methods += instance_methods.sort.uniq.map do |method_sym|
    begin
      method = klass.instance_method(method_sym)
    rescue => e
      ret << "# #{e}\n"
      next
    end
    next if denylisted_method(method)
    next if ancestor_has_method(method, klass)
    serialize_method(method, with_sig: false)
  end
  # uniq is not required here, but added to be on the safe side
  methods += Sorbet::Private::RealStdlib.real_singleton_methods(klass, false).sort.uniq.map do |method_sym|
    begin
      method = klass.singleton_method(method_sym)
    rescue => e
      ret << "# #{e}\n"
      next
    end
    next if denylisted_method(method)
    next if ancestor_has_method(method, Sorbet::Private::RealStdlib.real_singleton_class(klass))
    serialize_method(method, true, with_sig: false)
  end
  ret << methods.join("\n")
  ret << "end\n"
  ret
end

def comparable?(value)

def comparable?(value)
  return false if Sorbet::Private::RealStdlib.real_is_a?(value, BigDecimal) && value.nan?
  return false if Sorbet::Private::RealStdlib.real_is_a?(value, Float) && value.nan?
  return false if Sorbet::Private::RealStdlib.real_is_a?(value, Complex)
  true
end

def constant(const, value)

def constant(const, value)
  if KEYWORDS.include?(const.to_sym)
    return "# Illegal constant name: #{const}"
  end
  if defined?(T::Types) && Sorbet::Private::RealStdlib.real_is_a?(value, T::Types::TypeMember)
    value.variance == :invariant ? "  #{const} = type_member" : "  #{const} = type_member(#{value.variance.inspect})"
  elsif defined?(T::Types) && Sorbet::Private::RealStdlib.real_is_a?(value, T::Types::TypeTemplate)
    value.variance == :invariant ? "  #{const} = type_template" : "  #{const} = type_template(#{value.variance.inspect})"
  else
    "  #{const} = ::T.let(nil, ::T.untyped)"
  end
end

def denylisted_method(method)

def denylisted_method(method)
  method.name =~ /__validator__[0-9]{8}/ || method.name =~ /.*:.*/
end

def from_method(method)

def from_method(method)
  uniq = 0
  method.parameters.map.with_index do |(kind, name), index|
    if !name
      arg_name = method.name.to_s[0...-1]
      if (!KEYWORDS.include?(arg_name.to_sym)) && method.name.to_s.end_with?('=') && arg_name =~ /\A[a-z_][a-z0-9A-Z_]*\Z/ && index == 0
        name = arg_name
      else
        name = '_' + (uniq == 0 ? '' : uniq.to_s)
        uniq += 1
      end
    end
    # Sanitize parameter names that are not valid.
    # Ruby 2.7+ argument forwarding works by expanding `foo(...)`
    # to `foo(**, ****, &&)`, in other words, to a rest parameter named
    # `*`, a keyword rest parameter named `**` and a block argument named
    # `&`. Those are all illegal parameter names which we should NOT
    # generate. (Coincidentally, that is why Ruby 2.7+ uses those names,
    # so that user code cannot mess with the forwarded arguments)
    if ["*", "**", "&"].include?(name.to_s)
      name = '_' + (uniq == 0 ? '' : uniq.to_s)
      uniq += 1
    end
    [kind, name]
  end
end

def get_constants(mod, inherited=nil)

def get_constants(mod, inherited=nil)
constants ||= Module.instance_method(:constants)
erited.nil?
l_constants.bind(mod).call
l_constants.bind(mod).call(inherited)

def initialize(constant_cache)

def initialize(constant_cache)
  @constant_cache = constant_cache
end

def serialize_method(method, static=false, with_sig: true)

def serialize_method(method, static=false, with_sig: true)
  name = method.name.to_s
  if !valid_method_name(name)
    return "# Illegal method name: #{name}\n"
  end
  parameters = from_method(method)
  # a hack for appeasing Sorbet in the presence of the Enumerable interface
  if name == 'each' && !parameters.any? {|(kind, _)| kind == :block}
    parameters.push([:block, "blk"])
  end
  ret = String.new
  ret << serialize_sig(parameters) if with_sig
  args = parameters.map do |(kind, param_name)|
    to_sig(kind, param_name)
  end.compact.join(', ')
  ret << "  def #{static ? 'self.' : ''}#{name}(#{args}); end\n"
  ret
end

def serialize_sig(parameters)

def serialize_sig(parameters)
  ret = String.new
  if !parameters.empty?
    ret << "  sig do\n"
    ret << "    params(\n"
    parameters.each do |(_kind, name)|
      ret << "      #{name}: ::T.untyped,\n"
    end
    ret << "    )\n"
    ret << "    .returns(::T.untyped)\n"
    ret << "  end\n"
  else
    ret << "  sig {returns(::T.untyped)}\n"
  end
  ret
end

def to_sig(kind, name)

def to_sig(kind, name)
  case kind
  when :req
    name.to_s
  when :opt
    "#{name}=T.unsafe(nil)"
  when :rest
    "*#{name}"
  when :keyreq
    "#{name}:"
  when :key
    "#{name}: T.unsafe(nil)"
  when :keyrest
    "**#{name}"
  when :block
    "&#{name}"
  end
end

def valid_class_name(name)

def valid_class_name(name)
  name.split("::").each do |piece|
    return false if piece[0].upcase != piece[0]
  end
  return false if [
    'Sorbet::Private::GemGeneratorTracepoint::Tracer::ClassOverride',
    'Sorbet::Private::GemGeneratorTracepoint::Tracer::ModuleOverride',
    'Sorbet::Private::GemGeneratorTracepoint::Tracer::ObjectOverride',
  ].include?(name)
  true
end

def valid_method_name(name)

def valid_method_name(name)
  return true if SPECIAL_METHOD_NAMES.include?(name)
  return false if name =~ /^\d/
  name =~ /^[[:word:]]+[?!=]?$/
end