Skip to content

Commit 1d1ebd0

Browse files
committed
Do not rename references to class inside of the class body function
1 parent 21c2745 commit 1d1ebd0

File tree

5 files changed

+270
-2
lines changed

5 files changed

+270
-2
lines changed

src/compiler/transformers/es2015.ts

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3780,14 +3780,40 @@ namespace ts {
37803780
function substituteExpressionIdentifier(node: Identifier): Identifier {
37813781
if (enabledSubstitutions & ES2015SubstitutionFlags.BlockScopedBindings && !isInternalName(node)) {
37823782
const declaration = resolver.getReferencedDeclarationWithCollidingName(node);
3783-
if (declaration) {
3783+
if (declaration && !(isClassLike(declaration) && isPartOfClassBody(declaration, node))) {
37843784
return setTextRange(getGeneratedNameForNode(declaration.name), node);
37853785
}
37863786
}
37873787

37883788
return node;
37893789
}
37903790

3791+
function isPartOfClassBody(declaration: ClassLikeDeclaration, node: Identifier) {
3792+
let currentNode = getParseTreeNode(node);
3793+
if (!currentNode || currentNode === declaration || currentNode.end <= declaration.pos || currentNode.pos >= declaration.end) {
3794+
// if the node has no correlation to a parse tree node, its definitely not
3795+
// part of the body.
3796+
// if the node is outside of the document range of the declaration, its
3797+
// definitely not part of the body.
3798+
return false;
3799+
}
3800+
const blockScope = getEnclosingBlockScopeContainer(declaration);
3801+
while (currentNode) {
3802+
if (currentNode === blockScope || currentNode === declaration) {
3803+
// if we are in the enclosing block scope of the declaration, we are definitely
3804+
// not inside the class body.
3805+
return false;
3806+
}
3807+
if (isClassElement(currentNode) && currentNode.parent === declaration) {
3808+
// we are in the class body, but we treat static fields as outside of the class body
3809+
return currentNode.kind !== SyntaxKind.PropertyDeclaration
3810+
|| (getModifierFlags(currentNode) & ModifierFlags.Static) === 0;
3811+
}
3812+
currentNode = currentNode.parent;
3813+
}
3814+
return false;
3815+
}
3816+
37913817
/**
37923818
* Substitutes `this` when contained within an arrow function.
37933819
*
@@ -3803,7 +3829,7 @@ namespace ts {
38033829

38043830
function getClassMemberPrefix(node: ClassExpression | ClassDeclaration, member: ClassElement) {
38053831
return hasModifier(member, ModifierFlags.Static)
3806-
? getLocalName(node)
3832+
? getInternalName(node)
38073833
: createPropertyAccess(getInternalName(node), "prototype");
38083834
}
38093835

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//// [classBlockScoping.ts]
2+
function f(b: boolean) {
3+
let Foo: any;
4+
if (b) {
5+
Foo = class Foo {
6+
static y = new Foo();
7+
8+
static x() {
9+
new Foo();
10+
}
11+
12+
m() {
13+
new Foo();
14+
}
15+
};
16+
17+
new Foo();
18+
}
19+
else {
20+
class Foo {
21+
static y = new Foo();
22+
23+
static x() {
24+
new Foo();
25+
}
26+
27+
m() {
28+
new Foo();
29+
}
30+
}
31+
32+
new Foo();
33+
}
34+
}
35+
36+
//// [classBlockScoping.js]
37+
function f(b) {
38+
var Foo;
39+
if (b) {
40+
Foo = (_a = (function () {
41+
function Foo() {
42+
}
43+
Foo.x = function () {
44+
new Foo();
45+
};
46+
Foo.prototype.m = function () {
47+
new Foo();
48+
};
49+
return Foo;
50+
}()),
51+
_a.y = new _a(),
52+
_a);
53+
new Foo();
54+
}
55+
else {
56+
var Foo_1 = (function () {
57+
function Foo() {
58+
}
59+
Foo.x = function () {
60+
new Foo();
61+
};
62+
Foo.prototype.m = function () {
63+
new Foo();
64+
};
65+
return Foo;
66+
}());
67+
Foo_1.y = new Foo_1();
68+
new Foo_1();
69+
}
70+
var _a;
71+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
=== tests/cases/compiler/classBlockScoping.ts ===
2+
function f(b: boolean) {
3+
>f : Symbol(f, Decl(classBlockScoping.ts, 0, 0))
4+
>b : Symbol(b, Decl(classBlockScoping.ts, 0, 11))
5+
6+
let Foo: any;
7+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 1, 5))
8+
9+
if (b) {
10+
>b : Symbol(b, Decl(classBlockScoping.ts, 0, 11))
11+
12+
Foo = class Foo {
13+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 1, 5))
14+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 3, 9))
15+
16+
static y = new Foo();
17+
>y : Symbol(Foo.y, Decl(classBlockScoping.ts, 3, 21))
18+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 3, 9))
19+
20+
static x() {
21+
>x : Symbol(Foo.x, Decl(classBlockScoping.ts, 4, 27))
22+
23+
new Foo();
24+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 3, 9))
25+
}
26+
27+
m() {
28+
>m : Symbol(Foo.m, Decl(classBlockScoping.ts, 8, 7))
29+
30+
new Foo();
31+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 3, 9))
32+
}
33+
};
34+
35+
new Foo();
36+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 1, 5))
37+
}
38+
else {
39+
class Foo {
40+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
41+
42+
static y = new Foo();
43+
>y : Symbol(Foo.y, Decl(classBlockScoping.ts, 18, 15))
44+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
45+
46+
static x() {
47+
>x : Symbol(Foo.x, Decl(classBlockScoping.ts, 19, 27))
48+
49+
new Foo();
50+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
51+
}
52+
53+
m() {
54+
>m : Symbol(Foo.m, Decl(classBlockScoping.ts, 23, 7))
55+
56+
new Foo();
57+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
58+
}
59+
}
60+
61+
new Foo();
62+
>Foo : Symbol(Foo, Decl(classBlockScoping.ts, 17, 8))
63+
}
64+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
=== tests/cases/compiler/classBlockScoping.ts ===
2+
function f(b: boolean) {
3+
>f : (b: boolean) => void
4+
>b : boolean
5+
6+
let Foo: any;
7+
>Foo : any
8+
9+
if (b) {
10+
>b : boolean
11+
12+
Foo = class Foo {
13+
>Foo = class Foo { static y = new Foo(); static x() { new Foo(); } m() { new Foo(); } } : typeof Foo
14+
>Foo : any
15+
>class Foo { static y = new Foo(); static x() { new Foo(); } m() { new Foo(); } } : typeof Foo
16+
>Foo : typeof Foo
17+
18+
static y = new Foo();
19+
>y : Foo
20+
>new Foo() : Foo
21+
>Foo : typeof Foo
22+
23+
static x() {
24+
>x : () => void
25+
26+
new Foo();
27+
>new Foo() : Foo
28+
>Foo : typeof Foo
29+
}
30+
31+
m() {
32+
>m : () => void
33+
34+
new Foo();
35+
>new Foo() : Foo
36+
>Foo : typeof Foo
37+
}
38+
};
39+
40+
new Foo();
41+
>new Foo() : any
42+
>Foo : any
43+
}
44+
else {
45+
class Foo {
46+
>Foo : Foo
47+
48+
static y = new Foo();
49+
>y : Foo
50+
>new Foo() : Foo
51+
>Foo : typeof Foo
52+
53+
static x() {
54+
>x : () => void
55+
56+
new Foo();
57+
>new Foo() : Foo
58+
>Foo : typeof Foo
59+
}
60+
61+
m() {
62+
>m : () => void
63+
64+
new Foo();
65+
>new Foo() : Foo
66+
>Foo : typeof Foo
67+
}
68+
}
69+
70+
new Foo();
71+
>new Foo() : Foo
72+
>Foo : typeof Foo
73+
}
74+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
function f(b: boolean) {
2+
let Foo: any;
3+
if (b) {
4+
Foo = class Foo {
5+
static y = new Foo();
6+
7+
static x() {
8+
new Foo();
9+
}
10+
11+
m() {
12+
new Foo();
13+
}
14+
};
15+
16+
new Foo();
17+
}
18+
else {
19+
class Foo {
20+
static y = new Foo();
21+
22+
static x() {
23+
new Foo();
24+
}
25+
26+
m() {
27+
new Foo();
28+
}
29+
}
30+
31+
new Foo();
32+
}
33+
}

0 commit comments

Comments
 (0)