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

The following examples show how to use com.google.javascript.rhino.Node#detachFromParent() . 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: Closure_114_NameAnalyzer_t.java    From coming with MIT License 6 votes vote down vote up
/**
 * Merge a list of nodes into a single expression.  The value of the
 * new expression is determined by the last expression in the list.
 */
private Node collapseReplacements(List<Node> replacements) {
  Node expr = null;
  for (Node rep : replacements) {
    if (rep.isExprResult()) {
      rep = rep.getFirstChild();
      rep.detachFromParent();
    }

    if (expr == null) {
      expr = rep;
    } else {
      expr = IR.comma(expr, rep);
    }
  }

  return expr;
}
 
Example 2
Source File: Cardumen_00202_s.java    From coming with MIT License 6 votes vote down vote up
/**
 * Merge a list of nodes into a single expression.  The value of the
 * new expression is determined by the last expression in the list.
 */
private Node collapseReplacements(List<Node> replacements) {
  Node expr = null;
  for (Node rep : replacements) {
    if (rep.isExprResult()) {
      rep = rep.getFirstChild();
      rep.detachFromParent();
    }

    if (expr == null) {
      expr = rep;
    } else {
      expr = IR.comma(expr, rep);
    }
  }

  return expr;
}
 
Example 3
Source File: Cardumen_0020_s.java    From coming with MIT License 6 votes vote down vote up
/**
 * Merge a list of nodes into a single expression.  The value of the
 * new expression is determined by the last expression in the list.
 */
private Node collapseReplacements(List<Node> replacements) {
  Node expr = null;
  for (Node rep : replacements) {
    if (rep.isExprResult()) {
      rep = rep.getFirstChild();
      rep.detachFromParent();
    }

    if (expr == null) {
      expr = rep;
    } else {
      expr = IR.comma(expr, rep);
    }
  }

  return expr;
}
 
Example 4
Source File: PeepholeSubstituteAlternateSyntax.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Remove duplicate exits.  If the node following the exit node expression
 * has the same effect as exit node, the node can be removed.
 * For example:
 *   "if (a) {return f()} return f();" ==> "if (a) {} return f();"
 *   "if (a) {throw 'ow'} throw 'ow';" ==> "if (a) {} throw 'ow';"
 *
 * @param n An follow control exit expression (a THROW or RETURN node)
 * @return The replacement for n, or the original if no change was made.
 */
private Node tryRemoveRedundantExit(Node n) {
  Node exitExpr = n.getFirstChild();

  Node follow = ControlFlowAnalysis.computeFollowNode(n);

  // Skip pass all the finally blocks because both the fall through and return
  // will also trigger all the finally blocks.
  Node prefinallyFollows = follow;
  follow = skipFinallyNodes(follow);
  if (prefinallyFollows != follow) {
    // There were finally clauses
    if (!isPure(exitExpr)) {
      // Can't replace the return
      return n;
    }
  }

  if (follow == null && (n.isThrow() || exitExpr != null)) {
    // Can't complete remove a throw here or a return with a result.
    return n;
  }

  // When follow is null, this mean the follow of a break target is the
  // end of a function. This means a break is same as return.
  if (follow == null || areMatchingExits(n, follow)) {
    n.detachFromParent();
    reportCodeChange();
    return null;
  }

  return n;
}
 
Example 5
Source File: Closure_31_Compiler_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Removes an input file from AST.
 * @param id The id of the input to be removed.
 */
protected void removeExternInput(InputId id) {
  CompilerInput input = getInput(id);
  if (input == null) {
    return;
  }
  Preconditions.checkState(input.isExtern(), "Not an extern input: %s", input.getName());
  inputsById.remove(id);
  externs.remove(input);
  Node root = input.getAstRoot(this);
  if (root != null) {
    root.detachFromParent();
  }
}
 
Example 6
Source File: ClosureRewriteClass.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
private void maybeRewriteClassDefinition(
    Node n, Node target, Node value) {
  if (isGoogDefineClass(value)) {
    if (!target.isQualifiedName()) {
      compiler.report(JSError.make(n, GOOG_CLASS_TARGET_INVALID));
    }
    ClassDefinition def = extractClassDefinition(target, value);
    if (def != null) {
      value.detachFromParent();
      target.detachFromParent();
      rewriteGoogDefineClass(n, def);
    }
  }
}
 
Example 7
Source File: ClosureCodeRemoval.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
/**
 * Remove this node.
 */
public void remove() {
  Node rhs = node.getNext();
  Node last = parent;
  for (Node ancestor : assignAncestors) {
    if (ancestor.isExprResult()) {
      lastAncestor.removeChild(ancestor);
    } else {
      rhs.detachFromParent();
      ancestor.replaceChild(last, rhs);
    }
    last = ancestor;
  }
  compiler.reportCodeChange();
}
 
Example 8
Source File: Closure_92_ProcessClosurePrimitives_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Handles a goog.require call.
 */
private void processRequireCall(NodeTraversal t, Node n, Node parent) {
  Node left = n.getFirstChild();
  Node arg = left.getNext();
  if (verifyArgument(t, left, arg)) {
    String ns = arg.getString();
    ProvidedName provided = providedNames.get(ns);
    if (provided == null || !provided.isExplicitlyProvided()) {
      unrecognizedRequires.add(
          new UnrecognizedRequire(n, ns, t.getSourceName()));
    } else {
      JSModule providedModule = provided.explicitModule;

      // This must be non-null, because there was an explicit provide.
      Preconditions.checkNotNull(providedModule);

      JSModule module = t.getModule();
      if (moduleGraph != null &&
          module != providedModule &&
          !moduleGraph.dependsOn(module, providedModule)) {
        compiler.report(
            t.makeError(n, XMODULE_REQUIRE_ERROR, ns,
                providedModule.getName(),
                module.getName()));
      }
    }

    // Requires should be removed before runtime.  The one
    // exception is if the type has not been provided yet and
    // errors for broken requires are turned off, in which case,
    // we will be doing a later pass that may error, so we can
    // leave this here this time and let it error next time if it
    // is still not provided.
    if (provided != null || requiresLevel.isOn()) {
      parent.detachFromParent();
      compiler.reportCodeChange();
    }
  }
}
 
Example 9
Source File: Closure_40_NameAnalyzer_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Replace n with a simpler expression, while preserving program
 * behavior.
 *
 * If the n's value is used, replace it with its rhs; otherwise
 * replace it with the subexpressions that have side effects.
 */
private void replaceWithRhs(Node parent, Node n) {
  if (valueConsumedByParent(n, parent)) {
    // parent reads from n directly; replace it with n's rhs + lhs
    // subexpressions with side effects.
    List<Node> replacements = getRhsSubexpressions(n);
    List<Node> newReplacements = Lists.newArrayList();
    for (int i = 0; i < replacements.size() - 1; i++) {
      newReplacements.addAll(getSideEffectNodes(replacements.get(i)));
    }
    Node valueExpr = replacements.get(replacements.size() - 1);
    valueExpr.detachFromParent();
    newReplacements.add(valueExpr);
    changeProxy.replaceWith(
        parent, n, collapseReplacements(newReplacements));
  } else if (n.isAssign() && !parent.isFor()) {
    // assignment appears in a RHS expression.  we have already
    // considered names in the assignment's RHS as being referenced;
    // replace the assignment with its RHS.
    // TODO(user) make the pass smarter about these cases and/or run
    // this pass and RemoveConstantExpressions together in a loop.
    Node replacement = n.getLastChild();
    replacement.detachFromParent();
    changeProxy.replaceWith(parent, n, replacement);
  } else {
    replaceTopLevelExpressionWithRhs(parent, n);
  }
}
 
Example 10
Source File: PeepholeCollectPropertyAssignments.java    From astor with GNU General Public License v2.0 5 votes vote down vote up
private boolean collectObjectProperty(
    Node objectLiteral, Node propertyCandidate) {
  Node assignment = propertyCandidate.getFirstChild();
  Node lhs = assignment.getFirstChild(), rhs = lhs.getNext();
  Node obj = lhs.getFirstChild();
  Node property = obj.getNext();

  // The property must be statically known.
  if (lhs.isGetElem()
      && (!property.isString()
          && !property.isNumber())) {
    return false;
  }

  String propertyName;
  if (property.isNumber()) {
    propertyName = NodeUtil.getStringValue(property);
  } else {
    propertyName = property.getString();
  }

  Node newProperty = IR.stringKey(propertyName)
      .copyInformationFrom(property);
  // Preserve the quotedness of a property reference
  if (lhs.isGetElem()) {
    newProperty.setQuotedString();
  }
  Node newValue = rhs.detachFromParent();
  newProperty.addChildToBack(newValue);
  objectLiteral.addChildToBack(newProperty);

  propertyCandidate.detachFromParent();
  return true;
}
 
Example 11
Source File: Cardumen_0092_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Replace n with a simpler expression, while preserving program
 * behavior.
 *
 * If the n's value is used, replace it with its rhs; otherwise
 * replace it with the subexpressions that have side effects.
 */
private void replaceWithRhs(Node parent, Node n) {
  if (valueConsumedByParent(n, parent)) {
    // parent reads from n directly; replace it with n's rhs + lhs
    // subexpressions with side effects.
    List<Node> replacements = getRhsSubexpressions(n);
    List<Node> newReplacements = Lists.newArrayList();
    for (int i = 0; i < replacements.size() - 1; i++) {
      newReplacements.addAll(getSideEffectNodes(replacements.get(i)));
    }
    Node valueExpr = replacements.get(replacements.size() - 1);
    valueExpr.detachFromParent();
    newReplacements.add(valueExpr);
    changeProxy.replaceWith(
        parent, n, collapseReplacements(newReplacements));
  } else if (n.isAssign() && !parent.isFor()) {
    // assignment appears in a RHS expression.  we have already
    // considered names in the assignment's RHS as being referenced;
    // replace the assignment with its RHS.
    // TODO(user) make the pass smarter about these cases and/or run
    // this pass and RemoveConstantExpressions together in a loop.
    Node replacement = n.getLastChild();
    replacement.detachFromParent();
    changeProxy.replaceWith(parent, n, replacement);
  } else {
    replaceTopLevelExpressionWithRhs(parent, n);
  }
}
 
Example 12
Source File: Closure_64_Compiler_t.java    From coming with MIT License 5 votes vote down vote up
/**
 * Removes an input file from AST.
 * @param name The name of the file to be removed.
 */
protected void removeInput(String name) {
  CompilerInput input = getInput(name);
  if (input == null) {
    return;
  }
  inputsByName.remove(name);
  Node root = input.getAstRoot(this);
  if (root != null) {
    root.detachFromParent();
  }
}
 
Example 13
Source File: Closure_64_Compiler_s.java    From coming with MIT License 5 votes vote down vote up
/**
 * Removes an input file from AST.
 * @param name The name of the file to be removed.
 */
protected void removeInput(String name) {
  CompilerInput input = getInput(name);
  if (input == null) {
    return;
  }
  inputsByName.remove(name);
  Node root = input.getAstRoot(this);
  if (root != null) {
    root.detachFromParent();
  }
}
 
Example 14
Source File: Closure_72_FunctionToBlockMutator_s.java    From coming with MIT License 4 votes vote down vote up
/**
 * @param fnName The name to use when preparing human readable names.
 * @param fnNode The function to prepare.
 * @param callNode The call node that will be replaced.
 * @param resultName Function results should be assigned to this name.
 * @param needsDefaultResult Whether the result value must be set.
 * @param isCallInLoop Whether the function body must be prepared to be
 *   injected into the body of a loop.
 * @return A clone of the function body mutated to be suitable for injection
 *   as a statement into another code block.
 */
Node mutate(String fnName, Node fnNode, Node callNode,
    String resultName, boolean needsDefaultResult, boolean isCallInLoop) {
  Node newFnNode = fnNode.cloneTree();
  // Now that parameter names have been replaced, make sure all the local
  // names are unique, to allow functions to be inlined multiple times
  // without causing conflicts.
  makeLocalNamesUnique(newFnNode, isCallInLoop);

  // TODO(johnlenz): Mark NAME nodes constant for parameters that are not
  // modified.
  Set<String> namesToAlias =
      FunctionArgumentInjector.findModifiedParameters(newFnNode);
  LinkedHashMap<String, Node> args =
      FunctionArgumentInjector.getFunctionCallParameterMap(
          newFnNode, callNode, this.safeNameIdSupplier);
  boolean hasArgs = !args.isEmpty();
  if (hasArgs) {
    FunctionArgumentInjector.maybeAddTempsForCallArguments(
        newFnNode, args, namesToAlias, compiler.getCodingConvention());
  }

  Node newBlock = NodeUtil.getFunctionBody(newFnNode);
  // Make the newBlock insertable .
  newBlock.detachFromParent();

  if (hasArgs) {
    Node inlineResult = aliasAndInlineArguments(newBlock,
        args, namesToAlias);
    Preconditions.checkState(newBlock == inlineResult);
  }

  //
  // For calls inlined into loops, VAR declarations are not reinitialized to
  // undefined as they would have been if the function were called, so ensure
  // that they are properly initialized.
  //
  if (isCallInLoop) {
    fixUnitializedVarDeclarations(newBlock);
  }

  String labelName = getLabelNameForFunction(fnName);
  Node injectableBlock = replaceReturns(
      newBlock, resultName, labelName, needsDefaultResult);
  Preconditions.checkState(injectableBlock != null);

  return injectableBlock;
}
 
Example 15
Source File: ExpandJqueryAliases.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Expand jQuery.extend (and derivative) calls into direct object assignments
 * Example: jQuery.extend(obj1, {prop1: val1, prop2: val2}) ->
 *   obj1.prop1 = val1;
 *   obj1.prop2 = val2;
 */
private void maybeExpandJqueryExtendCall(Node n) {
  Node callTarget = n.getFirstChild();
  Node objectToExtend = callTarget.getNext(); // first argument
  Node extendArg = objectToExtend.getNext(); // second argument
  boolean ensureObjectDefined = true;

  if (extendArg == null) {
    // Only one argument was specified, so extend jQuery namespace
    extendArg = objectToExtend;
    objectToExtend = callTarget.getFirstChild();
    ensureObjectDefined = false;
  } else if (objectToExtend.isGetProp() &&
        (objectToExtend.getLastChild().getString().equals("prototype") ||
        convention.isPrototypeAlias(objectToExtend))) {
    ensureObjectDefined = false;
  }

  // Check for an empty object literal
  if (!extendArg.hasChildren()) {
    return;
  }

  // Since we are expanding jQuery.extend calls into multiple statements,
  // encapsulate the new statements in a new block.
  Node fncBlock = IR.block().srcref(n);

  if (ensureObjectDefined) {
    Node assignVal = IR.or(objectToExtend.cloneTree(),
        IR.objectlit().srcref(n)).srcref(n);
    Node assign = IR.assign(objectToExtend.cloneTree(), assignVal).srcref(n);
    fncBlock.addChildrenToFront(IR.exprResult(assign).srcref(n));
  }

  while (extendArg.hasChildren()) {
    Node currentProp = extendArg.removeFirstChild();
    currentProp.setType(Token.STRING);

    Node propValue = currentProp.removeFirstChild();

    Node newProp;
    if(currentProp.isQuotedString()) {
      newProp = IR.getelem(objectToExtend.cloneTree(),
          currentProp).srcref(currentProp);
    } else {
      newProp = IR.getprop(objectToExtend.cloneTree(),
          currentProp).srcref(currentProp);
    }

    Node assignNode = IR.assign(newProp, propValue).srcref(currentProp);
    fncBlock.addChildToBack(IR.exprResult(assignNode).srcref(currentProp));
  }

  // Check to see if the return value is used. If not, replace the original
  // call with new block. Otherwise, wrap the statements in an
  // immediately-called anonymous function.
  if (n.getParent().isExprResult()) {
    Node parent = n.getParent();
    parent.getParent().replaceChild(parent, fncBlock);
  } else {
    Node targetVal;
    if ("jQuery.prototype".equals(objectToExtend.getQualifiedName())) {
      // When extending the jQuery prototype, return the jQuery namespace.
      // This is not commonly used.
      targetVal = objectToExtend.removeFirstChild();
    } else {
      targetVal = objectToExtend.detachFromParent();
    }
    fncBlock.addChildToBack(IR.returnNode(targetVal).srcref(targetVal));

    Node fnc = IR.function(IR.name("").srcref(n),
        IR.paramList().srcref(n),
        fncBlock);
    n.replaceChild(callTarget, fnc);
    n.putBooleanProp(Node.FREE_CALL, true);

    // remove any other pre-existing call arguments
    while(fnc.getNext() != null) {
      n.removeChildAfter(fnc);
    }
  }
  compiler.reportCodeChange();
}
 
Example 16
Source File: FunctionToBlockMutator.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * @param fnName The name to use when preparing human readable names.
 * @param fnNode The function to prepare.
 * @param callNode The call node that will be replaced.
 * @param resultName Function results should be assigned to this name.
 * @param needsDefaultResult Whether the result value must be set.
 * @param isCallInLoop Whether the function body must be prepared to be
 *   injected into the body of a loop.
 * @return A clone of the function body mutated to be suitable for injection
 *   as a statement into another code block.
 */
Node mutate(String fnName, Node fnNode, Node callNode,
    String resultName, boolean needsDefaultResult, boolean isCallInLoop) {
  Node newFnNode = fnNode.cloneTree();
  // Now that parameter names have been replaced, make sure all the local
  // names are unique, to allow functions to be inlined multiple times
  // without causing conflicts.
  makeLocalNamesUnique(newFnNode, isCallInLoop);

  // Function declarations must be rewritten as function expressions as
  // they will be within a block and normalization prevents function
  // declarations within block as browser implementations vary.
  rewriteFunctionDeclarations(newFnNode.getLastChild());

  // TODO(johnlenz): Mark NAME nodes constant for parameters that are not
  // modified.
  Set<String> namesToAlias =
      FunctionArgumentInjector.findModifiedParameters(newFnNode);
  LinkedHashMap<String, Node> args =
      FunctionArgumentInjector.getFunctionCallParameterMap(
          newFnNode, callNode, this.safeNameIdSupplier);
  boolean hasArgs = !args.isEmpty();
  if (hasArgs) {
    FunctionArgumentInjector.maybeAddTempsForCallArguments(
        newFnNode, args, namesToAlias, compiler.getCodingConvention());
  }

  Node newBlock = NodeUtil.getFunctionBody(newFnNode);
  // Make the newBlock insertable .
  newBlock.detachFromParent();

  if (hasArgs) {
    Node inlineResult = aliasAndInlineArguments(newBlock,
        args, namesToAlias);
    Preconditions.checkState(newBlock == inlineResult);
  }

  //
  // For calls inlined into loops, VAR declarations are not reinitialized to
  // undefined as they would have been if the function were called, so ensure
  // that they are properly initialized.
  //
  if (isCallInLoop) {
    fixUnitializedVarDeclarations(newBlock);
  }

  String labelName = getLabelNameForFunction(fnName);
  Node injectableBlock = replaceReturns(
      newBlock, resultName, labelName, needsDefaultResult);
  Preconditions.checkState(injectableBlock != null);

  return injectableBlock;
}
 
Example 17
Source File: Closure_23_PeepholeFoldConstants_s.java    From coming with MIT License 4 votes vote down vote up
private Node tryFoldAssign(Node n, Node left, Node right) {
  Preconditions.checkArgument(n.isAssign());

  if (!late) {
    return n;
  }

  // Tries to convert x = x + y -> x += y;
  if (!right.hasChildren() ||
      right.getFirstChild().getNext() != right.getLastChild()) {
    // RHS must have two children.
    return n;
  }

  if (mayHaveSideEffects(left)) {
    return n;
  }

  Node newRight;
  if (areNodesEqualForInlining(left, right.getFirstChild())) {
    newRight = right.getLastChild();
  } else if (NodeUtil.isCommutative(right.getType()) &&
        areNodesEqualForInlining(left, right.getLastChild())) {
    newRight = right.getFirstChild();
  } else {
    return n;
  }

  int newType = -1;
  switch (right.getType()) {
    case Token.ADD:
      newType = Token.ASSIGN_ADD;
      break;
    case Token.BITAND:
      newType = Token.ASSIGN_BITAND;
      break;
    case Token.BITOR:
      newType = Token.ASSIGN_BITOR;
      break;
    case Token.BITXOR:
      newType = Token.ASSIGN_BITXOR;
      break;
    case Token.DIV:
      newType = Token.ASSIGN_DIV;
      break;
    case Token.LSH:
      newType = Token.ASSIGN_LSH;
      break;
    case Token.MOD:
      newType = Token.ASSIGN_MOD;
      break;
    case Token.MUL:
      newType = Token.ASSIGN_MUL;
      break;
    case Token.RSH:
      newType = Token.ASSIGN_RSH;
      break;
    case Token.SUB:
      newType = Token.ASSIGN_SUB;
      break;
    case Token.URSH:
      newType = Token.ASSIGN_URSH;
      break;
    default:
      return n;
  }

  Node newNode = new Node(newType,
      left.detachFromParent(), newRight.detachFromParent());
  n.getParent().replaceChild(n, newNode);

  reportCodeChange();

  return newNode;
}
 
Example 18
Source File: ProcessClosurePrimitives.java    From astor with GNU General Public License v2.0 4 votes vote down vote up
/**
 * Handles a goog.require call.
 */
private void processRequireCall(NodeTraversal t, Node n, Node parent) {
  Node left = n.getFirstChild();
  Node arg = left.getNext();
  if (verifyArgument(t, left, arg)) {
    String ns = arg.getString();
    ProvidedName provided = providedNames.get(ns);
    if (provided == null || !provided.isExplicitlyProvided()) {
      unrecognizedRequires.add(
          new UnrecognizedRequire(n, ns, t.getSourceName()));
    } else {
      JSModule providedModule = provided.explicitModule;

      // This must be non-null, because there was an explicit provide.
      Preconditions.checkNotNull(providedModule);

      JSModule module = t.getModule();
      if (moduleGraph != null &&
          module != providedModule &&
          !moduleGraph.dependsOn(module, providedModule)) {
        compiler.report(
            t.makeError(n, XMODULE_REQUIRE_ERROR, ns,
                providedModule.getName(),
                module.getName()));
      }
    }

    maybeAddToSymbolTable(left);
    maybeAddStringNodeToSymbolTable(arg);

    // Requires should be removed before runtime.  The one
    // exception is if the type has not been provided yet and
    // errors for broken requires are turned off, in which case,
    // we will be doing a later pass that may error, so we can
    // leave this here this time and let it error next time if it
    // is still not provided.
    if (provided != null || requiresLevel.isOn()) {
      parent.detachFromParent();
      compiler.reportCodeChange();
    }
  }
}
 
Example 19
Source File: Closure_78_PeepholeFoldConstants_t.java    From coming with MIT License 4 votes vote down vote up
private Node tryFoldAssign(Node n, Node left, Node right) {
  Preconditions.checkArgument(n.getType() == Token.ASSIGN);

  // Tries to convert x = x + y -> x += y;
  if (!right.hasChildren() ||
      right.getFirstChild().getNext() != right.getLastChild()) {
    // RHS must have two children.
    return n;
  }

  if (mayHaveSideEffects(left)) {
    return n;
  }

  Node newRight;
  if (areNodesEqualForInlining(left, right.getFirstChild())) {
    newRight = right.getLastChild();
  } else if (NodeUtil.isCommutative(right.getType()) &&
        areNodesEqualForInlining(left, right.getLastChild())) {
    newRight = right.getFirstChild();
  } else {
    return n;
  }

  int newType = -1;
  switch (right.getType()) {
    case Token.ADD:
      newType = Token.ASSIGN_ADD;
      break;
    case Token.BITAND:
      newType = Token.ASSIGN_BITAND;
      break;
    case Token.BITOR:
      newType = Token.ASSIGN_BITOR;
      break;
    case Token.BITXOR:
      newType = Token.ASSIGN_BITXOR;
      break;
    case Token.DIV:
      newType = Token.ASSIGN_DIV;
      break;
    case Token.LSH:
      newType = Token.ASSIGN_LSH;
      break;
    case Token.MOD:
      newType = Token.ASSIGN_MOD;
      break;
    case Token.MUL:
      newType = Token.ASSIGN_MUL;
      break;
    case Token.RSH:
      newType = Token.ASSIGN_RSH;
      break;
    case Token.SUB:
      newType = Token.ASSIGN_SUB;
      break;
    case Token.URSH:
      newType = Token.ASSIGN_URSH;
      break;
    default:
      return n;
  }

  Node newNode = new Node(newType,
      left.detachFromParent(), newRight.detachFromParent());
  n.getParent().replaceChild(n, newNode);

  reportCodeChange();

  return newNode;
}
 
Example 20
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;
}