Skip to content

Commit

Permalink
Update diagnostic message and quickfix for parameter property (#44010)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kingwl committed May 9, 2021
1 parent 3125398 commit 5b1e873
Show file tree
Hide file tree
Showing 13 changed files with 110 additions and 27 deletions.
2 changes: 1 addition & 1 deletion src/compiler/checker.ts
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
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
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
@@ -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
@@ -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
@@ -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
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
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
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
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
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
@@ -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
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
})

0 comments on commit 5b1e873

Please sign in to comment.