Skip to content

Commit fca0b39

Browse files
committed
Use related spans for "implement abstract class" errors
1 parent 9dbfaee commit fca0b39

13 files changed

+88
-56
lines changed

Diff for: src/compiler/checker.ts

+22-3
Original file line numberDiff line numberDiff line change
@@ -36173,6 +36173,8 @@ namespace ts {
3617336173

3617436174
// NOTE: assignability is checked in checkClassDeclaration
3617536175
const baseProperties = getPropertiesOfType(baseType);
36176+
const derivedClassDecl = getClassLikeDeclarationOfSymbol(type.symbol)!;
36177+
const inheritedAbstractMemberNotImplementedErrors: Diagnostic[] = [];
3617636178
basePropertyCheck: for (const baseProperty of baseProperties) {
3617736179
const base = getTargetSymbol(baseProperty);
3617836180

@@ -36193,7 +36195,6 @@ namespace ts {
3619336195
// type declaration, derived and base resolve to the same symbol even in the case of generic classes.
3619436196
if (derived === base) {
3619536197
// derived class inherits base without override/redeclaration
36196-
const derivedClassDecl = getClassLikeDeclarationOfSymbol(type.symbol)!;
3619736198

3619836199
// It is an error to inherit an abstract member without implementing it or being declared abstract.
3619936200
// If there is no declaration for the derived class (as in the case of class expressions),
@@ -36212,12 +36213,16 @@ namespace ts {
3621236213
}
3621336214

3621436215
if (derivedClassDecl.kind === SyntaxKind.ClassExpression) {
36215-
error(derivedClassDecl, Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
36216+
const err = createDiagnosticForNode(derivedClassDecl,
36217+
Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1,
3621636218
symbolToString(baseProperty), typeToString(baseType));
36219+
inheritedAbstractMemberNotImplementedErrors.push(err);
3621736220
}
3621836221
else {
36219-
error(derivedClassDecl, Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
36222+
const err = createDiagnosticForNode(derivedClassDecl,
36223+
Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2,
3622036224
typeToString(type), symbolToString(baseProperty), typeToString(baseType));
36225+
inheritedAbstractMemberNotImplementedErrors.push(err);
3622136226
}
3622236227
}
3622336228
}
@@ -36293,6 +36298,20 @@ namespace ts {
3629336298
error(getNameOfDeclaration(derived.valueDeclaration) || derived.valueDeclaration, errorMessage, typeToString(baseType), symbolToString(base), typeToString(type));
3629436299
}
3629536300
}
36301+
36302+
if (inheritedAbstractMemberNotImplementedErrors.length) {
36303+
const err = error(
36304+
derivedClassDecl,
36305+
Diagnostics.Non_abstract_class_0_does_not_implement_all_abstract_members_of_1,
36306+
typeToString(type), typeToString(baseType));
36307+
36308+
for (const inheritedAbstractMemberNotImplementedError of inheritedAbstractMemberNotImplementedErrors) {
36309+
addRelatedInfo(
36310+
err,
36311+
inheritedAbstractMemberNotImplementedError,
36312+
);
36313+
}
36314+
}
3629636315
}
3629736316

3629836317
function getNonInterhitedProperties(type: InterfaceType, baseTypes: BaseType[], properties: Symbol[]) {

Diff for: src/compiler/diagnosticMessages.json

+4
Original file line numberDiff line numberDiff line change
@@ -6346,5 +6346,9 @@
63466346
"Invalid value for 'jsxFragmentFactory'. '{0}' is not a valid identifier or qualified-name.": {
63476347
"category": "Error",
63486348
"code": 18035
6349+
},
6350+
"Non-abstract class '{0}' does not implement all abstract members of '{1}'": {
6351+
"category": "Error",
6352+
"code": 18036
63496353
}
63506354
}

Diff for: src/services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* @internal */
22
namespace ts.codefix {
33
const errorCodes = [
4+
Diagnostics.Non_abstract_class_0_does_not_implement_all_abstract_members_of_1.code,
45
Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2.code,
56
Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1.code,
67
];

Diff for: tests/baselines/reference/abstractPropertyNegative.errors.txt

+7-12
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
tests/cases/compiler/abstractPropertyNegative.ts(10,18): error TS2380: 'get' and 'set' accessor must have the same type.
22
tests/cases/compiler/abstractPropertyNegative.ts(11,18): error TS2380: 'get' and 'set' accessor must have the same type.
3-
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'm' from class 'B'.
4-
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'mismatch' from class 'B'.
5-
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'prop' from class 'B'.
6-
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'readonlyProp' from class 'B'.
3+
tests/cases/compiler/abstractPropertyNegative.ts(13,7): error TS18036: Non-abstract class 'C' does not implement all abstract members of 'B'
74
tests/cases/compiler/abstractPropertyNegative.ts(15,5): error TS1244: Abstract methods can only appear within an abstract class.
85
tests/cases/compiler/abstractPropertyNegative.ts(16,37): error TS1005: '{' expected.
96
tests/cases/compiler/abstractPropertyNegative.ts(19,3): error TS2540: Cannot assign to 'ro' because it is a read-only property.
@@ -19,7 +16,7 @@ tests/cases/compiler/abstractPropertyNegative.ts(40,9): error TS2676: Accessors
1916
tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors must both be abstract or non-abstract.
2017

2118

22-
==== tests/cases/compiler/abstractPropertyNegative.ts (16 errors) ====
19+
==== tests/cases/compiler/abstractPropertyNegative.ts (13 errors) ====
2320
interface A {
2421
prop: string;
2522
m(): string;
@@ -38,13 +35,11 @@ tests/cases/compiler/abstractPropertyNegative.ts(41,18): error TS2676: Accessors
3835
}
3936
class C extends B {
4037
~
41-
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'm' from class 'B'.
42-
~
43-
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'mismatch' from class 'B'.
44-
~
45-
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'prop' from class 'B'.
46-
~
47-
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'readonlyProp' from class 'B'.
38+
!!! error TS18036: Non-abstract class 'C' does not implement all abstract members of 'B'
39+
!!! related TS2515 tests/cases/compiler/abstractPropertyNegative.ts:13:7: Non-abstract class 'C' does not implement inherited abstract member 'prop' from class 'B'.
40+
!!! related TS2515 tests/cases/compiler/abstractPropertyNegative.ts:13:7: Non-abstract class 'C' does not implement inherited abstract member 'readonlyProp' from class 'B'.
41+
!!! related TS2515 tests/cases/compiler/abstractPropertyNegative.ts:13:7: Non-abstract class 'C' does not implement inherited abstract member 'm' from class 'B'.
42+
!!! related TS2515 tests/cases/compiler/abstractPropertyNegative.ts:13:7: Non-abstract class 'C' does not implement inherited abstract member 'mismatch' from class 'B'.
4843
readonly ro = "readonly please";
4944
abstract notAllowed: string;
5045
~~~~~~~~

Diff for: tests/baselines/reference/classAbstractDeclarations.d.errors.txt

+9-6
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(2,5): error TS1242: 'abstract' modifier can only appear on a class, method, or property declaration.
22
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(2,28): error TS1183: An implementation cannot be declared in ambient contexts.
3-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(11,15): error TS2515: Non-abstract class 'CC' does not implement inherited abstract member 'foo' from class 'AA'.
4-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(13,15): error TS2515: Non-abstract class 'DD' does not implement inherited abstract member 'foo' from class 'BB'.
5-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(17,15): error TS2515: Non-abstract class 'FF' does not implement inherited abstract member 'foo' from class 'CC'.
3+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(11,15): error TS18036: Non-abstract class 'CC' does not implement all abstract members of 'AA'
4+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(13,15): error TS18036: Non-abstract class 'DD' does not implement all abstract members of 'BB'
5+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts(17,15): error TS18036: Non-abstract class 'FF' does not implement all abstract members of 'CC'
66

77

88
==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts (5 errors) ====
@@ -22,17 +22,20 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst
2222

2323
declare class CC extends AA {}
2424
~~
25-
!!! error TS2515: Non-abstract class 'CC' does not implement inherited abstract member 'foo' from class 'AA'.
25+
!!! error TS18036: Non-abstract class 'CC' does not implement all abstract members of 'AA'
26+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts:11:15: Non-abstract class 'CC' does not implement inherited abstract member 'foo' from class 'AA'.
2627

2728
declare class DD extends BB {}
2829
~~
29-
!!! error TS2515: Non-abstract class 'DD' does not implement inherited abstract member 'foo' from class 'BB'.
30+
!!! error TS18036: Non-abstract class 'DD' does not implement all abstract members of 'BB'
31+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts:13:15: Non-abstract class 'DD' does not implement inherited abstract member 'foo' from class 'BB'.
3032

3133
declare abstract class EE extends BB {}
3234

3335
declare class FF extends CC {}
3436
~~
35-
!!! error TS2515: Non-abstract class 'FF' does not implement inherited abstract member 'foo' from class 'CC'.
37+
!!! error TS18036: Non-abstract class 'FF' does not implement all abstract members of 'CC'
38+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractDeclarations.d.ts:17:15: Non-abstract class 'FF' does not implement inherited abstract member 'foo' from class 'CC'.
3639

3740
declare abstract class GG extends CC {}
3841

Diff for: tests/baselines/reference/classAbstractExtends.errors.txt

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts(9,7): error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'.
1+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts(9,7): error TS18036: Non-abstract class 'C' does not implement all abstract members of 'B'
22

33

44
==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts (1 errors) ====
@@ -12,7 +12,8 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst
1212

1313
class C extends B { }
1414
~
15-
!!! error TS2515: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'.
15+
!!! error TS18036: Non-abstract class 'C' does not implement all abstract members of 'B'
16+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractExtends.ts:9:7: Non-abstract class 'C' does not implement inherited abstract member 'bar' from class 'B'.
1617

1718
abstract class D extends B {}
1819

Diff for: tests/baselines/reference/classAbstractGeneric.errors.txt

+15-15
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(10,7): error TS2515: Non-abstract class 'C<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
2-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(10,7): error TS2515: Non-abstract class 'C<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
3-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(12,7): error TS2515: Non-abstract class 'D' does not implement inherited abstract member 'bar' from class 'A<number>'.
4-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(12,7): error TS2515: Non-abstract class 'D' does not implement inherited abstract member 'foo' from class 'A<number>'.
5-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(14,7): error TS2515: Non-abstract class 'E<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
6-
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(18,7): error TS2515: Non-abstract class 'F<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
1+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(10,7): error TS18036: Non-abstract class 'C<T>' does not implement all abstract members of 'A<T>'
2+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(12,7): error TS18036: Non-abstract class 'D' does not implement all abstract members of 'A<number>'
3+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(14,7): error TS18036: Non-abstract class 'E<T>' does not implement all abstract members of 'A<T>'
4+
tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts(18,7): error TS18036: Non-abstract class 'F<T>' does not implement all abstract members of 'A<T>'
75

86

9-
==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts (6 errors) ====
7+
==== tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts (4 errors) ====
108
abstract class A<T> {
119
t: T;
1210

@@ -18,25 +16,27 @@ tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbst
1816

1917
class C<T> extends A<T> {} // error -- inherits abstract methods
2018
~
21-
!!! error TS2515: Non-abstract class 'C<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
22-
~
23-
!!! error TS2515: Non-abstract class 'C<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
19+
!!! error TS18036: Non-abstract class 'C<T>' does not implement all abstract members of 'A<T>'
20+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:10:7: Non-abstract class 'C<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
21+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:10:7: Non-abstract class 'C<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
2422

2523
class D extends A<number> {} // error -- inherits abstract methods
2624
~
27-
!!! error TS2515: Non-abstract class 'D' does not implement inherited abstract member 'bar' from class 'A<number>'.
28-
~
29-
!!! error TS2515: Non-abstract class 'D' does not implement inherited abstract member 'foo' from class 'A<number>'.
25+
!!! error TS18036: Non-abstract class 'D' does not implement all abstract members of 'A<number>'
26+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:12:7: Non-abstract class 'D' does not implement inherited abstract member 'foo' from class 'A<number>'.
27+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:12:7: Non-abstract class 'D' does not implement inherited abstract member 'bar' from class 'A<number>'.
3028

3129
class E<T> extends A<T> { // error -- doesn't implement bar
3230
~
33-
!!! error TS2515: Non-abstract class 'E<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
31+
!!! error TS18036: Non-abstract class 'E<T>' does not implement all abstract members of 'A<T>'
32+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:14:7: Non-abstract class 'E<T>' does not implement inherited abstract member 'bar' from class 'A<T>'.
3433
foo() { return this.t; }
3534
}
3635

3736
class F<T> extends A<T> { // error -- doesn't implement foo
3837
~
39-
!!! error TS2515: Non-abstract class 'F<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
38+
!!! error TS18036: Non-abstract class 'F<T>' does not implement all abstract members of 'A<T>'
39+
!!! related TS2515 tests/cases/conformance/classes/classDeclarations/classAbstractKeyword/classAbstractGeneric.ts:18:7: Non-abstract class 'F<T>' does not implement inherited abstract member 'foo' from class 'A<T>'.
4040
bar(t : T) {}
4141
}
4242

0 commit comments

Comments
 (0)