module RuboCop::AST::Traversal::CallbackCompiler

def body(child_node_types, expected_children_count)

def body(child_node_types, expected_children_count)
  visit_children_code =
    child_node_types
    .map.with_index do |child_type, i|
      TEMPLATE.fetch(child_type).gsub('%<index>i', i.to_s)
    end
    .join("\n")
  <<~BODY
    #{children_count_check_code(expected_children_count)}
    #{visit_children_code}
  BODY
end

def children_count_check_code(range)

def children_count_check_code(range)
  return '' unless ENV.fetch('RUBOCOP_DEBUG', false)
  <<~RUBY
    n = node.children.size
    raise DebugError, [
      'Expected #{range} children, got',
      n, 'for', node.inspect
    ].join(' ') unless (#{range}).cover?(node.children.size)
  RUBY
end

def def_callback(type, *child_node_types,

def def_callback(type, *child_node_types,
                 expected_children_count: child_node_types.size..child_node_types.size,
                 body: self.body(child_node_types, expected_children_count))
  type, *aliases = type
  lineno = caller_locations(1, 1).first.lineno
  module_eval(<<~RUBY, __FILE__, lineno)
    def on_#{type}(node)        # def on_send(node)
      #{body}                   #   # body ...
      nil                       #   nil
    end                         # end
  RUBY
  aliases.each do |m|
    alias_method :"on_#{m}", :"on_#{type}"
  end
end