Search in sources :

Example 1 with Tri

use of com.google.javascript.jscomp.base.Tri in project closure-compiler by google.

the class PeepholeRemoveDeadCode method tryFoldHook.

/**
 * Try folding HOOK (?:) if the condition results of the condition is known.
 * @return the replacement node, if changed, or the original if not
 */
private Node tryFoldHook(Node n) {
    checkState(n.isHook(), n);
    Node parent = n.getParent();
    checkNotNull(parent);
    Node cond = n.getFirstChild();
    Node thenBody = cond.getNext();
    Node elseBody = thenBody.getNext();
    Tri condValue = NodeUtil.getBooleanValue(cond);
    if (condValue == Tri.UNKNOWN) {
        // removed and it doesn't matter which.
        if (!areNodesEqualForInlining(thenBody, elseBody)) {
            // We can't remove branches otherwise!
            return n;
        }
    }
    // Transform "(a = 2) ? x =2 : y" into "a=2,x=2"
    Node branchToKeep;
    Node branchToRemove;
    if (condValue.toBoolean(true)) {
        branchToKeep = thenBody;
        branchToRemove = elseBody;
    } else {
        branchToKeep = elseBody;
        branchToRemove = thenBody;
    }
    Node replacement;
    boolean condHasSideEffects = mayHaveSideEffects(cond);
    // Must detach after checking for side effects, to ensure that the parents
    // of nodes are set correctly.
    n.detachChildren();
    if (condHasSideEffects) {
        replacement = IR.comma(cond, branchToKeep).srcref(n);
    } else {
        replacement = branchToKeep;
        markFunctionsDeleted(cond);
    }
    n.replaceWith(replacement);
    reportChangeToEnclosingScope(replacement);
    markFunctionsDeleted(branchToRemove);
    return replacement;
}
Also used : Node(com.google.javascript.rhino.Node) Tri(com.google.javascript.jscomp.base.Tri)

Example 2 with Tri

use of com.google.javascript.jscomp.base.Tri in project closure-compiler by google.

the class CheckSuspiciousCode method checkLeftOperandOfLogicalOperator.

/**
 * Check for the LHS of a logical operator (&& and ||) being deterministically truthy or
 * falsy, using both syntactic and type information. This is always suspicious (though for
 * different reasons: "truthy and" means the LHS is always ignored and should be removed, "falsy
 * and" means the RHS is dead code, and vice versa for "or". However, there are a number of
 * legitimate use cases where we need to back off from using type information (see {@link
 * #getBooleanValueWithTypes} for more details on these back offs).
 */
private void checkLeftOperandOfLogicalOperator(NodeTraversal t, Node n) {
    if (n.isOr() || n.isAnd()) {
        String operator = n.isOr() ? "||" : "&&";
        Tri v = getBooleanValueWithTypes(n.getFirstChild());
        if (v != Tri.UNKNOWN) {
            String result = v == Tri.TRUE ? "truthy" : "falsy";
            t.report(n, SUSPICIOUS_LEFT_OPERAND_OF_LOGICAL_OPERATOR, operator, result);
        }
    }
}
Also used : Tri(com.google.javascript.jscomp.base.Tri)

Example 3 with Tri

use of com.google.javascript.jscomp.base.Tri in project closure-compiler by google.

the class PeepholeFoldConstants method tryStrictEqualityComparison.

/**
 * http://www.ecma-international.org/ecma-262/6.0/#sec-strict-equality-comparison
 */
private static Tri tryStrictEqualityComparison(AbstractPeepholeOptimization peepholeOptimization, Node left, Node right) {
    // First, try to evaluate based on the general type.
    ValueType leftValueType = NodeUtil.getKnownValueType(left);
    ValueType rightValueType = NodeUtil.getKnownValueType(right);
    if (leftValueType != ValueType.UNDETERMINED && rightValueType != ValueType.UNDETERMINED) {
        // Strict equality can only be true for values of the same type.
        if (leftValueType != rightValueType) {
            return Tri.FALSE;
        }
        switch(leftValueType) {
            case VOID:
            case NULL:
                return Tri.TRUE;
            case NUMBER:
                {
                    if (NodeUtil.isNaN(left)) {
                        return Tri.FALSE;
                    }
                    if (NodeUtil.isNaN(right)) {
                        return Tri.FALSE;
                    }
                    Double lv = peepholeOptimization.getSideEffectFreeNumberValue(left);
                    Double rv = peepholeOptimization.getSideEffectFreeNumberValue(right);
                    if (lv != null && rv != null) {
                        return Tri.forBoolean(lv.doubleValue() == rv.doubleValue());
                    }
                    break;
                }
            case STRING:
                {
                    String lv = peepholeOptimization.getSideEffectFreeStringValue(left);
                    String rv = peepholeOptimization.getSideEffectFreeStringValue(right);
                    if (lv != null && rv != null) {
                        // equal if one contains \v.
                        if (lv.indexOf('\u000B') != -1 || rv.indexOf('\u000B') != -1) {
                            return Tri.UNKNOWN;
                        } else {
                            return lv.equals(rv) ? Tri.TRUE : Tri.FALSE;
                        }
                    } else if (left.isTypeOf() && right.isTypeOf() && left.getFirstChild().isName() && right.getFirstChild().isName() && left.getFirstChild().getString().equals(right.getFirstChild().getString())) {
                        // Special case, typeof a == typeof a is always true.
                        return Tri.TRUE;
                    }
                    break;
                }
            case BOOLEAN:
                {
                    Tri lv = peepholeOptimization.getSideEffectFreeBooleanValue(left);
                    Tri rv = peepholeOptimization.getSideEffectFreeBooleanValue(right);
                    return lv.and(rv).or(lv.not().and(rv.not()));
                }
            case BIGINT:
                {
                    BigInteger lv = peepholeOptimization.getSideEffectFreeBigIntValue(left);
                    BigInteger rv = peepholeOptimization.getSideEffectFreeBigIntValue(right);
                    return Tri.forBoolean(lv.equals(rv));
                }
            default:
                // Symbol and Object cannot be folded in the general case.
                return Tri.UNKNOWN;
        }
    }
    // Any strict equality comparison against NaN returns false.
    if (NodeUtil.isNaN(left) || NodeUtil.isNaN(right)) {
        return Tri.FALSE;
    }
    return Tri.UNKNOWN;
}
Also used : ValueType(com.google.javascript.jscomp.NodeUtil.ValueType) BigInteger(java.math.BigInteger) Tri(com.google.javascript.jscomp.base.Tri)

Example 4 with Tri

use of com.google.javascript.jscomp.base.Tri in project closure-compiler by google.

the class PeepholeFoldConstants method tryFoldUnaryOperator.

private Node tryFoldUnaryOperator(Node n) {
    checkState(n.hasOneChild(), n);
    Node left = n.getFirstChild();
    Node parent = n.getParent();
    if (left == null) {
        return n;
    }
    Tri leftVal = getSideEffectFreeBooleanValue(left);
    if (leftVal == Tri.UNKNOWN) {
        return n;
    }
    switch(n.getToken()) {
        case NOT:
            // Don't fold !0 and !1 back to false.
            if (late && left.isNumber()) {
                double numValue = left.getDouble();
                if (numValue == 0 || numValue == 1) {
                    return n;
                }
            }
            Node replacementNode = NodeUtil.booleanNode(!leftVal.toBoolean(true));
            n.replaceWith(replacementNode);
            reportChangeToEnclosingScope(parent);
            return replacementNode;
        case POS:
            if (NodeUtil.isNumericResult(left)) {
                // POS does nothing to numeric values.
                n.replaceWith(left.detach());
                reportChangeToEnclosingScope(parent);
                return left;
            }
            return n;
        case NEG:
            {
                Node result = null;
                if (left.isName() && left.getString().equals("NaN")) {
                    // "-NaN" is "NaN".
                    result = left.detach();
                } else if (left.isNeg()) {
                    Node leftLeft = left.getOnlyChild();
                    if (leftLeft.isBigInt() || leftLeft.isNumber()) {
                        // `-(-4)` is `4`
                        result = leftLeft.detach();
                    }
                }
                if (result != null) {
                    n.replaceWith(result);
                    reportChangeToEnclosingScope(parent);
                    return result;
                }
                return n;
            }
        case BITNOT:
            {
                Double doubleVal = this.getSideEffectFreeNumberValue(left);
                if (doubleVal != null) {
                    if (isMathematicalInteger(doubleVal)) {
                        int intVal = ecmascriptToInt32(doubleVal);
                        Node notIntValNode = NodeUtil.numberNode(~intVal, left);
                        n.replaceWith(notIntValNode);
                        reportChangeToEnclosingScope(parent);
                        return notIntValNode;
                    } else {
                        report(FRACTIONAL_BITWISE_OPERAND, left);
                        return n;
                    }
                }
                BigInteger bigintVal = this.getSideEffectFreeBigIntValue(n);
                if (bigintVal != null) {
                    Node bigintNotNode = bigintNode(bigintVal, n);
                    n.replaceWith(bigintNotNode);
                    reportChangeToEnclosingScope(parent);
                    return bigintNotNode;
                }
                return n;
            }
        default:
            return n;
    }
}
Also used : Node(com.google.javascript.rhino.Node) BigInteger(java.math.BigInteger) Tri(com.google.javascript.jscomp.base.Tri)

Example 5 with Tri

use of com.google.javascript.jscomp.base.Tri in project closure-compiler by google.

the class PeepholeFoldConstants method tryFoldAndOr.

/**
 * Try to fold a AND/OR node.
 */
private Node tryFoldAndOr(Node n, Node left, Node right) {
    Node parent = n.getParent();
    Node result = null;
    Node dropped = null;
    Token type = n.getToken();
    Tri leftVal = NodeUtil.getBooleanValue(left);
    if (leftVal != Tri.UNKNOWN) {
        boolean lval = leftVal.toBoolean(true);
        // (FALSE && x) => FALSE
        if (lval ? type == Token.OR : type == Token.AND) {
            result = left;
            dropped = right;
        } else if (!mayHaveSideEffects(left)) {
            // (FALSE || x) => x
            // (TRUE && x) => x
            result = right;
            dropped = left;
        } else {
            // Left side may have side effects, but we know its boolean value.
            // e.g. true_with_sideeffects || foo() => true_with_sideeffects, foo()
            // or: false_with_sideeffects && foo() => false_with_sideeffects, foo()
            // This, combined with PeepholeRemoveDeadCode, helps reduce expressions
            // like "x() || false || z()".
            n.detachChildren();
            result = IR.comma(left, right);
            dropped = null;
        }
    } else if (parent.getToken() == type && n == parent.getFirstChild()) {
        Tri rightValue = NodeUtil.getBooleanValue(right);
        if (!mayHaveSideEffects(right)) {
            if ((rightValue == Tri.FALSE && type == Token.OR) || (rightValue == Tri.TRUE && type == Token.AND)) {
                result = left;
                dropped = right;
            }
        }
    }
    if (result != null) {
        // Fold it!
        n.detachChildren();
        n.replaceWith(result);
        reportChangeToEnclosingScope(result);
        if (dropped != null) {
            markFunctionsDeleted(dropped);
        }
        return result;
    } else {
        return n;
    }
}
Also used : Node(com.google.javascript.rhino.Node) Token(com.google.javascript.rhino.Token) Tri(com.google.javascript.jscomp.base.Tri)

Aggregations

Tri (com.google.javascript.jscomp.base.Tri)17 Node (com.google.javascript.rhino.Node)12 Token (com.google.javascript.rhino.Token)3 BigInteger (java.math.BigInteger)3 JSType (com.google.javascript.rhino.jstype.JSType)2 MeasuredNode (com.google.javascript.jscomp.MinimizedCondition.MeasuredNode)1 ValueType (com.google.javascript.jscomp.NodeUtil.ValueType)1 EnumType (com.google.javascript.rhino.jstype.EnumType)1 Test (org.junit.Test)1