Added private and protected modifiers to constructors

This commit is contained in:
AbubakerB 2016-02-03 01:07:09 +00:00
parent 6cc44d1a15
commit f869b41f14
2 changed files with 101 additions and 16 deletions

View file

@ -5889,16 +5889,20 @@ namespace ts {
const sourceSignatures = getSignaturesOfType(source, kind);
const targetSignatures = getSignaturesOfType(target, kind);
if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length &&
isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
// An abstract constructor type is not assignable to a non-abstract constructor type
// as it would otherwise be possible to new an abstract class. Note that the assignablity
// check we perform for an extends clause excludes construct signatures from the target,
// so this check never proceeds.
if (reportErrors) {
reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
if (kind === SignatureKind.Construct && sourceSignatures.length && targetSignatures.length) {
if (isAbstractConstructorType(source) && !isAbstractConstructorType(target)) {
// An abstract constructor type is not assignable to a non-abstract constructor type
// as it would otherwise be possible to new an abstract class. Note that the assignablity
// check we perform for an extends clause excludes construct signatures from the target,
// so this check never proceeds.
if (reportErrors) {
reportError(Diagnostics.Cannot_assign_an_abstract_constructor_type_to_a_non_abstract_constructor_type);
}
return Ternary.False;
}
if (!constructorRelatedTo(sourceSignatures[0], targetSignatures[0], reportErrors)) {
return Ternary.False;
}
return Ternary.False;
}
let result = Ternary.True;
@ -6052,6 +6056,32 @@ namespace ts {
}
return Ternary.True;
}
function constructorRelatedTo(sourceSignature: Signature, targetSignature: Signature, reportErrors: boolean) {
if (sourceSignature && targetSignature && sourceSignature.declaration && targetSignature.declaration) {
const sourceAccessibility = sourceSignature.declaration.flags & (NodeFlags.Private | NodeFlags.Protected);
const targetAccessibility = targetSignature.declaration.flags & (NodeFlags.Private | NodeFlags.Protected);
const isRelated = sourceAccessibility === targetAccessibility;
if (!isRelated && reportErrors) {
reportError(Diagnostics.Cannot_assign_a_0_constructor_type_to_a_1_constructor_type, flagsToString(sourceAccessibility), flagsToString(targetAccessibility));
}
return isRelated;
}
return true;
function flagsToString(flags: NodeFlags) {
if (flags === NodeFlags.Private) {
return "private";
}
if (flags === NodeFlags.Protected) {
return "protected";
}
return "public";
}
}
}
// Return true if the given type is the constructor type for an abstract class
@ -10103,6 +10133,9 @@ namespace ts {
// that the user will not add any.
const constructSignatures = getSignaturesOfType(expressionType, SignatureKind.Construct);
if (constructSignatures.length) {
if (!isConstructorAccessible(node, constructSignatures[0])) {
return resolveErrorCall(node);
}
return resolveCall(node, constructSignatures, candidatesOutArray);
}
@ -10123,6 +10156,37 @@ namespace ts {
return resolveErrorCall(node);
}
function isConstructorAccessible(node: NewExpression, signature: Signature) {
if (!signature || !signature.declaration) {
return true;
}
const declaration = signature.declaration;
const flags = declaration.flags;
// Public constructor is accessible.
if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) {
return true;
}
const declaringClass = <InterfaceType>getDeclaredTypeOfSymbol(declaration.parent.symbol);
const enclosingClassDeclaration = getContainingClass(node);
const enclosingClass = enclosingClassDeclaration ? <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined;
// A private or protected constructor can only be instantiated within it's own class
if (declaringClass !== enclosingClass) {
if (flags & NodeFlags.Private) {
error(node, Diagnostics.Constructor_of_type_0_is_private_and_only_accessible_within_class_1, signatureToString(signature), typeToString(declaringClass));
}
if (flags & NodeFlags.Protected) {
error(node, Diagnostics.Constructor_of_type_0_is_protected_and_only_accessible_within_class_1, signatureToString(signature), typeToString(declaringClass));
}
return false;
}
return true;
}
function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[]): Signature {
const tagType = checkExpression(node.tag);
const apparentType = getApparentType(tagType);
@ -12059,7 +12123,7 @@ namespace ts {
error(o.name, Diagnostics.Overload_signatures_must_all_be_ambient_or_non_ambient);
}
else if (deviation & (NodeFlags.Private | NodeFlags.Protected)) {
error(o.name, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected);
error(o.name || o, Diagnostics.Overload_signatures_must_all_be_public_private_or_protected);
}
else if (deviation & NodeFlags.Abstract) {
error(o.name, Diagnostics.Overload_signatures_must_all_be_abstract_or_not_abstract);
@ -13928,6 +13992,7 @@ namespace ts {
if (baseTypes.length && produceDiagnostics) {
const baseType = baseTypes[0];
const staticBaseType = getBaseConstructorTypeOfClass(type);
checkBaseTypeAccessibility(staticBaseType, baseTypeNode);
checkSourceElement(baseTypeNode.expression);
if (baseTypeNode.typeArguments) {
forEach(baseTypeNode.typeArguments, checkSourceElement);
@ -13983,6 +14048,16 @@ namespace ts {
}
}
function checkBaseTypeAccessibility(type: ObjectType, node: ExpressionWithTypeArguments) {
const signatures = getSignaturesOfType(type, SignatureKind.Construct);
if (signatures.length) {
const declaration = signatures[0].declaration;
if (declaration && declaration.flags & NodeFlags.Private) {
error(node, Diagnostics.Cannot_extend_private_class_0, (<Identifier>node.expression).text);
}
}
}
function getTargetSymbol(s: Symbol) {
// if symbol is instantiated its flags are not copied from the 'target'
// so we'll need to get back original 'target' symbol to work with correct set of flags
@ -16348,12 +16423,6 @@ namespace ts {
if (flags & NodeFlags.Abstract) {
return grammarErrorOnNode(lastStatic, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "abstract");
}
else if (flags & NodeFlags.Protected) {
return grammarErrorOnNode(lastProtected, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "protected");
}
else if (flags & NodeFlags.Private) {
return grammarErrorOnNode(lastPrivate, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "private");
}
else if (flags & NodeFlags.Async) {
return grammarErrorOnNode(lastAsync, Diagnostics._0_modifier_cannot_appear_on_a_constructor_declaration, "async");
}

View file

@ -1823,6 +1823,22 @@
"category": "Error",
"code": 2671
},
"Cannot assign a '{0}' constructor type to a '{1}' constructor type.": {
"category": "Error",
"code": 2672
},
"Constructor of type '{0}' is private and only accessible within class '{1}'.": {
"category": "Error",
"code": 2673
},
"Constructor of type '{0}' is protected and only accessible within class '{1}'.": {
"category": "Error",
"code": 2674
},
"Cannot extend private class '{0}'.": {
"category": "Error",
"code": 2675
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000