Don't count self-reference when setting isReferenced
(#17495)
* Don't count self-reference when setting `isReferenced` * Improve comment
This commit is contained in:
parent
eb8bcd77cb
commit
94518e8533
|
@ -1086,7 +1086,10 @@ namespace ts {
|
||||||
location = location.parent;
|
location = location.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result && nameNotFoundMessage && noUnusedIdentifiers) {
|
// 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.
|
||||||
|
// That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
|
||||||
|
if (result && nameNotFoundMessage && noUnusedIdentifiers && result !== lastLocation.symbol) {
|
||||||
result.isReferenced = true;
|
result.isReferenced = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10800,17 +10803,6 @@ namespace ts {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLeftmostIdentifierOrThis(node: Node): Node {
|
|
||||||
switch (node.kind) {
|
|
||||||
case SyntaxKind.Identifier:
|
|
||||||
case SyntaxKind.ThisKeyword:
|
|
||||||
return node;
|
|
||||||
case SyntaxKind.PropertyAccessExpression:
|
|
||||||
return getLeftmostIdentifierOrThis((<PropertyAccessExpression>node).expression);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBindingElementNameText(element: BindingElement): string | undefined {
|
function getBindingElementNameText(element: BindingElement): string | undefined {
|
||||||
if (element.parent.kind === SyntaxKind.ObjectBindingPattern) {
|
if (element.parent.kind === SyntaxKind.ObjectBindingPattern) {
|
||||||
const name = element.propertyName || element.name;
|
const name = element.propertyName || element.name;
|
||||||
|
@ -18520,15 +18512,6 @@ namespace ts {
|
||||||
return forEachChild(n, containsSuperCall);
|
return forEachChild(n, containsSuperCall);
|
||||||
}
|
}
|
||||||
|
|
||||||
function markThisReferencesAsErrors(n: Node): void {
|
|
||||||
if (n.kind === SyntaxKind.ThisKeyword) {
|
|
||||||
error(n, Diagnostics.this_cannot_be_referenced_in_current_location);
|
|
||||||
}
|
|
||||||
else if (n.kind !== SyntaxKind.FunctionExpression && n.kind !== SyntaxKind.FunctionDeclaration) {
|
|
||||||
forEachChild(n, markThisReferencesAsErrors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isInstancePropertyWithInitializer(n: Node): boolean {
|
function isInstancePropertyWithInitializer(n: Node): boolean {
|
||||||
return n.kind === SyntaxKind.PropertyDeclaration &&
|
return n.kind === SyntaxKind.PropertyDeclaration &&
|
||||||
!(getModifierFlags(n) & ModifierFlags.Static) &&
|
!(getModifierFlags(n) & ModifierFlags.Static) &&
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
tests/cases/compiler/noUnusedLocals_selfReference.ts(3,10): error TS6133: 'f' is declared but never used.
|
||||||
|
tests/cases/compiler/noUnusedLocals_selfReference.ts(4,7): error TS6133: 'C' is declared but never used.
|
||||||
|
tests/cases/compiler/noUnusedLocals_selfReference.ts(7,6): error TS6133: 'E' is declared but never used.
|
||||||
|
|
||||||
|
|
||||||
|
==== tests/cases/compiler/noUnusedLocals_selfReference.ts (3 errors) ====
|
||||||
|
export {}; // Make this a module scope, so these are local variables.
|
||||||
|
|
||||||
|
function f() { f; }
|
||||||
|
~
|
||||||
|
!!! error TS6133: 'f' is declared but never used.
|
||||||
|
class C {
|
||||||
|
~
|
||||||
|
!!! error TS6133: 'C' is declared but never used.
|
||||||
|
m() { C; }
|
||||||
|
}
|
||||||
|
enum E { A = 0, B = E.A }
|
||||||
|
~
|
||||||
|
!!! error TS6133: 'E' is declared but never used.
|
||||||
|
|
||||||
|
// Does not detect mutual recursion.
|
||||||
|
function g() { D; }
|
||||||
|
class D { m() { g; } }
|
||||||
|
|
||||||
|
// Does not work on private methods.
|
||||||
|
class P { private m() { this.m; } }
|
||||||
|
P;
|
||||||
|
|
49
tests/baselines/reference/noUnusedLocals_selfReference.js
Normal file
49
tests/baselines/reference/noUnusedLocals_selfReference.js
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
//// [noUnusedLocals_selfReference.ts]
|
||||||
|
export {}; // Make this a module scope, so these are local variables.
|
||||||
|
|
||||||
|
function f() { f; }
|
||||||
|
class C {
|
||||||
|
m() { C; }
|
||||||
|
}
|
||||||
|
enum E { A = 0, B = E.A }
|
||||||
|
|
||||||
|
// Does not detect mutual recursion.
|
||||||
|
function g() { D; }
|
||||||
|
class D { m() { g; } }
|
||||||
|
|
||||||
|
// Does not work on private methods.
|
||||||
|
class P { private m() { this.m; } }
|
||||||
|
P;
|
||||||
|
|
||||||
|
|
||||||
|
//// [noUnusedLocals_selfReference.js]
|
||||||
|
"use strict";
|
||||||
|
exports.__esModule = true;
|
||||||
|
function f() { f; }
|
||||||
|
var C = (function () {
|
||||||
|
function C() {
|
||||||
|
}
|
||||||
|
C.prototype.m = function () { C; };
|
||||||
|
return C;
|
||||||
|
}());
|
||||||
|
var E;
|
||||||
|
(function (E) {
|
||||||
|
E[E["A"] = 0] = "A";
|
||||||
|
E[E["B"] = 0] = "B";
|
||||||
|
})(E || (E = {}));
|
||||||
|
// Does not detect mutual recursion.
|
||||||
|
function g() { D; }
|
||||||
|
var D = (function () {
|
||||||
|
function D() {
|
||||||
|
}
|
||||||
|
D.prototype.m = function () { g; };
|
||||||
|
return D;
|
||||||
|
}());
|
||||||
|
// Does not work on private methods.
|
||||||
|
var P = (function () {
|
||||||
|
function P() {
|
||||||
|
}
|
||||||
|
P.prototype.m = function () { this.m; };
|
||||||
|
return P;
|
||||||
|
}());
|
||||||
|
P;
|
|
@ -1,8 +1,9 @@
|
||||||
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(2,6): error TS6133: 'handler1' is declared but never used.
|
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(2,6): error TS6133: 'handler1' is declared but never used.
|
||||||
|
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(5,10): error TS6133: 'foo' is declared but never used.
|
||||||
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(6,10): error TS6133: 'handler2' is declared but never used.
|
tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(6,10): error TS6133: 'handler2' is declared but never used.
|
||||||
|
|
||||||
|
|
||||||
==== tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts (2 errors) ====
|
==== tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts (3 errors) ====
|
||||||
// unused
|
// unused
|
||||||
type handler1 = () => void;
|
type handler1 = () => void;
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
@ -10,6 +11,8 @@ tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(6,10): error TS613
|
||||||
|
|
||||||
|
|
||||||
function foo() {
|
function foo() {
|
||||||
|
~~~
|
||||||
|
!!! error TS6133: 'foo' is declared but never used.
|
||||||
type handler2 = () => void;
|
type handler2 = () => void;
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
!!! error TS6133: 'handler2' is declared but never used.
|
!!! error TS6133: 'handler2' is declared but never used.
|
||||||
|
|
17
tests/cases/compiler/noUnusedLocals_selfReference.ts
Normal file
17
tests/cases/compiler/noUnusedLocals_selfReference.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// @noUnusedLocals: true
|
||||||
|
|
||||||
|
export {}; // Make this a module scope, so these are local variables.
|
||||||
|
|
||||||
|
function f() { f; }
|
||||||
|
class C {
|
||||||
|
m() { C; }
|
||||||
|
}
|
||||||
|
enum E { A = 0, B = E.A }
|
||||||
|
|
||||||
|
// Does not detect mutual recursion.
|
||||||
|
function g() { D; }
|
||||||
|
class D { m() { g; } }
|
||||||
|
|
||||||
|
// Does not work on private methods.
|
||||||
|
class P { private m() { this.m; } }
|
||||||
|
P;
|
|
@ -125,22 +125,6 @@ function dir(dirPath: string, spec?: string, options?: any) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fs.rmdirSync won't delete directories with files in it
|
|
||||||
function deleteFolderRecursive(dirPath: string) {
|
|
||||||
if (fs.existsSync(dirPath)) {
|
|
||||||
fs.readdirSync(dirPath).forEach((file) => {
|
|
||||||
const curPath = path.join(dirPath, file);
|
|
||||||
if (fs.statSync(curPath).isDirectory()) { // recurse
|
|
||||||
deleteFolderRecursive(curPath);
|
|
||||||
}
|
|
||||||
else { // delete file
|
|
||||||
fs.unlinkSync(curPath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fs.rmdirSync(dirPath);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function writeFile(path: string, data: any) {
|
function writeFile(path: string, data: any) {
|
||||||
ensureDirectoriesExist(getDirectoryPath(path));
|
ensureDirectoriesExist(getDirectoryPath(path));
|
||||||
fs.writeFileSync(path, data);
|
fs.writeFileSync(path, data);
|
||||||
|
|
Loading…
Reference in a new issue