class RuboCop::Cop::Style::SwapValues
x, y = y, x
# good
y = tmp
x = y
tmp = x
# bad
@example
swap variables will be removed, but may be referred to elsewhere.
Autocorrection is unsafe, because the temporary variable used to
@safety
Enforces the use of shorthand-style swapping of 2 variables.
def allowed_assignment?(node)
def allowed_assignment?(node) node.parent&.mlhs_type? || node.parent&.shorthand_asgn? end
def correction_range(tmp_assign, y_assign)
def correction_range(tmp_assign, y_assign) range_by_whole_lines( range_between(tmp_assign.source_range.begin_pos, y_assign.source_range.end_pos) ) end
def lhs(node)
def lhs(node) case node.type when :casgn namespace, name, = *node if namespace "#{namespace.const_name}::#{name}" else name.to_s end else node.children[0].to_s end end
def message(x_assign, y_assign)
def message(x_assign, y_assign) format( MSG, x_line: x_assign.first_line, y_line: y_assign.first_line, replacement: replacement(x_assign) ) end
def on_asgn(node)
def on_asgn(node) return if allowed_assignment?(node) tmp_assign = node x_assign, y_assign = *node.right_siblings.take(2) return unless x_assign && y_assign && swapping_values?(tmp_assign, x_assign, y_assign) add_offense(node, message: message(x_assign, y_assign)) do |corrector| range = correction_range(tmp_assign, y_assign) corrector.replace(range, replacement(x_assign)) end end
def replacement(x_assign)
def replacement(x_assign) x = lhs(x_assign) y = rhs(x_assign) "#{x}, #{y} = #{y}, #{x}" end
def rhs(node)
def rhs(node) case node.type when :casgn node.children[2].source else node.children[1].source end end
def simple_assignment?(node)
def simple_assignment?(node) return false unless node.respond_to?(:type) SIMPLE_ASSIGNMENT_TYPES.include?(node.type) end
def swapping_values?(tmp_assign, x_assign, y_assign)
def swapping_values?(tmp_assign, x_assign, y_assign) simple_assignment?(tmp_assign) && simple_assignment?(x_assign) && simple_assignment?(y_assign) && lhs(x_assign) == rhs(tmp_assign) && lhs(y_assign) == rhs(x_assign) && rhs(y_assign) == lhs(tmp_assign) end