Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37214,7 +37214,7 @@ namespace ts {

if (!baseHasAbstract) {
const diag = memberIsParameterProperty ?
Diagnostics.This_parameter_property_must_be_rewritten_as_a_property_declaration_with_an_override_modifier_because_it_overrides_a_member_in_base_class_0 :
Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0 :
Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0;
error(member, diag, baseClassName);
}
Expand Down
2 changes: 1 addition & 1 deletion src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3717,7 +3717,7 @@
"category": "Error",
"code": 4114
},
"This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class '{0}'.": {
"This parameter property must have an 'override' modifier because it overrides a member in base class '{0}'.": {
"category": "Error",
"code": 4115
},
Expand Down
26 changes: 17 additions & 9 deletions src/services/codefixes/fixOverrideModifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@ namespace ts.codefix {
const fixAddOverrideId = "fixAddOverrideModifier";
const fixRemoveOverrideId = "fixRemoveOverrideModifier";

type ClassElementHasJSDoc =
type ClassElementLikeHasJSDoc =
| ConstructorDeclaration
| PropertyDeclaration
| MethodDeclaration
| GetAccessorDeclaration
| SetAccessorDeclaration;
| SetAccessorDeclaration
| ParameterPropertyDeclaration;

const errorCodes = [
Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0.code,
Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code,
Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code,
Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code
Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code,
Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code
];

const errorCodeFixIdMap: Record<number, [DiagnosticMessage, string | undefined, DiagnosticMessage | undefined]> = {
Expand All @@ -25,6 +27,9 @@ namespace ts.codefix {
[Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code]: [
Diagnostics.Remove_override_modifier, fixRemoveOverrideId, Diagnostics.Remove_all_unnecessary_override_modifiers
],
[Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code]: [
Diagnostics.Add_override_modifier, fixAddOverrideId, Diagnostics.Add_all_missing_override_modifiers,
],
[Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code]: [
Diagnostics.Add_override_modifier, fixAddOverrideId, Diagnostics.Remove_all_unnecessary_override_modifiers
],
Expand Down Expand Up @@ -70,6 +75,7 @@ namespace ts.codefix {
switch (errorCode) {
case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_a_member_in_the_base_class_0.code:
case Diagnostics.This_member_must_have_an_override_modifier_because_it_overrides_an_abstract_method_that_is_declared_in_the_base_class_0.code:
case Diagnostics.This_parameter_property_must_have_an_override_modifier_because_it_overrides_a_member_in_base_class_0.code:
return doAddOverrideModifierChange(changeTracker, context.sourceFile, pos);
case Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0.code:
case Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class.code:
Expand All @@ -80,7 +86,7 @@ namespace ts.codefix {
}

function doAddOverrideModifierChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) {
const classElement = findContainerClassElement(sourceFile, pos);
const classElement = findContainerClassElementLike(sourceFile, pos);
const modifiers = classElement.modifiers || emptyArray;
const staticModifier = find(modifiers, isStaticModifier);
const accessibilityModifier = find(modifiers, m => isAccessibilityModifier(m.kind));
Expand All @@ -92,34 +98,36 @@ namespace ts.codefix {
}

function doRemoveOverrideModifierChange(changeTracker: textChanges.ChangeTracker, sourceFile: SourceFile, pos: number) {
const classElement = findContainerClassElement(sourceFile, pos);
const classElement = findContainerClassElementLike(sourceFile, pos);
const overrideModifier = classElement.modifiers && find(classElement.modifiers, modifier => modifier.kind === SyntaxKind.OverrideKeyword);
Debug.assertIsDefined(overrideModifier);

changeTracker.deleteModifier(sourceFile, overrideModifier);
}

function isClassElementHasJSDoc(node: Node): node is ClassElementHasJSDoc {
function isClassElementLikeHasJSDoc(node: Node): node is ClassElementLikeHasJSDoc {
switch (node.kind) {
case SyntaxKind.Constructor:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return true;
case SyntaxKind.Parameter:
return isParameterPropertyDeclaration(node, node.parent);
default:
return false;
}
}

function findContainerClassElement(sourceFile: SourceFile, pos: number) {
function findContainerClassElementLike(sourceFile: SourceFile, pos: number) {
const token = getTokenAtPosition(sourceFile, pos);
const classElement = findAncestor(token, node => {
if (isClassLike(node)) return "quit";
return isClassElementHasJSDoc(node);
return isClassElementLikeHasJSDoc(node);
});

Debug.assert(classElement && isClassElementHasJSDoc(classElement));
Debug.assert(classElement && isClassElementLikeHasJSDoc(classElement));
return classElement;
}
}
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/override6.errors.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
tests/cases/conformance/override/override6.ts(9,12): error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'B'.
tests/cases/conformance/override/override6.ts(10,17): error TS4115: This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class 'B'.
tests/cases/conformance/override/override6.ts(10,37): error TS4115: This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class 'B'.
tests/cases/conformance/override/override6.ts(10,17): error TS4115: This parameter property must have an 'override' modifier because it overrides a member in base class 'B'.
tests/cases/conformance/override/override6.ts(10,37): error TS4115: This parameter property must have an 'override' modifier because it overrides a member in base class 'B'.


==== tests/cases/conformance/override/override6.ts (3 errors) ====
Expand All @@ -17,9 +17,9 @@ tests/cases/conformance/override/override6.ts(10,37): error TS4115: This paramet
!!! error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'B'.
constructor(public foo: string, public baz: number) {
~~~~~~~~~~~~~~~~~~
!!! error TS4115: This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class 'B'.
!!! error TS4115: This parameter property must have an 'override' modifier because it overrides a member in base class 'B'.
~~~~~~~~~~~~~~~~~~
!!! error TS4115: This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class 'B'.
!!! error TS4115: This parameter property must have an 'override' modifier because it overrides a member in base class 'B'.
super(foo, 42)
}
}
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/override8.errors.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tests/cases/conformance/override/override8.ts(6,17): error TS4115: This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class 'B'.
tests/cases/conformance/override/override8.ts(18,17): error TS4115: This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class 'BB'.
tests/cases/conformance/override/override8.ts(6,17): error TS4115: This parameter property must have an 'override' modifier because it overrides a member in base class 'B'.
tests/cases/conformance/override/override8.ts(18,17): error TS4115: This parameter property must have an 'override' modifier because it overrides a member in base class 'BB'.
tests/cases/conformance/override/override8.ts(24,12): error TS4114: This member must have an 'override' modifier because it overrides a member in the base class 'BB'.


Expand All @@ -11,7 +11,7 @@ tests/cases/conformance/override/override8.ts(24,12): error TS4114: This member
class D extends B {
constructor(public a: string, public b: string) {
~~~~~~~~~~~~~~~~
!!! error TS4115: This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class 'B'.
!!! error TS4115: This parameter property must have an 'override' modifier because it overrides a member in base class 'B'.
super();
}
}
Expand All @@ -25,7 +25,7 @@ tests/cases/conformance/override/override8.ts(24,12): error TS4114: This member
class DD extends BB {
constructor(public a: string) {
~~~~~~~~~~~~~~~~
!!! error TS4115: This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class 'BB'.
!!! error TS4115: This parameter property must have an 'override' modifier because it overrides a member in base class 'BB'.
super(a)
}
}
Expand Down
12 changes: 10 additions & 2 deletions tests/baselines/reference/overrideParameterProperty.errors.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
tests/cases/conformance/override/overrideParameterProperty.ts(20,24): error TS1029: 'public' modifier must precede 'override' modifier.
tests/cases/conformance/override/overrideParameterProperty.ts(25,5): error TS2369: A parameter property is only allowed in a constructor implementation.
tests/cases/conformance/override/overrideParameterProperty.ts(29,15): error TS4113: This member cannot have an 'override' modifier because it is not declared in the base class 'Base'.


==== tests/cases/conformance/override/overrideParameterProperty.ts (2 errors) ====
==== tests/cases/conformance/override/overrideParameterProperty.ts (3 errors) ====
class Base {
p1!: string;
}
Expand Down Expand Up @@ -33,4 +34,11 @@ tests/cases/conformance/override/overrideParameterProperty.ts(25,5): error TS236
~~~~~~~~~~~~~~~~~~~~
!!! error TS2369: A parameter property is only allowed in a constructor implementation.
}


class C4 extends Base {
constructor(public override p2: string) {
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS4113: This member cannot have an 'override' modifier because it is not declared in the base class 'Base'.
super();
}
}
16 changes: 15 additions & 1 deletion tests/baselines/reference/overrideParameterProperty.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ class C3 extends Base {

m(override p1: "hello") {}
}


class C4 extends Base {
constructor(public override p2: string) {
super();
}
}

//// [overrideParameterProperty.js]
var __extends = (this && this.__extends) || (function () {
Expand Down Expand Up @@ -79,3 +84,12 @@ var C3 = /** @class */ (function (_super) {
C3.prototype.m = function (p1) { };
return C3;
}(Base));
var C4 = /** @class */ (function (_super) {
__extends(C4, _super);
function C4(p2) {
var _this = _super.call(this) || this;
_this.p2 = p2;
return _this;
}
return C4;
}(Base));
11 changes: 11 additions & 0 deletions tests/baselines/reference/overrideParameterProperty.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,14 @@ class C3 extends Base {
>p1 : Symbol(p1, Decl(overrideParameterProperty.ts, 24, 4))
}

class C4 extends Base {
>C4 : Symbol(C4, Decl(overrideParameterProperty.ts, 25, 1))
>Base : Symbol(Base, Decl(overrideParameterProperty.ts, 0, 0))

constructor(public override p2: string) {
>p2 : Symbol(C4.p2, Decl(overrideParameterProperty.ts, 28, 14))

super();
>super : Symbol(Base, Decl(overrideParameterProperty.ts, 0, 0))
}
}
12 changes: 12 additions & 0 deletions tests/baselines/reference/overrideParameterProperty.types
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,15 @@ class C3 extends Base {
>p1 : "hello"
}

class C4 extends Base {
>C4 : C4
>Base : Base

constructor(public override p2: string) {
>p2 : string

super();
>super() : void
>super : typeof Base
}
}
6 changes: 6 additions & 0 deletions tests/cases/conformance/override/overrideParameterProperty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,9 @@ class C3 extends Base {

m(override p1: "hello") {}
}

class C4 extends Base {
constructor(public override p2: string) {
super();
}
}
8 changes: 6 additions & 2 deletions tests/cases/fourslash/codeFixOverrideModifier10.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@
//// }
//// class D extends B {
//// c = 10;
//// constructor(public a: string, public readonly b: string) {
//// constructor(public a: string, [|public readonly b: string|]) {
//// super();
//// }
//// }

verify.not.codeFixAvailable();
verify.codeFix({
description: "Add 'override' modifier",
newRangeContent: "public override readonly b: string",
index: 0
})
17 changes: 17 additions & 0 deletions tests/cases/fourslash/codeFixOverrideModifier21.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/// <reference path='fourslash.ts' />

// @noImplicitOverride: true

//// class B { }
//// class D extends B {
//// c = 10;
//// constructor([|public override a: string|]) {
//// super();
//// }
//// }

verify.codeFix({
description: "Remove 'override' modifier",
newRangeContent: "public a: string",
index: 0
})
9 changes: 6 additions & 3 deletions tests/cases/fourslash/codeFixOverrideModifier9.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,13 @@
//// a: string
//// }
//// class D extends B {
//// constructor(public a: string, public b: string) {
//// constructor([|public a: string|], public b: string) {
//// super();
//// }
//// }

verify.not.codeFixAvailable();

verify.codeFix({
description: "Add 'override' modifier",
newRangeContent: "public override a: string",
index: 0
})