Have Symbol#isReferenced check the SymbolFlags of the reference (#21996)

This commit is contained in:
Andy 2018-02-16 16:47:13 -08:00 committed by GitHub
parent ecddf8468f
commit 9ee51fadd9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 135 additions and 12 deletions

View file

@ -1394,7 +1394,7 @@ namespace ts {
// If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` 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 (isUse && result && nameNotFoundMessage && noUnusedIdentifiers && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) {
result.isReferenced = true;
result.isReferenced |= meaning;
}
if (!result) {
@ -15697,7 +15697,7 @@ namespace ts {
if (reactSym) {
// Mark local symbol as referenced here because it might not have been marked
// if jsx emit was not react as there wont be error being emitted
reactSym.isReferenced = true;
reactSym.isReferenced = SymbolFlags.All;
// If react symbol is alias, mark it as refereced
if (reactSym.flags & SymbolFlags.Alias && !isConstEnumOrConstEnumOnlyModule(resolveAlias(reactSym))) {
@ -16267,12 +16267,7 @@ namespace ts {
}
}
if (getCheckFlags(prop) & CheckFlags.Instantiated) {
getSymbolLinks(prop).target.isReferenced = true;
}
else {
prop.isReferenced = true;
}
(getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop).isReferenced = SymbolFlags.All;
}
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: __String): boolean {
@ -21442,7 +21437,9 @@ namespace ts {
function checkUnusedLocalsAndParameters(node: Node): void {
if (noUnusedIdentifiers && !(node.flags & NodeFlags.Ambient)) {
node.locals.forEach(local => {
if (!local.isReferenced) {
// If it's purely a type parameter, ignore, will be checked in `checkUnusedTypeParameters`.
// If it's a type parameter merged with a parameter, check if the parameter-side is used.
if (local.flags & SymbolFlags.TypeParameter ? (local.flags & SymbolFlags.Variable && !(local.isReferenced & SymbolFlags.Variable)) : !local.isReferenced) {
if (local.valueDeclaration && getRootDeclaration(local.valueDeclaration).kind === SyntaxKind.Parameter) {
const parameter = <ParameterDeclaration>getRootDeclaration(local.valueDeclaration);
const name = getNameOfDeclaration(local.valueDeclaration);
@ -21453,7 +21450,7 @@ namespace ts {
error(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local));
}
}
else if (local.flags & SymbolFlags.TypeParameter ? compilerOptions.noUnusedParameters : compilerOptions.noUnusedLocals) {
else if (compilerOptions.noUnusedLocals) {
forEach(local.declarations, d => errorUnusedLocal(d, symbolName(local)));
}
}
@ -21538,7 +21535,7 @@ namespace ts {
return;
}
for (const typeParameter of node.typeParameters) {
if (!getMergedSymbol(typeParameter.symbol).isReferenced && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) {
if (!(getMergedSymbol(typeParameter.symbol).isReferenced & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) {
error(typeParameter.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(typeParameter.symbol));
}
}

View file

@ -3307,7 +3307,7 @@ namespace ts {
/* @internal */ parent?: Symbol; // Parent symbol
/* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
/* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums
/* @internal */ isReferenced?: boolean; // True if the symbol is referenced elsewhere
/* @internal */ isReferenced?: SymbolFlags; // True if the symbol is referenced elsewhere. Keeps track of the meaning of a reference in case a symbol is both a type parameter and parameter.
/* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol?
/* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments
}

View file

@ -0,0 +1,27 @@
tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts(1,18): error TS6133: 'T' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts(1,21): error TS6133: 'T' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts(3,19): error TS6133: 'T' is declared but its value is never read.
tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts(7,26): error TS6133: 'T' is declared but its value is never read.
==== tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts (4 errors) ====
function useNone<T>(T: number) {}
~
!!! error TS6133: 'T' is declared but its value is never read.
~
!!! error TS6133: 'T' is declared but its value is never read.
function useParam<T>(T: number) {
~
!!! error TS6133: 'T' is declared but its value is never read.
return T;
}
function useTypeParam<T>(T: T) {}
~
!!! error TS6133: 'T' is declared but its value is never read.
function useBoth<T>(T: T) {
return T;
}

View file

@ -0,0 +1,23 @@
//// [noUnusedLocals_typeParameterMergedWithParameter.ts]
function useNone<T>(T: number) {}
function useParam<T>(T: number) {
return T;
}
function useTypeParam<T>(T: T) {}
function useBoth<T>(T: T) {
return T;
}
//// [noUnusedLocals_typeParameterMergedWithParameter.js]
function useNone(T) { }
function useParam(T) {
return T;
}
function useTypeParam(T) { }
function useBoth(T) {
return T;
}

View file

@ -0,0 +1,31 @@
=== tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts ===
function useNone<T>(T: number) {}
>useNone : Symbol(useNone, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 0))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 20))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 20))
function useParam<T>(T: number) {
>useParam : Symbol(useParam, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 33))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 18), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 21))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 18), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 21))
return T;
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 18), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 21))
}
function useTypeParam<T>(T: T) {}
>useTypeParam : Symbol(useTypeParam, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 4, 1))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 22), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 25))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 22), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 25))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 22), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 25))
function useBoth<T>(T: T) {
>useBoth : Symbol(useBoth, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 33))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 20))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 20))
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 20))
return T;
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 20))
}

View file

@ -0,0 +1,31 @@
=== tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts ===
function useNone<T>(T: number) {}
>useNone : <T>(T: number) => void
>T : T
>T : number
function useParam<T>(T: number) {
>useParam : <T>(T: number) => number
>T : T
>T : number
return T;
>T : number
}
function useTypeParam<T>(T: T) {}
>useTypeParam : <T>(T: T) => void
>T : T
>T : T
>T : T
function useBoth<T>(T: T) {
>useBoth : <T>(T: T) => T
>T : T
>T : T
>T : T
return T;
>T : T
}

View file

@ -0,0 +1,14 @@
// @noUnusedLocals: true
// @noUnusedParameters: true
function useNone<T>(T: number) {}
function useParam<T>(T: number) {
return T;
}
function useTypeParam<T>(T: T) {}
function useBoth<T>(T: T) {
return T;
}