Skip to content

Commit dca8896

Browse files
Closure Teamcopybara-github
authored andcommitted
Allow the super keyword calling a function to be used to instantiate public fields.
Before, when assigning a public field through the `super` keyword calling a function, we would throw `JSC_INVALID_SUPER_ACCESS`. We now check to see if we are in the context of a `MEMBER_FIELD_DEF` to allow the `super` keyword to call a function. A new class called `SuperPropertyAccessAllowedContext`, is now used to create a new context for static blocks and fields given their same behavior. PiperOrigin-RevId: 552580668
1 parent 631f8c1 commit dca8896

File tree

2 files changed

+81
-32
lines changed

2 files changed

+81
-32
lines changed

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

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,14 @@ public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
111111
}
112112
}
113113
break;
114-
114+
case MEMBER_FIELD_DEF:
115+
Context fieldContext = createMemberFieldDefContext(n);
116+
this.contextStack.push(fieldContext);
117+
break;
115118
case BLOCK: // For class static blocks
116119
if (NodeUtil.isClassStaticBlock(n)) {
117-
Context currentContext = contextStack.peek();
118-
Context newContext = new StaticBlockContext(n);
119-
if (newContext != currentContext) {
120-
this.contextStack.push(newContext);
121-
}
120+
Context newContext = createStaticBlockContext(n);
121+
this.contextStack.push(newContext);
122122
}
123123
break;
124124

@@ -241,6 +241,36 @@ void visitContextNode(NodeTraversal t) {
241241
}
242242
}
243243

244+
private static class SuperPropertyAccessAllowedContext extends Context {
245+
SuperPropertyAccessAllowedContext(Node contextNode) {
246+
super(contextNode);
247+
}
248+
249+
@Override
250+
void visitSuperPropertyAccess(NodeTraversal t, Node superNode) {
251+
// Super property should be allowed on a public field and inside static blocks.
252+
}
253+
254+
@Override
255+
void visitSuperConstructorCall(NodeTraversal t, Node superNode) {
256+
// Super constructor calls are only allowed in constructor() methods.
257+
t.report(superNode, INVALID_SUPER_CALL);
258+
}
259+
260+
@Override
261+
Context getContextForArrowFunctionNode(Node arrowFn) {
262+
return this;
263+
}
264+
}
265+
266+
private Context createMemberFieldDefContext(Node fieldNode) {
267+
return new SuperPropertyAccessAllowedContext(fieldNode);
268+
}
269+
270+
private Context createStaticBlockContext(Node staticBlock) {
271+
return new SuperPropertyAccessAllowedContext(staticBlock);
272+
}
273+
244274
/** Lexical context when not within a method, class, or object literal. */
245275
private static class SuperNotAllowedContext extends Context {
246276
SuperNotAllowedContext(Node contextNode) {
@@ -458,30 +488,4 @@ void visitSuperPropertyAccess(NodeTraversal t, Node superNode) {
458488
constructorContext.visitSuperPropertyAccess(t, superNode);
459489
}
460490
}
461-
462-
/** Lexical context within a static initialization block in a class. */
463-
private static class StaticBlockContext extends Context {
464-
465-
StaticBlockContext(Node contextNode) {
466-
super(contextNode);
467-
checkArgument(NodeUtil.isClassStaticBlock(contextNode), contextNode);
468-
}
469-
470-
@Override
471-
Context getContextForArrowFunctionNode(Node arrowFn) {
472-
// Arrow functions still use the same context as the class static block
473-
return this;
474-
}
475-
476-
@Override
477-
void visitSuperConstructorCall(NodeTraversal t, Node superNode) {
478-
// We're not inside a constructor.
479-
t.report(superNode, INVALID_SUPER_CALL);
480-
}
481-
482-
@Override
483-
void visitSuperPropertyAccess(NodeTraversal t, Node superNode) {
484-
// perfectly valid, nothing to do here
485-
}
486-
}
487491
}

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

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,51 @@ public void testMissingSuper() {
6262
error(SUPER_ACCESS_BEFORE_SUPER_CONSTRUCTOR));
6363
}
6464

65+
@Test
66+
public void testFieldSuperCall() {
67+
testSame(
68+
lines(
69+
"class Foo {",
70+
" x() {",
71+
" return 5;",
72+
" }",
73+
"}",
74+
"class Bar extends Foo {",
75+
" y = () => super.x()",
76+
"}"));
77+
78+
testError(
79+
lines(
80+
"class A {}", //
81+
"class B extends A { ",
82+
" x = super();",
83+
"}"),
84+
INVALID_SUPER_CALL);
85+
}
86+
87+
@Test
88+
public void testComputedSuperFields() {
89+
testError(
90+
lines(
91+
"class A {", //
92+
" x = 'fieldOne'",
93+
"}",
94+
"class B extends A { ",
95+
" [super.x] = 2;",
96+
"}"),
97+
INVALID_SUPER_ACCESS);
98+
99+
testError(
100+
lines(
101+
"class A {", //
102+
" x = 'fieldOne'",
103+
"}",
104+
"class B extends A { ",
105+
" static [super.x] = 2;",
106+
"}"),
107+
INVALID_SUPER_ACCESS);
108+
}
109+
65110
@Test
66111
public void testMissingSuper_nestedClass() {
67112
// Note that super is only called for anonymous class "E", not C.

0 commit comments

Comments
 (0)