Skip to content

Commit ec5741d

Browse files
Closure Teamcopybara-github
authored andcommitted
For instance members, declare the computed field keys with side effects as separate statements added before the class declaration.
PiperOrigin-RevId: 565794428
1 parent 0e9335f commit ec5741d

File tree

2 files changed

+72
-56
lines changed

2 files changed

+72
-56
lines changed

src/com/google/javascript/jscomp/RewriteClassMembers.java

Lines changed: 23 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.google.common.collect.ImmutableSet;
2222
import com.google.javascript.jscomp.parsing.parser.FeatureSet;
2323
import com.google.javascript.jscomp.parsing.parser.FeatureSet.Feature;
24+
import com.google.javascript.rhino.IR;
2425
import com.google.javascript.rhino.Node;
2526
import java.util.ArrayDeque;
2627
import java.util.Deque;
@@ -253,11 +254,10 @@ private void moveComputedFieldsWithSideEffectsInsideComputedFunction(
253254
* becomes
254255
*
255256
* <pre>
256-
* var $jscomp$computedfield$0;
257+
* var $jscomp$computedfield$0 = bar('str');
257258
* class Foo {
258259
* [$jscomp$computedfield$0] = 4;
259260
* }
260-
* $jscomp$computedfield$0 = bar('str');
261261
* </pre>
262262
*/
263263
private void extractExpressionFromCompField(
@@ -271,16 +271,12 @@ private void extractExpressionFromCompField(
271271

272272
Node compExpression = memberField.getFirstChild().detach();
273273
Node compFieldVar =
274-
astFactory.createSingleVarNameDeclaration(generateUniqueCompFieldVarName(t));
274+
astFactory.createSingleVarNameDeclaration(
275+
generateUniqueCompFieldVarName(t), compExpression);
275276
Node compFieldName = compFieldVar.getFirstChild();
276277
memberField.addChildToFront(compFieldName.cloneNode());
277278
compFieldVar.insertBefore(record.insertionPointBeforeClass);
278279
compFieldVar.srcrefTreeIfMissing(record.classNode);
279-
Node exprResult =
280-
astFactory.exprResult(astFactory.createAssign(compFieldName.cloneNode(), compExpression));
281-
exprResult.insertAfter(record.insertionPointAfterClass);
282-
record.insertionPointAfterClass = exprResult;
283-
exprResult.srcrefTreeIfMissing(record.classNode);
284280
}
285281

286282
/** Returns $jscomp$compfield$[FILE_ID]$[number] */
@@ -298,7 +294,7 @@ private void rewriteInstanceMembers(NodeTraversal t, ClassRecord record) {
298294
ctorCreator.synthesizeClassConstructorIfMissing(t, record.classNode);
299295
Node ctor = NodeUtil.getEs6ClassConstructorMemberFunctionDef(record.classNode);
300296
Node ctorBlock = ctor.getFirstChild().getLastChild();
301-
Node insertionPoint = findInitialInstanceInsertionPoint(ctorBlock);
297+
Node insertionPoint = addTemporaryInsertionPoint(ctorBlock);
302298

303299
while (!instanceMembers.isEmpty()) {
304300
Node instanceMember = instanceMembers.pop();
@@ -314,14 +310,14 @@ private void rewriteInstanceMembers(NodeTraversal t, ClassRecord record) {
314310
instanceMember.isMemberFieldDef()
315311
? convNonCompFieldToGetProp(thisNode, instanceMember.detach())
316312
: convCompFieldToGetElem(thisNode, instanceMember.detach());
317-
if (insertionPoint == ctorBlock) { // insert the field at the beginning of the block, no super
318-
ctorBlock.addChildToFront(transpiledNode);
319-
} else {
320-
transpiledNode.insertAfter(insertionPoint);
321-
}
322-
t.reportCodeChange(); // we moved the field from the class body
323-
t.reportCodeChange(ctorBlock); // to the constructor, so we need both
313+
314+
transpiledNode.insertBefore(insertionPoint);
324315
}
316+
317+
insertionPoint.detach();
318+
319+
t.reportCodeChange(); // we moved the field from the class body
320+
t.reportCodeChange(ctorBlock); // to the constructor, so we need both
325321
}
326322

327323
/** Rewrites and moves all static blocks and fields */
@@ -399,25 +395,22 @@ private Node convCompFieldToGetElem(Node receiver, Node computedField) {
399395
}
400396

401397
/**
402-
* Finds the location in the constructor to put the transpiled instance fields
403-
*
404-
* <p>Returns the constructor body if there is no super() call so the field can be put at the
405-
* beginning of the class
398+
* Finds the location of super() call in the constructor and add a temporary empty node after the
399+
* super() call. If there is no super() call, add a temporary empty node at the beginning of the
400+
* constructor body.
406401
*
407-
* <p>Returns the super() call otherwise so the field can be put after the super() call
402+
* <p>Returns the added temporary empty node
408403
*/
409-
private Node findInitialInstanceInsertionPoint(Node ctorBlock) {
410-
if (NodeUtil.referencesSuper(ctorBlock)) {
411-
// will use the fact that if there is super in the constructor, the first appearance of
412-
// super
413-
// must be the super call
404+
private Node addTemporaryInsertionPoint(Node ctorBlock) {
405+
Node tempNode = IR.empty();
414406
for (Node stmt = ctorBlock.getFirstChild(); stmt != null; stmt = stmt.getNext()) {
415407
if (NodeUtil.isExprCall(stmt) && stmt.getFirstFirstChild().isSuper()) {
416-
return stmt;
408+
tempNode.insertAfter(stmt);
409+
return tempNode;
417410
}
418411
}
419-
}
420-
return ctorBlock; // in case the super loop doesn't work, insert at beginning of block
412+
ctorBlock.addChildToFront(tempNode);
413+
return tempNode;
421414
}
422415

423416
/**
@@ -489,7 +482,7 @@ void enterField(Node field) {
489482
if (field.isStaticMember()) {
490483
staticMembers.push(field);
491484
} else {
492-
instanceMembers.push(field);
485+
instanceMembers.offer(field);
493486
}
494487
}
495488

test/com/google/javascript/jscomp/RewriteClassMembersTest.java

Lines changed: 49 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -283,17 +283,11 @@ public void testSuperInStaticField() {
283283
"class Bar {",
284284
" static a = { method1() {} };",
285285
" static b = { method2() { super.method1(); } };",
286-
"}",
287-
"Object.setPrototypeOf = function(c, d) {}",
288-
"Object.setPrototypeOf(Foo.b, Foo.a);",
289-
"Foo.b.method2();"),
286+
"}"),
290287
lines(
291288
"class Bar {}",
292289
"Bar.a = { method1() {} };",
293-
"Bar.b = { method2() { super.method1(); } };",
294-
"Object.setPrototypeOf = function(c, d) {}",
295-
"Object.setPrototypeOf(Foo.b, Foo.a);",
296-
"Foo.b.method2();"));
290+
"Bar.b = { method2() { super.method1(); } };"));
297291
}
298292

299293
@Test
@@ -302,15 +296,17 @@ public void testComputedPropInNonStaticField() {
302296
lines(
303297
"/** @unrestricted */",
304298
"class C {", //
305-
" ['x'];",
306-
" ['y'] = 3;",
299+
" [x+=1];",
300+
" [x+=2] = 3;",
307301
"}"),
308302
lines(
309-
"class C {", //
303+
"var $jscomp$compfield$m1146332801$0 = x += 1;",
304+
"var $jscomp$compfield$m1146332801$1 = x += 2;",
305+
"class C {",
310306
" constructor() {",
311-
" this['x'];",
312-
" this['y'] = 3;",
313-
" }",
307+
" this[$jscomp$compfield$m1146332801$0];",
308+
" this[$jscomp$compfield$m1146332801$1] = 3;",
309+
" }",
314310
"}"));
315311

316312
test(
@@ -492,14 +488,13 @@ public void testSideEffectsInComputedField() {
492488
lines(
493489
"function bar() {",
494490
" this.x = 3;",
495-
" var COMPFIELD$0;",
491+
" var COMPFIELD$0 = this.x;",
496492
" class Foo {",
497493
" constructor() {",
498494
" this.y;",
499495
" this[COMPFIELD$0] = 2;",
500496
" }",
501497
" }",
502-
" COMPFIELD$0 = this.x;",
503498
"}")));
504499

505500
computedFieldTest(
@@ -522,13 +517,12 @@ public void testSideEffectsInComputedField() {
522517
"}",
523518
"class F extends E {",
524519
" x() {",
525-
" var COMPFIELD$0;",
520+
" var COMPFIELD$0 = super.y();",
526521
" const testcode$classdecl$var0 = class {",
527522
" constructor() {",
528523
" this[COMPFIELD$0] = 4;",
529524
" }",
530525
" };",
531-
" COMPFIELD$0 = super.y();",
532526
" return testcode$classdecl$var0;",
533527
" }",
534528
"}")));
@@ -546,15 +540,13 @@ public void testSideEffectsInComputedField() {
546540
expected(
547541
lines(
548542
"function bar(num) {}",
549-
"var COMPFIELD$0;",
550-
"var COMPFIELD$1;",
543+
"var COMPFIELD$0 = bar(1);",
544+
"var COMPFIELD$1 = bar(2);",
551545
"class Foo {",
552546
" constructor() {",
553547
" this[COMPFIELD$0] = 'a'",
554548
" }",
555549
"}",
556-
"COMPFIELD$0 = bar(1);",
557-
"COMPFIELD$1 = bar(2);",
558550
"Foo.b = bar(3);",
559551
"Foo[COMPFIELD$1] = bar(4);")));
560552

@@ -569,9 +561,8 @@ public void testSideEffectsInComputedField() {
569561
expected(
570562
lines(
571563
"let x = 'hello';",
572-
"var COMPFIELD$0;",
564+
"var COMPFIELD$0 = x;",
573565
"class Foo {}",
574-
"COMPFIELD$0 = x;",
575566
"Foo.n = x = 5;",
576567
"Foo[COMPFIELD$0] = 'world';")));
577568

@@ -843,16 +834,20 @@ public void testStaticNoncomputed() {
843834
public void testInstanceNoncomputedWithNonemptyConstructor() {
844835
test(
845836
lines(
846-
"class C {", //
837+
"class C extends Object {", //
847838
" x = 1;",
839+
" z = 3;",
848840
" constructor() {",
841+
" super();",
849842
" this.y = 2;",
850843
" }",
851844
"}"),
852845
lines(
853-
"class C {", //
846+
"class C extends Object{", //
854847
" constructor() {",
848+
" super();",
855849
" this.x = 1",
850+
" this.z = 3",
856851
" this.y = 2;",
857852
" }",
858853
"}"));
@@ -962,6 +957,34 @@ public void testInstanceNoncomputedWithNonemptyConstructor() {
962957
"}"));
963958
}
964959

960+
@Test
961+
public void testInstanceComputedWithNonemptyConstructorAndSuper() {
962+
963+
computedFieldTest(
964+
srcs(
965+
lines(
966+
"class A { constructor() { alert(1); } }",
967+
"/** @unrestricted */ class C extends A {", //
968+
" ['x'] = 1;",
969+
" constructor() {",
970+
" super();",
971+
" this['y'] = 2;",
972+
" this['z'] = 3;",
973+
" }",
974+
"}")),
975+
expected(
976+
lines(
977+
"class A { constructor() { alert(1); } }",
978+
"class C extends A {", //
979+
" constructor() {",
980+
" super()",
981+
" this['x'] = 1",
982+
" this['y'] = 2;",
983+
" this['z'] = 3;",
984+
" }",
985+
"}")));
986+
}
987+
965988
@Test
966989
public void testInstanceNoncomputedWithNonemptyConstructorAndSuper() {
967990
test(

0 commit comments

Comments
 (0)