Java Code Examples for com.google.javascript.rhino.Node#removeChild()

The following examples show how to use com.google.javascript.rhino.Node#removeChild() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: Cardumen_0014_t.java    From coming with MIT License 6 votes vote down vote up
/**
 * Merge a block with its parent block.
 * @return Whether the block was removed.
 */
static boolean tryMergeBlock(Node block) {
  Preconditions.checkState(block.isBlock());
  Node parent = block.getParent();
  // Try to remove the block if its parent is a block/script or if its
  // parent is label and it has exactly one child.
  if (isStatementBlock(parent)) {
    Node previous = block;
    while (block.hasChildren()) {
      Node child = block.removeFirstChild();
      parent.addChildAfter(child, previous);
      previous = child;
    }
    parent.removeChild(block);
    return true;
  } else {
    return false;
  }
}
 
Example 2
Source File: Cardumen_00200_t.java    From coming with MIT License 6 votes vote down vote up
/**
 * Merge a block with its parent block.
 * @return Whether the block was removed.
 */
static boolean tryMergeBlock(Node block) {
  Preconditions.checkState(block.isBlock());
  Node parent = block.getParent();
  // Try to remove the block if its parent is a block/script or if its
  // parent is label and it has exactly one child.
  if (isStatementBlock(parent)) {
    Node previous = block;
    while (block.hasChildren()) {
      Node child = block.removeFirstChild();
      parent.addChildAfter(child, previous);
      previous = child;
    }
    parent.removeChild(block);
    return true;
  } else {
    return false;
  }
}
 
Example 3
Source File: MoveFunctionDeclarations.java    From astor with GNU General Public License v2.0 6 votes vote down vote up
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
  if (parent == null || !parent.isScript()) {
    return;
  }

  if (NodeUtil.isFunctionDeclaration(n)) {
    parent.removeChild(n);
    compiler.reportCodeChange();

    JSModule module = t.getModule();
    List<Node> moduleFunctions = functions.get(module);
    if (moduleFunctions == null) {
      moduleFunctions = Lists.newArrayList();
      functions.put(module, moduleFunctions);
    }
    moduleFunctions.add(n);
  }
}
 
Example 4
Source File: StripCode.java    From astor with GNU General Public License v2.0 6 votes vote down vote up
/**
 * Eliminates any object literal keys in an object literal declaration that
 * have strip names.
 *
 * @param t The traversal
 * @param n An OBJLIT node
 */
void eliminateKeysWithStripNamesFromObjLit(NodeTraversal t, Node n) {
  // OBJLIT
  //   key1
  //     value1
  //   key2
  //   ...
  Node key = n.getFirstChild();
  while (key != null) {
    if (isStripName(key.getString())) {
      Node value = key.getFirstChild();
      Node next = key.getNext();
      n.removeChild(key);
      key = next;
      compiler.reportCodeChange();
    } else {
      key = key.getNext();
    }
  }
}
 
Example 5
Source File: Closure_121_InlineVariables_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove the given VAR declaration.
 */
private void removeDeclaration(Reference decl) {
  Node varNode = decl.getParent();
  Node grandparent = decl.getGrandparent();

  compiler.reportChangeToEnclosingScope(decl.getNode());
  varNode.removeChild(decl.getNode());
  // Remove var node if empty
  if (!varNode.hasChildren()) {
    Preconditions.checkState(varNode.isVar());
    NodeUtil.removeChild(grandparent, varNode);
  }
}
 
Example 6
Source File: Closure_74_PeepholeFoldConstants_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Expressions such as [foo() * 10 * 20] generate parse trees
 * where no node has two const children ((foo() * 10) * 20), so
 * performArithmeticOp() won't fold it -- tryFoldLeftChildOp() will.
 * Specifically it folds associative expressions where:
 *  - The left child is also an associative expression of the same time.
 *  - The right child is a constant NUMBER constant.
 *  - The left child's right child is a NUMBER constant.
 */
private Node tryFoldLeftChildOp(Node n, Node left, Node right) {
  int opType = n.getType();
  Preconditions.checkState(
      (NodeUtil.isAssociative(opType) && NodeUtil.isCommutative(opType))
      || n.getType() == Token.ADD);

  Preconditions.checkState(
      n.getType() != Token.ADD || !NodeUtil.mayBeString(n));

  // Use getNumberValue to handle constants like "NaN" and "Infinity"
  // other values are converted to numbers elsewhere.
  Double rightValObj = NodeUtil.getNumberValue(right);
  if (rightValObj != null && left.getType() == opType) {
    Preconditions.checkState(left.getChildCount() == 2);

    Node ll = left.getFirstChild();
    Node lr = ll.getNext();

    Node valueToCombine = ll;
    Node replacement = performArithmeticOp(opType, valueToCombine, right);
    if (replacement == null) {
      valueToCombine = lr;
      replacement = performArithmeticOp(opType, valueToCombine, right);
    }
    if (replacement != null) {
      // Remove the child that has been combined
      left.removeChild(valueToCombine);
      // Replace the left op with the remaining child.
      n.replaceChild(left, left.removeFirstChild());
      // New "-Infinity" node need location info explicitly
      // added.
      replacement.copyInformationFromForTree(right);
      n.replaceChild(right, replacement);
      reportCodeChange();
    }
  }

  return n;
}
 
Example 7
Source File: Closure_45_RemoveUnusedVars_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Replace the current assign with its right hand side.
 */
void remove() {
  Node parent = assignNode.getParent();
  if (mayHaveSecondarySideEffects) {
    Node replacement = assignNode.getLastChild().detachFromParent();

    // Aggregate any expressions in GETELEMs.
    for (Node current = assignNode.getFirstChild();
         !current.isName();
         current = current.getFirstChild()) {
      if (current.isGetElem()) {
        replacement = IR.comma(
            current.getLastChild().detachFromParent(), replacement);
        replacement.copyInformationFrom(current);
      }
    }

    parent.replaceChild(assignNode, replacement);
  } else {
    Node gramps = parent.getParent();
    if (parent.isExprResult()) {
      gramps.removeChild(parent);
    } else {
      parent.replaceChild(assignNode,
          assignNode.getLastChild().detachFromParent());
    }
  }
}
 
Example 8
Source File: Closure_1_RemoveUnusedVars_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Replace the current assign with its right hand side.
 */
void remove() {
  Node parent = assignNode.getParent();
  if (mayHaveSecondarySideEffects) {
    Node replacement = assignNode.getLastChild().detachFromParent();

    // Aggregate any expressions in GETELEMs.
    for (Node current = assignNode.getFirstChild();
         !current.isName();
         current = current.getFirstChild()) {
      if (current.isGetElem()) {
        replacement = IR.comma(
            current.getLastChild().detachFromParent(), replacement);
        replacement.copyInformationFrom(current);
      }
    }

    parent.replaceChild(assignNode, replacement);
  } else {
    Node gramps = parent.getParent();
    if (parent.isExprResult()) {
      gramps.removeChild(parent);
    } else {
      parent.replaceChild(assignNode,
          assignNode.getLastChild().detachFromParent());
    }
  }
}
 
Example 9
Source File: jKali_007_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Removes unreferenced arguments from a function declaration and when
 * possible the function's callSites.
 *
 * @param fnScope The scope inside the function
 */
private void removeUnreferencedFunctionArgs(Scope fnScope) {
  // TODO(johnlenz): Update type registry for function signature changes.

  Node function = fnScope.getRootNode();

  Preconditions.checkState(function.isFunction());
  if (NodeUtil.isGetOrSetKey(function.getParent())) {
    // The parameters object literal setters can not be removed.
    return;
  }

  Node argList = getFunctionArgList(function);
  boolean modifyCallers = modifyCallSites
      && callSiteOptimizer.canModifyCallers(function);
  if (!modifyCallers) {
    // Strip unreferenced args off the end of the function declaration.
    Node lastArg;
    while ((lastArg = argList.getLastChild()) != null) {
      Var var = fnScope.getVar(lastArg.getString());
      if (!referenced.contains(var)) {
        argList.removeChild(lastArg);
        compiler.reportCodeChange();
      } else {
        break;
      }
    }
  } else {
    callSiteOptimizer.optimize(fnScope, referenced);
  }
}
 
Example 10
Source File: Closure_23_PeepholeFoldConstants_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Expressions such as [foo() * 10 * 20] generate parse trees
 * where no node has two const children ((foo() * 10) * 20), so
 * performArithmeticOp() won't fold it -- tryFoldLeftChildOp() will.
 * Specifically, it folds associative expressions where:
 *  - The left child is also an associative expression of the same time.
 *  - The right child is a constant NUMBER constant.
 *  - The left child's right child is a NUMBER constant.
 */
private Node tryFoldLeftChildOp(Node n, Node left, Node right) {
  int opType = n.getType();
  Preconditions.checkState(
      (NodeUtil.isAssociative(opType) && NodeUtil.isCommutative(opType))
      || n.isAdd());

  Preconditions.checkState(
      !n.isAdd()|| !NodeUtil.mayBeString(n));

  // Use getNumberValue to handle constants like "NaN" and "Infinity"
  // other values are converted to numbers elsewhere.
  Double rightValObj = NodeUtil.getNumberValue(right);
  if (rightValObj != null && left.getType() == opType) {
    Preconditions.checkState(left.getChildCount() == 2);

    Node ll = left.getFirstChild();
    Node lr = ll.getNext();

    Node valueToCombine = ll;
    Node replacement = performArithmeticOp(opType, valueToCombine, right);
    if (replacement == null) {
      valueToCombine = lr;
      replacement = performArithmeticOp(opType, valueToCombine, right);
    }
    if (replacement != null) {
      // Remove the child that has been combined
      left.removeChild(valueToCombine);
      // Replace the left op with the remaining child.
      n.replaceChild(left, left.removeFirstChild());
      // New "-Infinity" node need location info explicitly
      // added.
      replacement.copyInformationFromForTree(right);
      n.replaceChild(right, replacement);
      reportCodeChange();
    }
  }

  return n;
}
 
Example 11
Source File: Cardumen_00249_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Replace the current assign with its right hand side.
 */
void remove() {
  Node parent = assignNode.getParent();
  if (mayHaveSecondarySideEffects) {
    Node replacement = assignNode.getLastChild().detachFromParent();

    // Aggregate any expressions in GETELEMs.
    for (Node current = assignNode.getFirstChild();
         !current.isName();
         current = current.getFirstChild()) {
      if (current.isGetElem()) {
        replacement = IR.comma(
            current.getLastChild().detachFromParent(), replacement);
        replacement.copyInformationFrom(current);
      }
    }

    parent.replaceChild(assignNode, replacement);
  } else {
    Node gramps = parent.getParent();
    if (parent.isExprResult()) {
      gramps.removeChild(parent);
    } else {
      parent.replaceChild(assignNode,
          assignNode.getLastChild().detachFromParent());
    }
  }
}
 
Example 12
Source File: Cardumen_00249_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Removes unreferenced arguments from a function declaration and when
 * possible the function's callSites.
 *
 * @param fnScope The scope inside the function
 */
private void removeUnreferencedFunctionArgs(Scope fnScope) {
  // TODO(johnlenz): Update type registry for function signature changes.

  Node function = fnScope.getRootNode();

  Preconditions.checkState(function.isFunction());
  if (NodeUtil.isGetOrSetKey(function.getParent())) {
    // The parameters object literal setters can not be removed.
    return;
  }

  Node argList = getFunctionArgList(function);
  boolean modifyCallers = modifyCallSites
      && callSiteOptimizer.canModifyCallers(function);
  if (!modifyCallers) {
    // Strip unreferenced args off the end of the function declaration.
    Node lastArg;
    while ((lastArg = argList.getLastChild()) != null) {
      Var var = fnScope.getVar(lastArg.getString());
      if (!referenced.contains(var)) {
        argList.removeChild(lastArg);
        compiler.reportCodeChange();
      } else {
        break;
      }
    }
  } else {
    callSiteOptimizer.optimize(fnScope, referenced);
  }
}
 
Example 13
Source File: Closure_36_InlineVariables_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Remove the given VAR declaration.
 */
private void removeDeclaration(Reference declaration) {
  Node varNode = declaration.getParent();
  Node grandparent = declaration.getGrandparent();

  varNode.removeChild(declaration.getNode());

  // Remove var node if empty
  if (!varNode.hasChildren()) {
    Preconditions.checkState(varNode.isVar());
    NodeUtil.removeChild(grandparent, varNode);
  }

  compiler.reportCodeChange();
}
 
Example 14
Source File: CollapseProperties.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Declares global variables to serve as aliases for the values in an object
 * literal, optionally removing all of the object literal's keys and values.
 *
 * @param alias The object literal's flattened name (e.g. "a$b$c")
 * @param objlit The OBJLIT node
 * @param varNode The VAR node to which new global variables should be added
 *     as children
 * @param nameToAddAfter The child of {@code varNode} after which new
 *     variables should be added (may be null)
 * @param varParent {@code varNode}'s parent
 * @return The number of variables added
 */
private int declareVarsForObjLitValues(
    Name objlitName, String alias, Node objlit, Node varNode,
    Node nameToAddAfter, Node varParent) {
  int numVars = 0;
  int arbitraryNameCounter = 0;
  boolean discardKeys = !objlitName.shouldKeepKeys();

  for (Node key = objlit.getFirstChild(), nextKey; key != null;
       key = nextKey) {
    Node value = key.getFirstChild();
    nextKey = key.getNext();

    // A get or a set can not be rewritten as a VAR.
    if (key.isGetterDef() || key.isSetterDef()) {
      continue;
    }

    // We generate arbitrary names for keys that aren't valid JavaScript
    // identifiers, since those keys are never referenced. (If they were,
    // this object literal's child names wouldn't be collapsible.) The only
    // reason that we don't eliminate them entirely is the off chance that
    // their values are expressions that have side effects.
    boolean isJsIdentifier = !key.isNumber() &&
                             TokenStream.isJSIdentifier(key.getString());
    String propName = isJsIdentifier ?
        key.getString() : String.valueOf(++arbitraryNameCounter);

    // If the name cannot be collapsed, skip it.
    String qName = objlitName.getFullName() + '.' + propName;
    Name p = nameMap.get(qName);
    if (p != null && !p.canCollapse()) {
      continue;
    }

    String propAlias = appendPropForAlias(alias, propName);
    Node refNode = null;
    if (discardKeys) {
      objlit.removeChild(key);
      value.detachFromParent();
    } else {
      // Substitute a reference for the value.
      refNode = IR.name(propAlias);
      if (key.getBooleanProp(Node.IS_CONSTANT_NAME)) {
        refNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
      }

      key.replaceChild(value, refNode);
    }

    // Declare the collapsed name as a variable with the original value.
    Node nameNode = IR.name(propAlias);
    nameNode.addChildToFront(value);
    if (key.getBooleanProp(Node.IS_CONSTANT_NAME)) {
      nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
    }
    Node newVar = IR.var(nameNode)
        .copyInformationFromForTree(key);
    if (nameToAddAfter != null) {
      varParent.addChildAfter(newVar, nameToAddAfter);
    } else {
      varParent.addChildBefore(newVar, varNode);
    }
    compiler.reportCodeChange();
    nameToAddAfter = newVar;

    // Update the global name's node ancestry if it hasn't already been
    // done. (Duplicate keys in an object literal can bring us here twice
    // for the same global name.)
    if (isJsIdentifier && p != null) {
      if (!discardKeys) {
        Ref newAlias =
            p.getDeclaration().cloneAndReclassify(Ref.Type.ALIASING_GET);
        newAlias.node = refNode;
        p.addRef(newAlias);
      }

      p.getDeclaration().node = nameNode;

      if (value.isFunction()) {
        checkForHosedThisReferences(value, value.getJSDocInfo(), p);
      }
    }

    numVars++;
  }
  return numVars;
}
 
Example 15
Source File: Closure_23_PeepholeFoldConstants_t.java    From coming with MIT License 4 votes vote down vote up
private Node tryFoldArrayAccess(Node n, Node left, Node right) {
  Node parent = n.getParent();
  // If GETPROP/GETELEM is used as assignment target the array literal is
  // acting as a temporary we can't fold it here:
  //    "[][0] += 1"
  if (isAssignmentTarget(n)) {
    return n;
  }

  if (!right.isNumber()) {
    // Sometimes people like to use complex expressions to index into
    // arrays, or strings to index into array methods.
    return n;
  }

  double index = right.getDouble();
  int intIndex = (int) index;
  if (intIndex != index) {
    error(INVALID_GETELEM_INDEX_ERROR, right);
    return n;
  }

  if (intIndex < 0) {
    error(INDEX_OUT_OF_BOUNDS_ERROR, right);
    return n;
  }

  Node current = left.getFirstChild();
  Node elem = null;
  for (int i = 0; current != null; i++) {
    if (i != intIndex) {
      if (mayHaveSideEffects(current)) {
        return n;
      }
    } else {
      elem = current;
    }

    current = current.getNext();
  }

  if (elem == null) {
    error(INDEX_OUT_OF_BOUNDS_ERROR, right);
    return n;
  }

  if (elem.isEmpty()) {
    elem = NodeUtil.newUndefinedNode(elem);
  } else {
    left.removeChild(elem);
  }

  // Replace the entire GETELEM with the value
  n.getParent().replaceChild(n, elem);
  reportCodeChange();
  return elem;
}
 
Example 16
Source File: Closure_130_CollapseProperties_s.java    From coming with MIT License 4 votes vote down vote up
/**
 * Declares global variables to serve as aliases for the values in an object
 * literal, optionally removing all of the object literal's keys and values.
 *
 * @param alias The object literal's flattened name (e.g. "a$b$c")
 * @param objlit The OBJLIT node
 * @param varNode The VAR node to which new global variables should be added
 *     as children
 * @param nameToAddAfter The child of {@code varNode} after which new
 *     variables should be added (may be null)
 * @param varParent {@code varNode}'s parent
 * @return The number of variables added
 */
private int declareVarsForObjLitValues(
    Name objlitName, String alias, Node objlit, Node varNode,
    Node nameToAddAfter, Node varParent) {
  int numVars = 0;
  int arbitraryNameCounter = 0;
  boolean discardKeys = !objlitName.shouldKeepKeys();

  for (Node key = objlit.getFirstChild(), nextKey; key != null;
       key = nextKey) {
    Node value = key.getFirstChild();
    nextKey = key.getNext();

    // A get or a set can not be rewritten as a VAR.
    if (key.isGetterDef() || key.isSetterDef()) {
      continue;
    }

    // We generate arbitrary names for keys that aren't valid JavaScript
    // identifiers, since those keys are never referenced. (If they were,
    // this object literal's child names wouldn't be collapsible.) The only
    // reason that we don't eliminate them entirely is the off chance that
    // their values are expressions that have side effects.
    boolean isJsIdentifier = !key.isNumber() &&
                             TokenStream.isJSIdentifier(key.getString());
    String propName = isJsIdentifier ?
        key.getString() : String.valueOf(++arbitraryNameCounter);

    // If the name cannot be collapsed, skip it.
    String qName = objlitName.getFullName() + '.' + propName;
    Name p = nameMap.get(qName);
    if (p != null && !p.canCollapse()) {
      continue;
    }

    String propAlias = appendPropForAlias(alias, propName);
    Node refNode = null;
    if (discardKeys) {
      objlit.removeChild(key);
      value.detachFromParent();
    } else {
      // Substitute a reference for the value.
      refNode = IR.name(propAlias);
      if (key.getBooleanProp(Node.IS_CONSTANT_NAME)) {
        refNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
      }

      key.replaceChild(value, refNode);
    }

    // Declare the collapsed name as a variable with the original value.
    Node nameNode = IR.name(propAlias);
    nameNode.addChildToFront(value);
    if (key.getBooleanProp(Node.IS_CONSTANT_NAME)) {
      nameNode.putBooleanProp(Node.IS_CONSTANT_NAME, true);
    }
    Node newVar = IR.var(nameNode)
        .copyInformationFromForTree(key);
    if (nameToAddAfter != null) {
      varParent.addChildAfter(newVar, nameToAddAfter);
    } else {
      varParent.addChildBefore(newVar, varNode);
    }
    compiler.reportCodeChange();
    nameToAddAfter = newVar;

    // Update the global name's node ancestry if it hasn't already been
    // done. (Duplicate keys in an object literal can bring us here twice
    // for the same global name.)
    if (isJsIdentifier && p != null) {
      if (!discardKeys) {
        Ref newAlias =
            p.getDeclaration().cloneAndReclassify(Ref.Type.ALIASING_GET);
        newAlias.node = refNode;
        p.addRef(newAlias);
      }

      p.getDeclaration().node = nameNode;

      if (value.isFunction()) {
        checkForHosedThisReferences(value, value.getJSDocInfo(), p);
      }
    }

    numVars++;
  }
  return numVars;
}
 
Example 17
Source File: Closure_1_RemoveUnusedVars_t.java    From coming with MIT License 4 votes vote down vote up
/**
 * Removes unreferenced arguments from a function declaration and when
 * possible the function's callSites.
 *
 * @param fnScope The scope inside the function
 */
private void removeUnreferencedFunctionArgs(Scope fnScope) {
  // Notice that removing unreferenced function args breaks
  // Function.prototype.length. In advanced mode, we don't really care
  // about this: we consider "length" the equivalent of reflecting on
  // the function's lexical source.
  //
  // Rather than create a new option for this, we assume that if the user
  // is removing globals, then it's OK to remove unused function args.
  //
  // See http://code.google.com/p/closure-compiler/issues/detail?id=253
  if (!removeGlobals) {
    return;
  }

  Node function = fnScope.getRootNode();

  Preconditions.checkState(function.isFunction());
  if (NodeUtil.isGetOrSetKey(function.getParent())) {
    // The parameters object literal setters can not be removed.
    return;
  }

  Node argList = getFunctionArgList(function);
  boolean modifyCallers = modifyCallSites
      && callSiteOptimizer.canModifyCallers(function);
  if (!modifyCallers) {
    // Strip unreferenced args off the end of the function declaration.
    Node lastArg;
    while ((lastArg = argList.getLastChild()) != null) {
      Var var = fnScope.getVar(lastArg.getString());
      if (!referenced.contains(var)) {
        argList.removeChild(lastArg);
        compiler.reportCodeChange();
      } else {
        break;
      }
    }
  } else {
    callSiteOptimizer.optimize(fnScope, referenced);
  }
}
 
Example 18
Source File: Cardumen_0093_t.java    From coming with MIT License 4 votes vote down vote up
/**
 * Removes any vars in the scope that were not referenced. Removes any
 * assignments to those variables as well.
 */
private void removeUnreferencedVars() {
  CodingConvention convention = codingConvention;

  for (Iterator<Var> it = maybeUnreferenced.iterator(); it.hasNext(); ) {
    Var var = it.next();

    // Remove calls to inheritance-defining functions where the unreferenced
    // class is the subclass.
    for (Node exprCallNode : inheritsCalls.get(var)) {
      NodeUtil.removeChild(exprCallNode.getParent(), exprCallNode);
      compiler.reportCodeChange();
    }

    // Regardless of what happens to the original declaration,
    // we need to remove all assigns, because they may contain references
    // to other unreferenced variables.
    removeAllAssigns(var);

    compiler.addToDebugLog("Unreferenced var: " + var.name);
    Node nameNode = var.nameNode;
    Node toRemove = nameNode.getParent();
    Node parent = toRemove.getParent();

    Preconditions.checkState(
        toRemove.isVar() ||
        toRemove.isFunction() ||
        toRemove.isParamList() &&
        parent.isFunction(),
        "We should only declare vars and functions and function args");

    if (toRemove.isParamList() &&
        parent.isFunction()) {
      // Don't remove function arguments here. That's a special case
      // that's taken care of in removeUnreferencedFunctionArgs.
    } else if (NodeUtil.isFunctionExpression(toRemove)) {
      if (!preserveFunctionExpressionNames) {
        toRemove.getFirstChild().setString("");
        compiler.reportCodeChange();
      }
      // Don't remove bleeding functions.
    } else if (parent != null &&
        parent.isFor() &&
        parent.getChildCount() < 4) {
      // foreach iterations have 3 children. Leave them alone.
    } else if (toRemove.isVar() &&
        nameNode.hasChildren() &&
        NodeUtil.mayHaveSideEffects(nameNode.getFirstChild())) {
      // If this is a single var declaration, we can at least remove the
      // declaration itself and just leave the value, e.g.,
      // var a = foo(); => foo();
      if (toRemove.getChildCount() == 1) {
        parent.replaceChild(toRemove,
            IR.exprResult(nameNode.removeFirstChild()));
        compiler.reportCodeChange();
      }
    } else if (toRemove.isVar() &&
        toRemove.getChildCount() > 1) {
      // For var declarations with multiple names (i.e. var a, b, c),
      // only remove the unreferenced name
      toRemove.removeChild(nameNode);
      compiler.reportCodeChange();
    } else if (parent != null) {
      NodeUtil.removeChild(parent, toRemove);
      compiler.reportCodeChange();
    }
  }
}
 
Example 19
Source File: Closure_102_Normalize_s.java    From coming with MIT License 4 votes vote down vote up
/**
 * Remove duplicate VAR declarations encountered discovered during
 * scope creation.
 */
@Override
public void onRedeclaration(
    Scope s, String name, Node n, Node parent, Node gramps,
    Node nodeWithLineNumber) {
  Preconditions.checkState(n.getType() == Token.NAME);
  if (parent.getType() == Token.VAR) {
    Preconditions.checkState(parent.hasOneChild());

    //
    // Remove the parent VAR. There are three cases that need to be handled:
    //  1) "var a = b;" which is replaced with "a = b"
    //  2) "label:var a;" which is replaced with "label:;".  Ideally, the
    //     label itself would be removed but that is not possible in the
    //     context in which "onRedeclaration" is called.
    //  3) "for (var a in b) ..." which is replaced with "for (a in b)..."
    // Cases we don't need to handle are VARs with multiple children,
    // which have already been split into separate declarations, so there
    // is no need to handle that here, and "for (var a;;);", which has
    // been moved out of the loop.
    //
    // The result of this is that in each case the parent node is replaced
    // which is generally dangerous in a traversal but is fine here with
    // the scope creator, as the next node of interest is the parent's
    // next sibling.
    //
    if (n.hasChildren()) {
      // The var is being initialize, preserve the new value.
      parent.removeChild(n);
      // Convert "var name = value" to "name = value"
      Node value = n.getFirstChild();
      n.removeChild(value);
      Node replacement = new Node(Token.ASSIGN, n, value);
      gramps.replaceChild(parent, new Node(Token.EXPR_RESULT, replacement));
    } else {
      // It is an empty reference remove it.
      if (NodeUtil.isStatementBlock(gramps)) {
        gramps.removeChild(parent);
      } else if (gramps.getType() == Token.FOR) {
        // This is the "for (var a in b)..." case.  We don't need to worry
        // about initializers in "for (var a;;)..." as those are moved out
        // as part of the other normalizations.
        parent.removeChild(n);
        gramps.replaceChild(parent, n);
      } else {
        Preconditions.checkState(gramps.getType() == Token.LABEL);
        gramps.replaceChild(parent, new Node(Token.EMPTY));
      }
    }
    reportCodeChange("Duplicate VAR declaration");
  }
}
 
Example 20
Source File: Closure_130_CollapseProperties_t.java    From coming with MIT License 4 votes vote down vote up
/**
 * Updates the initial assignment to a collapsible property at global scope
 * by changing it to a variable declaration (e.g. a.b = 1 -> var a$b = 1).
 * The property's value may either be a primitive or an object literal or
 * function whose properties aren't collapsible.
 *
 * @param alias The flattened property name (e.g. "a$b")
 * @param refName The name for the reference being updated.
 * @param ref An object containing information about the assignment getting
 *     updated
 */
private void updateSimpleDeclaration(String alias, Name refName, Ref ref) {
  Node rvalue = ref.node.getNext();
  Node parent = ref.node.getParent();
  Node gramps = parent.getParent();
  Node greatGramps = gramps.getParent();

  if (rvalue != null && rvalue.isFunction()) {
    checkForHosedThisReferences(rvalue, refName.docInfo, refName);
  }

  // Create the new alias node.
  Node nameNode = NodeUtil.newName(
      compiler.getCodingConvention(), alias, gramps.getFirstChild(),
      refName.getFullName());
  NodeUtil.copyNameAnnotations(ref.node.getLastChild(), nameNode);

  if (gramps.isExprResult()) {
    // BEFORE: a.b.c = ...;
    //   exprstmt
    //     assign
    //       getprop
    //         getprop
    //           name a
    //           string b
    //         string c
    //       NODE
    // AFTER: var a$b$c = ...;
    //   var
    //     name a$b$c
    //       NODE

    // Remove the r-value (NODE).
    parent.removeChild(rvalue);
    nameNode.addChildToFront(rvalue);

    Node varNode = IR.var(nameNode);
    greatGramps.replaceChild(gramps, varNode);
  } else {
    // This must be a complex assignment.
    Preconditions.checkNotNull(ref.getTwin());

    // BEFORE:
    // ... (x.y = 3);
    //
    // AFTER:
    // var x$y;
    // ... (x$y = 3);

    Node current = gramps;
    Node currentParent = gramps.getParent();
    for (; !currentParent.isScript() &&
           !currentParent.isBlock();
         current = currentParent,
         currentParent = currentParent.getParent()) {}

    // Create a stub variable declaration right
    // before the current statement.
    Node stubVar = IR.var(nameNode.cloneTree())
        .copyInformationFrom(nameNode);
    currentParent.addChildBefore(stubVar, current);

    parent.replaceChild(ref.node, nameNode);
  }

  compiler.reportCodeChange();
}