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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -10800,17 +10803,6 @@ namespace ts {
|
|||
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 {
|
||||
if (element.parent.kind === SyntaxKind.ObjectBindingPattern) {
|
||||
const name = element.propertyName || element.name;
|
||||
|
@ -18520,15 +18512,6 @@ namespace ts {
|
|||
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 {
|
||||
return n.kind === SyntaxKind.PropertyDeclaration &&
|
||||
!(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(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 (2 errors) ====
|
||||
==== tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts (3 errors) ====
|
||||
// unused
|
||||
type handler1 = () => void;
|
||||
~~~~~~~~
|
||||
|
@ -10,6 +11,8 @@ tests/cases/compiler/unusedLocalsAndParametersTypeAliases2.ts(6,10): error TS613
|
|||
|
||||
|
||||
function foo() {
|
||||
~~~
|
||||
!!! error TS6133: 'foo' is declared but never used.
|
||||
type handler2 = () => void;
|
||||
~~~~~~~~
|
||||
!!! 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) {
|
||||
ensureDirectoriesExist(getDirectoryPath(path));
|
||||
fs.writeFileSync(path, data);
|
||||
|
|
Loading…
Reference in a new issue