/** For each node, update the block stack and reference collection as appropriate. */
  @Override
  public void visit(NodeTraversal t, Node n, Node parent) {
    if (n.isName()
        || n.isRest()
        || (n.isStringKey() && parent.isObjectPattern() && !n.hasChildren())) {
      Var v;
      if (n.getString().equals("arguments")) {
        v = t.getScope().getArgumentsVar();
      } else {
        v = t.getScope().getVar(n.getString());
      }

      if (v != null) {
        if (varFilter.apply(v)) {
          addReference(v, new Reference(n, t, peek(blockStack)));
        }

        if (v.getParentNode() != null
            && NodeUtil.isHoistedFunctionDeclaration(v.getParentNode())
            &&
            // If we're only traversing a narrow scope, do not try to climb outside.
            (narrowScope == null || narrowScope.getDepth() <= v.getScope().getDepth())) {
          outOfBandTraversal(v);
        }
      }
    }

    if (isBlockBoundary(n, parent)) {
      pop(blockStack);
    }
  }
 /** @return The first property in the objlit that matches the key. */
 private static Node extractProperty(Node objlit, String keyName) {
   for (Node keyNode : objlit.children()) {
     if (keyNode.getString().equals(keyName)) {
       return keyNode.isStringKey() ? keyNode.getFirstChild() : null;
     }
   }
   return null;
 }
 // Only unquoted plain properties are currently supported.
 private static boolean validateObjLit(Node objlit) {
   for (Node key : objlit.children()) {
     if (!key.isStringKey() || key.isQuotedString()) {
       return false;
     }
   }
   return true;
 }
 private boolean hasShorthandAssignment(Node objLit) {
   Preconditions.checkState(objLit.isObjectLit());
   for (Node property : objLit.children()) {
     if (property.isStringKey() && !property.hasChildren()) {
       return true;
     }
   }
   return false;
 }
 private boolean isContainedInGoogDefineClass(Node n) {
   while (n != null) {
     n = n.getParent();
     if (n.isCall()) {
       if (isGoogDefineClass(n)) {
         return true;
       }
     } else if (!n.isObjectLit() && !n.isStringKey()) {
       break;
     }
   }
   return false;
 }
Example #6
0
 private void validateObjectPattern(int type, Node n) {
   validateNodeType(Token.OBJECT_PATTERN, n);
   for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
     // When the object pattern is a direct child of a var/let/const node,
     // the last element is the RHS of the assignment.
     if (c == n.getLastChild() && NodeUtil.isNameDeclaration(n.getParent())) {
       validateExpression(c);
     } else if (c.isStringKey()) {
       validateObjectPatternStringKey(type, c);
     } else {
       // Nested destructuring pattern.
       validateNameDeclarationChild(type, c);
     }
   }
 }
  /**
   * @return A list of functions from a behavior which should be copied to the element prototype.
   */
  private List<MemberDefinition> getBehaviorFunctionsToCopy(Node behaviorObjLit) {
    Preconditions.checkState(behaviorObjLit.isObjectLit());
    ImmutableList.Builder<MemberDefinition> functionsToCopy = ImmutableList.builder();

    for (Node keyNode : behaviorObjLit.children()) {
      if ((keyNode.isStringKey() && keyNode.getFirstChild().isFunction()
              || keyNode.isMemberFunctionDef())
          && !behaviorNamesNotToCopy.contains(keyNode.getString())) {
        functionsToCopy.add(
            new MemberDefinition(
                NodeUtil.getBestJSDocInfo(keyNode), keyNode, keyNode.getFirstChild()));
      }
    }

    return functionsToCopy.build();
  }
    private static boolean isDeclarationHelper(Node node) {
      Node parent = node.getParent();

      // Special case for class B extends A, A is not a declaration.
      if (parent.isClass() && node != parent.getFirstChild()) {
        return false;
      }

      // This condition can be true during InlineVariables.
      if (parent.getParent() == null) {
        return false;
      }

      if (NodeUtil.isNameDeclaration(parent.getParent()) && node == parent.getLastChild()) {
        // Unless it is something like "for (var/let/const a of x){}",
        // this is the RHS of a var/let/const and thus not a declaration.
        if (parent.getParent().getParent() == null || !parent.getParent().getParent().isForOf()) {
          return false;
        }
      }

      // Special cases for destructuring patterns.
      if (parent.isDestructuringPattern()
          || (parent.isStringKey() && parent.getParent().isObjectPattern())
          || (parent.isComputedProp()
              && parent.getParent().isObjectPattern()
              && node == parent.getLastChild())
          || (parent.isDefaultValue() && node == parent.getFirstChild())) {
        return isDeclarationHelper(parent);
      }

      // Special case for arrow function
      if (parent.isArrowFunction()) {
        return node == parent.getFirstChild();
      }

      return DECLARATION_PARENTS.contains(parent.getType());
    }
  private void visitArrayPattern(NodeTraversal t, Node arrayPattern, Node parent) {
    Node rhs, nodeToDetach;
    if (NodeUtil.isNameDeclaration(parent) && !NodeUtil.isEnhancedFor(parent.getParent())) {
      // The array pattern is the only child, because Es6SplitVariableDeclarations
      // has already run.
      Preconditions.checkState(arrayPattern.getNext() == null);
      rhs = arrayPattern.getLastChild();
      nodeToDetach = parent;
    } else if (parent.isAssign()) {
      rhs = arrayPattern.getNext();
      nodeToDetach = parent.getParent();
      Preconditions.checkState(nodeToDetach.isExprResult());
    } else if (parent.isArrayPattern() || parent.isDefaultValue() || parent.isStringKey()) {
      // This is a nested array pattern. Don't do anything now; we'll visit it
      // after visiting the parent.
      return;
    } else if (NodeUtil.isEnhancedFor(parent) || NodeUtil.isEnhancedFor(parent.getParent())) {
      visitDestructuringPatternInEnhancedFor(arrayPattern);
      return;
    } else {
      Preconditions.checkState(parent.isCatch() || parent.isForOf());
      cannotConvertYet(
          arrayPattern, "ARRAY_PATTERN that is a child of a " + Token.name(parent.getType()));
      return;
    }

    // Convert 'var [x, y] = rhs' to:
    // var temp = rhs;
    // var x = temp[0];
    // var y = temp[1];
    String tempVarName = DESTRUCTURING_TEMP_VAR + (destructuringVarCounter++);
    Node tempDecl =
        IR.var(IR.name(tempVarName), rhs.detachFromParent())
            .useSourceInfoIfMissingFromForTree(arrayPattern);
    nodeToDetach.getParent().addChildBefore(tempDecl, nodeToDetach);

    int i = 0;
    for (Node child = arrayPattern.getFirstChild(), next; child != null; child = next, i++) {
      next = child.getNext();
      if (child.isEmpty()) {
        continue;
      }

      Node newLHS, newRHS;
      if (child.isDefaultValue()) {
        Node getElem = IR.getelem(IR.name(tempVarName), IR.number(i));
        //   [x = defaultValue] = rhs;
        // becomes
        //   var temp = rhs;
        //   x = (temp[0] === undefined) ? defaultValue : temp[0];
        newLHS = child.getFirstChild().detachFromParent();
        newRHS = defaultValueHook(getElem, child.getLastChild().detachFromParent());
      } else if (child.isRest()) {
        newLHS = child.detachFromParent();
        newLHS.setType(Token.NAME);
        // [].slice.call(temp, i)
        newRHS =
            IR.call(
                IR.getprop(IR.getprop(IR.arraylit(), IR.string("slice")), IR.string("call")),
                IR.name(tempVarName),
                IR.number(i));
      } else {
        newLHS = child.detachFromParent();
        newRHS = IR.getelem(IR.name(tempVarName), IR.number(i));
      }
      Node newNode;
      if (parent.isAssign()) {
        Node assignment = IR.assign(newLHS, newRHS);
        newNode = IR.exprResult(assignment);
      } else {
        newNode = IR.declaration(newLHS, newRHS, parent.getType());
      }
      newNode.useSourceInfoIfMissingFromForTree(arrayPattern);

      nodeToDetach.getParent().addChildBefore(newNode, nodeToDetach);
      // Explicitly visit the LHS of the new node since it may be a nested
      // destructuring pattern.
      visit(t, newLHS, newLHS.getParent());
    }
    nodeToDetach.detachFromParent();
    compiler.reportCodeChange();
  }
  private void visitObjectPattern(NodeTraversal t, Node objectPattern, Node parent) {
    Node rhs, nodeToDetach;
    if (NodeUtil.isNameDeclaration(parent) && !NodeUtil.isEnhancedFor(parent.getParent())) {
      rhs = objectPattern.getLastChild();
      nodeToDetach = parent;
    } else if (parent.isAssign() && parent.getParent().isExprResult()) {
      rhs = parent.getLastChild();
      nodeToDetach = parent.getParent();
    } else if (parent.isStringKey() || parent.isArrayPattern() || parent.isDefaultValue()) {
      // Nested object pattern; do nothing. We will visit it after rewriting the parent.
      return;
    } else if (NodeUtil.isEnhancedFor(parent) || NodeUtil.isEnhancedFor(parent.getParent())) {
      visitDestructuringPatternInEnhancedFor(objectPattern);
      return;
    } else {
      Preconditions.checkState(parent.isCatch(), parent);
      cannotConvertYet(
          objectPattern, "OBJECT_PATTERN that is a child of a " + Token.name(parent.getType()));
      return;
    }

    // Convert 'var {a: b, c: d} = rhs' to:
    // var temp = rhs;
    // var b = temp.a;
    // var d = temp.c;
    String tempVarName = DESTRUCTURING_TEMP_VAR + (destructuringVarCounter++);
    Node tempDecl =
        IR.var(IR.name(tempVarName), rhs.detachFromParent())
            .useSourceInfoIfMissingFromForTree(objectPattern);
    nodeToDetach.getParent().addChildBefore(tempDecl, nodeToDetach);

    for (Node child = objectPattern.getFirstChild(), next; child != null; child = next) {
      next = child.getNext();

      Node newLHS, newRHS;
      if (child.isStringKey()) {
        Preconditions.checkState(child.hasChildren());
        Node getprop =
            new Node(
                child.isQuotedString() ? Token.GETELEM : Token.GETPROP,
                IR.name(tempVarName),
                IR.string(child.getString()));

        Node value = child.removeFirstChild();
        if (!value.isDefaultValue()) {
          newLHS = value;
          newRHS = getprop;
        } else {
          newLHS = value.removeFirstChild();
          Node defaultValue = value.removeFirstChild();
          newRHS = defaultValueHook(getprop, defaultValue);
        }
      } else if (child.isComputedProp()) {
        if (child.getLastChild().isDefaultValue()) {
          newLHS = child.getLastChild().removeFirstChild();
          Node getelem = IR.getelem(IR.name(tempVarName), child.removeFirstChild());

          String intermediateTempVarName = DESTRUCTURING_TEMP_VAR + (destructuringVarCounter++);
          Node intermediateDecl = IR.var(IR.name(intermediateTempVarName), getelem);
          intermediateDecl.useSourceInfoIfMissingFromForTree(child);
          nodeToDetach.getParent().addChildBefore(intermediateDecl, nodeToDetach);

          newRHS =
              defaultValueHook(
                  IR.name(intermediateTempVarName), child.getLastChild().removeFirstChild());
        } else {
          newRHS = IR.getelem(IR.name(tempVarName), child.removeFirstChild());
          newLHS = child.removeFirstChild();
        }
      } else if (child.isDefaultValue()) {
        newLHS = child.removeFirstChild();
        Node defaultValue = child.removeFirstChild();
        Node getprop = IR.getprop(IR.name(tempVarName), IR.string(newLHS.getString()));
        newRHS = defaultValueHook(getprop, defaultValue);
      } else {
        throw new IllegalStateException("Unexpected OBJECT_PATTERN child: " + child);
      }

      Node newNode;
      if (NodeUtil.isNameDeclaration(parent)) {
        newNode = IR.declaration(newLHS, newRHS, parent.getType());
      } else if (parent.isAssign()) {
        newNode = IR.exprResult(IR.assign(newLHS, newRHS));
      } else {
        throw new IllegalStateException("not reached");
      }
      newNode.useSourceInfoIfMissingFromForTree(child);

      nodeToDetach.getParent().addChildBefore(newNode, nodeToDetach);

      // Explicitly visit the LHS of the new node since it may be a nested
      // destructuring pattern.
      visit(t, newLHS, newLHS.getParent());
    }

    nodeToDetach.detachFromParent();
    compiler.reportCodeChange();
  }