class SyntaxTree::CallNode


receiver.message
CallNode represents a method call.

def ===(other)

def ===(other)
  other.is_a?(CallNode) && receiver === other.receiver &&
    operator === other.operator && message === other.message &&
    arguments === other.arguments
end

def accept(visitor)

def accept(visitor)
  visitor.visit_call(self)
end

def arity

def arity
  arguments&.arity || 0
end

def child_nodes

def child_nodes
  [
    receiver,
    (operator if operator != :"::"),
    (message if message != :call),
    arguments
  ]
end

def copy(

def copy(
  receiver: nil,
  operator: nil,
  message: nil,
  arguments: nil,
  location: nil
)
  node =
    CallNode.new(
      receiver: receiver || self.receiver,
      operator: operator || self.operator,
      message: message || self.message,
      arguments: arguments || self.arguments,
      location: location || self.location
    )
  node.comments.concat(comments.map(&:copy))
  node
end

def deconstruct_keys(_keys)

def deconstruct_keys(_keys)
  {
    receiver: receiver,
    operator: operator,
    message: message,
    arguments: arguments,
    location: location,
    comments: comments
  }
end

def format(q)

def format(q)
  if receiver
    # If we're at the top of a call chain, then we're going to do some
    # specialized printing in case we can print it nicely. We _only_ do this
    # at the top of the chain to avoid weird recursion issues.
    if CallChainFormatter.chained?(receiver) &&
         !CallChainFormatter.chained?(q.parent)
      q.group do
        q
          .if_break { CallChainFormatter.new(self).format(q) }
          .if_flat { format_contents(q) }
      end
    else
      format_contents(q)
    end
  else
    q.format(message)
    # Note that this explicitly leaves parentheses in place even if they are
    # empty. There are two reasons we would need to do this. The first is if
    # we're calling something that looks like a constant, as in:
    #
    #     Foo()
    #
    # In this case if we remove the parentheses then this becomes a constant
    # reference and not a method call. The second is if we're calling a
    # method that is the same name as a local variable that is in scope, as
    # in:
    #
    #     foo = foo()
    #
    # In this case we have to keep the parentheses or else it treats this
    # like assigning nil to the local variable. Note that we could attempt
    # to be smarter about this by tracking the local variables that are in
    # scope, but for now it's simpler and more efficient to just leave the
    # parentheses in place.
    q.format(arguments) if arguments
  end
end

def format_arguments(q)

nothing.
Print out the arguments to this call. If there are no arguments, then do
def format_arguments(q)
  case arguments
  when ArgParen
    q.format(arguments)
  when Args
    q.text(" ")
    q.format(arguments)
  end
end

def format_contents(q)

def format_contents(q)
  call_operator = CallOperatorFormatter.new(operator)
  q.group do
    q.format(receiver)
    # If there are trailing comments on the call operator, then we need to
    # use the trailing form as opposed to the leading form.
    q.format(call_operator) if call_operator.comments.any?
    q.group do
      q.indent do
        if receiver.comments.any? || call_operator.comments.any?
          q.breakable_force
        end
        if call_operator.comments.empty?
          q.format(call_operator, stackable: false)
        end
        q.format(message) if message != :call
      end
      format_arguments(q)
    end
  end
end

def initialize(receiver:, operator:, message:, arguments:, location:)

def initialize(receiver:, operator:, message:, arguments:, location:)
  @receiver = receiver
  @operator = operator
  @message = message
  @arguments = arguments
  @location = location
  @comments = []
end