Skip to content

Commit 94518e8

Browse files
author
Andy
authored
Don't count self-reference when setting isReferenced (#17495)
* Don't count self-reference when setting `isReferenced` * Improve comment
1 parent eb8bcd7 commit 94518e8

6 files changed

+102
-38
lines changed

src/compiler/checker.ts

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,10 @@ namespace ts {
10861086
location = location.parent;
10871087
}
10881088

1089-
if (result && nameNotFoundMessage && noUnusedIdentifiers) {
1089+
// We just climbed up parents looking for the name, meaning that we started in a descendant node of `lastLocation`.
1090+
// If `result === lastLocation.symbol`, that means that we are somewhere inside `lastLocation` looking up a name, and resolving to `lastLocation` itself.
1091+
// That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
1092+
if (result && nameNotFoundMessage && noUnusedIdentifiers && result !== lastLocation.symbol) {
10901093
result.isReferenced = true;
10911094
}
10921095

@@ -10800,17 +10803,6 @@ namespace ts {
1080010803
return undefined;
1080110804
}
1080210805

10803-
function getLeftmostIdentifierOrThis(node: Node): Node {
10804-
switch (node.kind) {
10805-
case SyntaxKind.Identifier:
10806-
case SyntaxKind.ThisKeyword:
10807-
return node;
10808-
case SyntaxKind.PropertyAccessExpression:
10809-
return getLeftmostIdentifierOrThis((<PropertyAccessExpression>node).expression);
10810-
}
10811-
return undefined;
10812-
}
10813-
1081410806
function getBindingElementNameText(element: BindingElement): string | undefined {
1081510807
if (element.parent.kind === SyntaxKind.ObjectBindingPattern) {
1081610808
const name = element.propertyName || element.name;
@@ -18520,15 +18512,6 @@ namespace ts {
1852018512
return forEachChild(n, containsSuperCall);
1852118513
}
1852218514

18523-
function markThisReferencesAsErrors(n: Node): void {
18524-
if (n.kind === SyntaxKind.ThisKeyword) {
18525-
error(n, Diagnostics.this_cannot_be_referenced_in_current_location);
18526-
}
18527-
else if (n.kind !== SyntaxKind.FunctionExpression && n.kind !== SyntaxKind.FunctionDeclaration) {
18528-
forEachChild(n, markThisReferencesAsErrors);
18529-
}
18530-
}
18531-
1853218515
function isInstancePropertyWithInitializer(n: Node): boolean {
1853318516
return n.kind === SyntaxKind.PropertyDeclaration &&
1853418517
!(getModifierFlags(n) & ModifierFlags.Static) &&
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
tests/cases/compiler/noUnusedLocals_selfReference.ts(3,10): error TS6133: 'f' is declared but never used.
2+
tests/cases/compiler/noUnusedLocals_selfReference.ts(4,7): error TS6133: 'C' is declared but never used.
3+
tests/cases/compiler/noUnusedLocals_selfReference.ts(7,6): error TS6133: 'E' is declared but never used.
4+
5+
6+
==== tests/cases/compiler/noUnusedLocals_selfReference.ts (3 errors) ====
7+
export {}; // Make this a module scope, so these are local variables.
8+
9+
function f() { f; }
10+
~
11+
!!! error TS6133: 'f' is declared but never used.
12+
class C {
13+
~
14+
!!! error TS6133: 'C' is declared but never used.
15+
m() { C; }
16+
}
17+
enum E { A = 0, B = E.A }
18+
~
19+
!!! error TS6133: 'E' is declared but never used.
20+
21+
// Does not detect mutual recursion.
22+
function g() { D; }
23+
class D { m() { g; } }
24+
25+
// Does not work on private methods.
26+
class P { private m() { this.m; } }
27+
P;
28+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
//// [noUnusedLocals_selfReference.ts]
2+
export {}; // Make this a module scope, so these are local variables.
3+
4+
function f() { f; }
5+
class C {
6+
m() { C; }
7+
}
8+
enum E { A = 0, B = E.A }
9+
10+
// Does not detect mutual recursion.
11+
function g() { D; }
12+
class D { m() { g; } }
13+
14+
// Does not work on private methods.
15+
class P { private m() { this.m; } }
16+
P;
17+
18+
19+
//// [noUnusedLocals_selfReference.js]
20+
"use strict";
21+
exports.__esModule = true;
22+
function f() { f; }
23+
var C = (function () {
24+
function C() {
25+
}
26+
C.prototype.m = function () { C; };
27+
return C;
28+
}());
29+
var E;
30+
(function (E) {
31+
E[E["A"] = 0] = "A";
32+
E[E["B"] = 0] = "B";
33+
})(E || (E = {}));
34+
// Does not detect mutual recursion.
35+
function g() { D; }
36+
var D = (function () {
37+
function D() {
38+
}
39+
D.prototype.m = function () { g; };
40+
return D;
41+
}());
42+
// Does not work on private methods.
43+
var P = (function () {
44+
function P() {
45+
}
46+
P.prototype.m = function () { this.m; };
47+
return P;
48+
}());
49+
P;

tests/baselines/reference/unusedLocalsAndParametersTypeAliases2.errors.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(2,6): error TS6133: 'handler1' is declared but never used.
2+
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(5,10): error TS6133: 'foo' is declared but never used.
23
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(6,10): error TS6133: 'handler2' is declared but never used.
34

45

5-
==== tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts (2 errors) ====
6+
==== tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts (3 errors) ====
67
// unused
78
type handler1 = () => void;
89
~~~~~~~~
910
!!! error TS6133: 'handler1' is declared but never used.
1011

1112

1213
function foo() {
14+
~~~
15+
!!! error TS6133: 'foo' is declared but never used.
1316
type handler2 = () => void;
1417
~~~~~~~~
1518
!!! error TS6133: 'handler2' is declared but never used.
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// @noUnusedLocals: true
2+
3+
export {}; // Make this a module scope, so these are local variables.
4+
5+
function f() { f; }
6+
class C {
7+
m() { C; }
8+
}
9+
enum E { A = 0, B = E.A }
10+
11+
// Does not detect mutual recursion.
12+
function g() { D; }
13+
class D { m() { g; } }
14+
15+
// Does not work on private methods.
16+
class P { private m() { this.m; } }
17+
P;

tests/webTestServer.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,6 @@ function dir(dirPath: string, spec?: string, options?: any) {
125125
}
126126
}
127127

128-
// fs.rmdirSync won't delete directories with files in it
129-
function deleteFolderRecursive(dirPath: string) {
130-
if (fs.existsSync(dirPath)) {
131-
fs.readdirSync(dirPath).forEach((file) => {
132-
const curPath = path.join(dirPath, file);
133-
if (fs.statSync(curPath).isDirectory()) { // recurse
134-
deleteFolderRecursive(curPath);
135-
}
136-
else { // delete file
137-
fs.unlinkSync(curPath);
138-
}
139-
});
140-
fs.rmdirSync(dirPath);
141-
}
142-
};
143-
144128
function writeFile(path: string, data: any) {
145129
ensureDirectoriesExist(getDirectoryPath(path));
146130
fs.writeFileSync(path, data);

0 commit comments

Comments
 (0)