use of com.google.javascript.jscomp.base.Tri in project closure-compiler by google.
the class CheckSuspiciousCode method getBooleanValueWithTypes.
/**
* Returns the possible boolean values of a node. This is a combination of {@link
* NodeUtil#getBooleanValue} and {@link JSType#getPossibleToBooleanOutcomes}, with some additional
* backoff for situations that are known to be less accurate (to wit, qualified names and truthy
* return types, which return UNKNOWN even if the type information seems conclusive). Another
* difference from the NodeUtil and JSTyoe methods is that we include some specific optimization
* to avoid quadratic behavior of large nested logical operations.
*
* <p>The specifics of when this method returns UNKNOWN instead of TRUE or FALSE is as follows:
*
* <ul>
* <li>We should not determine that a qualified name (expanded slightly to include computed
* properties) is always truthy or always falsy. There are many cases where an extern
* defines a name to be truthy, but it still makes sense to feature-test in the browser.
* <li>We should not determine that a getelem or a function call is always truthy (though we
* expand it to simply never complain about always-truthy based only on types) since the
* standard externs lie about the return type of {@code Map.prototype.get} and array
* accesses, which can both return undefined despite what the externs say.
* </ul>
*
* We do not back off from boolean literals (e.g. "{@code true &&}"), though they appear to be
* common in generated code. Instead, such code should suppress "suspiciousCode". We also do not
* back off from always-falsy function call results, since it provides a valuable check and lies
* in this direction are much less common.
*/
private Tri getBooleanValueWithTypes(Node n) {
switch(n.getToken()) {
case ASSIGN:
case COMMA:
return getBooleanValueWithTypes(n.getLastChild());
case NOT:
return getBooleanValueWithTypes(n.getLastChild()).not();
case AND:
// prevents revisiting deeper nodes repeatedly, which would result in O(n^2) performance.
return Tri.UNKNOWN.and(getBooleanValueWithTypes(n.getLastChild()));
case OR:
// prevents revisiting deeper nodes repeatedly, which would result in O(n^2) performance.
return Tri.UNKNOWN.or(getBooleanValueWithTypes(n.getLastChild()));
case HOOK:
{
Tri trueValue = getBooleanValueWithTypes(n.getSecondChild());
Tri falseValue = getBooleanValueWithTypes(n.getLastChild());
return trueValue.equals(falseValue) ? trueValue : Tri.UNKNOWN;
}
case FUNCTION:
case CLASS:
case NEW:
case ARRAYLIT:
case OBJECTLIT:
return Tri.TRUE;
case VOID:
return Tri.FALSE;
case GETPROP:
case GETELEM:
case OPTCHAIN_GETELEM:
case OPTCHAIN_GETPROP:
// initialization of globals ({@code x.y = x.y || {}}).
return Tri.UNKNOWN;
default:
}
// If we reach this point then all the composite structures that we can decompose have
// already been handled, leaving only qualified names and type-aware checks to handle below.
// Note that much of the switch above in fact duplicates the logic in getImpureBooleanValue,
// though with some subtle differences. Important differences include (1) avoiding recursion
// into the left-hand-side of nested logical operators, instead treating them as unknown since
// they would have already been reported elsewhere in the traversal had they been otherwise
// (this guarantees we visit each node once, rather than quadratically repeating work);
// (2) it propagates our unique amalgam of syntax-based and type-based checks to work when more
// deeply nested (i.e. recursively). These differences rely on assumptions that are very
// specific to this use case, so it does not make sense to upstream them.
Tri literalValue = NodeUtil.getBooleanValue(n);
if (literalValue != Tri.UNKNOWN || n.isName()) {
// Alternatively, NAME nodes also get a pass since we don't trust the type information.
return literalValue;
}
JSType type = n.getJSType();
if (type != null) {
// those type annotations to be lies. ANDing with UNKNOWN ensures we never return TRUE.
return Tri.UNKNOWN.and(type.getPossibleToBooleanOutcomes().toTri());
}
return Tri.UNKNOWN;
}
use of com.google.javascript.jscomp.base.Tri in project closure-compiler by google.
the class UnionType method testForEquality.
@Override
public Tri testForEquality(JSType that) {
Tri result = null;
for (int i = 0; i < alternates.size(); i++) {
JSType t = alternates.get(i);
Tri test = t.testForEquality(that);
if (result == null) {
result = test;
} else if (!result.equals(test)) {
return Tri.UNKNOWN;
}
}
return result;
}
Aggregations