class RuboCop::Cop::Sorbet::SignatureBuildOrder

rubocop:todo InternalAffairs/InheritDeprecatedCopClass
sig { params(x: Integer).returns(Integer) }
# good
sig { returns(Integer).params(x: Integer) }
# bad
sig { abstract.void }
# good
sig { void.abstract }
# bad
@example
- soft, checked, or on_failure
- returns, or void
- params
- type_parameters
- abstract, override, or overridable
Checks for the correct order of sig builder methods:

def autocorrect(node)

def autocorrect(node)
  return unless can_autocorrect?
  lambda do |corrector|
    tree = call_chain(node_reparsed_with_modern_features(node))
      .sort_by { |call| ORDER[call.method_name] }
      .reduce(nil) do |receiver, caller|
        caller.updated(nil, [receiver] + caller.children.drop(1))
      end
    corrector.replace(
      node,
      Unparser.unparse(tree),
    )
  end
end

def call_chain(sig_child_node)

def call_chain(sig_child_node)
  return [] if sig_child_node.nil?
  call_node = root_call(sig_child_node).first
  return [] unless call_node
  calls = []
  while call_node != sig_child_node
    calls << call_node
    call_node = call_node.parent
  end
  calls << sig_child_node
  calls
end

def can_autocorrect?

def can_autocorrect?
  defined?(::Unparser)
end

def node_reparsed_with_modern_features(node)

Otherwise, we would get the unparsed node as `foo.[](bar)`.
"index sends" (i.e. `[]` calls) back to index accessors (i.e. as `foo[bar]``).
Modern features include "index send" emitting, which is necessary to unparse
This method exists to reparse the current node with modern features enabled.
def node_reparsed_with_modern_features(node)
  # Create a new parser with a modern builder class instance
  parser = Parser::CurrentRuby.new(ModernBuilder.new)
  # Create a new source buffer with the node source
  buffer = Parser::Source::Buffer.new(processed_source.path, source: node.source)
  # Re-parse the buffer
  parser.parse(buffer)
end

def on_signature(node)

def on_signature(node)
  calls = call_chain(node.children[2]).map(&:method_name)
  return if calls.empty?
  # While the developer is typing, we may have an incomplete call statement, which means `ORDER[call]` will
  # return `nil`. In that case, invoking `sort_by` will raise
  return if calls.any? { |call| ORDER[call].nil? }
  expected_order = calls.sort_by { |call| ORDER[call] }
  return if expected_order == calls
  message = "Sig builders must be invoked in the following order: #{expected_order.join(", ")}."
  unless can_autocorrect?
    message += " For autocorrection, add the `unparser` gem to your project."
  end
  add_offense(
    node.children[2],
    message: message,
  )
  node
end