Skip to content

Commit

Permalink
When there is a function literal inside a call to super(), make sure …
Browse files Browse the repository at this point in the history
…the function literal (not a clone of it) is kept in the tree.

If we clone it, the MemoizedScopeCreator keeps a reference to the original, which causes problems in the SymbolTable.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=144231537
  • Loading branch information
tbreisacher authored and blickly committed Jan 12, 2017
1 parent eab9129 commit 63cdab9
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -255,15 +255,15 @@ public void visit(NodeTraversal t, Node n, Node parent) {
}
private Node createNewSuperCall(String superClassQName, Node superCall) {
checkArgument(superCall.isCall(), superCall);
Node newSuperCall = superCall.cloneTree();
Node callee = newSuperCall.getFirstChild();
Node newSuperCall = superCall.cloneNode();
Node callee = superCall.removeFirstChild();

if (callee.isSuper()) {
// super(...) -> SuperClass.call(this, ...)
Node superClassDotCall =
IR.getprop(NodeUtil.newQName(compiler, superClassQName), IR.string("call"))
.useSourceInfoFromForTree(callee);
newSuperCall.replaceChild(callee, superClassDotCall);
newSuperCall.addChildToBack(superClassDotCall);
newSuperCall.putBooleanProp(Node.FREE_CALL, false); // callee is now a getprop
newSuperCall.addChildAfter(IR.thisNode().useSourceInfoFrom(callee), superClassDotCall);
} else {
Expand All @@ -272,20 +272,24 @@ private Node createNewSuperCall(String superClassQName, Node superCall) {
Node applyNode = checkNotNull(callee.getSecondChild());
checkState(applyNode.getString().equals("apply"), applyNode);

Node superDotApply = newSuperCall.getFirstChild();
Node superNode = superDotApply.getFirstChild();
superDotApply.replaceChild(
newSuperCall.addChildToBack(callee);
Node superNode = callee.getFirstChild();
callee.replaceChild(
superNode,
NodeUtil.newQName(compiler, superClassQName).useSourceInfoFromForTree(superNode));
// super.apply(null, ...) is generated by spread transpilation
// super.apply(this, arguments) is used by Es6ConvertSuper in automatically-generated
// constructors.
Node nullOrThisNode = newSuperCall.getSecondChild();
Node nullOrThisNode = superCall.getFirstChild();
if (!nullOrThisNode.isThis()) {
checkState(nullOrThisNode.isNull(), nullOrThisNode);
newSuperCall.replaceChild(nullOrThisNode, IR.thisNode().useSourceInfoFrom(nullOrThisNode));
superCall.removeChild(nullOrThisNode);
newSuperCall.addChildToBack(IR.thisNode().useSourceInfoFrom(nullOrThisNode));
}
}
while (superCall.hasChildren()) {
newSuperCall.addChildToBack(superCall.removeFirstChild());
}
return newSuperCall;
}

Expand Down
16 changes: 16 additions & 0 deletions test/com/google/javascript/jscomp/SymbolTableTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.google.javascript.jscomp;

import static com.google.common.truth.Truth.assertThat;
import static com.google.javascript.jscomp.CompilerTestCase.LINE_JOINER;
import static com.google.javascript.jscomp.parsing.Config.JsDocParsing.INCLUDE_DESCRIPTIONS_NO_WHITESPACE;

import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -66,6 +67,21 @@ public void setUp() throws Exception {
options.setParseJsDocDocumentation(INCLUDE_DESCRIPTIONS_NO_WHITESPACE);
}

/**
* Make sure rewrite of super() call containing a function literal doesn't cause
* the SymbolTable to crash.
*/
public void testFunctionInCall() {
createSymbolTable(
LINE_JOINER.join(
"class Y { constructor(fn) {} }",
"class X extends Y {",
" constructor() {",
" super(function() {});",
" }",
"}"));
}

public void testGlobalVar() throws Exception {
SymbolTable table = createSymbolTable(
"/** @type {number} */ var x = 5;");
Expand Down

0 comments on commit 63cdab9

Please sign in to comment.