Fix #9636: Report unused type paramters only on last declaration

This commit is contained in:
Mohamed Hegazy 2016-07-17 23:51:17 -07:00
parent 9ef65cf3af
commit 290caad402
16 changed files with 298 additions and 3 deletions

View File

@ -13274,7 +13274,7 @@ namespace ts {
checkAsyncFunctionReturnType(<FunctionLikeDeclaration>node);
}
}
if (!(<FunctionDeclaration>node).body) {
if (noUnusedIdentifiers && !(<FunctionDeclaration>node).body) {
checkUnusedTypeParameters(node);
}
}
@ -14609,8 +14609,15 @@ namespace ts {
function checkUnusedTypeParameters(node: ClassDeclaration | ClassExpression | FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction | ConstructorDeclaration | SignatureDeclaration | InterfaceDeclaration) {
if (compilerOptions.noUnusedLocals && !isInAmbientContext(node)) {
if (node.typeParameters) {
// Only report errors on the last declaration for the type parameter container;
// this ensures that all uses have been accounted for.
const symbol = node.symbol && getMergedSymbol(node.symbol);
const lastDeclaration = symbol && symbol.declarations && lastOrUndefined(symbol.declarations);
if (lastDeclaration !== node) {
return;
}
for (const typeParameter of node.typeParameters) {
if (!typeParameter.symbol.isReferenced) {
if (!getMergedSymbol(typeParameter.symbol).isReferenced) {
error(typeParameter.name, Diagnostics._0_is_declared_but_never_used, typeParameter.symbol.name);
}
}
@ -16119,7 +16126,7 @@ namespace ts {
if (produceDiagnostics) {
checkTypeForDuplicateIndexSignatures(node);
checkUnusedTypeParameters(node);
registerForUnusedIdentifiersCheck(node);
}
}

View File

@ -0,0 +1,16 @@
//// [tests/cases/compiler/unusedTypeParameters6.ts] ////
//// [a.ts]
class C<T> { }
//// [b.ts]
interface C<T> { a: T; }
//// [a.js]
var C = (function () {
function C() {
}
return C;
}());
//// [b.js]

View File

@ -0,0 +1,13 @@
=== tests/cases/compiler/a.ts ===
class C<T> { }
>C : Symbol(C, Decl(a.ts, 0, 0), Decl(b.ts, 0, 0))
>T : Symbol(T, Decl(a.ts, 1, 8), Decl(b.ts, 0, 12))
=== tests/cases/compiler/b.ts ===
interface C<T> { a: T; }
>C : Symbol(C, Decl(a.ts, 0, 0), Decl(b.ts, 0, 0))
>T : Symbol(T, Decl(a.ts, 1, 8), Decl(b.ts, 0, 12))
>a : Symbol(C.a, Decl(b.ts, 0, 16))
>T : Symbol(T, Decl(a.ts, 1, 8), Decl(b.ts, 0, 12))

View File

@ -0,0 +1,13 @@
=== tests/cases/compiler/a.ts ===
class C<T> { }
>C : C<T>
>T : T
=== tests/cases/compiler/b.ts ===
interface C<T> { a: T; }
>C : C<T>
>T : T
>a : T
>T : T

View File

@ -0,0 +1,16 @@
//// [tests/cases/compiler/unusedTypeParameters7.ts] ////
//// [a.ts]
class C<T> { a: T; }
//// [b.ts]
interface C<T> { }
//// [a.js]
var C = (function () {
function C() {
}
return C;
}());
//// [b.js]

View File

@ -0,0 +1,13 @@
=== tests/cases/compiler/a.ts ===
class C<T> { a: T; }
>C : Symbol(C, Decl(a.ts, 0, 0), Decl(b.ts, 0, 0))
>T : Symbol(T, Decl(a.ts, 1, 8), Decl(b.ts, 0, 12))
>a : Symbol(C.a, Decl(a.ts, 1, 12))
>T : Symbol(T, Decl(a.ts, 1, 8), Decl(b.ts, 0, 12))
=== tests/cases/compiler/b.ts ===
interface C<T> { }
>C : Symbol(C, Decl(a.ts, 0, 0), Decl(b.ts, 0, 0))
>T : Symbol(T, Decl(a.ts, 1, 8), Decl(b.ts, 0, 12))

View File

@ -0,0 +1,13 @@
=== tests/cases/compiler/a.ts ===
class C<T> { a: T; }
>C : C<T>
>T : T
>a : T
>T : T
=== tests/cases/compiler/b.ts ===
interface C<T> { }
>C : C<T>
>T : T

View File

@ -0,0 +1,11 @@
tests/cases/compiler/b.ts(1,13): error TS6133: 'T' is declared but never used.
==== tests/cases/compiler/a.ts (0 errors) ====
class C<T> { }
==== tests/cases/compiler/b.ts (1 errors) ====
interface C<T> { }
~
!!! error TS6133: 'T' is declared but never used.

View File

@ -0,0 +1,16 @@
//// [tests/cases/compiler/unusedTypeParameters8.ts] ////
//// [a.ts]
class C<T> { }
//// [b.ts]
interface C<T> { }
//// [a.js]
var C = (function () {
function C() {
}
return C;
}());
//// [b.js]

View File

@ -0,0 +1,30 @@
//// [unusedTypeParameters9.ts]
// clas + interface
class C1<T> { }
interface C1<T> { a: T; }
// interface + class
class C2<T> { a: T; }
interface C2<T> { }
// interfaces
interface C3<T> { a(c: (p: T) => void): void; }
interface C3<T> { b: string; }
interface C3<T> { c: number; }
interface C3<T> { d: boolean; }
interface C3<T> { e: any; }
//// [unusedTypeParameters9.js]
// clas + interface
var C1 = (function () {
function C1() {
}
return C1;
}());
// interface + class
var C2 = (function () {
function C2() {
}
return C2;
}());

View File

@ -0,0 +1,53 @@
=== tests/cases/compiler/unusedTypeParameters9.ts ===
// clas + interface
class C1<T> { }
>C1 : Symbol(C1, Decl(unusedTypeParameters9.ts, 0, 0), Decl(unusedTypeParameters9.ts, 2, 15))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 2, 9), Decl(unusedTypeParameters9.ts, 3, 13))
interface C1<T> { a: T; }
>C1 : Symbol(C1, Decl(unusedTypeParameters9.ts, 0, 0), Decl(unusedTypeParameters9.ts, 2, 15))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 2, 9), Decl(unusedTypeParameters9.ts, 3, 13))
>a : Symbol(C1.a, Decl(unusedTypeParameters9.ts, 3, 17))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 2, 9), Decl(unusedTypeParameters9.ts, 3, 13))
// interface + class
class C2<T> { a: T; }
>C2 : Symbol(C2, Decl(unusedTypeParameters9.ts, 3, 25), Decl(unusedTypeParameters9.ts, 6, 21))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 6, 9), Decl(unusedTypeParameters9.ts, 7, 13))
>a : Symbol(C2.a, Decl(unusedTypeParameters9.ts, 6, 13))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 6, 9), Decl(unusedTypeParameters9.ts, 7, 13))
interface C2<T> { }
>C2 : Symbol(C2, Decl(unusedTypeParameters9.ts, 3, 25), Decl(unusedTypeParameters9.ts, 6, 21))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 6, 9), Decl(unusedTypeParameters9.ts, 7, 13))
// interfaces
interface C3<T> { a(c: (p: T) => void): void; }
>C3 : Symbol(C3, Decl(unusedTypeParameters9.ts, 7, 19), Decl(unusedTypeParameters9.ts, 10, 47), Decl(unusedTypeParameters9.ts, 11, 30), Decl(unusedTypeParameters9.ts, 12, 30), Decl(unusedTypeParameters9.ts, 13, 32))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 10, 13), Decl(unusedTypeParameters9.ts, 11, 13), Decl(unusedTypeParameters9.ts, 12, 13), Decl(unusedTypeParameters9.ts, 13, 13), Decl(unusedTypeParameters9.ts, 14, 13))
>a : Symbol(C3.a, Decl(unusedTypeParameters9.ts, 10, 17))
>c : Symbol(c, Decl(unusedTypeParameters9.ts, 10, 20))
>p : Symbol(p, Decl(unusedTypeParameters9.ts, 10, 24))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 10, 13), Decl(unusedTypeParameters9.ts, 11, 13), Decl(unusedTypeParameters9.ts, 12, 13), Decl(unusedTypeParameters9.ts, 13, 13), Decl(unusedTypeParameters9.ts, 14, 13))
interface C3<T> { b: string; }
>C3 : Symbol(C3, Decl(unusedTypeParameters9.ts, 7, 19), Decl(unusedTypeParameters9.ts, 10, 47), Decl(unusedTypeParameters9.ts, 11, 30), Decl(unusedTypeParameters9.ts, 12, 30), Decl(unusedTypeParameters9.ts, 13, 32))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 10, 13), Decl(unusedTypeParameters9.ts, 11, 13), Decl(unusedTypeParameters9.ts, 12, 13), Decl(unusedTypeParameters9.ts, 13, 13), Decl(unusedTypeParameters9.ts, 14, 13))
>b : Symbol(C3.b, Decl(unusedTypeParameters9.ts, 11, 17))
interface C3<T> { c: number; }
>C3 : Symbol(C3, Decl(unusedTypeParameters9.ts, 7, 19), Decl(unusedTypeParameters9.ts, 10, 47), Decl(unusedTypeParameters9.ts, 11, 30), Decl(unusedTypeParameters9.ts, 12, 30), Decl(unusedTypeParameters9.ts, 13, 32))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 10, 13), Decl(unusedTypeParameters9.ts, 11, 13), Decl(unusedTypeParameters9.ts, 12, 13), Decl(unusedTypeParameters9.ts, 13, 13), Decl(unusedTypeParameters9.ts, 14, 13))
>c : Symbol(C3.c, Decl(unusedTypeParameters9.ts, 12, 17))
interface C3<T> { d: boolean; }
>C3 : Symbol(C3, Decl(unusedTypeParameters9.ts, 7, 19), Decl(unusedTypeParameters9.ts, 10, 47), Decl(unusedTypeParameters9.ts, 11, 30), Decl(unusedTypeParameters9.ts, 12, 30), Decl(unusedTypeParameters9.ts, 13, 32))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 10, 13), Decl(unusedTypeParameters9.ts, 11, 13), Decl(unusedTypeParameters9.ts, 12, 13), Decl(unusedTypeParameters9.ts, 13, 13), Decl(unusedTypeParameters9.ts, 14, 13))
>d : Symbol(C3.d, Decl(unusedTypeParameters9.ts, 13, 17))
interface C3<T> { e: any; }
>C3 : Symbol(C3, Decl(unusedTypeParameters9.ts, 7, 19), Decl(unusedTypeParameters9.ts, 10, 47), Decl(unusedTypeParameters9.ts, 11, 30), Decl(unusedTypeParameters9.ts, 12, 30), Decl(unusedTypeParameters9.ts, 13, 32))
>T : Symbol(T, Decl(unusedTypeParameters9.ts, 10, 13), Decl(unusedTypeParameters9.ts, 11, 13), Decl(unusedTypeParameters9.ts, 12, 13), Decl(unusedTypeParameters9.ts, 13, 13), Decl(unusedTypeParameters9.ts, 14, 13))
>e : Symbol(C3.e, Decl(unusedTypeParameters9.ts, 14, 17))

View File

@ -0,0 +1,53 @@
=== tests/cases/compiler/unusedTypeParameters9.ts ===
// clas + interface
class C1<T> { }
>C1 : C1<T>
>T : T
interface C1<T> { a: T; }
>C1 : C1<T>
>T : T
>a : T
>T : T
// interface + class
class C2<T> { a: T; }
>C2 : C2<T>
>T : T
>a : T
>T : T
interface C2<T> { }
>C2 : C2<T>
>T : T
// interfaces
interface C3<T> { a(c: (p: T) => void): void; }
>C3 : C3<T>
>T : T
>a : (c: (p: T) => void) => void
>c : (p: T) => void
>p : T
>T : T
interface C3<T> { b: string; }
>C3 : C3<T>
>T : T
>b : string
interface C3<T> { c: number; }
>C3 : C3<T>
>T : T
>c : number
interface C3<T> { d: boolean; }
>C3 : C3<T>
>T : T
>d : boolean
interface C3<T> { e: any; }
>C3 : C3<T>
>T : T
>e : any

View File

@ -0,0 +1,8 @@
//@noUnusedLocals:true
//@noUnusedParameters:true
// @fileName: a.ts
class C<T> { }
// @fileName: b.ts
interface C<T> { a: T; }

View File

@ -0,0 +1,8 @@
//@noUnusedLocals:true
//@noUnusedParameters:true
// @fileName: a.ts
class C<T> { a: T; }
// @fileName: b.ts
interface C<T> { }

View File

@ -0,0 +1,8 @@
//@noUnusedLocals:true
//@noUnusedParameters:true
// @fileName: a.ts
class C<T> { }
// @fileName: b.ts
interface C<T> { }

View File

@ -0,0 +1,17 @@
//@noUnusedLocals:true
//@noUnusedParameters:true
// clas + interface
class C1<T> { }
interface C1<T> { a: T; }
// interface + class
class C2<T> { a: T; }
interface C2<T> { }
// interfaces
interface C3<T> { a(c: (p: T) => void): void; }
interface C3<T> { b: string; }
interface C3<T> { c: number; }
interface C3<T> { d: boolean; }
interface C3<T> { e: any; }