Skip to content

Commit 9ee51fa

Browse files
author
Andy
authored
Have Symbol#isReferenced check the SymbolFlags of the reference (#21996)
1 parent ecddf84 commit 9ee51fa

7 files changed

+135
-12
lines changed

src/compiler/checker.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1394,7 +1394,7 @@ namespace ts {
13941394
// If `result === lastSelfReferenceLocation.symbol`, that means that we are somewhere inside `lastSelfReferenceLocation` looking up a name, and resolving to `lastLocation` itself.
13951395
// That means that this is a self-reference of `lastLocation`, and shouldn't count this when considering whether `lastLocation` is used.
13961396
if (isUse && result && nameNotFoundMessage && noUnusedIdentifiers && (!lastSelfReferenceLocation || result !== lastSelfReferenceLocation.symbol)) {
1397-
result.isReferenced = true;
1397+
result.isReferenced |= meaning;
13981398
}
13991399

14001400
if (!result) {
@@ -15697,7 +15697,7 @@ namespace ts {
1569715697
if (reactSym) {
1569815698
// Mark local symbol as referenced here because it might not have been marked
1569915699
// if jsx emit was not react as there wont be error being emitted
15700-
reactSym.isReferenced = true;
15700+
reactSym.isReferenced = SymbolFlags.All;
1570115701

1570215702
// If react symbol is alias, mark it as refereced
1570315703
if (reactSym.flags & SymbolFlags.Alias && !isConstEnumOrConstEnumOnlyModule(resolveAlias(reactSym))) {
@@ -16267,12 +16267,7 @@ namespace ts {
1626716267
}
1626816268
}
1626916269

16270-
if (getCheckFlags(prop) & CheckFlags.Instantiated) {
16271-
getSymbolLinks(prop).target.isReferenced = true;
16272-
}
16273-
else {
16274-
prop.isReferenced = true;
16275-
}
16270+
(getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop).isReferenced = SymbolFlags.All;
1627616271
}
1627716272

1627816273
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: __String): boolean {
@@ -21442,7 +21437,9 @@ namespace ts {
2144221437
function checkUnusedLocalsAndParameters(node: Node): void {
2144321438
if (noUnusedIdentifiers && !(node.flags & NodeFlags.Ambient)) {
2144421439
node.locals.forEach(local => {
21445-
if (!local.isReferenced) {
21440+
// If it's purely a type parameter, ignore, will be checked in `checkUnusedTypeParameters`.
21441+
// If it's a type parameter merged with a parameter, check if the parameter-side is used.
21442+
if (local.flags & SymbolFlags.TypeParameter ? (local.flags & SymbolFlags.Variable && !(local.isReferenced & SymbolFlags.Variable)) : !local.isReferenced) {
2144621443
if (local.valueDeclaration && getRootDeclaration(local.valueDeclaration).kind === SyntaxKind.Parameter) {
2144721444
const parameter = <ParameterDeclaration>getRootDeclaration(local.valueDeclaration);
2144821445
const name = getNameOfDeclaration(local.valueDeclaration);
@@ -21453,7 +21450,7 @@ namespace ts {
2145321450
error(name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(local));
2145421451
}
2145521452
}
21456-
else if (local.flags & SymbolFlags.TypeParameter ? compilerOptions.noUnusedParameters : compilerOptions.noUnusedLocals) {
21453+
else if (compilerOptions.noUnusedLocals) {
2145721454
forEach(local.declarations, d => errorUnusedLocal(d, symbolName(local)));
2145821455
}
2145921456
}
@@ -21538,7 +21535,7 @@ namespace ts {
2153821535
return;
2153921536
}
2154021537
for (const typeParameter of node.typeParameters) {
21541-
if (!getMergedSymbol(typeParameter.symbol).isReferenced && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) {
21538+
if (!(getMergedSymbol(typeParameter.symbol).isReferenced & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderScore(typeParameter.name)) {
2154221539
error(typeParameter.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(typeParameter.symbol));
2154321540
}
2154421541
}

src/compiler/types.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3307,7 +3307,7 @@ namespace ts {
33073307
/* @internal */ parent?: Symbol; // Parent symbol
33083308
/* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
33093309
/* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums
3310-
/* @internal */ isReferenced?: boolean; // True if the symbol is referenced elsewhere
3310+
/* @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.
33113311
/* @internal */ isReplaceableByMethod?: boolean; // Can this Javascript class property be replaced by a method symbol?
33123312
/* @internal */ isAssigned?: boolean; // True if the symbol is a parameter with assignments
33133313
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts(1,18): error TS6133: 'T' is declared but its value is never read.
2+
tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts(1,21): error TS6133: 'T' is declared but its value is never read.
3+
tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts(3,19): error TS6133: 'T' is declared but its value is never read.
4+
tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts(7,26): error TS6133: 'T' is declared but its value is never read.
5+
6+
7+
==== tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts (4 errors) ====
8+
function useNone<T>(T: number) {}
9+
~
10+
!!! error TS6133: 'T' is declared but its value is never read.
11+
~
12+
!!! error TS6133: 'T' is declared but its value is never read.
13+
14+
function useParam<T>(T: number) {
15+
~
16+
!!! error TS6133: 'T' is declared but its value is never read.
17+
return T;
18+
}
19+
20+
function useTypeParam<T>(T: T) {}
21+
~
22+
!!! error TS6133: 'T' is declared but its value is never read.
23+
24+
function useBoth<T>(T: T) {
25+
return T;
26+
}
27+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
//// [noUnusedLocals_typeParameterMergedWithParameter.ts]
2+
function useNone<T>(T: number) {}
3+
4+
function useParam<T>(T: number) {
5+
return T;
6+
}
7+
8+
function useTypeParam<T>(T: T) {}
9+
10+
function useBoth<T>(T: T) {
11+
return T;
12+
}
13+
14+
15+
//// [noUnusedLocals_typeParameterMergedWithParameter.js]
16+
function useNone(T) { }
17+
function useParam(T) {
18+
return T;
19+
}
20+
function useTypeParam(T) { }
21+
function useBoth(T) {
22+
return T;
23+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts ===
2+
function useNone<T>(T: number) {}
3+
>useNone : Symbol(useNone, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 0))
4+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 20))
5+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 20))
6+
7+
function useParam<T>(T: number) {
8+
>useParam : Symbol(useParam, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 0, 33))
9+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 18), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 21))
10+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 18), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 21))
11+
12+
return T;
13+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 18), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 2, 21))
14+
}
15+
16+
function useTypeParam<T>(T: T) {}
17+
>useTypeParam : Symbol(useTypeParam, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 4, 1))
18+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 22), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 25))
19+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 22), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 25))
20+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 22), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 25))
21+
22+
function useBoth<T>(T: T) {
23+
>useBoth : Symbol(useBoth, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 6, 33))
24+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 20))
25+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 20))
26+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 20))
27+
28+
return T;
29+
>T : Symbol(T, Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 17), Decl(noUnusedLocals_typeParameterMergedWithParameter.ts, 8, 20))
30+
}
31+
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
=== tests/cases/compiler/noUnusedLocals_typeParameterMergedWithParameter.ts ===
2+
function useNone<T>(T: number) {}
3+
>useNone : <T>(T: number) => void
4+
>T : T
5+
>T : number
6+
7+
function useParam<T>(T: number) {
8+
>useParam : <T>(T: number) => number
9+
>T : T
10+
>T : number
11+
12+
return T;
13+
>T : number
14+
}
15+
16+
function useTypeParam<T>(T: T) {}
17+
>useTypeParam : <T>(T: T) => void
18+
>T : T
19+
>T : T
20+
>T : T
21+
22+
function useBoth<T>(T: T) {
23+
>useBoth : <T>(T: T) => T
24+
>T : T
25+
>T : T
26+
>T : T
27+
28+
return T;
29+
>T : T
30+
}
31+
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// @noUnusedLocals: true
2+
// @noUnusedParameters: true
3+
4+
function useNone<T>(T: number) {}
5+
6+
function useParam<T>(T: number) {
7+
return T;
8+
}
9+
10+
function useTypeParam<T>(T: T) {}
11+
12+
function useBoth<T>(T: T) {
13+
return T;
14+
}

0 commit comments

Comments
 (0)