mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 08:11:30 -06:00
fix(41027): handle unused static members (#41103)
This commit is contained in:
parent
5053b0b987
commit
3c576f108c
@ -14334,7 +14334,7 @@ namespace ts {
|
||||
addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string);
|
||||
}
|
||||
if (accessExpression) {
|
||||
markPropertyAsReferenced(prop, accessExpression, /*isThisAccess*/ accessExpression.expression.kind === SyntaxKind.ThisKeyword);
|
||||
markPropertyAsReferenced(prop, accessExpression, isSelfTypeAccess(accessExpression.expression, objectType.symbol));
|
||||
if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) {
|
||||
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop));
|
||||
return undefined;
|
||||
@ -26796,7 +26796,7 @@ namespace ts {
|
||||
addDeprecatedSuggestion(right, prop.declarations, right.escapedText as string);
|
||||
}
|
||||
checkPropertyNotUsedBeforeDeclaration(prop, node, right);
|
||||
markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
|
||||
markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol));
|
||||
getNodeLinks(node).resolvedSymbol = prop;
|
||||
checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop);
|
||||
if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
|
||||
@ -27125,7 +27125,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) {
|
||||
function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isSelfTypeAccess: boolean) {
|
||||
const valueDeclaration = prop && (prop.flags & SymbolFlags.ClassMember) && prop.valueDeclaration;
|
||||
if (!valueDeclaration) {
|
||||
return;
|
||||
@ -27138,8 +27138,7 @@ namespace ts {
|
||||
if (nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) && !(prop.flags & SymbolFlags.SetAccessor)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isThisAccess) {
|
||||
if (isSelfTypeAccess) {
|
||||
// Find any FunctionLikeDeclaration because those create a new 'this' binding. But this should only matter for methods (or getters/setters).
|
||||
const containingMethod = findAncestor(nodeForCheckWriteOnly, isFunctionLikeDeclaration);
|
||||
if (containingMethod && containingMethod.symbol === prop) {
|
||||
@ -27150,6 +27149,11 @@ namespace ts {
|
||||
(getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop)!.isReferenced = SymbolFlags.All;
|
||||
}
|
||||
|
||||
function isSelfTypeAccess(name: Expression | QualifiedName, parent: Symbol | undefined) {
|
||||
return name.kind === SyntaxKind.ThisKeyword
|
||||
|| !!parent && isEntityNameExpression(name) && parent === getResolvedSymbol(getFirstIdentifier(name));
|
||||
}
|
||||
|
||||
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: __String): boolean {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
@ -34700,7 +34704,7 @@ namespace ts {
|
||||
const nameText = getPropertyNameFromType(exprType);
|
||||
const property = getPropertyOfType(parentType, nameText);
|
||||
if (property) {
|
||||
markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isThisAccess*/ false); // A destructuring is never a write-only reference.
|
||||
markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isSelfTypeAccess*/ false); // A destructuring is never a write-only reference.
|
||||
checkPropertyAccessibility(node, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, parentType, property);
|
||||
}
|
||||
}
|
||||
@ -41504,5 +41508,4 @@ namespace ts {
|
||||
export function signatureHasLiteralTypes(s: Signature) {
|
||||
return !!(s.flags & SignatureFlags.HasLiteralTypes);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,58 @@
|
||||
tests/cases/compiler/unusedPrivateStaticMembers.ts(16,20): error TS6133: 'p1' is declared but its value is never read.
|
||||
tests/cases/compiler/unusedPrivateStaticMembers.ts(17,20): error TS6133: 'm1' is declared but its value is never read.
|
||||
tests/cases/compiler/unusedPrivateStaticMembers.ts(21,20): error TS6133: 'm1' is declared but its value is never read.
|
||||
tests/cases/compiler/unusedPrivateStaticMembers.ts(25,20): error TS6133: 'm2' is declared but its value is never read.
|
||||
|
||||
|
||||
==== tests/cases/compiler/unusedPrivateStaticMembers.ts (4 errors) ====
|
||||
class Test1 {
|
||||
private static m1() {}
|
||||
public static test() {
|
||||
Test1.m1();
|
||||
}
|
||||
}
|
||||
|
||||
class Test2 {
|
||||
private static p1 = 0
|
||||
public static test() {
|
||||
Test2.p1;
|
||||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
private static p1 = 0;
|
||||
~~
|
||||
!!! error TS6133: 'p1' is declared but its value is never read.
|
||||
private static m1() {}
|
||||
~~
|
||||
!!! error TS6133: 'm1' is declared but its value is never read.
|
||||
}
|
||||
|
||||
class Test4 {
|
||||
private static m1(n: number): number {
|
||||
~~
|
||||
!!! error TS6133: 'm1' is declared but its value is never read.
|
||||
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
|
||||
}
|
||||
|
||||
private static m2(n: number): number {
|
||||
~~
|
||||
!!! error TS6133: 'm2' is declared but its value is never read.
|
||||
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
|
||||
}
|
||||
}
|
||||
|
||||
class Test5 {
|
||||
private static m1() {}
|
||||
public static test() {
|
||||
Test5["m1"]();
|
||||
}
|
||||
}
|
||||
|
||||
class Test6 {
|
||||
private static p1 = 0;
|
||||
public static test() {
|
||||
Test6["p1"];
|
||||
}
|
||||
}
|
||||
|
||||
82
tests/baselines/reference/unusedPrivateStaticMembers.js
Normal file
82
tests/baselines/reference/unusedPrivateStaticMembers.js
Normal file
@ -0,0 +1,82 @@
|
||||
//// [unusedPrivateStaticMembers.ts]
|
||||
class Test1 {
|
||||
private static m1() {}
|
||||
public static test() {
|
||||
Test1.m1();
|
||||
}
|
||||
}
|
||||
|
||||
class Test2 {
|
||||
private static p1 = 0
|
||||
public static test() {
|
||||
Test2.p1;
|
||||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
private static p1 = 0;
|
||||
private static m1() {}
|
||||
}
|
||||
|
||||
class Test4 {
|
||||
private static m1(n: number): number {
|
||||
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
|
||||
}
|
||||
|
||||
private static m2(n: number): number {
|
||||
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
|
||||
}
|
||||
}
|
||||
|
||||
class Test5 {
|
||||
private static m1() {}
|
||||
public static test() {
|
||||
Test5["m1"]();
|
||||
}
|
||||
}
|
||||
|
||||
class Test6 {
|
||||
private static p1 = 0;
|
||||
public static test() {
|
||||
Test6["p1"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//// [unusedPrivateStaticMembers.js]
|
||||
class Test1 {
|
||||
static m1() { }
|
||||
static test() {
|
||||
Test1.m1();
|
||||
}
|
||||
}
|
||||
class Test2 {
|
||||
static test() {
|
||||
Test2.p1;
|
||||
}
|
||||
}
|
||||
Test2.p1 = 0;
|
||||
class Test3 {
|
||||
static m1() { }
|
||||
}
|
||||
Test3.p1 = 0;
|
||||
class Test4 {
|
||||
static m1(n) {
|
||||
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
|
||||
}
|
||||
static m2(n) {
|
||||
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
|
||||
}
|
||||
}
|
||||
class Test5 {
|
||||
static m1() { }
|
||||
static test() {
|
||||
Test5["m1"]();
|
||||
}
|
||||
}
|
||||
class Test6 {
|
||||
static test() {
|
||||
Test6["p1"];
|
||||
}
|
||||
}
|
||||
Test6.p1 = 0;
|
||||
102
tests/baselines/reference/unusedPrivateStaticMembers.symbols
Normal file
102
tests/baselines/reference/unusedPrivateStaticMembers.symbols
Normal file
@ -0,0 +1,102 @@
|
||||
=== tests/cases/compiler/unusedPrivateStaticMembers.ts ===
|
||||
class Test1 {
|
||||
>Test1 : Symbol(Test1, Decl(unusedPrivateStaticMembers.ts, 0, 0))
|
||||
|
||||
private static m1() {}
|
||||
>m1 : Symbol(Test1.m1, Decl(unusedPrivateStaticMembers.ts, 0, 13))
|
||||
|
||||
public static test() {
|
||||
>test : Symbol(Test1.test, Decl(unusedPrivateStaticMembers.ts, 1, 26))
|
||||
|
||||
Test1.m1();
|
||||
>Test1.m1 : Symbol(Test1.m1, Decl(unusedPrivateStaticMembers.ts, 0, 13))
|
||||
>Test1 : Symbol(Test1, Decl(unusedPrivateStaticMembers.ts, 0, 0))
|
||||
>m1 : Symbol(Test1.m1, Decl(unusedPrivateStaticMembers.ts, 0, 13))
|
||||
}
|
||||
}
|
||||
|
||||
class Test2 {
|
||||
>Test2 : Symbol(Test2, Decl(unusedPrivateStaticMembers.ts, 5, 1))
|
||||
|
||||
private static p1 = 0
|
||||
>p1 : Symbol(Test2.p1, Decl(unusedPrivateStaticMembers.ts, 7, 13))
|
||||
|
||||
public static test() {
|
||||
>test : Symbol(Test2.test, Decl(unusedPrivateStaticMembers.ts, 8, 25))
|
||||
|
||||
Test2.p1;
|
||||
>Test2.p1 : Symbol(Test2.p1, Decl(unusedPrivateStaticMembers.ts, 7, 13))
|
||||
>Test2 : Symbol(Test2, Decl(unusedPrivateStaticMembers.ts, 5, 1))
|
||||
>p1 : Symbol(Test2.p1, Decl(unusedPrivateStaticMembers.ts, 7, 13))
|
||||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
>Test3 : Symbol(Test3, Decl(unusedPrivateStaticMembers.ts, 12, 1))
|
||||
|
||||
private static p1 = 0;
|
||||
>p1 : Symbol(Test3.p1, Decl(unusedPrivateStaticMembers.ts, 14, 13))
|
||||
|
||||
private static m1() {}
|
||||
>m1 : Symbol(Test3.m1, Decl(unusedPrivateStaticMembers.ts, 15, 26))
|
||||
}
|
||||
|
||||
class Test4 {
|
||||
>Test4 : Symbol(Test4, Decl(unusedPrivateStaticMembers.ts, 17, 1))
|
||||
|
||||
private static m1(n: number): number {
|
||||
>m1 : Symbol(Test4.m1, Decl(unusedPrivateStaticMembers.ts, 19, 13))
|
||||
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 20, 22))
|
||||
|
||||
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
|
||||
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 20, 22))
|
||||
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 20, 22))
|
||||
>Test4.m1 : Symbol(Test4.m1, Decl(unusedPrivateStaticMembers.ts, 19, 13))
|
||||
>Test4 : Symbol(Test4, Decl(unusedPrivateStaticMembers.ts, 17, 1))
|
||||
>m1 : Symbol(Test4.m1, Decl(unusedPrivateStaticMembers.ts, 19, 13))
|
||||
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 20, 22))
|
||||
}
|
||||
|
||||
private static m2(n: number): number {
|
||||
>m2 : Symbol(Test4.m2, Decl(unusedPrivateStaticMembers.ts, 22, 5))
|
||||
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 24, 22))
|
||||
|
||||
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
|
||||
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 24, 22))
|
||||
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 24, 22))
|
||||
>Test4 : Symbol(Test4, Decl(unusedPrivateStaticMembers.ts, 17, 1))
|
||||
>"m2" : Symbol(Test4.m2, Decl(unusedPrivateStaticMembers.ts, 22, 5))
|
||||
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 24, 22))
|
||||
}
|
||||
}
|
||||
|
||||
class Test5 {
|
||||
>Test5 : Symbol(Test5, Decl(unusedPrivateStaticMembers.ts, 27, 1))
|
||||
|
||||
private static m1() {}
|
||||
>m1 : Symbol(Test5.m1, Decl(unusedPrivateStaticMembers.ts, 29, 13))
|
||||
|
||||
public static test() {
|
||||
>test : Symbol(Test5.test, Decl(unusedPrivateStaticMembers.ts, 30, 26))
|
||||
|
||||
Test5["m1"]();
|
||||
>Test5 : Symbol(Test5, Decl(unusedPrivateStaticMembers.ts, 27, 1))
|
||||
>"m1" : Symbol(Test5.m1, Decl(unusedPrivateStaticMembers.ts, 29, 13))
|
||||
}
|
||||
}
|
||||
|
||||
class Test6 {
|
||||
>Test6 : Symbol(Test6, Decl(unusedPrivateStaticMembers.ts, 34, 1))
|
||||
|
||||
private static p1 = 0;
|
||||
>p1 : Symbol(Test6.p1, Decl(unusedPrivateStaticMembers.ts, 36, 13))
|
||||
|
||||
public static test() {
|
||||
>test : Symbol(Test6.test, Decl(unusedPrivateStaticMembers.ts, 37, 26))
|
||||
|
||||
Test6["p1"];
|
||||
>Test6 : Symbol(Test6, Decl(unusedPrivateStaticMembers.ts, 34, 1))
|
||||
>"p1" : Symbol(Test6.p1, Decl(unusedPrivateStaticMembers.ts, 36, 13))
|
||||
}
|
||||
}
|
||||
|
||||
130
tests/baselines/reference/unusedPrivateStaticMembers.types
Normal file
130
tests/baselines/reference/unusedPrivateStaticMembers.types
Normal file
@ -0,0 +1,130 @@
|
||||
=== tests/cases/compiler/unusedPrivateStaticMembers.ts ===
|
||||
class Test1 {
|
||||
>Test1 : Test1
|
||||
|
||||
private static m1() {}
|
||||
>m1 : () => void
|
||||
|
||||
public static test() {
|
||||
>test : () => void
|
||||
|
||||
Test1.m1();
|
||||
>Test1.m1() : void
|
||||
>Test1.m1 : () => void
|
||||
>Test1 : typeof Test1
|
||||
>m1 : () => void
|
||||
}
|
||||
}
|
||||
|
||||
class Test2 {
|
||||
>Test2 : Test2
|
||||
|
||||
private static p1 = 0
|
||||
>p1 : number
|
||||
>0 : 0
|
||||
|
||||
public static test() {
|
||||
>test : () => void
|
||||
|
||||
Test2.p1;
|
||||
>Test2.p1 : number
|
||||
>Test2 : typeof Test2
|
||||
>p1 : number
|
||||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
>Test3 : Test3
|
||||
|
||||
private static p1 = 0;
|
||||
>p1 : number
|
||||
>0 : 0
|
||||
|
||||
private static m1() {}
|
||||
>m1 : () => void
|
||||
}
|
||||
|
||||
class Test4 {
|
||||
>Test4 : Test4
|
||||
|
||||
private static m1(n: number): number {
|
||||
>m1 : (n: number) => number
|
||||
>n : number
|
||||
|
||||
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
|
||||
>(n === 0) ? 1 : (n * Test4.m1(n - 1)) : number
|
||||
>(n === 0) : boolean
|
||||
>n === 0 : boolean
|
||||
>n : number
|
||||
>0 : 0
|
||||
>1 : 1
|
||||
>(n * Test4.m1(n - 1)) : number
|
||||
>n * Test4.m1(n - 1) : number
|
||||
>n : number
|
||||
>Test4.m1(n - 1) : number
|
||||
>Test4.m1 : (n: number) => number
|
||||
>Test4 : typeof Test4
|
||||
>m1 : (n: number) => number
|
||||
>n - 1 : number
|
||||
>n : number
|
||||
>1 : 1
|
||||
}
|
||||
|
||||
private static m2(n: number): number {
|
||||
>m2 : (n: number) => number
|
||||
>n : number
|
||||
|
||||
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
|
||||
>(n === 0) ? 1 : (n * Test4["m2"](n - 1)) : number
|
||||
>(n === 0) : boolean
|
||||
>n === 0 : boolean
|
||||
>n : number
|
||||
>0 : 0
|
||||
>1 : 1
|
||||
>(n * Test4["m2"](n - 1)) : number
|
||||
>n * Test4["m2"](n - 1) : number
|
||||
>n : number
|
||||
>Test4["m2"](n - 1) : number
|
||||
>Test4["m2"] : (n: number) => number
|
||||
>Test4 : typeof Test4
|
||||
>"m2" : "m2"
|
||||
>n - 1 : number
|
||||
>n : number
|
||||
>1 : 1
|
||||
}
|
||||
}
|
||||
|
||||
class Test5 {
|
||||
>Test5 : Test5
|
||||
|
||||
private static m1() {}
|
||||
>m1 : () => void
|
||||
|
||||
public static test() {
|
||||
>test : () => void
|
||||
|
||||
Test5["m1"]();
|
||||
>Test5["m1"]() : void
|
||||
>Test5["m1"] : () => void
|
||||
>Test5 : typeof Test5
|
||||
>"m1" : "m1"
|
||||
}
|
||||
}
|
||||
|
||||
class Test6 {
|
||||
>Test6 : Test6
|
||||
|
||||
private static p1 = 0;
|
||||
>p1 : number
|
||||
>0 : 0
|
||||
|
||||
public static test() {
|
||||
>test : () => void
|
||||
|
||||
Test6["p1"];
|
||||
>Test6["p1"] : number
|
||||
>Test6 : typeof Test6
|
||||
>"p1" : "p1"
|
||||
}
|
||||
}
|
||||
|
||||
45
tests/cases/compiler/unusedPrivateStaticMembers.ts
Normal file
45
tests/cases/compiler/unusedPrivateStaticMembers.ts
Normal file
@ -0,0 +1,45 @@
|
||||
// @noUnusedLocals: true
|
||||
// @target: esnext
|
||||
|
||||
class Test1 {
|
||||
private static m1() {}
|
||||
public static test() {
|
||||
Test1.m1();
|
||||
}
|
||||
}
|
||||
|
||||
class Test2 {
|
||||
private static p1 = 0
|
||||
public static test() {
|
||||
Test2.p1;
|
||||
}
|
||||
}
|
||||
|
||||
class Test3 {
|
||||
private static p1 = 0;
|
||||
private static m1() {}
|
||||
}
|
||||
|
||||
class Test4 {
|
||||
private static m1(n: number): number {
|
||||
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
|
||||
}
|
||||
|
||||
private static m2(n: number): number {
|
||||
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
|
||||
}
|
||||
}
|
||||
|
||||
class Test5 {
|
||||
private static m1() {}
|
||||
public static test() {
|
||||
Test5["m1"]();
|
||||
}
|
||||
}
|
||||
|
||||
class Test6 {
|
||||
private static p1 = 0;
|
||||
public static test() {
|
||||
Test6["p1"];
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user