Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

--noImplicitOverride #39669

Merged
merged 76 commits into from
Mar 26, 2021
Merged
Show file tree
Hide file tree
Changes from 46 commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
8b90b8d
wip: add types
Kingwl Jul 15, 2020
ea5608a
wip
Kingwl Jul 17, 2020
9371d87
Add cases
Kingwl Jul 17, 2020
6cb7f5e
Add some case
Kingwl Jul 17, 2020
061cd27
Add more check
Kingwl Jul 20, 2020
37ada55
accept baseline
Kingwl Jul 20, 2020
6401e1a
add abstract abd declare method
Kingwl Jul 20, 2020
be00363
add override in declaration
Kingwl Jul 20, 2020
fbb6e28
accept baseline
Kingwl Jul 20, 2020
6014a3a
add property override
Kingwl Jul 21, 2020
a65df91
Fix decalre modifier
Kingwl Jul 21, 2020
43d9f70
update baseline
Kingwl Jul 21, 2020
e73c941
Add more cases
Kingwl Jul 21, 2020
c0edf6f
make lint happy
Kingwl Jul 21, 2020
dca93ac
make lint happy
Kingwl Jul 21, 2020
2fd560a
Update description
Kingwl Jul 21, 2020
94187c7
Add codefix
Kingwl Aug 19, 2020
2b57fbd
simplify code
Kingwl Aug 19, 2020
3a2286b
Merge branch 'master' into exprement-override
Kingwl Aug 19, 2020
d34afb9
accept baseline
Kingwl Aug 19, 2020
b4614d1
Update desc
Kingwl Aug 21, 2020
1ef034d
Accept baseline
Kingwl Aug 21, 2020
aebfb28
Add override completions
Kingwl Aug 24, 2020
7753983
filter out implements field in override context
Kingwl Aug 24, 2020
5c04ccc
fix tests
Kingwl Aug 24, 2020
add16c9
Add parameter property check
Kingwl Aug 24, 2020
5316e2f
Accept baseline
Kingwl Aug 24, 2020
f36fede
acept baseline
Kingwl Aug 24, 2020
811bd1e
Add parameter property to declaration code action
Kingwl Aug 25, 2020
d0f5095
Add quickfix for override parameter property
Kingwl Aug 25, 2020
dd51815
Merge branch 'master' into exprement-override
Kingwl Sep 1, 2020
22bb09d
fix code style
Kingwl Sep 3, 2020
eee3b77
Add override with interface tests
Kingwl Sep 3, 2020
f94e93c
Add more cases about modifier position
Kingwl Sep 3, 2020
74f14c3
Merge branch 'master' into exprement-override
Kingwl Sep 14, 2020
e35ee17
rename flag
Kingwl Sep 14, 2020
d8fda5f
rename flags
Kingwl Sep 14, 2020
18434fd
Added tests.
DanielRosenwasser Sep 14, 2020
5ab5a7f
Accepted baselines.
DanielRosenwasser Sep 15, 2020
f52822a
Always issue errors for unnecessary 'override' modifiers.
DanielRosenwasser Sep 15, 2020
48c23a5
Accepted baselines.
DanielRosenwasser Sep 15, 2020
a3f0443
Merge branch 'master' into exprement-override
Kingwl Sep 15, 2020
cdd0739
Override perf (#4)
Kingwl Sep 15, 2020
8e53ad3
Merge branch 'master' into exprement-override
Kingwl Sep 16, 2020
827bc95
Do not issue error if implement abstract
Kingwl Sep 16, 2020
618f883
Add abstract-spec check
Kingwl Sep 16, 2020
bc4d758
Avoid override dead lock
Kingwl Sep 16, 2020
47296d6
Add more case
Kingwl Sep 16, 2020
5d19a90
Add codefix for new error
Kingwl Sep 16, 2020
68e1440
Fix error message
Kingwl Sep 16, 2020
82109e9
Merge branch 'master' into exprement-override
Kingwl Oct 30, 2020
2552495
Add jsdoc override tag (#6)
Kingwl Nov 2, 2020
cf5dc7e
Override jsdoc tag (#7)
Kingwl Nov 2, 2020
b65d244
Disallow codefix in js
Kingwl Nov 2, 2020
84cc69d
Merge branch 'master' into exprement-override
Kingwl Nov 5, 2020
6d89a7a
update baseline
Kingwl Nov 5, 2020
062f149
update baseline
Kingwl Nov 5, 2020
feb9093
Omit override in d.ts
Kingwl Nov 5, 2020
0c09a2e
Add more case in js
Kingwl Nov 5, 2020
3cf3c28
Accept baseline
Kingwl Nov 5, 2020
d874ae8
fix override js test
Kingwl Nov 6, 2020
e361ddc
Merge branch 'master' into exprement-override
Kingwl Dec 31, 2020
40da344
Merge branch 'master' into exprement-override
Kingwl Jan 7, 2021
f9384bc
fix crlf
Kingwl Jan 7, 2021
eea8259
Revert merge conflict changes
Kingwl Jan 7, 2021
ff3cbc1
Accept baseline
Kingwl Jan 7, 2021
a3766d2
Avoid space
Kingwl Jan 7, 2021
e2c245e
Merge branch 'master' into exprement-override
Kingwl Feb 4, 2021
8f3dcb9
Merge branch 'master' into exprement-override
Kingwl Mar 5, 2021
1db64fb
Fix CR issues
Kingwl Mar 5, 2021
71c00d5
Merge branch 'master' into exprement-override
Kingwl Mar 8, 2021
e3c0993
Accept baseline
Kingwl Mar 8, 2021
89517a0
Fix typo and add more check
Kingwl Mar 9, 2021
6c8d00d
Fix error name
Kingwl Mar 9, 2021
bbfb7eb
Merge branch 'master' into exprement-override
Kingwl Mar 10, 2021
4575b5a
Merge branch 'master' into exprement-override
Kingwl Mar 26, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
80 changes: 78 additions & 2 deletions src/compiler/checker.ts
Expand Up @@ -34882,7 +34882,8 @@ namespace ts {
checkClassForDuplicateDeclarations(node);

// Only check for reserved static identifiers on non-ambient context.
if (!(node.flags & NodeFlags.Ambient)) {
const nodeInAmbientContext = !!(node.flags & NodeFlags.Ambient);
if (!nodeInAmbientContext) {
checkClassForStaticPropertyNameConflicts(node);
}

Expand Down Expand Up @@ -34938,6 +34939,8 @@ namespace ts {
}
}

checkMembersForMissingOverrideModifier(node, type, typeWithThis);

const implementedTypeNodes = getEffectiveImplementsTypeNodes(node);
if (implementedTypeNodes) {
for (const typeRefNode of implementedTypeNodes) {
Expand Down Expand Up @@ -34972,6 +34975,53 @@ namespace ts {
}
}

function checkMembersForMissingOverrideModifier(node: ClassLikeDeclaration, type: InterfaceType, typeWithThis: Type) {
const nodeInAmbientContext = !!(node.flags & NodeFlags.Ambient);
const baseTypeNode = getEffectiveBaseTypeNode(node);
const baseTypes = baseTypeNode && getBaseTypes(type);
const baseWithThis = baseTypes?.length ? getTypeWithThisArgument(first(baseTypes), type.thisType) : undefined;

for (const member of node.members) {
if (isConstructorDeclaration(member)) {
forEach(member.parameters, param => {
if (isParameterPropertyDeclaration(param, member)) {
checkClassMember(param, /*memberIsParameterProperty*/ true);
}
});
}
checkClassMember(member);
}
function checkClassMember(member: ClassElement | ParameterPropertyDeclaration, memberIsParameterProperty?: boolean) {
const hasOverride = hasOverrideModifier(member);
if (baseWithThis && (hasOverride || compilerOptions.noImplicitOverride)) {
const declaredProp = member.name && getSymbolAtLocation(member.name) || getSymbolAtLocation(member);
if (declaredProp) {
const baseClassName = typeToString(baseWithThis);
const prop = getPropertyOfType(typeWithThis, declaredProp.escapedName);
const baseProp = getPropertyOfType(baseWithThis, declaredProp.escapedName);
if (prop && !baseProp && hasOverride) {
error(member, Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_not_declared_in_the_base_class_0, baseClassName);
}
else if (prop && baseProp && compilerOptions.noImplicitOverride && !nodeInAmbientContext) {
if (!hasOverride) {
const diag = memberIsParameterProperty ?
Diagnostics.This_parameter_must_convert_into_property_declaration_because_it_overrides_a_member_in_the_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);
}
else if (!hasAbstractModifier(member) && hasAbstractModifier(baseProp.valueDeclaration)) {
error(member, Diagnostics.This_member_cannot_have_an_override_modifier_because_it_is_implemented_an_abstract_method_that_declared_in_the_base_class_0, baseClassName);
}
}
}
}
else if (hasOverride) {
const className = typeToString(type);
error(member, Diagnostics.This_member_cannot_have_an_override_modifier_because_its_containing_class_0_does_not_extend_another_class, className);
}
}
}

function issueMemberSpecificError(node: ClassLikeDeclaration, typeWithThis: Type, baseWithThis: Type, broadDiag: DiagnosticMessage) {
// iterate over all implemented properties and issue errors on each one which isn't compatible, rather than the class as a whole, if possible
let issuedMemberError = false;
Expand Down Expand Up @@ -38304,7 +38354,7 @@ namespace ts {
return quickResult;
}

let lastStatic: Node | undefined, lastDeclare: Node | undefined, lastAsync: Node | undefined, lastReadonly: Node | undefined;
let lastStatic: Node | undefined, lastDeclare: Node | undefined, lastAsync: Node | undefined, lastReadonly: Node | undefined, lastOverride: Node | undefined;
let flags = ModifierFlags.None;
for (const modifier of node.modifiers!) {
if (modifier.kind !== SyntaxKind.ReadonlyKeyword) {
Expand All @@ -38321,6 +38371,20 @@ namespace ts {
return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword));
}
break;
case SyntaxKind.OverrideKeyword:
if (flags & ModifierFlags.Override) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override");
}
else if (flags & ModifierFlags.Ambient) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "override", "declare");
}
else if (flags & ModifierFlags.Static) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override");
}
flags |= ModifierFlags.Override;
lastOverride = modifier;
break;

case SyntaxKind.PublicKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.PrivateKeyword:
Expand All @@ -38329,6 +38393,9 @@ namespace ts {
if (flags & ModifierFlags.AccessibilityModifier) {
return grammarErrorOnNode(modifier, Diagnostics.Accessibility_modifier_already_seen);
}
else if (compilerOptions.noImplicitOverride && flags & ModifierFlags.Override) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "override");
}
else if (flags & ModifierFlags.Static) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, text, "static");
}
Expand Down Expand Up @@ -38362,6 +38429,9 @@ namespace ts {
else if (flags & ModifierFlags.Readonly) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "readonly");
}
else if (compilerOptions.noImplicitOverride && flags & ModifierFlags.Override) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override");
}
else if (flags & ModifierFlags.Async) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "static", "async");
}
Expand Down Expand Up @@ -38429,6 +38499,9 @@ namespace ts {
else if (flags & ModifierFlags.Async) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async");
}
else if (compilerOptions.noImplicitOverride && flags & ModifierFlags.Override) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "override");
}
else if (isClassLike(node.parent) && !isPropertyDeclaration(node)) {
return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_class_element, "declare");
}
Expand Down Expand Up @@ -38502,6 +38575,9 @@ namespace ts {
if (flags & ModifierFlags.Abstract) {
return grammarErrorOnNode(lastStatic!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "abstract"); // TODO: GH#18217
}
if (compilerOptions.noImplicitOverride && flags & ModifierFlags.Override) {
return grammarErrorOnNode(lastOverride!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "override"); // TODO: GH#18217
}
else if (flags & ModifierFlags.Async) {
return grammarErrorOnNode(lastAsync!, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async");
}
Expand Down
8 changes: 8 additions & 0 deletions src/compiler/commandLineParser.ts
Expand Up @@ -632,6 +632,14 @@ namespace ts {
category: Diagnostics.Additional_Checks,
description: Diagnostics.Include_undefined_in_index_signature_results
},
{
name: "noImplicitOverride",
type: "boolean",
affectsSemanticDiagnostics: true,
showInSimplifiedHelpView: false,
category: Diagnostics.Additional_Checks,
description: Diagnostics.Force_overriding_members_in_derived_classes_to_be_marked_with_an_override_modifier
},

// Module Resolution
{
Expand Down
48 changes: 48 additions & 0 deletions src/compiler/diagnosticMessages.json
Expand Up @@ -3412,6 +3412,26 @@
"category": "Error",
"code": 4110
},
"This member cannot have an 'override' modifier because its containing class '{0}' does not extend another class.": {
"category": "Error",
"code": 4111
},
"This member cannot have an 'override' modifier because it is not declared in the base class '{0}'.": {
"category": "Error",
"code": 4112
},
"This member must have an 'override' modifier because it overrides a member in the base class '{0}'.": {
"category": "Error",
"code": 4113
},
"This parameter must convert into property declaration because it overrides a member in the base class '{0}'.": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"This parameter must convert into property declaration because it overrides a member in the base class '{0}'.": {
This parameter property must be rewritten as a property declaration with an 'override' modifier because it overrides a member in base class '{0}'.

"category": "Error",
"code": 4114
},
"This member cannot have an 'override' modifier because it is implemented an abstract method that declared in the base class '{0}'.": {
Kingwl marked this conversation as resolved.
Show resolved Hide resolved
"category": "Error",
"code": 4115
},

"The current host does not support the '{0}' option.": {
"category": "Error",
Expand Down Expand Up @@ -4724,6 +4744,10 @@
"category": "Error",
"code": 6504
},
"Force overriding members in derived classes to be marked with an 'override' modifier.": {
"category": "Error",
"code": 6801
},

"Include 'undefined' in index signature results": {
"category": "Message",
Expand Down Expand Up @@ -5939,6 +5963,30 @@
"category": "Message",
"code": 95144
},
"Add 'override' modifier": {
"category": "Message",
"code": 95145
},
"Remove 'override' modifier": {
"category": "Message",
"code": 95146
},
"Add all 'override' modifier": {
Kingwl marked this conversation as resolved.
Show resolved Hide resolved
"category": "Message",
"code": 95147
},
"Remove all 'override' modifier": {
Kingwl marked this conversation as resolved.
Show resolved Hide resolved
"category": "Message",
"code": 95148
},
"Convert to property declaration and add 'override' modifier": {
"category": "Message",
"code": 95149
},
"Convert all to property declaration and add 'override' modifier": {
Kingwl marked this conversation as resolved.
Show resolved Hide resolved
"category": "Message",
"code": 95150
},

"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
"category": "Error",
Expand Down
1 change: 1 addition & 0 deletions src/compiler/factory/nodeFactory.ts
Expand Up @@ -1035,6 +1035,7 @@ namespace ts {
if (flags & ModifierFlags.Static) { result.push(createModifier(SyntaxKind.StaticKeyword)); }
if (flags & ModifierFlags.Readonly) { result.push(createModifier(SyntaxKind.ReadonlyKeyword)); }
if (flags & ModifierFlags.Async) { result.push(createModifier(SyntaxKind.AsyncKeyword)); }
if (flags & ModifierFlags.Override) { result.push(createModifier(SyntaxKind.OverrideKeyword)); }
return result;
}

Expand Down
1 change: 1 addition & 0 deletions src/compiler/scanner.ts
Expand Up @@ -125,6 +125,7 @@ namespace ts {
private: SyntaxKind.PrivateKeyword,
protected: SyntaxKind.ProtectedKeyword,
public: SyntaxKind.PublicKeyword,
override: SyntaxKind.OverrideKeyword,
readonly: SyntaxKind.ReadonlyKeyword,
require: SyntaxKind.RequireKeyword,
global: SyntaxKind.GlobalKeyword,
Expand Down
11 changes: 9 additions & 2 deletions src/compiler/types.ts
Expand Up @@ -186,6 +186,7 @@ namespace ts {
FromKeyword,
GlobalKeyword,
BigIntKeyword,
OverrideKeyword,
UppercaseKeyword,
LowercaseKeyword,
CapitalizeKeyword,
Expand Down Expand Up @@ -591,6 +592,7 @@ namespace ts {
| SyntaxKind.ProtectedKeyword
| SyntaxKind.PublicKeyword
| SyntaxKind.ReadonlyKeyword
| SyntaxKind.OverrideKeyword
| SyntaxKind.RequireKeyword
| SyntaxKind.ReturnKeyword
| SyntaxKind.SetKeyword
Expand Down Expand Up @@ -628,6 +630,7 @@ namespace ts {
| SyntaxKind.ProtectedKeyword
| SyntaxKind.PublicKeyword
| SyntaxKind.ReadonlyKeyword
| SyntaxKind.OverrideKeyword
| SyntaxKind.StaticKeyword
;

Expand Down Expand Up @@ -803,16 +806,17 @@ namespace ts {
HasComputedJSDocModifiers = 1 << 12, // Indicates the computed modifier flags include modifiers from JSDoc.

Deprecated = 1 << 13, // Deprecated tag.
Override = 1 << 14, // Override method.
HasComputedFlags = 1 << 29, // Modifier flags have been computed

AccessibilityModifier = Public | Private | Protected,
// Accessibility modifiers and 'readonly' can be attached to a parameter in a constructor to make it a property.
ParameterPropertyModifier = AccessibilityModifier | Readonly,
NonPublicAccessibilityModifier = Private | Protected,

TypeScriptModifier = Ambient | Public | Private | Protected | Readonly | Abstract | Const,
TypeScriptModifier = Ambient | Public | Private | Protected | Readonly | Abstract | Const | Override,
ExportDefault = Export | Default,
All = Export | Ambient | Public | Private | Protected | Static | Readonly | Abstract | Async | Default | Const | Deprecated
All = Export | Ambient | Public | Private | Protected | Static | Readonly | Abstract | Async | Default | Const | Deprecated | Override
}

export const enum JsxFlags {
Expand Down Expand Up @@ -1032,6 +1036,7 @@ namespace ts {
export type ProtectedKeyword = ModifierToken<SyntaxKind.ProtectedKeyword>;
export type PublicKeyword = ModifierToken<SyntaxKind.PublicKeyword>;
export type ReadonlyKeyword = ModifierToken<SyntaxKind.ReadonlyKeyword>;
export type OverrideKeyword = ModifierToken<SyntaxKind.OverrideKeyword>;
export type StaticKeyword = ModifierToken<SyntaxKind.StaticKeyword>;

/** @deprecated Use `ReadonlyKeyword` instead. */
Expand All @@ -1047,6 +1052,7 @@ namespace ts {
| PrivateKeyword
| ProtectedKeyword
| PublicKeyword
| OverrideKeyword
| ReadonlyKeyword
| StaticKeyword
;
Expand Down Expand Up @@ -5792,6 +5798,7 @@ namespace ts {
/*@internal*/ pathsBasePath?: string;
/*@internal*/ plugins?: PluginImport[];
preserveConstEnums?: boolean;
noImplicitOverride?: boolean;
preserveSymlinks?: boolean;
/* @internal */ preserveWatchOutput?: boolean;
project?: string;
Expand Down
17 changes: 17 additions & 0 deletions src/compiler/utilities.ts
Expand Up @@ -4573,6 +4573,18 @@ namespace ts {
return hasSyntacticModifier(node, ModifierFlags.Static);
}

export function hasOverrideModifier(node: Node): boolean {
return hasSyntacticModifier(node, ModifierFlags.Override);
}

export function hasAbstractModifier(node: Node): boolean {
return hasSyntacticModifier(node, ModifierFlags.Abstract);
}

export function hasAmbientModifier(node: Node): boolean {
return hasSyntacticModifier(node, ModifierFlags.Ambient);
}
Comment on lines +4662 to +4668
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm finding the need for these somewhat surprising. How were we checking for ambient-ness and abtract-ness before? Are there cheaper ways?

Copy link
Contributor Author

@Kingwl Kingwl Sep 16, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. Does it expensive? Even I found cache inside hasSyntacticModifier

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't see where this was used, so I don’t know for sure that this is what you’re looking for, but you can use node.flags & NodeFlags.Ambient to determine if any node is in an ambient context. It gets propagated down to all child nodes, so e.g. everything inside a declare module block will have that. Not sure if there’s an equivalent flag for abstract off the top of my head.


export function hasEffectiveReadonlyModifier(node: Node): boolean {
return hasEffectiveModifier(node, ModifierFlags.Readonly);
}
Expand Down Expand Up @@ -4683,10 +4695,15 @@ namespace ts {
case SyntaxKind.DefaultKeyword: return ModifierFlags.Default;
case SyntaxKind.AsyncKeyword: return ModifierFlags.Async;
case SyntaxKind.ReadonlyKeyword: return ModifierFlags.Readonly;
case SyntaxKind.OverrideKeyword: return ModifierFlags.Override;
}
return ModifierFlags.None;
}

export function createModifiers(modifierFlags: ModifierFlags): ModifiersArray | undefined {
return modifierFlags ? factory.createNodeArray(factory.createModifiersFromModifierFlags(modifierFlags)) : undefined;
}

export function isLogicalOperator(token: SyntaxKind): boolean {
return token === SyntaxKind.BarBarToken
|| token === SyntaxKind.AmpersandAmpersandToken
Expand Down
3 changes: 2 additions & 1 deletion src/compiler/utilitiesPublic.ts
Expand Up @@ -1129,6 +1129,7 @@ namespace ts {
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.StaticKeyword:
case SyntaxKind.OverrideKeyword:
return true;
}
return false;
Expand All @@ -1141,7 +1142,7 @@ namespace ts {

/* @internal */
export function isClassMemberModifier(idToken: SyntaxKind): boolean {
return isParameterPropertyModifier(idToken) || idToken === SyntaxKind.StaticKeyword;
return isParameterPropertyModifier(idToken) || idToken === SyntaxKind.StaticKeyword || idToken === SyntaxKind.OverrideKeyword;
}

export function isModifier(node: Node): node is Modifier {
Expand Down
3 changes: 2 additions & 1 deletion src/harness/fourslashInterfaceImpl.ts
Expand Up @@ -1138,6 +1138,7 @@ namespace FourSlashInterface {
case "symbol":
case "type":
case "unique":
case "override":
case "unknown":
case "global":
case "bigint":
Expand All @@ -1149,7 +1150,7 @@ namespace FourSlashInterface {
}

export const classElementKeywords: readonly ExpectedCompletionEntryObject[] =
["private", "protected", "public", "static", "abstract", "async", "constructor", "declare", "get", "readonly", "set"].map(keywordEntry);
["private", "protected", "public", "static", "abstract", "async", "constructor", "declare", "get", "readonly", "set", "override"].map(keywordEntry);

export const classElementInJsKeywords = getInJsKeywords(classElementKeywords);

Expand Down