Simplified checkClassPropertyAccess -- fixed bug in super access
This commit is contained in:
parent
868138834b
commit
8f1790de4a
3 changed files with 71 additions and 48 deletions
|
@ -6658,42 +6658,91 @@ namespace ts {
|
|||
return s.valueDeclaration ? getCombinedNodeFlags(s.valueDeclaration) : s.flags & SymbolFlags.Prototype ? NodeFlags.Public | NodeFlags.Static : 0;
|
||||
}
|
||||
|
||||
function checkClassPropertyAccess(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, type: Type, prop: Symbol) {
|
||||
/**
|
||||
* Check whether the requested property access is valid.
|
||||
* Returns true if node passed the check, and false otherwise.
|
||||
* @param node The node to be checked.
|
||||
* @param left The left hand side of the property access (eg: the super is `super.*`).
|
||||
* @param type The type of left.
|
||||
* @param prop The symbol for the right hand side of the property access.
|
||||
*/
|
||||
function checkClassPropertyAccess(node: PropertyAccessExpression | QualifiedName, left: Expression | QualifiedName, type: Type, prop: Symbol) : boolean {
|
||||
let flags = getDeclarationFlagsFromSymbol(prop);
|
||||
// Public properties are always accessible
|
||||
if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) {
|
||||
return;
|
||||
let declaringClass : InterfaceType;
|
||||
|
||||
if (left.kind === SyntaxKind.SuperKeyword) {
|
||||
let errorNode = (<PropertyAccessExpression>node).name ?
|
||||
(<PropertyAccessExpression>node).name :
|
||||
(<QualifiedName>node).right;
|
||||
|
||||
// TS 1.0 spec (April 2014): 4.8.2
|
||||
// - In a constructor, instance member function, instance member accessor, or
|
||||
// instance member variable initializer where this references a derived class instance,
|
||||
// a super property access is permitted and must specify a public instance member function of the base class.
|
||||
// - In a static member function or static member accessor
|
||||
// where this references the constructor function object of a derived class,
|
||||
// a super property access is permitted and must specify a public static member function of the base class.
|
||||
if (getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) { // prop is a property access
|
||||
|
||||
error(errorNode, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword);
|
||||
return false;
|
||||
}
|
||||
// Property is known to be private or protected at this point
|
||||
// Get the declaring and enclosing class instance types
|
||||
|
||||
// In a super call, the member function can be accessed if the method is not abstract.
|
||||
// Note that a member cannot be private and abstract -- this is checked elsewhere.
|
||||
if (flags & NodeFlags.Abstract) {
|
||||
// Get the declaring the class instance type for the error message.
|
||||
declaringClass = <InterfaceType>getDeclaredTypeOfSymbol(prop.parent);
|
||||
|
||||
error(errorNode, Diagnostics.Abstract_member_function_0_on_type_1_cannot_be_called_via_super_expression, symbolToString(prop), typeToString(declaringClass));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Public properties are otherwise accessible.
|
||||
if (!(flags & (NodeFlags.Private | NodeFlags.Protected))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Property is known to be private or protected at this point.
|
||||
|
||||
// Get the declaring and enclosing class instance types.
|
||||
let enclosingClassDeclaration = getAncestor(node, SyntaxKind.ClassDeclaration);
|
||||
// Debug.assert(!!enclosingClassDeclaration, "Should be defined");
|
||||
let enclosingClass = enclosingClassDeclaration ? <InterfaceType>getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined;
|
||||
let declaringClass = <InterfaceType>getDeclaredTypeOfSymbol(prop.parent);
|
||||
declaringClass = <InterfaceType>getDeclaredTypeOfSymbol(prop.parent);
|
||||
|
||||
// Private property is accessible if declaring and enclosing class are the same
|
||||
if (flags & NodeFlags.Private) {
|
||||
if (declaringClass !== enclosingClass) {
|
||||
error(node, Diagnostics.Property_0_is_private_and_only_accessible_within_class_1, symbolToString(prop), typeToString(declaringClass));
|
||||
return false;
|
||||
}
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Property is known to be protected at this point
|
||||
|
||||
// All protected properties of a supertype are accessible in a super access
|
||||
if (left.kind === SyntaxKind.SuperKeyword) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
// A protected property is accessible in the declaring class and classes derived from it
|
||||
if (!enclosingClass || !hasBaseType(enclosingClass, declaringClass)) {
|
||||
error(node, Diagnostics.Property_0_is_protected_and_only_accessible_within_class_1_and_its_subclasses, symbolToString(prop), typeToString(declaringClass));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// No further restrictions for static properties
|
||||
if (flags & NodeFlags.Static) {
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
// An instance property must be accessed through an instance of the enclosing class
|
||||
// TODO: why is the first part of this check here?
|
||||
if (!(getTargetType(type).flags & (TypeFlags.Class | TypeFlags.Interface) && hasBaseType(<InterfaceType>type, enclosingClass))) {
|
||||
error(node, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1, symbolToString(prop), typeToString(enclosingClass));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkPropertyAccessExpression(node: PropertyAccessExpression) {
|
||||
|
@ -6722,32 +6771,13 @@ namespace ts {
|
|||
}
|
||||
return unknownType;
|
||||
}
|
||||
getNodeLinks(node).resolvedSymbol = prop;
|
||||
if (prop.parent && prop.parent.flags & SymbolFlags.Class) {
|
||||
// TS 1.0 spec (April 2014): 4.8.2
|
||||
// - In a constructor, instance member function, instance member accessor, or
|
||||
// instance member variable initializer where this references a derived class instance,
|
||||
// a super property access is permitted and must specify a public instance member function of the base class.
|
||||
// - In a static member function or static member accessor
|
||||
// where this references the constructor function object of a derived class,
|
||||
// a super property access is permitted and must specify a public static member function of the base class.
|
||||
if (left.kind === SyntaxKind.SuperKeyword) {
|
||||
if (getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) {
|
||||
error(right, Diagnostics.Only_public_and_protected_methods_of_the_base_class_are_accessible_via_the_super_keyword);
|
||||
}
|
||||
|
||||
// Abstract methods cannot be accessed through super property accesses. Eg:
|
||||
// class A { abstract foo(); }
|
||||
// class B extends A { bar() { super.foo();} }
|
||||
// is illegal.
|
||||
if (getDeclarationFlagsFromSymbol(prop) & NodeFlags.Abstract) {
|
||||
error(right, Diagnostics.Abstract_member_function_0_on_type_1_cannot_be_called_via_super_expression, declarationNameToString(right), typeToString(type));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// TODO: Why is this line here?
|
||||
getNodeLinks(node).resolvedSymbol = prop;
|
||||
|
||||
if (prop.parent && prop.parent.flags & SymbolFlags.Class) {
|
||||
checkClassPropertyAccess(node, left, type, prop);
|
||||
}
|
||||
}
|
||||
return getTypeOfSymbol(prop);
|
||||
}
|
||||
|
||||
|
@ -6760,14 +6790,7 @@ namespace ts {
|
|||
if (type !== unknownType && !isTypeAny(type)) {
|
||||
let prop = getPropertyOfType(getWidenedType(type), propertyName);
|
||||
if (prop && prop.parent && prop.parent.flags & SymbolFlags.Class) {
|
||||
if (left.kind === SyntaxKind.SuperKeyword && getDeclarationKindFromSymbol(prop) !== SyntaxKind.MethodDeclaration) {
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
let modificationCount = diagnostics.getModificationCount();
|
||||
checkClassPropertyAccess(node, left, type, prop);
|
||||
return diagnostics.getModificationCount() === modificationCount;
|
||||
}
|
||||
return checkClassPropertyAccess(node, left, type, prop);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -231,10 +231,10 @@ namespace ts {
|
|||
this_cannot_be_referenced_in_a_static_property_initializer: { code: 2334, category: DiagnosticCategory.Error, key: "'this' cannot be referenced in a static property initializer." },
|
||||
super_can_only_be_referenced_in_a_derived_class: { code: 2335, category: DiagnosticCategory.Error, key: "'super' can only be referenced in a derived class." },
|
||||
super_cannot_be_referenced_in_constructor_arguments: { code: 2336, category: DiagnosticCategory.Error, key: "'super' cannot be referenced in constructor arguments." },
|
||||
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" },
|
||||
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" },
|
||||
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." },
|
||||
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." },
|
||||
Property_0_does_not_exist_on_type_1: { code: 2339, category: DiagnosticCategory.Error, key: "Property '{0}' does not exist on type '{1}'." },
|
||||
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" },
|
||||
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." },
|
||||
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}'." },
|
||||
An_index_expression_argument_must_be_of_type_string_number_symbol_or_any: { code: 2342, category: DiagnosticCategory.Error, key: "An index expression argument must be of type 'string', 'number', 'symbol, or 'any'." },
|
||||
Type_0_does_not_satisfy_the_constraint_1: { code: 2344, category: DiagnosticCategory.Error, key: "Type '{0}' does not satisfy the constraint '{1}'." },
|
||||
|
|
|
@ -911,11 +911,11 @@
|
|||
"category": "Error",
|
||||
"code": 2336
|
||||
},
|
||||
"Super calls are not permitted outside constructors or in nested functions inside constructors": {
|
||||
"Super calls are not permitted outside constructors or in nested functions inside constructors.": {
|
||||
"category": "Error",
|
||||
"code": 2337
|
||||
},
|
||||
"'super' property access is permitted only in a constructor, member function, or member accessor of a derived class": {
|
||||
"'super' property access is permitted only in a constructor, member function, or member accessor of a derived class.": {
|
||||
"category": "Error",
|
||||
"code": 2338
|
||||
},
|
||||
|
@ -923,7 +923,7 @@
|
|||
"category": "Error",
|
||||
"code": 2339
|
||||
},
|
||||
"Only public and protected methods of the base class are accessible via the 'super' keyword": {
|
||||
"Only public and protected methods of the base class are accessible via the 'super' keyword.": {
|
||||
"category": "Error",
|
||||
"code": 2340
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue