class RuboCop::Cop::Style::ParallelAssignment

c = 3
b = 2
a = 1
a, b = b, a
a, b = foo()
one, two = *foo
# good
a, b, c = [1, 2, 3]
a, b, c = 1, 2, 3
# bad
@example
being assigned matched the number of assigning variables.
This will only complain when the number of variables
Checks for simple usages of parallel assignment.

def add_self_to_getters(right_elements)

`self.a, self.b = b, a`.
This makes the sorting algorithm work for expressions such as
Converts (send nil :something) nodes to (send (:self) :something).
def add_self_to_getters(right_elements)
  right_elements.map do |e|
    implicit_self_getter?(e) { |var| s(:send, s(:self), var) } || e
  end
end

def allowed_lhs?(node)

def allowed_lhs?(node)
  elements = *node
  # Account for edge cases using one variable with a comma
  # E.g.: `foo, = *bar`
  elements.one? || elements.any?(&:splat_type?)
end

def allowed_masign?(lhs_elements, rhs_elements)

def allowed_masign?(lhs_elements, rhs_elements)
  lhs_elements.size != rhs_elements.size ||
    !find_valid_order(lhs_elements,
                      add_self_to_getters(rhs_elements))
end

def allowed_rhs?(node)

def allowed_rhs?(node)
  # Edge case for one constant
  elements = [*node].compact
  # Account for edge case of `Constant::CONSTANT`
  !node.array_type? ||
    return_of_method_call?(node) ||
    elements.any?(&:splat_type?)
end

def assignment_corrector(node, order)

def assignment_corrector(node, order)
  _assignment, modifier = *node.parent
  if modifier_statement?(node.parent)
    ModifierCorrector.new(node, config, order)
  elsif rescue_modifier?(modifier)
    RescueCorrector.new(node, config, order)
  else
    GenericCorrector.new(node, config, order)
  end
end

def autocorrect(node)

def autocorrect(node)
  lambda do |corrector|
    left, right = *node
    left_elements = *left
    right_elements = [*right].compact
    order = find_valid_order(left_elements, right_elements)
    correction = assignment_corrector(node, order)
    corrector.replace(correction.correction_range,
                      correction.correction)
  end
end

def find_valid_order(left_elements, right_elements)

def find_valid_order(left_elements, right_elements)
  # arrange left_elements in an order such that no corresponding right
  # element refers to a left element earlier in the sequence
  # this can be done using an algorithm called a "topological sort"
  # fortunately for us, Ruby's stdlib contains an implementation
  assignments = left_elements.zip(right_elements)
  begin
    AssignmentSorter.new(assignments).tsort
  rescue TSort::Cyclic
    nil
  end
end

def modifier_statement?(node)

def modifier_statement?(node)
  node && %i[if while until].include?(node.type) && node.modifier_form?
end

def on_masgn(node)

def on_masgn(node)
  lhs, rhs = *node
  lhs_elements = *lhs
  rhs_elements = [*rhs].compact # edge case for one constant
  return if allowed_lhs?(lhs) || allowed_rhs?(rhs) ||
            allowed_masign?(lhs_elements, rhs_elements)
  add_offense(node)
end

def return_of_method_call?(node)

def return_of_method_call?(node)
  node.block_type? || node.send_type?
end