Skip to content

Commit

Permalink
fix(42678): detect access to uninitialized variable in IIFE (microsof…
Browse files Browse the repository at this point in the history
…t#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 <5341706+jakebailey@users.noreply.github.com>
  • Loading branch information
2 people authored and mprobst committed Jan 10, 2022
1 parent d9d3ff3 commit bec7f73
Show file tree
Hide file tree
Showing 7 changed files with 201 additions and 3 deletions.
4 changes: 3 additions & 1 deletion src/compiler/checker.ts
Expand Up @@ -2536,10 +2536,12 @@ namespace ts {

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

function getAnyImportSyntax(node: Node): AnyImportSyntax | undefined {
Expand Down
Expand Up @@ -2,9 +2,12 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(2,13): error TS2448: Bl
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(58,20): error TS2448: Block-scoped variable 'x' used before its declaration.
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(65,20): error TS2448: Block-scoped variable 'x' used before its declaration.
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448: Block-scoped variable 'x' used before its declaration.
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(111,28): error TS2448: Block-scoped variable 'a' used before its declaration.
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(112,21): error TS2448: Block-scoped variable 'a' used before its declaration.
tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(122,22): error TS2448: Block-scoped variable 'a' used before its declaration.


==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (4 errors) ====
==== tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts (7 errors) ====
function foo0() {
let a = x;
~
Expand Down Expand Up @@ -120,4 +123,33 @@ tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts(100,12): error TS2448:
}
let x
}

function foo15() {
// https://github.com/microsoft/TypeScript/issues/42678
const [
a,
b,
] = ((): [number, number] => {
(() => console.log(a))(); // should error
~
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:108:9: 'a' is declared here.
console.log(a); // should error
~
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:108:9: 'a' is declared here.
const b = () => a; // should be ok
return [
0,
0,
];
})();
}

function foo16() {
let [a] = (() => a)();
~
!!! error TS2448: Block-scoped variable 'a' used before its declaration.
!!! related TS2728 tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts:122:10: 'a' is declared here.
}

35 changes: 35 additions & 0 deletions tests/baselines/reference/blockScopedVariablesUseBeforeDef.js
Expand Up @@ -102,6 +102,26 @@ function foo14() {
}
let x
}

function foo15() {
// https://github.com/microsoft/TypeScript/issues/42678
const [
a,
b,
] = ((): [number, number] => {
(() => console.log(a))(); // should error
console.log(a); // should error
const b = () => a; // should be ok
return [
0,
0,
];
})();
}

function foo16() {
let [a] = (() => a)();
}


//// [blockScopedVariablesUseBeforeDef.js]
Expand Down Expand Up @@ -219,3 +239,18 @@ function foo14() {
};
var x;
}
function foo15() {
// https://github.com/microsoft/TypeScript/issues/42678
var _a = (function () {
(function () { return console.log(a); })(); // should error
console.log(a); // should error
var b = function () { return a; }; // should be ok
return [
0,
0,
];
})(), a = _a[0], b = _a[1];
}
function foo16() {
var a = (function () { return a; })()[0];
}
43 changes: 43 additions & 0 deletions tests/baselines/reference/blockScopedVariablesUseBeforeDef.symbols
Expand Up @@ -213,3 +213,46 @@ function foo14() {
>x : Symbol(x, Decl(blockScopedVariablesUseBeforeDef.ts, 101, 7))
}

function foo15() {
>foo15 : Symbol(foo15, Decl(blockScopedVariablesUseBeforeDef.ts, 102, 1))

// https://github.com/microsoft/TypeScript/issues/42678
const [
a,
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 106, 11))

b,
>b : Symbol(b, Decl(blockScopedVariablesUseBeforeDef.ts, 107, 10))

] = ((): [number, number] => {
(() => console.log(a))(); // should error
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 106, 11))

console.log(a); // should error
>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 106, 11))

const b = () => a; // should be ok
>b : Symbol(b, Decl(blockScopedVariablesUseBeforeDef.ts, 112, 13))
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 106, 11))

return [
0,
0,
];
})();
}

function foo16() {
>foo16 : Symbol(foo16, Decl(blockScopedVariablesUseBeforeDef.ts, 118, 1))

let [a] = (() => a)();
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 121, 9))
>a : Symbol(a, Decl(blockScopedVariablesUseBeforeDef.ts, 121, 9))
}

62 changes: 62 additions & 0 deletions tests/baselines/reference/blockScopedVariablesUseBeforeDef.types
Expand Up @@ -225,3 +225,65 @@ function foo14() {
>x : any
}

function foo15() {
>foo15 : () => void

// https://github.com/microsoft/TypeScript/issues/42678
const [
a,
>a : number

b,
>b : number

] = ((): [number, number] => {
>((): [number, number] => { (() => console.log(a))(); // should error console.log(a); // should error const b = () => a; // should be ok return [ 0, 0, ]; })() : [number, number]
>((): [number, number] => { (() => console.log(a))(); // should error console.log(a); // should error const b = () => a; // should be ok return [ 0, 0, ]; }) : () => [number, number]
>(): [number, number] => { (() => console.log(a))(); // should error console.log(a); // should error const b = () => a; // should be ok return [ 0, 0, ]; } : () => [number, number]

(() => console.log(a))(); // should error
>(() => console.log(a))() : void
>(() => console.log(a)) : () => void
>() => console.log(a) : () => void
>console.log(a) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>a : number

console.log(a); // should error
>console.log(a) : void
>console.log : (...data: any[]) => void
>console : Console
>log : (...data: any[]) => void
>a : number

const b = () => a; // should be ok
>b : () => number
>() => a : () => number
>a : number

return [
>[ 0, 0, ] : [number, number]

0,
>0 : 0

0,
>0 : 0

];
})();
}

function foo16() {
>foo16 : () => void

let [a] = (() => a)();
>a : any
>(() => a)() : any
>(() => a) : () => any
>() => a : () => any
>a : any
}

Expand Up @@ -2,10 +2,11 @@ tests/cases/compiler/tryCatchFinallyControlFlow.ts(105,5): error TS7027: Unreach
tests/cases/compiler/tryCatchFinallyControlFlow.ts(118,9): error TS7027: Unreachable code detected.
tests/cases/compiler/tryCatchFinallyControlFlow.ts(218,13): error TS7027: Unreachable code detected.
tests/cases/compiler/tryCatchFinallyControlFlow.ts(220,9): error TS7027: Unreachable code detected.
tests/cases/compiler/tryCatchFinallyControlFlow.ts(255,9): error TS2448: Block-scoped variable 'x' used before its declaration.
tests/cases/compiler/tryCatchFinallyControlFlow.ts(255,9): error TS7027: Unreachable code detected.


==== tests/cases/compiler/tryCatchFinallyControlFlow.ts (5 errors) ====
==== tests/cases/compiler/tryCatchFinallyControlFlow.ts (6 errors) ====
// Repro from #34797

function f1() {
Expand Down Expand Up @@ -270,6 +271,9 @@ tests/cases/compiler/tryCatchFinallyControlFlow.ts(255,9): error TS7027: Unreach
return null;
}
x; // Unreachable
~
!!! error TS2448: Block-scoped variable 'x' used before its declaration.
!!! related TS2728 tests/cases/compiler/tryCatchFinallyControlFlow.ts:248:11: 'x' is declared here.
~~
!!! error TS7027: Unreachable code detected.
})();
Expand Down
20 changes: 20 additions & 0 deletions tests/cases/compiler/blockScopedVariablesUseBeforeDef.ts
Expand Up @@ -102,3 +102,23 @@ function foo14() {
}
let x
}

function foo15() {
// https://github.com/microsoft/TypeScript/issues/42678
const [
a,
b,
] = ((): [number, number] => {
(() => console.log(a))(); // should error
console.log(a); // should error
const b = () => a; // should be ok
return [
0,
0,
];
})();
}

function foo16() {
let [a] = (() => a)();
}

0 comments on commit bec7f73

Please sign in to comment.