Don't count self-reference when setting isReferenced (#17495)

* Don't count self-reference when setting `isReferenced`

* Improve comment
This commit is contained in:
Andy 2017-08-08 11:18:20 -07:00 committed by GitHub
parent eb8bcd77cb
commit 94518e8533
6 changed files with 102 additions and 38 deletions

View file

@ -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) &&

View file

@ -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;

View 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;

View file

@ -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.

View 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;

View file

@ -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);