diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9455b659c08..ca5ce39cef7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1187,7 +1187,7 @@ namespace ts { } break; } - if (location.kind !== SyntaxKind.Block) { + if (isNonBlockLocation(location)) { lastNonBlockLocation = location; } lastLocation = location; @@ -1195,7 +1195,7 @@ namespace ts { } // We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`. - // If `result === lastLocation.symbol`, that means that we are somewhere inside `lastLocation` looking up a name, and resolving to `lastLocation` itself. + // If `result === lastNonBlockLocation.symbol`, that means that we are somewhere inside `lastNonBlockLocation` looking up a name, and resolving to `lastLocation` itself. // That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used. if (isUse && result && nameNotFoundMessage && noUnusedIdentifiers && result !== lastNonBlockLocation.symbol) { result.isReferenced = true; @@ -1278,6 +1278,20 @@ namespace ts { return result; } + function isNonBlockLocation({ kind }: Node): boolean { + switch (kind) { + case SyntaxKind.Block: + case SyntaxKind.ModuleBlock: + case SyntaxKind.SwitchStatement: + case SyntaxKind.CaseBlock: + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + return false; + default: + return true; + } + } + function diagnosticName(nameArg: __String | Identifier) { return isString(nameArg) ? unescapeLeadingUnderscores(nameArg as __String) : declarationNameToString(nameArg as Identifier); } diff --git a/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.errors.txt b/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.errors.txt new file mode 100644 index 00000000000..9ea0147978a --- /dev/null +++ b/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.errors.txt @@ -0,0 +1,29 @@ +tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(2,14): error TS6133: 'f' is declared but its value is never read. +tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(8,22): error TS6133: 'g' is declared but its value is never read. +tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts(12,22): error TS6133: 'h' is declared but its value is never read. + + +==== tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts (3 errors) ==== + namespace n { + function f() { + ~ +!!! error TS6133: 'f' is declared but its value is never read. + f; + } + + switch (0) { + case 0: + function g() { + ~ +!!! error TS6133: 'g' is declared but its value is never read. + g; + } + default: + function h() { + ~ +!!! error TS6133: 'h' is declared but its value is never read. + h; + } + } + } + \ No newline at end of file diff --git a/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.js b/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.js new file mode 100644 index 00000000000..2b33ed8c31d --- /dev/null +++ b/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.js @@ -0,0 +1,36 @@ +//// [noUnusedLocals_selfReference_skipsBlockLocations.ts] +namespace n { + function f() { + f; + } + + switch (0) { + case 0: + function g() { + g; + } + default: + function h() { + h; + } + } +} + + +//// [noUnusedLocals_selfReference_skipsBlockLocations.js] +var n; +(function (n) { + function f() { + f; + } + switch (0) { + case 0: + function g() { + g; + } + default: + function h() { + h; + } + } +})(n || (n = {})); diff --git a/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.symbols b/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.symbols new file mode 100644 index 00000000000..7607caf3d7e --- /dev/null +++ b/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.symbols @@ -0,0 +1,29 @@ +=== tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts === +namespace n { +>n : Symbol(n, Decl(noUnusedLocals_selfReference_skipsBlockLocations.ts, 0, 0)) + + function f() { +>f : Symbol(f, Decl(noUnusedLocals_selfReference_skipsBlockLocations.ts, 0, 13)) + + f; +>f : Symbol(f, Decl(noUnusedLocals_selfReference_skipsBlockLocations.ts, 0, 13)) + } + + switch (0) { + case 0: + function g() { +>g : Symbol(g, Decl(noUnusedLocals_selfReference_skipsBlockLocations.ts, 6, 15)) + + g; +>g : Symbol(g, Decl(noUnusedLocals_selfReference_skipsBlockLocations.ts, 6, 15)) + } + default: + function h() { +>h : Symbol(h, Decl(noUnusedLocals_selfReference_skipsBlockLocations.ts, 10, 16)) + + h; +>h : Symbol(h, Decl(noUnusedLocals_selfReference_skipsBlockLocations.ts, 10, 16)) + } + } +} + diff --git a/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.types b/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.types new file mode 100644 index 00000000000..6675db4f1c3 --- /dev/null +++ b/tests/baselines/reference/noUnusedLocals_selfReference_skipsBlockLocations.types @@ -0,0 +1,33 @@ +=== tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts === +namespace n { +>n : typeof n + + function f() { +>f : () => void + + f; +>f : () => void + } + + switch (0) { +>0 : 0 + + case 0: +>0 : 0 + + function g() { +>g : () => void + + g; +>g : () => void + } + default: + function h() { +>h : () => void + + h; +>h : () => void + } + } +} + diff --git a/tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts b/tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts new file mode 100644 index 00000000000..bcaa9010715 --- /dev/null +++ b/tests/cases/compiler/noUnusedLocals_selfReference_skipsBlockLocations.ts @@ -0,0 +1,18 @@ +// @noUnusedLocals: true + +namespace n { + function f() { + f; + } + + switch (0) { + case 0: + function g() { + g; + } + default: + function h() { + h; + } + } +}