Skip to content

Commit bec7f73

Browse files
Zzzenjakebailey
authored andcommitted
fix(42678): detect access to uninitialized variable in IIFE (microsoft#42776)
* fix(42678): detect access to uninitialized variable in IIFE * improve performance * Add missing space to match coding guidelines * simplify the implementation Co-authored-by: Jake Bailey <[email protected]>
1 parent d9d3ff3 commit bec7f73

7 files changed

+201
-3
lines changed

src/compiler/checker.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2536,10 +2536,12 @@ namespace ts {
25362536

25372537
/* Starting from 'initial' node walk up the parent chain until 'stopAt' node is reached.
25382538
* If at any point current node is equal to 'parent' node - return true.
2539+
* If current node is an IIFE, continue walking up.
25392540
* Return false if 'stopAt' node is reached or isFunctionLike(current) === true.
25402541
*/
25412542
function isSameScopeDescendentOf(initial: Node, parent: Node | undefined, stopAt: Node): boolean {
2542-
return !!parent && !!findAncestor(initial, n => n === stopAt || isFunctionLike(n) ? "quit" : n === parent);
2543+
return !!parent && !!findAncestor(initial, n => n === parent
2544+
|| (n === stopAt || isFunctionLike(n) && !getImmediatelyInvokedFunctionExpression(n) ? "quit" : false));
25432545
}
25442546

25452547
function getAnyImportSyntax(node: Node): AnyImportSyntax | undefined {

tests/baselines/reference/blockScopedVariablesUseBeforeDef.errors.txt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,12 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(2,13): error TS2448: Bl
22
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(58,20): error TS2448: Block-scoped variable 'x' used before its declaration.
33
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(65,20): error TS2448: Block-scoped variable 'x' used before its declaration.
44
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448: Block-scoped variable 'x' used before its declaration.
5+
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(111,28): error TS2448: Block-scoped variable 'a' used before its declaration.
6+
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(112,21): error TS2448: Block-scoped variable 'a' used before its declaration.
7+
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(122,22): error TS2448: Block-scoped variable 'a' used before its declaration.
58

69

7-
==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (4 errors) ====
10+
==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (7 errors) ====
811
function foo0() {
912
let a = x;
1013
~
@@ -120,4 +123,33 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448:
120123
}
121124
let x
122125
}
126+
127+
function foo15() {
128+
// https://github.com/microsoft/TypeScript/issues/42678
129+
const [
130+
a,
131+
b,
132+
] = ((): [number, number] => {
133+
(() => console.log(a))(); // should error
134+
~
135+
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
136+
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:108:9: 'a' is declared here.
137+
console.log(a); // should error
138+
~
139+
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
140+
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:108:9: 'a' is declared here.
141+
const b = () => a; // should be ok
142+
return [
143+
0,
144+
0,
145+
];
146+
})();
147+
}
148+
149+
function foo16() {
150+
let [a] = (() => a)();
151+
~
152+
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
153+
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:122:10: 'a' is declared here.
154+
}
123155

tests/baselines/reference/blockScopedVariablesUseBeforeDef.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,26 @@ function foo14() {
102102
}
103103
let x
104104
}
105+
106+
function foo15() {
107+
// https://github.com/microsoft/TypeScript/issues/42678
108+
const [
109+
a,
110+
b,
111+
] = ((): [number, number] => {
112+
(() => console.log(a))(); // should error
113+
console.log(a); // should error
114+
const b = () => a; // should be ok
115+
return [
116+
0,
117+
0,
118+
];
119+
})();
120+
}
121+
122+
function foo16() {
123+
let [a] = (() => a)();
124+
}
105125

106126

107127
//// [blockScopedVariablesUseBeforeDef.js]
@@ -219,3 +239,18 @@ function foo14() {
219239
};
220240
var x;
221241
}
242+
function foo15() {
243+
// https://github.com/microsoft/TypeScript/issues/42678
244+
var _a = (function () {
245+
(function () { return console.log(a); })(); // should error
246+
console.log(a); // should error
247+
var b = function () { return a; }; // should be ok
248+
return [
249+
0,
250+
0,
251+
];
252+
})(), a = _a[0], b = _a[1];
253+
}
254+
function foo16() {
255+
var a = (function () { return a; })()[0];
256+
}

tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,46 @@ function foo14() {
213213
>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 101, 7))
214214
}
215215

216+
function foo15() {
217+
>foo15 : Symbol(foo15, Decl(blockScopedVariablesUseBeforeDef.ts, 102, 1))
218+
219+
// https://github.com/microsoft/TypeScript/issues/42678
220+
const [
221+
a,
222+
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 106, 11))
223+
224+
b,
225+
>b : Symbol(b, Decl(blockScopedVariablesUseBeforeDef.ts, 107, 10))
226+
227+
] = ((): [number, number] => {
228+
(() => console.log(a))(); // should error
229+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
230+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
231+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
232+
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 106, 11))
233+
234+
console.log(a); // should error
235+
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
236+
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
237+
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
238+
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 106, 11))
239+
240+
const b = () => a; // should be ok
241+
>b : Symbol(b, Decl(blockScopedVariablesUseBeforeDef.ts, 112, 13))
242+
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 106, 11))
243+
244+
return [
245+
0,
246+
0,
247+
];
248+
})();
249+
}
250+
251+
function foo16() {
252+
>foo16 : Symbol(foo16, Decl(blockScopedVariablesUseBeforeDef.ts, 118, 1))
253+
254+
let [a] = (() => a)();
255+
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 121, 9))
256+
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 121, 9))
257+
}
258+

tests/baselines/reference/blockScopedVariablesUseBeforeDef.types

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,65 @@ function foo14() {
225225
>x : any
226226
}
227227

228+
function foo15() {
229+
>foo15 : () => void
230+
231+
// https://github.com/microsoft/TypeScript/issues/42678
232+
const [
233+
a,
234+
>a : number
235+
236+
b,
237+
>b : number
238+
239+
] = ((): [number, number] => {
240+
>((): [number, number] => { (() => console.log(a))(); // should error console.log(a); // should error const b = () => a; // should be ok return [ 0, 0, ]; })() : [number, number]
241+
>((): [number, number] => { (() => console.log(a))(); // should error console.log(a); // should error const b = () => a; // should be ok return [ 0, 0, ]; }) : () => [number, number]
242+
>(): [number, number] => { (() => console.log(a))(); // should error console.log(a); // should error const b = () => a; // should be ok return [ 0, 0, ]; } : () => [number, number]
243+
244+
(() => console.log(a))(); // should error
245+
>(() => console.log(a))() : void
246+
>(() => console.log(a)) : () => void
247+
>() => console.log(a) : () => void
248+
>console.log(a) : void
249+
>console.log : (...data: any[]) => void
250+
>console : Console
251+
>log : (...data: any[]) => void
252+
>a : number
253+
254+
console.log(a); // should error
255+
>console.log(a) : void
256+
>console.log : (...data: any[]) => void
257+
>console : Console
258+
>log : (...data: any[]) => void
259+
>a : number
260+
261+
const b = () => a; // should be ok
262+
>b : () => number
263+
>() => a : () => number
264+
>a : number
265+
266+
return [
267+
>[ 0, 0, ] : [number, number]
268+
269+
0,
270+
>0 : 0
271+
272+
0,
273+
>0 : 0
274+
275+
];
276+
})();
277+
}
278+
279+
function foo16() {
280+
>foo16 : () => void
281+
282+
let [a] = (() => a)();
283+
>a : any
284+
>(() => a)() : any
285+
>(() => a) : () => any
286+
>() => a : () => any
287+
>a : any
288+
}
289+

tests/baselines/reference/tryCatchFinallyControlFlow.errors.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ tests/cases/compiler/tryCatchFinallyControlFlow.ts(105,5): error TS7027: Unreach
22
tests/cases/compiler/tryCatchFinallyControlFlow.ts(118,9): error TS7027: Unreachable code detected.
33
tests/cases/compiler/tryCatchFinallyControlFlow.ts(218,13): error TS7027: Unreachable code detected.
44
tests/cases/compiler/tryCatchFinallyControlFlow.ts(220,9): error TS7027: Unreachable code detected.
5+
tests/cases/compiler/tryCatchFinallyControlFlow.ts(255,9): error TS2448: Block-scoped variable 'x' used before its declaration.
56
tests/cases/compiler/tryCatchFinallyControlFlow.ts(255,9): error TS7027: Unreachable code detected.
67

78

8-
==== tests/cases/compiler/tryCatchFinallyControlFlow.ts (5 errors) ====
9+
==== tests/cases/compiler/tryCatchFinallyControlFlow.ts (6 errors) ====
910
// Repro from #34797
1011

1112
function f1() {
@@ -270,6 +271,9 @@ tests/cases/compiler/tryCatchFinallyControlFlow.ts(255,9): error TS7027: Unreach
270271
return null;
271272
}
272273
x; // Unreachable
274+
~
275+
!!! error TS2448: Block-scoped variable 'x' used before its declaration.
276+
!!! related TS2728 tests/cases/compiler/tryCatchFinallyControlFlow.ts:248:11: 'x' is declared here.
273277
~~
274278
!!! error TS7027: Unreachable code detected.
275279
})();

tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,3 +102,23 @@ function foo14() {
102102
}
103103
let x
104104
}
105+
106+
function foo15() {
107+
// https://github.com/microsoft/TypeScript/issues/42678
108+
const [
109+
a,
110+
b,
111+
] = ((): [number, number] => {
112+
(() => console.log(a))(); // should error
113+
console.log(a); // should error
114+
const b = () => a; // should be ok
115+
return [
116+
0,
117+
0,
118+
];
119+
})();
120+
}
121+
122+
function foo16() {
123+
let [a] = (() => a)();
124+
}

0 commit comments

Comments
 (0)