Skip to content

Commit

Permalink
Make evaluatesToLocalValue handle tagged template literals.
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=173584828
  • Loading branch information
tbreisacher authored and blickly committed Oct 27, 2017
1 parent 48d86ce commit a0dcb0b
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 24 deletions.
7 changes: 6 additions & 1 deletion src/com/google/javascript/jscomp/NodeUtil.java
Expand Up @@ -1437,7 +1437,7 @@ private static boolean isTypedAsString(Node n, AbstractCompiler compiler) {
* @return Whether the call has a local result. * @return Whether the call has a local result.
*/ */
static boolean callHasLocalResult(Node n) { static boolean callHasLocalResult(Node n) {
checkState(n.isCall(), n); checkState(n.isCall() || n.isTaggedTemplateLit(), n);
return (n.getSideEffectFlags() & Node.FLAG_LOCAL_RESULTS) > 0; return (n.getSideEffectFlags() & Node.FLAG_LOCAL_RESULTS) > 0;
} }


Expand Down Expand Up @@ -4606,6 +4606,11 @@ static boolean evaluatesToLocalValue(Node value, Predicate<Node> locals) {
return callHasLocalResult(value) return callHasLocalResult(value)
|| isToStringMethodCall(value) || isToStringMethodCall(value)
|| locals.apply(value); || locals.apply(value);
case TAGGED_TEMPLATELIT:
if (!callHasLocalResult(value)) {
return false;
}
return evaluatesToLocalValue(value.getLastChild());
case NEW: case NEW:
return newHasLocalResult(value) || locals.apply(value); return newHasLocalResult(value) || locals.apply(value);
case DELPROP: case DELPROP:
Expand Down
6 changes: 3 additions & 3 deletions src/com/google/javascript/rhino/Node.java
Expand Up @@ -2646,9 +2646,9 @@ public final boolean isYieldAll() {
*/ */
public final void setSideEffectFlags(int flags) { public final void setSideEffectFlags(int flags) {
checkArgument( checkArgument(
this.isCall() || this.isNew(), this.isCall() || this.isNew() || this.isTaggedTemplateLit(),
"setIsNoSideEffectsCall only supports CALL and NEW nodes, got %s", "setIsNoSideEffectsCall only supports call-like nodes, got %s",
this.getToken()); this);


putIntProp(SIDE_EFFECT_FLAGS, flags); putIntProp(SIDE_EFFECT_FLAGS, flags);
} }
Expand Down
63 changes: 43 additions & 20 deletions test/com/google/javascript/jscomp/NodeUtilTest.java
Expand Up @@ -1512,59 +1512,82 @@ public void testLocalValue1() throws Exception {
assertFalse(NodeUtil.evaluatesToLocalValue(getNode("o.valueOf()"))); assertFalse(NodeUtil.evaluatesToLocalValue(getNode("o.valueOf()")));


assertTrue(NodeUtil.evaluatesToLocalValue(getNode("delete a.b"))); assertTrue(NodeUtil.evaluatesToLocalValue(getNode("delete a.b")));
}


public void testLocalValueTemplateLit() {
assertTrue(NodeUtil.evaluatesToLocalValue(getNode("`hello`"))); assertTrue(NodeUtil.evaluatesToLocalValue(getNode("`hello`")));
assertFalse(NodeUtil.evaluatesToLocalValue(getNode("`hello ${name}`"))); assertFalse(NodeUtil.evaluatesToLocalValue(getNode("`hello ${name}`")));
assertTrue(NodeUtil.evaluatesToLocalValue(getNode("`${'name'}`"))); assertTrue(NodeUtil.evaluatesToLocalValue(getNode("`${'name'}`")));
}


public void testLocalValueTaggedTemplateLit1() {
Node n = getNode("tag`simple string`");
assertFalse(NodeUtil.evaluatesToLocalValue(n));

Node.SideEffectFlags flags = new Node.SideEffectFlags();
flags.clearAllFlags();
n.setSideEffectFlags(flags);

assertTrue(NodeUtil.evaluatesToLocalValue(n));
} }


public void testLocalValue2() { public void testLocalValueTaggedTemplateLit2() {
// Here, replacement() may have side effects.
Node n = getNode("tag`string with ${replacement()}`");
assertFalse(NodeUtil.evaluatesToLocalValue(n));

Node.SideEffectFlags flags = new Node.SideEffectFlags();
flags.clearAllFlags();
n.setSideEffectFlags(flags);

assertFalse(NodeUtil.evaluatesToLocalValue(n));
}

public void testLocalValueNewExpr() {
Node newExpr = getNode("new x()"); Node newExpr = getNode("new x()");
assertFalse(NodeUtil.evaluatesToLocalValue(newExpr)); assertFalse(NodeUtil.evaluatesToLocalValue(newExpr));


checkState(newExpr.isNew()); checkState(newExpr.isNew());
Node.SideEffectFlags flags = new Node.SideEffectFlags(); Node.SideEffectFlags flags = new Node.SideEffectFlags();


flags.clearAllFlags(); flags.clearAllFlags();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);


assertTrue(NodeUtil.evaluatesToLocalValue(newExpr)); assertTrue(NodeUtil.evaluatesToLocalValue(newExpr));


flags.clearAllFlags(); flags.clearAllFlags();
flags.setMutatesThis(); flags.setMutatesThis();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);


assertTrue(NodeUtil.evaluatesToLocalValue(newExpr)); assertTrue(NodeUtil.evaluatesToLocalValue(newExpr));


flags.clearAllFlags(); flags.clearAllFlags();
flags.setReturnsTainted(); flags.setReturnsTainted();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);


assertTrue(NodeUtil.evaluatesToLocalValue(newExpr)); assertTrue(NodeUtil.evaluatesToLocalValue(newExpr));


flags.clearAllFlags(); flags.clearAllFlags();
flags.setThrows(); flags.setThrows();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);


assertFalse(NodeUtil.evaluatesToLocalValue(newExpr)); assertFalse(NodeUtil.evaluatesToLocalValue(newExpr));


flags.clearAllFlags(); flags.clearAllFlags();
flags.setMutatesArguments(); flags.setMutatesArguments();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);


assertFalse(NodeUtil.evaluatesToLocalValue(newExpr)); assertFalse(NodeUtil.evaluatesToLocalValue(newExpr));


flags.clearAllFlags(); flags.clearAllFlags();
flags.setMutatesGlobalState(); flags.setMutatesGlobalState();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);


assertFalse(NodeUtil.evaluatesToLocalValue(newExpr)); assertFalse(NodeUtil.evaluatesToLocalValue(newExpr));
} }


public void testLocalValue3() { public void testLocalValueSpread() {
Node newExpr = getNode("[...x]"); assertFalse(NodeUtil.evaluatesToLocalValue(getNode("[...x]")));
assertFalse(NodeUtil.evaluatesToLocalValue(newExpr));
} }


public void testCallSideEffects() { public void testCallSideEffects() {
Expand All @@ -1577,43 +1600,43 @@ public void testCallSideEffects() {


// No side effects, local result // No side effects, local result
flags.clearAllFlags(); flags.clearAllFlags();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);
flags.clearAllFlags(); flags.clearAllFlags();
callExpr.setSideEffectFlags(flags.valueOf()); callExpr.setSideEffectFlags(flags);


assertTrue(NodeUtil.evaluatesToLocalValue(callExpr)); assertTrue(NodeUtil.evaluatesToLocalValue(callExpr));
assertFalse(NodeUtil.functionCallHasSideEffects(callExpr)); assertFalse(NodeUtil.functionCallHasSideEffects(callExpr));
assertFalse(NodeUtil.mayHaveSideEffects(callExpr)); assertFalse(NodeUtil.mayHaveSideEffects(callExpr));


// Modifies this, local result // Modifies this, local result
flags.clearAllFlags(); flags.clearAllFlags();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);
flags.clearAllFlags(); flags.clearAllFlags();
flags.setMutatesThis(); flags.setMutatesThis();
callExpr.setSideEffectFlags(flags.valueOf()); callExpr.setSideEffectFlags(flags);


assertTrue(NodeUtil.evaluatesToLocalValue(callExpr)); assertTrue(NodeUtil.evaluatesToLocalValue(callExpr));
assertFalse(NodeUtil.functionCallHasSideEffects(callExpr)); assertFalse(NodeUtil.functionCallHasSideEffects(callExpr));
assertFalse(NodeUtil.mayHaveSideEffects(callExpr)); assertFalse(NodeUtil.mayHaveSideEffects(callExpr));


// Modifies this, non-local result // Modifies this, non-local result
flags.clearAllFlags(); flags.clearAllFlags();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);
flags.clearAllFlags(); flags.clearAllFlags();
flags.setMutatesThis(); flags.setMutatesThis();
flags.setReturnsTainted(); flags.setReturnsTainted();
callExpr.setSideEffectFlags(flags.valueOf()); callExpr.setSideEffectFlags(flags);


assertFalse(NodeUtil.evaluatesToLocalValue(callExpr)); assertFalse(NodeUtil.evaluatesToLocalValue(callExpr));
assertFalse(NodeUtil.functionCallHasSideEffects(callExpr)); assertFalse(NodeUtil.functionCallHasSideEffects(callExpr));
assertFalse(NodeUtil.mayHaveSideEffects(callExpr)); assertFalse(NodeUtil.mayHaveSideEffects(callExpr));


// No modifications, non-local result // No modifications, non-local result
flags.clearAllFlags(); flags.clearAllFlags();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);
flags.clearAllFlags(); flags.clearAllFlags();
flags.setReturnsTainted(); flags.setReturnsTainted();
callExpr.setSideEffectFlags(flags.valueOf()); callExpr.setSideEffectFlags(flags);


assertFalse(NodeUtil.evaluatesToLocalValue(callExpr)); assertFalse(NodeUtil.evaluatesToLocalValue(callExpr));
assertFalse(NodeUtil.functionCallHasSideEffects(callExpr)); assertFalse(NodeUtil.functionCallHasSideEffects(callExpr));
Expand All @@ -1623,9 +1646,9 @@ public void testCallSideEffects() {
// This call could be removed, but not the new. // This call could be removed, but not the new.
flags.clearAllFlags(); flags.clearAllFlags();
flags.setMutatesGlobalState(); flags.setMutatesGlobalState();
newExpr.setSideEffectFlags(flags.valueOf()); newExpr.setSideEffectFlags(flags);
flags.clearAllFlags(); flags.clearAllFlags();
callExpr.setSideEffectFlags(flags.valueOf()); callExpr.setSideEffectFlags(flags);


assertTrue(NodeUtil.evaluatesToLocalValue(callExpr)); assertTrue(NodeUtil.evaluatesToLocalValue(callExpr));
assertFalse(NodeUtil.functionCallHasSideEffects(callExpr)); assertFalse(NodeUtil.functionCallHasSideEffects(callExpr));
Expand Down

0 comments on commit a0dcb0b

Please sign in to comment.