Skip to content

Commit

Permalink
Make remove unused vars compatible with rest parameters
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=164866596
  • Loading branch information
simran-arora authored and blickly committed Aug 10, 2017
1 parent 1817533 commit 580282c
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 15 deletions.
4 changes: 3 additions & 1 deletion src/com/google/javascript/jscomp/NodeUtil.java
Expand Up @@ -2763,7 +2763,6 @@ public static void removeChild(Node parent, Node node) {
parent.replaceChild(node, IR.empty()); parent.replaceChild(node, IR.empty());
} else if (parent.isObjectPattern()) { } else if (parent.isObjectPattern()) {
// Remove the name from the object pattern // Remove the name from the object pattern

parent.removeChild(node); parent.removeChild(node);
} else if (parent.isArrayPattern()) { } else if (parent.isArrayPattern()) {
if (node == parent.getLastChild()) { if (node == parent.getLastChild()) {
Expand All @@ -2779,6 +2778,9 @@ public static void removeChild(Node parent, Node node) {
// want to remove it from the AST // want to remove it from the AST
removeChild(parent.getParent(), parent); removeChild(parent.getParent(), parent);
} }
} else if (parent.isRest()) {
// Rest params can only ever have one child node
parent.detach();
} else if (parent.isParamList()) { } else if (parent.isParamList()) {
parent.removeChild(node); parent.removeChild(node);
} else if (parent.isDefaultValue()) { } else if (parent.isDefaultValue()) {
Expand Down
33 changes: 19 additions & 14 deletions src/com/google/javascript/jscomp/RemoveUnusedVars.java
Expand Up @@ -536,7 +536,9 @@ private void removeUnusedDestructuringNames(Node argList, Scope fparamScope) {
if (toRemove.getParent().isStringKey()) { if (toRemove.getParent().isStringKey()) {
toRemove = toRemove.getParent(); toRemove = toRemove.getParent();
} }
NodeUtil.deleteNode(toRemove, compiler); NodeUtil.markFunctionsDeleted(toRemove, compiler);
compiler.reportChangeToEnclosingScope(toRemove.getParent());
NodeUtil.removeChild(toRemove.getParent(), toRemove);
} }
} }
} }
Expand All @@ -553,30 +555,33 @@ private void removeUnusedDestructuringNames(Node argList, Scope fparamScope) {
private void maybeRemoveUnusedTrailingParameters(Node argList, Scope fparamScope) { private void maybeRemoveUnusedTrailingParameters(Node argList, Scope fparamScope) {
Node lastArg; Node lastArg;
while ((lastArg = argList.getLastChild()) != null) { while ((lastArg = argList.getLastChild()) != null) {
Node toRemove = lastArg; Node lValue = lastArg;
if (lastArg.isDefaultValue()) { if (lastArg.isDefaultValue()) {
toRemove = lastArg.getFirstChild(); lValue = lastArg.getFirstChild();
Node defaultValueSecondChild = toRemove.getNext(); Node defaultValueSecondChild = lValue.getNext();
if (NodeUtil.mayHaveSideEffects(defaultValueSecondChild)) { if (NodeUtil.mayHaveSideEffects(defaultValueSecondChild)) {
break; break;
} }
} }


if (toRemove.isDestructuringPattern()) { if (lValue.isRest()) {
if (!toRemove.hasChildren()) { lValue = lValue.getFirstChild();
}

if (lValue.isDestructuringPattern()) {
if (lValue.hasChildren()) {
break;
} else {
// Remove empty destructuring patterns and their associated object literal assignment // Remove empty destructuring patterns and their associated object literal assignment
// if it exists and if the right hand side does not have side effects. Note, a // if it exists and if the right hand side does not have side effects. Note, a
// destructuring pattern with a "leftover" property key as in {a:{}} is not considered // destructuring pattern with a "leftover" property key as in {a:{}} is not considered
// empty in this case! // empty in this case!
NodeUtil.deleteNode(lastArg, compiler); NodeUtil.deleteNode(lastArg, compiler);
continue; continue;
} else {
break;
} }
} }


// Remove unreferenced parameters Var var = fparamScope.getVar(lValue.getString());
Var var = fparamScope.getVar(toRemove.getString());
if (!referenced.contains(var)) { if (!referenced.contains(var)) {
NodeUtil.deleteNode(lastArg, compiler); NodeUtil.deleteNode(lastArg, compiler);
} else { } else {
Expand Down Expand Up @@ -1006,14 +1011,14 @@ private void removeUnreferencedVars() {
|| toRemove.isArrayPattern() // Array Pattern || toRemove.isArrayPattern() // Array Pattern
|| parent.isObjectPattern() // Object Pattern || parent.isObjectPattern() // Object Pattern
|| toRemove.isClass() || toRemove.isClass()
|| ((toRemove.isDefaultValue() || (toRemove.isDefaultValue()
&& NodeUtil.getEnclosingScopeRoot(toRemove).isFunction()) && NodeUtil.getEnclosingScopeRoot(toRemove).isFunction())
|| ((parent.isDefaultValue()) || (toRemove.isRest() && NodeUtil.getEnclosingScopeRoot(toRemove).isFunction()),
&& NodeUtil.getEnclosingScopeRoot(parent).isFunction())),
"We should only declare Vars and functions and function args and classes"); "We should only declare Vars and functions and function args and classes");


if ((toRemove.isParamList() && parent.isFunction()) if ((toRemove.isParamList() && parent.isFunction())
|| (toRemove.isDefaultValue() && NodeUtil.getEnclosingScopeRoot(parent).isFunction())) { || (toRemove.isDefaultValue() && NodeUtil.getEnclosingScopeRoot(toRemove).isFunction())
|| (toRemove.isRest() && NodeUtil.getEnclosingScopeRoot(toRemove).isFunction())) {
// Don't remove function arguments here. That's a special case // Don't remove function arguments here. That's a special case
// that's taken care of in removeUnreferencedFunctionArgs. // that's taken care of in removeUnreferencedFunctionArgs.
} else if (toRemove.isComputedProp()) { } else if (toRemove.isComputedProp()) {
Expand Down
24 changes: 24 additions & 0 deletions test/com/google/javascript/jscomp/RemoveUnusedVarsTest.java
Expand Up @@ -312,6 +312,30 @@ public void testArrayDestructuringParams() {
test("function f([x] = [foo()]) {}; f();", "function f([] = [foo()]) {}; f();"); test("function f([x] = [foo()]) {}; f();", "function f([] = [foo()]) {}; f();");
} }


public void testRestParams() {
test(
"function foo(...args) {/**rest param unused*/}; foo();",
"function foo( ) {/**rest param unused*/}; foo();");

testSame("function foo(a, ...args) { args[0]; }; foo();");

// Rest param in pattern
testSame(
LINE_JOINER.join(
"function countArgs(x, ...{length}) {",
" return length;",
"}",
"alert(countArgs(1, 1, 1, 1, 1));"));

test(
" function foo([...rest]) {/**rest unused*/}; foo();",
" function foo() {/**rest unused*/}; foo();");

test(
" function foo([x, ...rest]) { x; }; foo();",
" function foo([x]) { x; }; foo();");
}

public void testFunctionsDeadButEscaped() { public void testFunctionsDeadButEscaped() {
testSame("function b(a) { a = 1; print(arguments[0]) }; b(6)"); testSame("function b(a) { a = 1; print(arguments[0]) }; b(6)");
testSame("function b(a) { var c = 2; a = c; print(arguments[0]) }; b(6)"); testSame("function b(a) { var c = 2; a = c; print(arguments[0]) }; b(6)");
Expand Down

0 comments on commit 580282c

Please sign in to comment.