From 8f1790de4ad05a86f94dffb6586a42b090e8e7e3 Mon Sep 17 00:00:00 2001 From: Arthur Ozga Date: Fri, 19 Jun 2015 15:34:19 -0700 Subject: [PATCH] Simplified checkClassPropertyAccess -- fixed bug in super access --- src/compiler/checker.ts | 107 +++++++++++------- .../diagnosticInformationMap.generated.ts | 6 +- src/compiler/diagnosticMessages.json | 6 +- 3 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index cb0016c9496..741863f0334 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -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 = (node).name ? + (node).name : + (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; + } + + // 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 = 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; + } } - // Property is known to be private or protected at this point - // Get the declaring and enclosing class instance types + + // 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 ? getDeclaredTypeOfSymbol(getSymbolOfNode(enclosingClassDeclaration)) : undefined; - let declaringClass = getDeclaredTypeOfSymbol(prop.parent); + declaringClass = 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(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,31 +6771,12 @@ namespace ts { } return unknownType; } + + // TODO: Why is this line here? 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 { - checkClassPropertyAccess(node, left, type, prop); - } + 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; diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index e89a4e03c03..071570482df 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -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}'." }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 10ff7cbae35..85c8e46c246 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -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 },