Skip to content

Commit 6c74008

Browse files
Closure Teamcopybara-github
authored andcommitted
Convert this and super in class static block.
PiperOrigin-RevId: 566709884
1 parent c0d8383 commit 6c74008

File tree

3 files changed

+146
-44
lines changed

3 files changed

+146
-44
lines changed

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,11 @@ private static boolean isHoistScopeRootNode(Node n) {
13061306
case MODULE_BODY:
13071307
case ROOT:
13081308
return rootNode;
1309+
case BLOCK:
1310+
if (NodeUtil.isClassStaticBlock(rootNode)) {
1311+
return rootNode;
1312+
}
1313+
continue;
13091314
default:
13101315
continue;
13111316
}

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

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,6 @@ public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
8989
if (!NodeUtil.isClassStaticBlock(n)) {
9090
break;
9191
}
92-
if (NodeUtil.referencesEnclosingReceiver(n)) {
93-
t.report(n, TranspilationUtil.CANNOT_CONVERT_YET, "Member references this or super");
94-
classStack.peek().cannotConvert = true;
95-
break;
96-
}
9792
checkState(!classStack.isEmpty());
9893
classStack.peek().recordStaticBlock(n);
9994
break;
@@ -163,12 +158,44 @@ private void visitThis(NodeTraversal t, Node thisNode) {
163158
Node className = classRecord.createNewNameReferenceNode().srcrefTree(thisNode);
164159
thisNode.replaceWith(className);
165160
t.reportCodeChange(className);
161+
} else if (rootNode.isBlock()) {
162+
final ClassRecord classRecord = classStack.peek();
163+
Node className = classRecord.createNewNameReferenceNode().srcrefTree(thisNode);
164+
thisNode.replaceWith(className);
165+
t.reportCodeChange(className);
166166
}
167167
}
168168

169+
/**
170+
* Rename super in static context to super class name.
171+
*
172+
* <p>CASE : rootNode.isMemberFieldDef() && rootNode.isStaticMember()
173+
*
174+
* <pre><code>
175+
* class C {
176+
* static x = 2;
177+
* }
178+
* class D extends C {
179+
* static y = super.x;
180+
* }
181+
* </code></pre>
182+
*
183+
* <p>CASE : rootNode.isBlock()
184+
*
185+
* <pre><code>
186+
* class B {
187+
* static y = 3;
188+
* }
189+
* class C extends B {
190+
* static {
191+
* let x = super.y;
192+
* }
193+
* }
194+
* </code></pre>
195+
*/
169196
private void visitSuper(NodeTraversal t, Node n) {
170-
Node rootNode = t.getClosestScopeRootNodeBindingThisOrSuper();
171-
if (rootNode.isMemberFieldDef() && rootNode.isStaticMember()) {
197+
Node rootNode = t.getClosestScopeRootNodeBindingThisOrSuper(); // returns BLOCK if static block
198+
if ((rootNode.isMemberFieldDef() && rootNode.isStaticMember()) || rootNode.isBlock()) {
172199
Node superclassName = rootNode.getGrandparent().getChildAtIndex(1).cloneNode();
173200
n.replaceWith(superclassName);
174201
t.reportCodeChange(superclassName);
@@ -279,9 +306,6 @@ private void rewriteStaticMembers(NodeTraversal t, ClassRecord record) {
279306

280307
switch (staticMember.getToken()) {
281308
case BLOCK:
282-
if (!NodeUtil.getVarsDeclaredInBranch(staticMember).isEmpty()) {
283-
t.report(staticMember, TranspilationUtil.CANNOT_CONVERT_YET, "Var in static block");
284-
}
285309
transpiledNode = staticMember.detach();
286310
break;
287311
case MEMBER_FIELD_DEF:

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

Lines changed: 107 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@
1515
*/
1616
package com.google.javascript.jscomp;
1717

18-
import static com.google.javascript.jscomp.TranspilationUtil.CANNOT_CONVERT_YET;
19-
2018
import com.google.common.collect.ImmutableMap;
2119
import org.junit.Before;
2220
import org.junit.Test;
@@ -70,70 +68,145 @@ private void computedFieldTest(Sources srcs, Expected originalExpected) {
7068
}
7169

7270
@Test
73-
public void testCannotConvertYet() {
74-
testError(
71+
public void testClassStaticBlock() {
72+
test(
7573
lines(
7674
"class C {", //
7775
" static {",
7876
" let x = 2",
7977
" this.y = x",
8078
" }",
8179
"}"),
82-
/*lines(
83-
"class C {}", //
84-
"{",
85-
" let x = 2;",
86-
" C.y = x", // TODO(b/235871861): Need to correct references to `this`
87-
"}")*/
88-
CANNOT_CONVERT_YET); // uses `this` in static block
80+
lines(
81+
"class C {}", //
82+
"{",
83+
" let x = 2;",
84+
" C.y = x",
85+
"}")); // uses `this` in static block
8986

90-
testError(
87+
test(
9188
lines(
89+
"class B {",
90+
" static y = 3;",
91+
"}",
9292
"class C extends B {", //
9393
" static {",
94-
" let x = super.y",
94+
" let x = super.y;",
9595
" }",
9696
"}"),
97-
CANNOT_CONVERT_YET); // uses `super`
97+
lines(
98+
"class B {}",
99+
"B.y = 3;",
100+
"class C extends B {}", //
101+
"{",
102+
// TODO (user): Object.getPrototypeOf(C) is the technically correct way.
103+
// We are not doing this for code size reasons.
104+
" let x = B.y", /* Object.getPrototypeOf(C).y */
105+
"}")); // uses `super`
98106

99-
testError(
107+
test(
100108
lines(
101109
"class C {", //
102110
" static {",
103111
" C.x = 2",
104112
" const y = this.x",
105113
" }",
106114
"}"),
107-
/*lines(
108-
"class C {}", //
109-
"{",
110-
" C.x = 2;",
111-
" const y = C.x",
112-
"}")*/
113-
CANNOT_CONVERT_YET); // uses `this` in static block
115+
lines(
116+
"class C {}", //
117+
"{",
118+
" C.x = 2;",
119+
" const y = C.x",
120+
"}")); // uses `this` in static block
114121

115-
testError(
122+
test(
123+
lines(
124+
"var z = 1", //
125+
"class C {",
126+
" static {",
127+
" let x = 2",
128+
" var z = 3;",
129+
" }",
130+
"}"),
131+
lines(
132+
"var z = 1", //
133+
"class C {}",
134+
"{",
135+
" let x = 2",
136+
" var z$jscomp$1 = 3;",
137+
"}")); // `var` in static block
138+
139+
test(
116140
lines(
117141
"let C = class {",
118142
" static prop = 5;",
119-
"},",
120-
"D = class extends C {",
143+
"};",
144+
"let D = class extends C {",
121145
" static {",
122-
" console.log(this.prop);",
146+
" this.prop = 10;",
123147
" }",
124-
"}"),
125-
CANNOT_CONVERT_YET); // uses `this` in static block
148+
"};"),
149+
lines(
150+
"let C = class {}",
151+
"C.prop = 5;",
152+
"let D = class extends C {}",
153+
"{",
154+
" D.prop = 10;",
155+
"}")); //
126156

127-
testError(
157+
// TODO (user): This will be fixed by moving the RewriteClassMembers pass after
158+
// normalization, because normalization will split these two declarations into separate let
159+
// assignments.
160+
test(
128161
lines(
129-
"var z = 1", //
130-
"class C {",
162+
"let C = class {",
163+
" static prop = 5;",
164+
"},",
165+
"D = class extends C {",
131166
" static {",
132-
" let x = 2",
133-
" var z = 3;",
167+
" this.prop = 10;",
134168
" }",
135169
"}"),
136-
CANNOT_CONVERT_YET); // `var` in static block
170+
lines(
171+
"let C = class {}, D = class extends C {}",
172+
"{",
173+
" D.prop = 10;",
174+
"}",
175+
"C.prop = 5;")); // defines classes in the same let statement
176+
}
177+
178+
@Test
179+
public void testMultipleStaticBlocks() {
180+
computedFieldTest(
181+
srcs(
182+
lines(
183+
"var z = 1", //
184+
"/** @unrestricted */",
185+
"class C {",
186+
" static x = 2;",
187+
" static {",
188+
" z = z + this.x;",
189+
" }",
190+
" static [z] = 3;",
191+
" static w = 5;",
192+
" static {",
193+
" z = z + this.w;",
194+
" }",
195+
"}")),
196+
expected(
197+
lines(
198+
"var z = 1", //
199+
"var COMPFIELD$0 = z;",
200+
"class C {}",
201+
"C.x = 2;",
202+
"{",
203+
" z = z + C.x;",
204+
"}",
205+
"C[COMPFIELD$0] = 3;",
206+
"C.w = 5;",
207+
"{",
208+
" z = z + C.w;",
209+
"}"))); //
137210
}
138211

139212
@Test

0 commit comments

Comments
 (0)