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?(elements)

def allowed_lhs?(elements)
  # 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 = Array(node).compact
  # Account for edge case of `Constant::CONSTANT`
  !node.array_type? || elements.any?(&:splat_type?)
end

def assignment_corrector(node, rhs, order)

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

def autocorrect(corrector, node, rhs)

def autocorrect(corrector, node, rhs)
  order = find_valid_order(node.assignments, Array(rhs).compact)
  correction = assignment_corrector(node, rhs, order)
  corrector.replace(correction.correction_range, correction.correction)
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)
  return false unless node
  node.basic_conditional? && node.modifier_form?
end

def on_masgn(node) # rubocop:disable Metrics/AbcSize

rubocop:disable Metrics/AbcSize
def on_masgn(node) # rubocop:disable Metrics/AbcSize
  rhs = node.rhs
  rhs = rhs.body if rhs.rescue_type?
  rhs_elements = Array(rhs).compact # edge case for one constant
  return if allowed_lhs?(node.assignments) || allowed_rhs?(rhs) ||
            allowed_masign?(node.assignments, rhs_elements)
  range = node.source_range.begin.join(rhs.source_range.end)
  add_offense(range) do |corrector|
    autocorrect(corrector, node, rhs)
  end
end