Skip to content

Commit 2484390

Browse files
Added override keyword to codefix implemented abstract methods (#51033)
* Added override keyword to codefixed implemented abstract methods * Only when noImplicitOverrides is true, and always check abstract modifier * Added test on abstract/override already being there * Added back a few test cases * Check declaration modifier, not class modifier
1 parent 193a8a7 commit 2484390

14 files changed

+97
-34
lines changed

src/compiler/core.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,8 @@ export function append<T>(to: T[], value: T | undefined): T[] | undefined {
11371137
*
11381138
* @internal
11391139
*/
1140+
export function combine<T>(xs: T[] | undefined, ys: T[] | undefined): T[] | undefined;
1141+
/** @internal */
11401142
export function combine<T>(xs: T | readonly T[] | undefined, ys: T | readonly T[] | undefined): T | readonly T[] | undefined;
11411143
/** @internal */
11421144
export function combine<T>(xs: T | T[] | undefined, ys: T | T[] | undefined): T | T[] | undefined;

src/services/codefixes/helpers.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
CharacterCodes,
99
ClassLikeDeclaration,
1010
CodeFixContextBase,
11+
combine,
1112
Debug,
1213
Diagnostics,
1314
emptyArray,
@@ -31,6 +32,7 @@ import {
3132
getSynthesizedDeepClone,
3233
getTokenAtPosition,
3334
getTsConfigObjectLiteralExpression,
35+
hasAbstractModifier,
3436
Identifier,
3537
idText,
3638
IntersectionType,
@@ -197,7 +199,7 @@ export function addNewNodeForMemberSymbol(
197199
if (declaration && isAutoAccessorPropertyDeclaration(declaration)) {
198200
modifierFlags |= ModifierFlags.Accessor;
199201
}
200-
const modifiers = modifierFlags ? factory.createNodeArray(factory.createModifiersFromModifierFlags(modifierFlags)) : undefined;
202+
const modifiers = createModifiers();
201203
const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration));
202204
const optional = !!(symbol.flags & SymbolFlags.Optional);
203205
const ambient = !!(enclosingDeclaration.flags & NodeFlags.Ambient) || isAmbient;
@@ -304,6 +306,25 @@ export function addNewNodeForMemberSymbol(
304306
if (method) addClassElement(method);
305307
}
306308

309+
310+
function createModifiers(): NodeArray<Modifier> | undefined {
311+
let modifiers: Modifier[] | undefined;
312+
313+
if (modifierFlags) {
314+
modifiers = combine(modifiers, factory.createModifiersFromModifierFlags(modifierFlags));
315+
}
316+
317+
if (shouldAddOverrideKeyword()) {
318+
modifiers = append(modifiers, factory.createToken(SyntaxKind.OverrideKeyword));
319+
}
320+
321+
return modifiers && factory.createNodeArray(modifiers);
322+
}
323+
324+
function shouldAddOverrideKeyword(): boolean {
325+
return !!(context.program.getCompilerOptions().noImplicitOverride && declaration && hasAbstractModifier(declaration));
326+
}
327+
307328
function createName(node: PropertyName) {
308329
if (isIdentifier(node) && node.escapedText === "constructor") {
309330
return factory.createComputedPropertyName(factory.createStringLiteral(idText(node), quotePreference === QuotePreference.Single));

tests/cases/fourslash/codeFixAmbientClassExtendAbstractMethod.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// abstract f(a: number, b: string): boolean;
56
//// abstract f(a: number, b: string): this;
@@ -30,12 +31,12 @@ verify.codeFix({
3031
}
3132
3233
declare class C extends A {
33-
f(a: number, b: string): boolean;
34-
f(a: number, b: string): this;
35-
f(a: string, b: number): Function;
36-
f(a: string): Function;
37-
f1(this: A): number;
38-
f2(this: A, a: number, b: string): number;
39-
foo(): number;
34+
override f(a: number, b: string): boolean;
35+
override f(a: number, b: string): this;
36+
override f(a: string, b: number): Function;
37+
override f(a: string): Function;
38+
override f1(this: A): number;
39+
override f2(this: A, a: number, b: string): number;
40+
override foo(): number;
4041
}`
4142
});

tests/cases/fourslash/codeFixClassExtendAbstractGetterSetter.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// abstract get a(): number | string;
56
//// abstract get b(): this;
@@ -38,28 +39,28 @@ verify.codeFix({
3839
abstract class B extends A {}
3940
4041
class C extends A {
41-
get a(): string | number {
42+
override get a(): string | number {
4243
throw new Error("Method not implemented.");
4344
}
44-
get b(): this {
45+
override get b(): this {
4546
throw new Error("Method not implemented.");
4647
}
47-
get c(): A {
48+
override get c(): A {
4849
throw new Error("Method not implemented.");
4950
}
50-
set d(arg: string | number) {
51+
override set d(arg: string | number) {
5152
throw new Error("Method not implemented.");
5253
}
53-
set e(arg: this) {
54+
override set e(arg: this) {
5455
throw new Error("Method not implemented.");
5556
}
56-
set f(arg: A) {
57+
override set f(arg: A) {
5758
throw new Error("Method not implemented.");
5859
}
59-
get g(): string {
60+
override get g(): string {
6061
throw new Error("Method not implemented.");
6162
}
62-
set g(newName: string) {
63+
override set g(newName: string) {
6364
throw new Error("Method not implemented.");
6465
}
6566
}`

tests/cases/fourslash/codeFixClassExtendAbstractMethod.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// abstract f(a: number, b: string): boolean;
56
//// abstract f(a: number, b: string): this;
@@ -22,14 +23,14 @@ verify.codeFix({
2223
}
2324
2425
class C extends A {
25-
f(a: number, b: string): boolean;
26-
f(a: number, b: string): this;
27-
f(a: string, b: number): Function;
28-
f(a: string): Function;
29-
f(a: unknown, b?: unknown): boolean | Function | this {
26+
override f(a: number, b: string): boolean;
27+
override f(a: number, b: string): this;
28+
override f(a: string, b: number): Function;
29+
override f(a: string): Function;
30+
override f(a: unknown, b?: unknown): boolean | Function | this {
3031
throw new Error("Method not implemented.");
3132
}
32-
foo(): number {
33+
override foo(): number {
3334
throw new Error("Method not implemented.");
3435
}
3536
}`
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
// @noImplicitOverride: true
4+
//// abstract class A {
5+
//// abstract foo(n: number | string): number | string;
6+
//// }
7+
////
8+
//// abstract class B extends A {
9+
//// abstract override foo(n: number): number;
10+
//// }
11+
////
12+
//// class C extends B { }
13+
14+
verify.codeFix({
15+
description: "Implement inherited abstract class",
16+
newFileContent: `abstract class A {
17+
abstract foo(n: number | string): number | string;
18+
}
19+
20+
abstract class B extends A {
21+
abstract override foo(n: number): number;
22+
}
23+
24+
class C extends B {
25+
override foo(n: number): number {
26+
throw new Error("Method not implemented.");
27+
}
28+
}`,
29+
});

tests/cases/fourslash/codeFixClassExtendAbstractMethod_all.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// abstract m(): void;
56
//// abstract n(): void;
@@ -16,18 +17,18 @@ verify.codeFixAll({
1617
abstract n(): void;
1718
}
1819
class B extends A {
19-
m(): void {
20+
override m(): void {
2021
throw new Error("Method not implemented.");
2122
}
22-
n(): void {
23+
override n(): void {
2324
throw new Error("Method not implemented.");
2425
}
2526
}
2627
class C extends A {
27-
m(): void {
28+
override m(): void {
2829
throw new Error("Method not implemented.");
2930
}
30-
n(): void {
31+
override n(): void {
3132
throw new Error("Method not implemented.");
3233
}
3334
}`,

tests/cases/fourslash/codeFixClassExtendAbstractMethod_comment.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// abstract m() : void;
56
////}
@@ -16,7 +17,7 @@ verify.codeFix({
1617
}
1718
1819
class B extends A {
19-
m(): void {
20+
override m(): void {
2021
throw new Error("Method not implemented.");
2122
}
2223
// comment

tests/cases/fourslash/codeFixClassExtendAbstractPrivateProperty.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
//// abstract class A {
45
//// private abstract x: number;
56
//// m() { this.x; } // Avoid unused private

tests/cases/fourslash/codeFixClassExtendAbstractProperty.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// abstract x: number;
56
//// abstract y: this;
@@ -18,8 +19,8 @@ verify.codeFix({
1819
}
1920
2021
class C extends A {
21-
x: number;
22-
y: this;
23-
z: A;
22+
override x: number;
23+
override y: this;
24+
override z: A;
2425
}`
2526
});

tests/cases/fourslash/codeFixClassExtendAbstractPropertyThis.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// abstract x: this;
56
////}
@@ -14,6 +15,6 @@ verify.codeFix({
1415
}
1516
1617
class C extends A {
17-
x: this;
18+
override x: this;
1819
}`,
1920
});

tests/cases/fourslash/codeFixClassExtendAbstractProtectedProperty.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// protected abstract x: number;
56
////}
@@ -14,6 +15,6 @@ verify.codeFix({
1415
}
1516
1617
class C extends A {
17-
protected x: number;
18+
protected override x: number;
1819
}`,
1920
});

tests/cases/fourslash/codeFixClassExtendAbstractPublicProperty.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
////abstract class A {
45
//// public abstract x: number;
56
////}
@@ -14,6 +15,6 @@ verify.codeFix({
1415
}
1516
1617
class C extends A {
17-
public x: number;
18+
public override x: number;
1819
}`,
1920
});

tests/cases/fourslash/codeFixClassExtendAbstractSomePropertiesPresent.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/// <reference path='fourslash.ts' />
22

3+
// @noImplicitOverride: true
34
//// abstract class A {
45
//// abstract x: number;
56
//// abstract y: number;
@@ -12,5 +13,5 @@
1213
//// }
1314

1415
verify.rangeAfterCodeFix(`
15-
z: number;
16+
override z: number;
1617
`);

0 commit comments

Comments
 (0)