text: /**
   * @fileoverview Rule to disallow assignments where both sides are exactly the same
   * @author Toru Nagashima
   * @copyright 2016 Toru Nagashima. All rights reserved.
   * See LICENSE file in root directory for full license.
   */
  
  "use strict";
  
  //------------------------------------------------------------------------------
  // Helpers
  //------------------------------------------------------------------------------
  
  /**
   * Traverses 2 Pattern nodes in parallel, then reports self-assignments.
   *
   * @param {ASTNode|null} left - A left node to traverse. This is a Pattern or
   *      a Property.
   * @param {ASTNode|null} right - A right node to traverse. This is a Pattern or
   *      a Property.
   * @param {function} report - A callback function to report.
   * @returns {void}
   */
  function eachSelfAssignment(left, right, report) {
      var i, j;
  
      if (!left || !right) {
  
          // do nothing
      } else if (
          left.type === "Identifier" &&
          right.type === "Identifier" &&
          left.name === right.name
      ) {
          report(right);
      } else if (
          left.type === "ArrayPattern" &&
          right.type === "ArrayExpression"
      ) {
          var end = Math.min(left.elements.length, right.elements.length);
  
          for (i = 0; i < end; ++i) {
              var rightElement = right.elements[i];
  
              eachSelfAssignment(left.elements[i], rightElement, report);
  
              // After a spread element, those indices are unknown.
              if (rightElement && rightElement.type === "SpreadElement") {
                  break;
              }
          }
      } else if (
          left.type === "RestElement" &&
          right.type === "SpreadElement"
      ) {
          eachSelfAssignment(left.argument, right.argument, report);
      } else if (
          left.type === "ObjectPattern" &&
          right.type === "ObjectExpression" &&
          right.properties.length >= 1
      ) {
  
          // Gets the index of the last spread property.
          // It's possible to overwrite properties followed by it.
          var startJ = 0;
  
          for (i = right.properties.length - 1; i >= 0; --i) {
              if (right.properties[i].type === "ExperimentalSpreadProperty") {
                  startJ = i + 1;
                  break;
              }
          }
  
          for (i = 0; i < left.properties.length; ++i) {
              for (j = startJ; j < right.properties.length; ++j) {
                  eachSelfAssignment(
                      left.properties[i],
                      right.properties[j],
                      report
                  );
              }
          }
      } else if (
          left.type === "Property" &&
          right.type === "Property" &&
          !left.computed &&
          !right.computed &&
          right.kind === "init" &&
          !right.method &&
          left.key.name === right.key.name
      ) {
          eachSelfAssignment(left.value, right.value, report);
      }
  }
  
  //------------------------------------------------------------------------------
  // Rule Definition
  //------------------------------------------------------------------------------
  
  module.exports = function(context) {
  
      /**
       * Reports a given node as self assignments.
       *
       * @param {ASTNode} node - A node to report. This is an Identifier node.
       * @returns {void}
       */
      function report(node) {
          context.report({
              node: node,
              message: "'{{name}}' is assigned to itself.",
              data: node
          });
      }
  
      return {
          "AssignmentExpression": function(node) {
              if (node.operator === "=") {
                  eachSelfAssignment(node.left, node.right, report);
              }
          }
      };
  };
  
  module.exports.schema = [];
  