private Node tryFoldIf(Node n) {
    checkState(n.isIf(), n);
    Node parent = n.getParent();
    checkNotNull(parent);
    Token type = n.getToken();
    Node cond = n.getFirstChild();
    Node thenBody = cond.getNext();
    Node elseBody = thenBody.getNext();

    // if (x) { .. } else { } --> if (x) { ... }
    if (elseBody != null && !mayHaveSideEffects(elseBody)) {
      n.removeChild(elseBody);
      reportChangeToEnclosingScope(n);
      elseBody = null;
    }

    // if (x) { } else { ... } --> if (!x) { ... }
    if (!mayHaveSideEffects(thenBody) && elseBody != null) {
      n.removeChild(elseBody);
      n.replaceChild(thenBody, elseBody);
      Node notCond = new Node(Token.NOT);
      n.replaceChild(cond, notCond);
      reportChangeToEnclosingScope(n);
      notCond.addChildToFront(cond);
      cond = notCond;
      thenBody = cond.getNext();
      elseBody = null;
    }

    // if (x()) { }
    if (!mayHaveSideEffects(thenBody) && elseBody == null) {
      if (mayHaveSideEffects(cond)) {
        // x() has side effects, just leave the condition on its own.
        n.removeChild(cond);
        Node replacement = NodeUtil.newExpr(cond);
        parent.replaceChild(n, replacement);
        reportChangeToEnclosingScope(parent);
        return replacement;
      } else {
        // x() has no side effects, the whole tree is useless now.
        NodeUtil.removeChild(parent, n);
        reportChangeToEnclosingScope(parent);
        return null;
      }
    }

    // Try transforms that apply to both IF and HOOK.
    TernaryValue condValue = NodeUtil.getImpureBooleanValue(cond);
    if (condValue == TernaryValue.UNKNOWN) {
      return n;  // We can't remove branches otherwise!
    }

    if (mayHaveSideEffects(cond)) {
      // Transform "if (a = 2) {x =2}" into "if (true) {a=2;x=2}"
      boolean newConditionValue = condValue == TernaryValue.TRUE;
      // Add an elseBody if it is needed.
      if (!newConditionValue && elseBody == null) {
        elseBody = IR.block().srcref(n);
        n.addChildToBack(elseBody);
      }
      Node newCond = NodeUtil.booleanNode(newConditionValue);
      n.replaceChild(cond, newCond);
      Node branchToKeep = newConditionValue ? thenBody : elseBody;
      branchToKeep.addChildToFront(IR.exprResult(cond).srcref(cond));
      reportChangeToEnclosingScope(branchToKeep);
      cond = newCond;
    }

    boolean condTrue = condValue.toBoolean(true);
    if (n.hasTwoChildren()) {
      checkState(type == Token.IF);

      if (condTrue) {
        // Replace "if (true) { X }" with "X".
        Node thenStmt = n.getSecondChild();
        n.removeChild(thenStmt);
        parent.replaceChild(n, thenStmt);
        reportChangeToEnclosingScope(thenStmt);
        return thenStmt;
      } else {
        // Remove "if (false) { X }" completely.
        NodeUtil.redeclareVarsInsideBranch(n);
        NodeUtil.removeChild(parent, n);
        reportChangeToEnclosingScope(parent);
        markFunctionsDeleted(n);
        return null;
      }
    } else {
      // Replace "if (true) { X } else { Y }" with X, or
      // replace "if (false) { X } else { Y }" with Y.
      Node trueBranch = n.getSecondChild();
      Node falseBranch = trueBranch.getNext();
      Node branchToKeep = condTrue ? trueBranch : falseBranch;
      Node branchToRemove = condTrue ? falseBranch : trueBranch;
      NodeUtil.redeclareVarsInsideBranch(branchToRemove);
      n.removeChild(branchToKeep);
      parent.replaceChild(n, branchToKeep);
      reportChangeToEnclosingScope(branchToKeep);
      markFunctionsDeleted(n);
      return branchToKeep;
    }
  }
private Node tryFoldIf ( Node n ) { checkState ( n . isIf ( ) , n ) ; Node parent = n . getParent ( ) ; checkNotNull ( parent ) ; Token type = n . getToken ( ) ; Node cond = n . getFirstChild ( ) ; Node thenBody = cond . getNext ( ) ; Node elseBody = thenBody . getNext ( ) ; if ( elseBody != null && ! mayHaveSideEffects ( elseBody ) ) { n . removeChild ( elseBody ) ; reportChangeToEnclosingScope ( n ) ; elseBody = null ; } if ( ! mayHaveSideEffects ( thenBody ) && elseBody != null ) { n . removeChild ( elseBody ) ; n . replaceChild ( thenBody , elseBody ) ; Node notCond = new Node ( Token . NOT ) ; n . replaceChild ( cond , notCond ) ; reportChangeToEnclosingScope ( n ) ; notCond . addChildToFront ( cond ) ; cond = notCond ; thenBody = cond . getNext ( ) ; elseBody = null ; } if ( ! mayHaveSideEffects ( thenBody ) && elseBody == null ) { if ( mayHaveSideEffects ( cond ) ) { n . removeChild ( cond ) ; Node replacement = NodeUtil . newExpr ( cond ) ; parent . replaceChild ( n , replacement ) ; reportChangeToEnclosingScope ( parent ) ; return replacement ; } else { NodeUtil . removeChild ( parent , n ) ; reportChangeToEnclosingScope ( parent ) ; return null ; } } TernaryValue condValue = NodeUtil . getImpureBooleanValue ( cond ) ; if ( condValue == TernaryValue . UNKNOWN ) { return n ; } if ( mayHaveSideEffects ( cond ) ) { boolean newConditionValue = condValue == TernaryValue . TRUE ; if ( ! newConditionValue && elseBody == null ) { elseBody = IR . block ( ) . srcref ( n ) ; n . addChildToBack ( elseBody ) ; } Node newCond = NodeUtil . booleanNode ( newConditionValue ) ; n . replaceChild ( cond , newCond ) ; Node branchToKeep = newConditionValue ? thenBody : elseBody ; branchToKeep . addChildToFront ( IR . exprResult ( cond ) . srcref ( cond ) ) ; reportChangeToEnclosingScope ( branchToKeep ) ; cond = newCond ; } boolean condTrue = condValue . toBoolean ( true ) ; if ( n . hasTwoChildren ( ) ) { checkState ( type == Token . IF ) ; if ( condTrue ) { Node thenStmt = n . getSecondChild ( ) ; n . removeChild ( thenStmt ) ; parent . replaceChild ( n , thenStmt ) ; reportChangeToEnclosingScope ( thenStmt ) ; return thenStmt ; } else { NodeUtil . redeclareVarsInsideBranch ( n ) ; NodeUtil . removeChild ( parent , n ) ; reportChangeToEnclosingScope ( parent ) ; markFunctionsDeleted ( n ) ; return null ; } } else { Node trueBranch = n . getSecondChild ( ) ; Node falseBranch = trueBranch . getNext ( ) ; Node branchToKeep = condTrue ? trueBranch : falseBranch ; Node branchToRemove = condTrue ? falseBranch : trueBranch ; NodeUtil . redeclareVarsInsideBranch ( branchToRemove ) ; n . removeChild ( branchToKeep ) ; parent . replaceChild ( n , branchToKeep ) ; reportChangeToEnclosingScope ( branchToKeep ) ; markFunctionsDeleted ( n ) ; return branchToKeep ; } }
Try folding IF nodes by removing dead branches.
@return the replacement node, if changed, or the original if not