Skip to content

Commit 2a1b898

Browse files
committed
Merge pull request #3509 from Microsoft/simplerStrictModeChecking
Simpler strict mode checking
2 parents 46a842e + c20f682 commit 2a1b898

12 files changed

+126
-228
lines changed

src/compiler/binder.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -560,6 +560,23 @@ namespace ts {
560560
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
561561
}
562562

563+
// The binder visits every node in the syntax tree so it is a convenient place to perform a single localized
564+
// check for reserved words used as identifiers in strict mode code.
565+
function checkStrictModeIdentifier(node: Identifier) {
566+
if (node.parserContextFlags & ParserContextFlags.StrictMode &&
567+
node.originalKeywordKind >= SyntaxKind.FirstFutureReservedWord &&
568+
node.originalKeywordKind <= SyntaxKind.LastFutureReservedWord &&
569+
!isIdentifierName(node)) {
570+
// Report error only if there are no parse errors in file
571+
if (!file.parseDiagnostics.length) {
572+
let message = getAncestor(node, SyntaxKind.ClassDeclaration) || getAncestor(node, SyntaxKind.ClassExpression) ?
573+
Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode :
574+
Diagnostics.Identifier_expected_0_is_a_reserved_word_in_strict_mode;
575+
file.bindDiagnostics.push(createDiagnosticForNode(node, message, declarationNameToString(node)));
576+
}
577+
}
578+
}
579+
563580
function getDestructuringParameterName(node: Declaration) {
564581
return "__" + indexOf((<SignatureDeclaration>node.parent).parameters, node);
565582
}
@@ -588,6 +605,8 @@ namespace ts {
588605

589606
function bindWorker(node: Node) {
590607
switch (node.kind) {
608+
case SyntaxKind.Identifier:
609+
return checkStrictModeIdentifier(<Identifier>node);
591610
case SyntaxKind.TypeParameter:
592611
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.TypeParameter, SymbolFlags.TypeParameterExcludes);
593612
case SyntaxKind.Parameter:

src/compiler/checker.ts

Lines changed: 16 additions & 180 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,6 @@ namespace ts {
171171
A_class_declaration_without_the_default_modifier_must_have_a_name: { code: 1211, category: DiagnosticCategory.Error, key: "A class declaration without the 'default' modifier must have a name" },
172172
Identifier_expected_0_is_a_reserved_word_in_strict_mode: { code: 1212, category: DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode" },
173173
Identifier_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1213, category: DiagnosticCategory.Error, key: "Identifier expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." },
174-
Type_expected_0_is_a_reserved_word_in_strict_mode: { code: 1215, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode" },
175-
Type_expected_0_is_a_reserved_word_in_strict_mode_Class_definitions_are_automatically_in_strict_mode: { code: 1216, category: DiagnosticCategory.Error, key: "Type expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode." },
176174
Export_assignment_is_not_supported_when_module_flag_is_system: { code: 1218, category: DiagnosticCategory.Error, key: "Export assignment is not supported when '--module' flag is 'system'." },
177175
Experimental_support_for_decorators_is_a_feature_that_is_subject_to_change_in_a_future_release_Specify_experimentalDecorators_to_remove_this_warning: { code: 1219, category: DiagnosticCategory.Error, key: "Experimental support for decorators is a feature that is subject to change in a future release. Specify '--experimentalDecorators' to remove this warning." },
178176
Generators_are_only_available_when_targeting_ECMAScript_6_or_higher: { code: 1220, category: DiagnosticCategory.Error, key: "Generators are only available when targeting ECMAScript 6 or higher." },

src/compiler/diagnosticMessages.json

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -671,14 +671,6 @@
671671
"category": "Error",
672672
"code": 1213
673673
},
674-
"Type expected. '{0}' is a reserved word in strict mode": {
675-
"category": "Error",
676-
"code": 1215
677-
},
678-
"Type expected. '{0}' is a reserved word in strict mode. Class definitions are automatically in strict mode.": {
679-
"category": "Error",
680-
"code": 1216
681-
},
682674
"Export assignment is not supported when '--module' flag is 'system'.": {
683675
"category": "Error",
684676
"code": 1218

src/compiler/utilities.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,41 @@ namespace ts {
11771177
return false;
11781178
}
11791179

1180+
// Return true if the given identifier is classified as an IdentifierName
1181+
export function isIdentifierName(node: Identifier): boolean {
1182+
let parent = node.parent;
1183+
switch (parent.kind) {
1184+
case SyntaxKind.PropertyDeclaration:
1185+
case SyntaxKind.PropertySignature:
1186+
case SyntaxKind.MethodDeclaration:
1187+
case SyntaxKind.MethodSignature:
1188+
case SyntaxKind.GetAccessor:
1189+
case SyntaxKind.SetAccessor:
1190+
case SyntaxKind.EnumMember:
1191+
case SyntaxKind.PropertyAssignment:
1192+
case SyntaxKind.PropertyAccessExpression:
1193+
// Name in member declaration or property name in property access
1194+
return (<Declaration | PropertyAccessExpression>parent).name === node;
1195+
case SyntaxKind.QualifiedName:
1196+
// Name on right hand side of dot in a type query
1197+
if ((<QualifiedName>parent).right === node) {
1198+
while (parent.kind === SyntaxKind.QualifiedName) {
1199+
parent = parent.parent;
1200+
}
1201+
return parent.kind === SyntaxKind.TypeQuery;
1202+
}
1203+
return false;
1204+
case SyntaxKind.BindingElement:
1205+
case SyntaxKind.ImportSpecifier:
1206+
// Property name in binding element or import specifier
1207+
return (<BindingElement | ImportSpecifier>parent).propertyName === node;
1208+
case SyntaxKind.ExportSpecifier:
1209+
// Any name in an export specifier
1210+
return true;
1211+
}
1212+
return false;
1213+
}
1214+
11801215
// An alias symbol is created by one of the following declarations:
11811216
// import <symbol> = ...
11821217
// import <symbol> from ...

tests/baselines/reference/parser553699.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tests/cases/conformance/parser/ecmascript5/RegressionTests/parser553699.ts(3,21): error TS1216: Type expected. 'public' is a reserved word in strict mode. Class definitions are automatically in strict mode.
1+
tests/cases/conformance/parser/ecmascript5/RegressionTests/parser553699.ts(3,21): error TS1213: Identifier expected. 'public' is a reserved word in strict mode. Class definitions are automatically in strict mode.
22
tests/cases/conformance/parser/ecmascript5/RegressionTests/parser553699.ts(3,21): error TS2304: Cannot find name 'public'.
33

44

@@ -7,7 +7,7 @@ tests/cases/conformance/parser/ecmascript5/RegressionTests/parser553699.ts(3,21)
77
constructor() { }
88
public banana (x: public) { }
99
~~~~~~
10-
!!! error TS1216: Type expected. 'public' is a reserved word in strict mode. Class definitions are automatically in strict mode.
10+
!!! error TS1213: Identifier expected. 'public' is a reserved word in strict mode. Class definitions are automatically in strict mode.
1111
~~~~~~
1212
!!! error TS2304: Cannot find name 'public'.
1313
}

tests/baselines/reference/strictModeReservedWord.errors.txt

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,30 +16,32 @@ tests/cases/compiler/strictModeReservedWord.ts(12,41): error TS1212: Identifier
1616
tests/cases/compiler/strictModeReservedWord.ts(13,11): error TS1212: Identifier expected. 'private' is a reserved word in strict mode
1717
tests/cases/compiler/strictModeReservedWord.ts(13,20): error TS1212: Identifier expected. 'public' is a reserved word in strict mode
1818
tests/cases/compiler/strictModeReservedWord.ts(13,28): error TS1212: Identifier expected. 'package' is a reserved word in strict mode
19+
tests/cases/compiler/strictModeReservedWord.ts(15,25): error TS1213: Identifier expected. 'package' is a reserved word in strict mode. Class definitions are automatically in strict mode.
1920
tests/cases/compiler/strictModeReservedWord.ts(15,25): error TS9003: 'class' expressions are not currently supported.
21+
tests/cases/compiler/strictModeReservedWord.ts(15,41): error TS1213: Identifier expected. 'public' is a reserved word in strict mode. Class definitions are automatically in strict mode.
2022
tests/cases/compiler/strictModeReservedWord.ts(17,9): error TS2300: Duplicate identifier 'b'.
21-
tests/cases/compiler/strictModeReservedWord.ts(17,12): error TS1215: Type expected. 'public' is a reserved word in strict mode
23+
tests/cases/compiler/strictModeReservedWord.ts(17,12): error TS1212: Identifier expected. 'public' is a reserved word in strict mode
2224
tests/cases/compiler/strictModeReservedWord.ts(17,12): error TS2503: Cannot find namespace 'public'.
23-
tests/cases/compiler/strictModeReservedWord.ts(19,21): error TS1215: Type expected. 'private' is a reserved word in strict mode
25+
tests/cases/compiler/strictModeReservedWord.ts(19,21): error TS1212: Identifier expected. 'private' is a reserved word in strict mode
2426
tests/cases/compiler/strictModeReservedWord.ts(19,21): error TS2503: Cannot find namespace 'private'.
25-
tests/cases/compiler/strictModeReservedWord.ts(20,22): error TS1215: Type expected. 'private' is a reserved word in strict mode
27+
tests/cases/compiler/strictModeReservedWord.ts(20,22): error TS1212: Identifier expected. 'private' is a reserved word in strict mode
2628
tests/cases/compiler/strictModeReservedWord.ts(20,22): error TS2503: Cannot find namespace 'private'.
27-
tests/cases/compiler/strictModeReservedWord.ts(20,30): error TS1215: Type expected. 'package' is a reserved word in strict mode
28-
tests/cases/compiler/strictModeReservedWord.ts(21,22): error TS1215: Type expected. 'private' is a reserved word in strict mode
29+
tests/cases/compiler/strictModeReservedWord.ts(20,30): error TS1212: Identifier expected. 'package' is a reserved word in strict mode
30+
tests/cases/compiler/strictModeReservedWord.ts(21,22): error TS1212: Identifier expected. 'private' is a reserved word in strict mode
2931
tests/cases/compiler/strictModeReservedWord.ts(21,22): error TS2503: Cannot find namespace 'private'.
30-
tests/cases/compiler/strictModeReservedWord.ts(21,30): error TS1215: Type expected. 'package' is a reserved word in strict mode
31-
tests/cases/compiler/strictModeReservedWord.ts(21,38): error TS1215: Type expected. 'protected' is a reserved word in strict mode
32+
tests/cases/compiler/strictModeReservedWord.ts(21,30): error TS1212: Identifier expected. 'package' is a reserved word in strict mode
33+
tests/cases/compiler/strictModeReservedWord.ts(21,38): error TS1212: Identifier expected. 'protected' is a reserved word in strict mode
3234
tests/cases/compiler/strictModeReservedWord.ts(22,9): error TS2300: Duplicate identifier 'b'.
33-
tests/cases/compiler/strictModeReservedWord.ts(22,12): error TS1215: Type expected. 'interface' is a reserved word in strict mode
35+
tests/cases/compiler/strictModeReservedWord.ts(22,12): error TS1212: Identifier expected. 'interface' is a reserved word in strict mode
3436
tests/cases/compiler/strictModeReservedWord.ts(22,12): error TS2503: Cannot find namespace 'interface'.
35-
tests/cases/compiler/strictModeReservedWord.ts(22,22): error TS1215: Type expected. 'package' is a reserved word in strict mode
36-
tests/cases/compiler/strictModeReservedWord.ts(22,30): error TS1215: Type expected. 'implements' is a reserved word in strict mode
37+
tests/cases/compiler/strictModeReservedWord.ts(22,22): error TS1212: Identifier expected. 'package' is a reserved word in strict mode
38+
tests/cases/compiler/strictModeReservedWord.ts(22,30): error TS1212: Identifier expected. 'implements' is a reserved word in strict mode
3739
tests/cases/compiler/strictModeReservedWord.ts(23,5): error TS2304: Cannot find name 'ublic'.
3840
tests/cases/compiler/strictModeReservedWord.ts(24,5): error TS1212: Identifier expected. 'static' is a reserved word in strict mode
3941
tests/cases/compiler/strictModeReservedWord.ts(24,5): error TS2349: Cannot invoke an expression whose type lacks a call signature.
4042

4143

42-
==== tests/cases/compiler/strictModeReservedWord.ts (39 errors) ====
44+
==== tests/cases/compiler/strictModeReservedWord.ts (41 errors) ====
4345
let let = 10;
4446

4547
function foo() {
@@ -92,48 +94,52 @@ tests/cases/compiler/strictModeReservedWord.ts(24,5): error TS2349: Cannot invok
9294

9395
var myClass = class package extends public {}
9496
~~~~~~~
97+
!!! error TS1213: Identifier expected. 'package' is a reserved word in strict mode. Class definitions are automatically in strict mode.
98+
~~~~~~~
9599
!!! error TS9003: 'class' expressions are not currently supported.
100+
~~~~~~
101+
!!! error TS1213: Identifier expected. 'public' is a reserved word in strict mode. Class definitions are automatically in strict mode.
96102

97103
var b: public.bar;
98104
~
99105
!!! error TS2300: Duplicate identifier 'b'.
100106
~~~~~~
101-
!!! error TS1215: Type expected. 'public' is a reserved word in strict mode
107+
!!! error TS1212: Identifier expected. 'public' is a reserved word in strict mode
102108
~~~~~~
103109
!!! error TS2503: Cannot find namespace 'public'.
104110

105111
function foo(x: private.x) { }
106112
~~~~~~~
107-
!!! error TS1215: Type expected. 'private' is a reserved word in strict mode
113+
!!! error TS1212: Identifier expected. 'private' is a reserved word in strict mode
108114
~~~~~~~
109115
!!! error TS2503: Cannot find namespace 'private'.
110116
function foo1(x: private.package.x) { }
111117
~~~~~~~
112-
!!! error TS1215: Type expected. 'private' is a reserved word in strict mode
118+
!!! error TS1212: Identifier expected. 'private' is a reserved word in strict mode
113119
~~~~~~~
114120
!!! error TS2503: Cannot find namespace 'private'.
115121
~~~~~~~
116-
!!! error TS1215: Type expected. 'package' is a reserved word in strict mode
122+
!!! error TS1212: Identifier expected. 'package' is a reserved word in strict mode
117123
function foo2(x: private.package.protected) { }
118124
~~~~~~~
119-
!!! error TS1215: Type expected. 'private' is a reserved word in strict mode
125+
!!! error TS1212: Identifier expected. 'private' is a reserved word in strict mode
120126
~~~~~~~
121127
!!! error TS2503: Cannot find namespace 'private'.
122128
~~~~~~~
123-
!!! error TS1215: Type expected. 'package' is a reserved word in strict mode
129+
!!! error TS1212: Identifier expected. 'package' is a reserved word in strict mode
124130
~~~~~~~~~
125-
!!! error TS1215: Type expected. 'protected' is a reserved word in strict mode
131+
!!! error TS1212: Identifier expected. 'protected' is a reserved word in strict mode
126132
let b: interface.package.implements.B;
127133
~
128134
!!! error TS2300: Duplicate identifier 'b'.
129135
~~~~~~~~~
130-
!!! error TS1215: Type expected. 'interface' is a reserved word in strict mode
136+
!!! error TS1212: Identifier expected. 'interface' is a reserved word in strict mode
131137
~~~~~~~~~
132138
!!! error TS2503: Cannot find namespace 'interface'.
133139
~~~~~~~
134-
!!! error TS1215: Type expected. 'package' is a reserved word in strict mode
140+
!!! error TS1212: Identifier expected. 'package' is a reserved word in strict mode
135141
~~~~~~~~~~
136-
!!! error TS1215: Type expected. 'implements' is a reserved word in strict mode
142+
!!! error TS1212: Identifier expected. 'implements' is a reserved word in strict mode
137143
ublic();
138144
~~~~~
139145
!!! error TS2304: Cannot find name 'ublic'.

0 commit comments

Comments
 (0)