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;
}
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);
}
}
}
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;
}
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;
}
}
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;
}
}
Aggregations