Skip to content

Commit 7cc6bbb

Browse files
committed
Merge pull request #688 from Microsoft/protectedMembers
Support for protected members in classes
2 parents 80bab05 + b5b0777 commit 7cc6bbb

File tree

108 files changed

+2163
-517
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

108 files changed

+2163
-517
lines changed

src/compiler/binder.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ module ts {
226226
function bindConstructorDeclaration(node: ConstructorDeclaration) {
227227
bindDeclaration(node, SymbolFlags.Constructor, 0);
228228
forEach(node.parameters, p => {
229-
if (p.flags & (NodeFlags.Public | NodeFlags.Private)) {
229+
if (p.flags & (NodeFlags.Public | NodeFlags.Private | NodeFlags.Protected)) {
230230
bindDeclaration(p, SymbolFlags.Property, SymbolFlags.PropertyExcludes);
231231
}
232232
});

src/compiler/checker.ts

Lines changed: 120 additions & 73 deletions
Large diffs are not rendered by default.

src/compiler/diagnosticInformationMap.generated.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,9 @@ module ts {
138138
Type_0_is_not_assignable_to_type_1_Colon: { code: 2322, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}':" },
139139
Type_0_is_not_assignable_to_type_1: { code: 2323, category: DiagnosticCategory.Error, key: "Type '{0}' is not assignable to type '{1}'." },
140140
Property_0_is_missing_in_type_1: { code: 2324, category: DiagnosticCategory.Error, key: "Property '{0}' is missing in type '{1}'." },
141-
Private_property_0_cannot_be_reimplemented: { code: 2325, category: DiagnosticCategory.Error, key: "Private property '{0}' cannot be reimplemented." },
141+
Property_0_is_private_in_type_1_but_not_in_type_2: { code: 2325, category: DiagnosticCategory.Error, key: "Property '{0}' is private in type '{1}' but not in type '{2}'." },
142142
Types_of_property_0_are_incompatible_Colon: { code: 2326, category: DiagnosticCategory.Error, key: "Types of property '{0}' are incompatible:" },
143-
Required_property_0_cannot_be_reimplemented_with_optional_property_in_1: { code: 2327, category: DiagnosticCategory.Error, key: "Required property '{0}' cannot be reimplemented with optional property in '{1}'." },
143+
Property_0_is_optional_in_type_1_but_required_in_type_2: { code: 2327, category: DiagnosticCategory.Error, key: "Property '{0}' is optional in type '{1}' but required in type '{2}'." },
144144
Types_of_parameters_0_and_1_are_incompatible_Colon: { code: 2328, category: DiagnosticCategory.Error, key: "Types of parameters '{0}' and '{1}' are incompatible:" },
145145
Index_signature_is_missing_in_type_0: { code: 2329, category: DiagnosticCategory.Error, key: "Index signature is missing in type '{0}'." },
146146
Index_signatures_are_incompatible_Colon: { code: 2330, category: DiagnosticCategory.Error, key: "Index signatures are incompatible:" },
@@ -153,8 +153,8 @@ module ts {
153153
Super_calls_are_not_permitted_outside_constructors_or_in_nested_functions_inside_constructors: { code: 2337, category: DiagnosticCategory.Error, key: "Super calls are not permitted outside constructors or in nested functions inside constructors" },
154154
super_property_access_is_permitted_only_in_a_constructor_member_function_or_member_accessor_of_a_derived_class: { code: 2338, category: DiagnosticCategory.Error, key: "'super' property access is permitted only in a constructor, member function, or member accessor of a derived class" },
155155
Property_0_does_not_exist_on_type_1: { code: 2339, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on type '{1}'." },
156-
Only_public_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public methods of the base class are accessible via the 'super' keyword" },
157-
Property_0_is_inaccessible: { code: 2341, category: DiagnosticCategory.Error, key: "Property '{0}' is inaccessible." },
156+
Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword: { code: 2340, category: DiagnosticCategory.Error, key: "Only public and protected methods of the base class are accessible via the 'super' keyword" },
157+
Property_0_is_private_and_only_accessible_within_class_1: { code: 2341, category: DiagnosticCategory.Error, key: "Property '{0}' is private and only accessible within class '{1}'." },
158158
An_index_expression_argument_must_be_of_type_string_number_or_any: { code: 2342, category: DiagnosticCategory.Error, key: "An index expression argument must be of type 'string', 'number', or 'any'." },
159159
Type_0_does_not_satisfy_the_constraint_1_Colon: { code: 2343, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}':" },
160160
Type_0_does_not_satisfy_the_constraint_1: { code: 2344, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}'." },
@@ -198,7 +198,7 @@ module ts {
198198
Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature: { code: 2382, category: DiagnosticCategory.Error, key: "Specialized overload signature is not assignable to any non-specialized signature." },
199199
Overload_signatures_must_all_be_exported_or_not_exported: { code: 2383, category: DiagnosticCategory.Error, key: "Overload signatures must all be exported or not exported." },
200200
Overload_signatures_must_all_be_ambient_or_non_ambient: { code: 2384, category: DiagnosticCategory.Error, key: "Overload signatures must all be ambient or non-ambient." },
201-
Overload_signatures_must_all_be_public_or_private: { code: 2385, category: DiagnosticCategory.Error, key: "Overload signatures must all be public or private." },
201+
Overload_signatures_must_all_be_public_private_or_protected: { code: 2385, category: DiagnosticCategory.Error, key: "Overload signatures must all be public, private or protected." },
202202
Overload_signatures_must_all_be_optional_or_required: { code: 2386, category: DiagnosticCategory.Error, key: "Overload signatures must all be optional or required." },
203203
Function_overload_must_be_static: { code: 2387, category: DiagnosticCategory.Error, key: "Function overload must be static." },
204204
Function_overload_must_not_be_static: { code: 2388, category: DiagnosticCategory.Error, key: "Function overload must not be static." },
@@ -255,6 +255,11 @@ module ts {
255255
Import_declaration_in_an_ambient_external_module_declaration_cannot_reference_external_module_through_relative_external_module_name: { code: 2439, category: DiagnosticCategory.Error, key: "Import declaration in an ambient external module declaration cannot reference external module through relative external module name." },
256256
Import_declaration_conflicts_with_local_declaration_of_0: { code: 2440, category: DiagnosticCategory.Error, key: "Import declaration conflicts with local declaration of '{0}'" },
257257
Duplicate_identifier_0_Compiler_reserves_name_1_in_top_level_scope_of_an_external_module: { code: 2441, category: DiagnosticCategory.Error, key: "Duplicate identifier '{0}'. Compiler reserves name '{1}' in top level scope of an external module." },
258+
Types_have_separate_declarations_of_a_private_property_0: { code: 2442, category: DiagnosticCategory.Error, key: "Types have separate declarations of a private property '{0}'." },
259+
Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2: { code: 2443, category: DiagnosticCategory.Error, key: "Property '{0}' is protected but type '{1}' is not a class derived from '{2}'." },
260+
Property_0_is_protected_in_type_1_but_public_in_type_2: { code: 2444, category: DiagnosticCategory.Error, key: "Property '{0}' is protected in type '{1}' but public in type '{2}'." },
261+
Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses: { code: 2445, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible within class '{1}' and its subclasses." },
262+
Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1: { code: 2446, category: DiagnosticCategory.Error, key: "Property '{0}' is protected and only accessible through an instance of class '{1}'." },
258263
Import_declaration_0_is_using_private_name_1: { code: 4000, category: DiagnosticCategory.Error, key: "Import declaration '{0}' is using private name '{1}'." },
259264
Type_parameter_0_of_exported_class_has_or_is_using_name_1_from_private_module_2: { code: 4001, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using name '{1}' from private module '{2}'." },
260265
Type_parameter_0_of_exported_class_has_or_is_using_private_name_1: { code: 4002, category: DiagnosticCategory.Error, key: "Type parameter '{0}' of exported class has or is using private name '{1}'." },

src/compiler/diagnosticMessages.json

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -544,15 +544,15 @@
544544
"category": "Error",
545545
"code": 2324
546546
},
547-
"Private property '{0}' cannot be reimplemented.": {
547+
"Property '{0}' is private in type '{1}' but not in type '{2}'.": {
548548
"category": "Error",
549549
"code": 2325
550550
},
551551
"Types of property '{0}' are incompatible:": {
552552
"category": "Error",
553553
"code": 2326
554554
},
555-
"Required property '{0}' cannot be reimplemented with optional property in '{1}'.": {
555+
"Property '{0}' is optional in type '{1}' but required in type '{2}'.": {
556556
"category": "Error",
557557
"code": 2327
558558
},
@@ -604,11 +604,11 @@
604604
"category": "Error",
605605
"code": 2339
606606
},
607-
"Only public methods of the base class are accessible via the 'super' keyword": {
607+
"Only public and protected methods of the base class are accessible via the 'super' keyword": {
608608
"category": "Error",
609609
"code": 2340
610610
},
611-
"Property '{0}' is inaccessible.": {
611+
"Property '{0}' is private and only accessible within class '{1}'.": {
612612
"category": "Error",
613613
"code": 2341
614614
},
@@ -784,7 +784,7 @@
784784
"category": "Error",
785785
"code": 2384
786786
},
787-
"Overload signatures must all be public or private.": {
787+
"Overload signatures must all be public, private or protected.": {
788788
"category": "Error",
789789
"code": 2385
790790
},
@@ -1012,7 +1012,26 @@
10121012
"category": "Error",
10131013
"code": 2441
10141014
},
1015-
1015+
"Types have separate declarations of a private property '{0}'.": {
1016+
"category": "Error",
1017+
"code": 2442
1018+
},
1019+
"Property '{0}' is protected but type '{1}' is not a class derived from '{2}'.": {
1020+
"category": "Error",
1021+
"code": 2443
1022+
},
1023+
"Property '{0}' is protected in type '{1}' but public in type '{2}'.": {
1024+
"category": "Error",
1025+
"code": 2444
1026+
},
1027+
"Property '{0}' is protected and only accessible within class '{1}' and its subclasses.": {
1028+
"category": "Error",
1029+
"code": 2445
1030+
},
1031+
"Property '{0}' is protected and only accessible through an instance of class '{1}'.": {
1032+
"category": "Error",
1033+
"code": 2446
1034+
},
10161035

10171036
"Import declaration '{0}' is using private name '{1}'.": {
10181037
"category": "Error",

src/compiler/emitter.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2371,12 +2371,18 @@ module ts {
23712371
if (node.flags & NodeFlags.Private) {
23722372
write("private ");
23732373
}
2374+
else if (node.flags & NodeFlags.Protected) {
2375+
write("protected ");
2376+
}
23742377
write("static ");
23752378
}
23762379
else {
23772380
if (node.flags & NodeFlags.Private) {
23782381
write("private ");
23792382
}
2383+
else if (node.flags & NodeFlags.Protected) {
2384+
write("protected ");
2385+
}
23802386
// If the node is parented in the current source file we need to emit export declare or just export
23812387
else if (node.parent === currentSourceFile) {
23822388
// If the node is exported

src/compiler/parser.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ module ts {
656656
switch (token) {
657657
case SyntaxKind.PublicKeyword:
658658
case SyntaxKind.PrivateKeyword:
659+
case SyntaxKind.ProtectedKeyword:
659660
case SyntaxKind.StaticKeyword:
660661
case SyntaxKind.ExportKeyword:
661662
case SyntaxKind.DeclareKeyword:
@@ -2981,6 +2982,7 @@ module ts {
29812982
}
29822983
case SyntaxKind.PublicKeyword:
29832984
case SyntaxKind.PrivateKeyword:
2985+
case SyntaxKind.ProtectedKeyword:
29842986
case SyntaxKind.StaticKeyword:
29852987
// When followed by an identifier or keyword, these do not start a statement but
29862988
// might instead be following type members
@@ -3299,6 +3301,8 @@ module ts {
32993301
var lastDeclareModifierLength: number;
33003302
var lastPrivateModifierStart: number;
33013303
var lastPrivateModifierLength: number;
3304+
var lastProtectedModifierStart: number;
3305+
var lastProtectedModifierLength: number;
33023306

33033307
while (true) {
33043308
var modifierStart = scanner.getTokenPos();
@@ -3338,6 +3342,21 @@ module ts {
33383342
flags |= NodeFlags.Private;
33393343
break;
33403344

3345+
case SyntaxKind.ProtectedKeyword:
3346+
if (flags & NodeFlags.Public || flags & NodeFlags.Private || flags & NodeFlags.Protected) {
3347+
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics.Accessibility_modifier_already_seen);
3348+
}
3349+
else if (flags & NodeFlags.Static) {
3350+
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics._0_modifier_must_precede_1_modifier, "protected", "static");
3351+
}
3352+
else if (context === ModifierContext.ModuleElements || context === ModifierContext.SourceElements) {
3353+
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics._0_modifier_cannot_appear_on_a_module_element, "protected");
3354+
}
3355+
lastProtectedModifierStart = modifierStart;
3356+
lastProtectedModifierLength = modifierLength;
3357+
flags |= NodeFlags.Protected;
3358+
break;
3359+
33413360
case SyntaxKind.StaticKeyword:
33423361
if (flags & NodeFlags.Static) {
33433362
grammarErrorAtPos(modifierStart, modifierLength, Diagnostics._0_modifier_already_seen, "static");
@@ -3395,6 +3414,9 @@ module ts {
33953414
else if (token === SyntaxKind.ConstructorKeyword && flags & NodeFlags.Private) {
33963415
grammarErrorAtPos(lastPrivateModifierStart, lastPrivateModifierLength, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private");
33973416
}
3417+
else if (token === SyntaxKind.ConstructorKeyword && flags & NodeFlags.Protected) {
3418+
grammarErrorAtPos(lastProtectedModifierStart, lastProtectedModifierLength, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected");
3419+
}
33983420
else if (token === SyntaxKind.ImportKeyword) {
33993421
if (flags & NodeFlags.Ambient) {
34003422
grammarErrorAtPos(lastDeclareModifierStart, lastDeclareModifierLength, Diagnostics.A_declare_modifier_cannot_be_used_with_an_import_declaration, "declare");
@@ -3671,6 +3693,7 @@ module ts {
36713693
case SyntaxKind.DeclareKeyword:
36723694
case SyntaxKind.PublicKeyword:
36733695
case SyntaxKind.PrivateKeyword:
3696+
case SyntaxKind.ProtectedKeyword:
36743697
case SyntaxKind.StaticKeyword:
36753698
// Check for modifier on source element
36763699
return lookAhead(() => { nextToken(); return isDeclaration(); });

src/compiler/types.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,13 +238,14 @@ module ts {
238238
Rest = 0x00000008, // Parameter
239239
Public = 0x00000010, // Property/Method
240240
Private = 0x00000020, // Property/Method
241-
Static = 0x00000040, // Property/Method
242-
MultiLine = 0x00000080, // Multi-line array or object literal
243-
Synthetic = 0x00000100, // Synthetic node (for full fidelity)
244-
DeclarationFile = 0x00000200, // Node is a .d.ts file
245-
246-
Modifier = Export | Ambient | Public | Private | Static,
247-
AccessibilityModifier = Public | Private
241+
Protected = 0x00000040, // Property/Method
242+
Static = 0x00000080, // Property/Method
243+
MultiLine = 0x00000100, // Multi-line array or object literal
244+
Synthetic = 0x00000200, // Synthetic node (for full fidelity)
245+
DeclarationFile = 0x00000400, // Node is a .d.ts file
246+
247+
Modifier = Export | Ambient | Public | Private | Protected | Static,
248+
AccessibilityModifier = Public | Private | Protected
248249
}
249250

250251
export interface Node extends TextRange {

tests/baselines/reference/ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts(11,16): error TS2341: Property 'clodule.sfn' is inaccessible.
1+
tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts(11,16): error TS2341: Property 'sfn' is private and only accessible within class 'clodule<T>'.
22

33

44
==== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts (1 errors) ====
@@ -14,7 +14,7 @@ tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMer
1414
export function fn<T>(x: T, y: T): number {
1515
return clodule.sfn('a');
1616
~~~~~~~~~~~
17-
!!! error TS2341: Property 'clodule.sfn' is inaccessible.
17+
!!! error TS2341: Property 'sfn' is private and only accessible within class 'clodule<T>'.
1818
}
1919
}
2020

0 commit comments

Comments
 (0)