Skip to content

Commit a003c18

Browse files
committed
fix(41027): handle unused static members
1 parent 5deb676 commit a003c18

File tree

6 files changed

+427
-7
lines changed

6 files changed

+427
-7
lines changed

src/compiler/checker.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14189,7 +14189,7 @@ namespace ts {
1418914189
addDeprecatedSuggestion(deprecatedNode, prop.declarations, propName as string);
1419014190
}
1419114191
if (accessExpression) {
14192-
markPropertyAsReferenced(prop, accessExpression, /*isThisAccess*/ accessExpression.expression.kind === SyntaxKind.ThisKeyword);
14192+
markPropertyAsReferenced(prop, accessExpression, isSelfTypeAccess(accessExpression.expression, objectType.symbol));
1419314193
if (isAssignmentToReadonlyEntity(accessExpression, prop, getAssignmentTargetKind(accessExpression))) {
1419414194
error(accessExpression.argumentExpression, Diagnostics.Cannot_assign_to_0_because_it_is_a_read_only_property, symbolToString(prop));
1419514195
return undefined;
@@ -26411,7 +26411,7 @@ namespace ts {
2641126411
addDeprecatedSuggestion(right, prop.declarations, right.escapedText as string);
2641226412
}
2641326413
checkPropertyNotUsedBeforeDeclaration(prop, node, right);
26414-
markPropertyAsReferenced(prop, node, left.kind === SyntaxKind.ThisKeyword);
26414+
markPropertyAsReferenced(prop, node, isSelfTypeAccess(left, parentSymbol));
2641526415
getNodeLinks(node).resolvedSymbol = prop;
2641626416
checkPropertyAccessibility(node, left.kind === SyntaxKind.SuperKeyword, apparentType, prop);
2641726417
if (isAssignmentToReadonlyEntity(node as Expression, prop, assignmentKind)) {
@@ -26740,7 +26740,7 @@ namespace ts {
2674026740
}
2674126741
}
2674226742

26743-
function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isThisAccess: boolean) {
26743+
function markPropertyAsReferenced(prop: Symbol, nodeForCheckWriteOnly: Node | undefined, isSelfTypeAccess: boolean) {
2674426744
const valueDeclaration = prop && (prop.flags & SymbolFlags.ClassMember) && prop.valueDeclaration;
2674526745
if (!valueDeclaration) {
2674626746
return;
@@ -26753,8 +26753,7 @@ namespace ts {
2675326753
if (nodeForCheckWriteOnly && isWriteOnlyAccess(nodeForCheckWriteOnly) && !(prop.flags & SymbolFlags.SetAccessor)) {
2675426754
return;
2675526755
}
26756-
26757-
if (isThisAccess) {
26756+
if (isSelfTypeAccess) {
2675826757
// Find any FunctionLikeDeclaration because those create a new 'this' binding. But this should only matter for methods (or getters/setters).
2675926758
const containingMethod = findAncestor(nodeForCheckWriteOnly, isFunctionLikeDeclaration);
2676026759
if (containingMethod && containingMethod.symbol === prop) {
@@ -26765,6 +26764,11 @@ namespace ts {
2676526764
(getCheckFlags(prop) & CheckFlags.Instantiated ? getSymbolLinks(prop).target : prop)!.isReferenced = SymbolFlags.All;
2676626765
}
2676726766

26767+
function isSelfTypeAccess(name: Expression | QualifiedName, parent: Symbol | undefined) {
26768+
return name.kind === SyntaxKind.ThisKeyword
26769+
|| !!parent && parent === getNodeLinks(name).resolvedSymbol;
26770+
}
26771+
2676826772
function isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName | ImportTypeNode, propertyName: __String): boolean {
2676926773
switch (node.kind) {
2677026774
case SyntaxKind.PropertyAccessExpression:
@@ -34350,7 +34354,7 @@ namespace ts {
3435034354
const nameText = getPropertyNameFromType(exprType);
3435134355
const property = getPropertyOfType(parentType, nameText);
3435234356
if (property) {
34353-
markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isThisAccess*/ false); // A destructuring is never a write-only reference.
34357+
markPropertyAsReferenced(property, /*nodeForCheckWriteOnly*/ undefined, /*isSelfTypeAccess*/ false); // A destructuring is never a write-only reference.
3435434358
checkPropertyAccessibility(parent, !!parent.initializer && parent.initializer.kind === SyntaxKind.SuperKeyword, parentType, property);
3435534359
}
3435634360
}
@@ -41108,5 +41112,4 @@ namespace ts {
4110841112
export function signatureHasLiteralTypes(s: Signature) {
4110941113
return !!(s.flags & SignatureFlags.HasLiteralTypes);
4111041114
}
41111-
4111241115
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
tests/cases/compiler/unusedPrivateStaticMembers.ts(16,20): error TS6133: 'p1' is declared but its value is never read.
2+
tests/cases/compiler/unusedPrivateStaticMembers.ts(17,20): error TS6133: 'm1' is declared but its value is never read.
3+
tests/cases/compiler/unusedPrivateStaticMembers.ts(21,20): error TS6133: 'm1' is declared but its value is never read.
4+
tests/cases/compiler/unusedPrivateStaticMembers.ts(25,20): error TS6133: 'm2' is declared but its value is never read.
5+
6+
7+
==== tests/cases/compiler/unusedPrivateStaticMembers.ts (4 errors) ====
8+
class Test1 {
9+
private static m1() {}
10+
public static test() {
11+
Test1.m1();
12+
}
13+
}
14+
15+
class Test2 {
16+
private static p1 = 0
17+
public static test() {
18+
Test2.p1;
19+
}
20+
}
21+
22+
class Test3 {
23+
private static p1 = 0;
24+
~~
25+
!!! error TS6133: 'p1' is declared but its value is never read.
26+
private static m1() {}
27+
~~
28+
!!! error TS6133: 'm1' is declared but its value is never read.
29+
}
30+
31+
class Test4 {
32+
private static m1(n: number): number {
33+
~~
34+
!!! error TS6133: 'm1' is declared but its value is never read.
35+
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
36+
}
37+
38+
private static m2(n: number): number {
39+
~~
40+
!!! error TS6133: 'm2' is declared but its value is never read.
41+
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
42+
}
43+
}
44+
45+
class Test5 {
46+
private static m1() {}
47+
public static test() {
48+
Test5["m1"]();
49+
}
50+
}
51+
52+
class Test6 {
53+
private static p1 = 0;
54+
public static test() {
55+
Test6["p1"];
56+
}
57+
}
58+
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
//// [unusedPrivateStaticMembers.ts]
2+
class Test1 {
3+
private static m1() {}
4+
public static test() {
5+
Test1.m1();
6+
}
7+
}
8+
9+
class Test2 {
10+
private static p1 = 0
11+
public static test() {
12+
Test2.p1;
13+
}
14+
}
15+
16+
class Test3 {
17+
private static p1 = 0;
18+
private static m1() {}
19+
}
20+
21+
class Test4 {
22+
private static m1(n: number): number {
23+
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
24+
}
25+
26+
private static m2(n: number): number {
27+
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
28+
}
29+
}
30+
31+
class Test5 {
32+
private static m1() {}
33+
public static test() {
34+
Test5["m1"]();
35+
}
36+
}
37+
38+
class Test6 {
39+
private static p1 = 0;
40+
public static test() {
41+
Test6["p1"];
42+
}
43+
}
44+
45+
46+
//// [unusedPrivateStaticMembers.js]
47+
class Test1 {
48+
static m1() { }
49+
static test() {
50+
Test1.m1();
51+
}
52+
}
53+
class Test2 {
54+
static test() {
55+
Test2.p1;
56+
}
57+
}
58+
Test2.p1 = 0;
59+
class Test3 {
60+
static m1() { }
61+
}
62+
Test3.p1 = 0;
63+
class Test4 {
64+
static m1(n) {
65+
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
66+
}
67+
static m2(n) {
68+
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
69+
}
70+
}
71+
class Test5 {
72+
static m1() { }
73+
static test() {
74+
Test5["m1"]();
75+
}
76+
}
77+
class Test6 {
78+
static test() {
79+
Test6["p1"];
80+
}
81+
}
82+
Test6.p1 = 0;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
=== tests/cases/compiler/unusedPrivateStaticMembers.ts ===
2+
class Test1 {
3+
>Test1 : Symbol(Test1, Decl(unusedPrivateStaticMembers.ts, 0, 0))
4+
5+
private static m1() {}
6+
>m1 : Symbol(Test1.m1, Decl(unusedPrivateStaticMembers.ts, 0, 13))
7+
8+
public static test() {
9+
>test : Symbol(Test1.test, Decl(unusedPrivateStaticMembers.ts, 1, 26))
10+
11+
Test1.m1();
12+
>Test1.m1 : Symbol(Test1.m1, Decl(unusedPrivateStaticMembers.ts, 0, 13))
13+
>Test1 : Symbol(Test1, Decl(unusedPrivateStaticMembers.ts, 0, 0))
14+
>m1 : Symbol(Test1.m1, Decl(unusedPrivateStaticMembers.ts, 0, 13))
15+
}
16+
}
17+
18+
class Test2 {
19+
>Test2 : Symbol(Test2, Decl(unusedPrivateStaticMembers.ts, 5, 1))
20+
21+
private static p1 = 0
22+
>p1 : Symbol(Test2.p1, Decl(unusedPrivateStaticMembers.ts, 7, 13))
23+
24+
public static test() {
25+
>test : Symbol(Test2.test, Decl(unusedPrivateStaticMembers.ts, 8, 25))
26+
27+
Test2.p1;
28+
>Test2.p1 : Symbol(Test2.p1, Decl(unusedPrivateStaticMembers.ts, 7, 13))
29+
>Test2 : Symbol(Test2, Decl(unusedPrivateStaticMembers.ts, 5, 1))
30+
>p1 : Symbol(Test2.p1, Decl(unusedPrivateStaticMembers.ts, 7, 13))
31+
}
32+
}
33+
34+
class Test3 {
35+
>Test3 : Symbol(Test3, Decl(unusedPrivateStaticMembers.ts, 12, 1))
36+
37+
private static p1 = 0;
38+
>p1 : Symbol(Test3.p1, Decl(unusedPrivateStaticMembers.ts, 14, 13))
39+
40+
private static m1() {}
41+
>m1 : Symbol(Test3.m1, Decl(unusedPrivateStaticMembers.ts, 15, 26))
42+
}
43+
44+
class Test4 {
45+
>Test4 : Symbol(Test4, Decl(unusedPrivateStaticMembers.ts, 17, 1))
46+
47+
private static m1(n: number): number {
48+
>m1 : Symbol(Test4.m1, Decl(unusedPrivateStaticMembers.ts, 19, 13))
49+
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 20, 22))
50+
51+
return (n === 0) ? 1 : (n * Test4.m1(n - 1));
52+
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 20, 22))
53+
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 20, 22))
54+
>Test4.m1 : Symbol(Test4.m1, Decl(unusedPrivateStaticMembers.ts, 19, 13))
55+
>Test4 : Symbol(Test4, Decl(unusedPrivateStaticMembers.ts, 17, 1))
56+
>m1 : Symbol(Test4.m1, Decl(unusedPrivateStaticMembers.ts, 19, 13))
57+
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 20, 22))
58+
}
59+
60+
private static m2(n: number): number {
61+
>m2 : Symbol(Test4.m2, Decl(unusedPrivateStaticMembers.ts, 22, 5))
62+
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 24, 22))
63+
64+
return (n === 0) ? 1 : (n * Test4["m2"](n - 1));
65+
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 24, 22))
66+
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 24, 22))
67+
>Test4 : Symbol(Test4, Decl(unusedPrivateStaticMembers.ts, 17, 1))
68+
>"m2" : Symbol(Test4.m2, Decl(unusedPrivateStaticMembers.ts, 22, 5))
69+
>n : Symbol(n, Decl(unusedPrivateStaticMembers.ts, 24, 22))
70+
}
71+
}
72+
73+
class Test5 {
74+
>Test5 : Symbol(Test5, Decl(unusedPrivateStaticMembers.ts, 27, 1))
75+
76+
private static m1() {}
77+
>m1 : Symbol(Test5.m1, Decl(unusedPrivateStaticMembers.ts, 29, 13))
78+
79+
public static test() {
80+
>test : Symbol(Test5.test, Decl(unusedPrivateStaticMembers.ts, 30, 26))
81+
82+
Test5["m1"]();
83+
>Test5 : Symbol(Test5, Decl(unusedPrivateStaticMembers.ts, 27, 1))
84+
>"m1" : Symbol(Test5.m1, Decl(unusedPrivateStaticMembers.ts, 29, 13))
85+
}
86+
}
87+
88+
class Test6 {
89+
>Test6 : Symbol(Test6, Decl(unusedPrivateStaticMembers.ts, 34, 1))
90+
91+
private static p1 = 0;
92+
>p1 : Symbol(Test6.p1, Decl(unusedPrivateStaticMembers.ts, 36, 13))
93+
94+
public static test() {
95+
>test : Symbol(Test6.test, Decl(unusedPrivateStaticMembers.ts, 37, 26))
96+
97+
Test6["p1"];
98+
>Test6 : Symbol(Test6, Decl(unusedPrivateStaticMembers.ts, 34, 1))
99+
>"p1" : Symbol(Test6.p1, Decl(unusedPrivateStaticMembers.ts, 36, 13))
100+
}
101+
}
102+

0 commit comments

Comments
 (0)