@@ -15756,6 +15756,10 @@ namespace ts {
15756
15756
checkGrammarDecorators(node) || checkGrammarModifiers(node) || checkGrammarProperty(node) || checkGrammarComputedPropertyName(node.name);
15757
15757
15758
15758
checkVariableLikeDeclaration(node);
15759
+
15760
+ if (getModifierFlags(node) & ModifierFlags.Override) {
15761
+ checkOverrideDeclaration(node);
15762
+ }
15759
15763
}
15760
15764
15761
15765
function checkMethodDeclaration(node: MethodDeclaration) {
@@ -15771,20 +15775,15 @@ namespace ts {
15771
15775
error(node, Diagnostics.Method_0_cannot_have_an_implementation_because_it_is_marked_abstract, declarationNameToString(node.name));
15772
15776
}
15773
15777
15774
- // Is this the correct time to make assertions against the inheritance chain?
15775
- // Have all other methods been resolved? Probably need to record that an override exists
15776
- // and perform the actual resolution later.
15777
15778
if (getModifierFlags(node) & ModifierFlags.Override) {
15778
- checkOverrideMethodDeclaration (node);
15779
+ checkOverrideDeclaration (node);
15779
15780
}
15780
15781
}
15781
15782
15782
- function checkOverrideMethodDeclaration(node: MethodDeclaration) {
15783
- forEachEnclosingClass(node, enclosingClass => {
15784
- // TODO: save the methodDeclaration node here in a cache and
15785
- // perform the actual assertion later.
15786
- console.log(`override method ${node.symbol.name} is enclosed by class ${enclosingClass.symbol.name}`);
15787
- });
15783
+ function checkOverrideDeclaration(node: MethodDeclaration | PropertyDeclaration | AccessorDeclaration) {
15784
+ if (node.questionToken) {
15785
+ error(node, Diagnostics.override_modifier_cannot_be_used_with_an_optional_property_declaration);
15786
+ }
15788
15787
}
15789
15788
15790
15789
function checkConstructorDeclaration(node: ConstructorDeclaration) {
@@ -15899,6 +15898,11 @@ namespace ts {
15899
15898
checkGrammarFunctionLikeDeclaration(node) || checkGrammarAccessor(node) || checkGrammarComputedPropertyName(node.name);
15900
15899
15901
15900
checkDecorators(node);
15901
+
15902
+ if (getModifierFlags(node) & ModifierFlags.Override) {
15903
+ checkOverrideDeclaration(node);
15904
+ }
15905
+
15902
15906
checkSignatureDeclaration(node);
15903
15907
if (node.kind === SyntaxKind.GetAccessor) {
15904
15908
if (!isInAmbientContext(node) && nodeIsPresent(node.body) && (node.flags & NodeFlags.HasImplicitReturn)) {
@@ -15925,6 +15929,9 @@ namespace ts {
15925
15929
if (hasModifier(node, ModifierFlags.Abstract) !== hasModifier(otherAccessor, ModifierFlags.Abstract)) {
15926
15930
error(node.name, Diagnostics.Accessors_must_both_be_abstract_or_non_abstract);
15927
15931
}
15932
+ if (hasModifier(node, ModifierFlags.Override) !== hasModifier(otherAccessor, ModifierFlags.Override)) {
15933
+ error(node.name, Diagnostics.Accessors_must_both_be_override_or_non_override);
15934
+ }
15928
15935
15929
15936
// TypeScript 1.0 spec (April 2014): 4.5
15930
15937
// If both accessors include type annotations, the specified types must be identical.
@@ -15944,6 +15951,7 @@ namespace ts {
15944
15951
else {
15945
15952
checkNodeDeferred(node);
15946
15953
}
15954
+
15947
15955
}
15948
15956
15949
15957
function checkAccessorDeclarationTypesIdentical(first: AccessorDeclaration, second: AccessorDeclaration, getAnnotatedType: (a: AccessorDeclaration) => Type, message: DiagnosticMessage) {
@@ -16119,6 +16127,9 @@ namespace ts {
16119
16127
else if (deviation & ModifierFlags.Abstract) {
16120
16128
error(o.name, Diagnostics.Overload_signatures_must_all_be_abstract_or_non_abstract);
16121
16129
}
16130
+ else if (deviation & ModifierFlags.Override) {
16131
+ error(o.name, Diagnostics.Overload_signatures_must_all_be_override_or_non_override);
16132
+ }
16122
16133
});
16123
16134
}
16124
16135
}
@@ -18318,6 +18329,13 @@ namespace ts {
18318
18329
checkKindsOfPropertyMemberOverrides(type, baseType);
18319
18330
}
18320
18331
}
18332
+ else {
18333
+ const properties = createMap<Symbol>();
18334
+ for (const prop of getPropertiesOfObjectType(type)) {
18335
+ properties[prop.name] = prop;
18336
+ }
18337
+ checkImplicitPropertyMemberOverrides(type, properties);
18338
+ }
18321
18339
18322
18340
const implementedTypeNodes = getClassImplementsHeritageClauseElements(node);
18323
18341
if (implementedTypeNodes) {
@@ -18370,6 +18388,44 @@ namespace ts {
18370
18388
return forEach(symbol.declarations, d => isClassLike(d) ? d : undefined);
18371
18389
}
18372
18390
18391
+ function checkImplicitPropertyMemberOverrides(type: InterfaceType, propertiesToCheck: Map<Symbol>): void {
18392
+ // If the class does not explicitly declare 'extends Object',
18393
+ // declarations that mask 'Object' members ('toString()', 'hasOwnProperty()', etc...)
18394
+ // are considered here.
18395
+ const objectType = getSymbol(globals, "Object", SymbolFlags.Type);
18396
+ if (!objectType) {
18397
+ return;
18398
+ }
18399
+ for (const name in propertiesToCheck) {
18400
+ const derived = getTargetSymbol(propertiesToCheck[name]);
18401
+ const derivedDeclarationFlags = getDeclarationModifierFlagsFromSymbol(derived);
18402
+ const found = objectType.members[name];
18403
+ if (found) {
18404
+ if (compilerOptions.noImplicitOverride) {
18405
+ const foundSymbol = getTargetSymbol(found);
18406
+ let detail = "masks Object." + symbolToString(found);
18407
+ // assert that the type of the derived
18408
+ // property matches that of the base property.
18409
+ if (!isPropertyIdenticalTo(derived, foundSymbol)) {
18410
+ detail += "). The override declaration ("
18411
+ + typeToString(getTypeOfSymbol(derived))
18412
+ + ") also has a different type signature than the original ("
18413
+ + typeToString(getTypeOfSymbol(foundSymbol));
18414
+ }
18415
+ error(derived.valueDeclaration.name, Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_1,
18416
+ symbolToString(derived), detail);
18417
+ }
18418
+ }
18419
+ // No matching property found on the object type. It
18420
+ // is an error for the derived property to falsely
18421
+ // claim 'override'.
18422
+ else if (derivedDeclarationFlags & ModifierFlags.Override) {
18423
+ error(derived.valueDeclaration.name, Diagnostics.Class_member_0_was_marked_override_but_no_matching_definition_was_found_in_any_supertype_of_1,
18424
+ symbolToString(derived), typeToString(type));
18425
+ }
18426
+ }
18427
+ }
18428
+
18373
18429
function checkKindsOfPropertyMemberOverrides(type: InterfaceType, baseType: ObjectType): void {
18374
18430
18375
18431
// TypeScript 1.0 spec (April 2014): 8.2.3
@@ -18387,9 +18443,17 @@ namespace ts {
18387
18443
// derived class instance member variables and accessors, but not by other kinds of members.
18388
18444
18389
18445
// NOTE: assignability is checked in checkClassDeclaration
18446
+
18447
+ // Track which symbols in the derived class have not been seen.
18448
+ const onlyInDerived = createMap<Symbol>();
18449
+ for (const prop of getPropertiesOfObjectType(type)) {
18450
+ onlyInDerived[prop.name] = prop;
18451
+ }
18452
+
18390
18453
const baseProperties = getPropertiesOfObjectType(baseType);
18391
18454
for (const baseProperty of baseProperties) {
18392
18455
const base = getTargetSymbol(baseProperty);
18456
+ delete onlyInDerived[base.name];
18393
18457
18394
18458
if (base.flags & SymbolFlags.Prototype) {
18395
18459
continue;
@@ -18422,6 +18486,7 @@ namespace ts {
18422
18486
typeToString(type), symbolToString(baseProperty), typeToString(baseType));
18423
18487
}
18424
18488
}
18489
+
18425
18490
}
18426
18491
else {
18427
18492
// derived overrides base.
@@ -18438,6 +18503,16 @@ namespace ts {
18438
18503
18439
18504
if ((base.flags & derived.flags & SymbolFlags.Method) || ((base.flags & SymbolFlags.PropertyOrAccessor) && (derived.flags & SymbolFlags.PropertyOrAccessor))) {
18440
18505
// method is overridden with method or property/accessor is overridden with property/accessor - correct case
18506
+
18507
+ // Before accepting the correct case, ensure 'override' is marked if --noImplicitOverride is true.
18508
+ // Abstract members are an exception as override checks are suspended until the implementation solidifies.
18509
+ if (compilerOptions.noImplicitOverride
18510
+ && !(derivedDeclarationFlags & ModifierFlags.Abstract)
18511
+ && !(derivedDeclarationFlags & ModifierFlags.Override)) {
18512
+ error(derived.valueDeclaration.name, Diagnostics.Class_member_0_must_be_marked_override_when_noImplicitOverride_is_enabled_1,
18513
+ symbolToString(derived), "inherited from " + typeToString(baseType));
18514
+ }
18515
+
18441
18516
continue;
18442
18517
}
18443
18518
@@ -18465,6 +18540,8 @@ namespace ts {
18465
18540
}
18466
18541
}
18467
18542
}
18543
+
18544
+ checkImplicitPropertyMemberOverrides(type, onlyInDerived);
18468
18545
}
18469
18546
18470
18547
function isAccessor(kind: SyntaxKind): boolean {
@@ -21075,38 +21152,38 @@ namespace ts {
21075
21152
flags |= ModifierFlags.Abstract;
21076
21153
break;
21077
21154
21078
- case SyntaxKind.AsyncKeyword :
21079
- if (flags & ModifierFlags.Async ) {
21080
- return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async ");
21081
- }
21082
- else if (flags & ModifierFlags.Ambient || isInAmbientContext(node.parent) ) {
21083
- return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context , "async ");
21084
- }
21085
- else if (node.kind === SyntaxKind.Parameter ) {
21086
- return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter , "async ");
21087
- }
21088
- flags |= ModifierFlags.Async;
21089
- lastAsync = modifier;
21090
- break;
21091
-
21092
- case SyntaxKind.OverrideKeyword:
21093
- if (flags & ModifierFlags.Override) {
21094
- return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override") ;
21095
- }
21096
- else if (flags & ModifierFlags.Static) {
21097
- return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "static", "override");
21098
- }
21099
- else if (flags & ModifierFlags.Private) {
21100
- return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "private", "override");
21101
- }
21102
- else if (flags & ModifierFlags.Abstract) {
21103
- return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override");
21104
- }
21105
- else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) {
21106
- return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override");
21107
- }
21108
- flags |= ModifierFlags.Override ;
21109
- break;
21155
+ case SyntaxKind.OverrideKeyword :
21156
+ if (flags & ModifierFlags.Override ) {
21157
+ return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "override ");
21158
+ }
21159
+ else if (flags & ModifierFlags.Static ) {
21160
+ return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier , "static", "override ");
21161
+ }
21162
+ else if (flags & ModifierFlags.Private ) {
21163
+ return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier , "private", "override ");
21164
+ }
21165
+ else if ( flags & ModifierFlags.Abstract) {
21166
+ return grammarErrorOnNode( modifier, Diagnostics._0_modifier_cannot_be_used_with_1_modifier, "abstract", "override") ;
21167
+ }
21168
+ else if (node.parent.kind === SyntaxKind.ModuleBlock || node.parent.kind === SyntaxKind.SourceFile) {
21169
+ return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_module_or_namespace_element, "override");
21170
+ }
21171
+ flags |= ModifierFlags.Override ;
21172
+ break;
21173
+
21174
+ case SyntaxKind.AsyncKeyword:
21175
+ if (flags & ModifierFlags.Async) {
21176
+ return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "async");
21177
+ }
21178
+ else if (flags & ModifierFlags.Ambient || isInAmbientContext(node.parent)) {
21179
+ return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_be_used_in_an_ambient_context, "async");
21180
+ }
21181
+ else if (node.kind === SyntaxKind.Parameter) {
21182
+ return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_parameter, "async");
21183
+ }
21184
+ flags |= ModifierFlags.Async;
21185
+ lastAsync = modifier ;
21186
+ break;
21110
21187
}
21111
21188
}
21112
21189
0 commit comments