Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix #11480, disallow delete operator on readonly property or index signature #11990

Merged
merged 6 commits into from
Dec 26, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6072,7 +6072,7 @@ namespace ts {
getIndexInfoOfType(objectType, IndexKind.String) ||
undefined;
if (indexInfo) {
if (accessExpression && isAssignmentTarget(accessExpression) && indexInfo.isReadonly) {
if (accessExpression && indexInfo.isReadonly && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) {
error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
return unknownType;
}
Expand Down Expand Up @@ -14386,6 +14386,16 @@ namespace ts {

function checkDeleteExpression(node: DeleteExpression): Type {
checkExpression(node.expression);
const expr = skipParentheses(node.expression);
if (expr.kind !== SyntaxKind.PropertyAccessExpression && expr.kind !== SyntaxKind.ElementAccessExpression) {
error(expr, Diagnostics.The_operand_of_a_delete_operator_must_be_a_property_reference);
return booleanType;
}
const links = getNodeLinks(expr);
const symbol = getExportSymbolOfValueSymbolIfExported(links.resolvedSymbol);
if (symbol && isReadonlySymbol(symbol)) {
error(expr, Diagnostics.The_operand_of_a_delete_operator_cannot_be_a_read_only_property);
}
return booleanType;
}

Expand Down
8 changes: 8 additions & 0 deletions src/compiler/diagnosticMessages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2019,6 +2019,14 @@
"category": "Error",
"code": 2702
},
"The operand of a delete operator must be a property reference": {
"category": "Error",
"code": 2703
},
"The operand of a delete operator cannot be a read-only property": {
"category": "Error",
"code": 2704
},

"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
Expand Down
14 changes: 13 additions & 1 deletion src/compiler/utilities.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/// <reference path="sys.ts" />
/// <reference path="sys.ts" />

/* @internal */
namespace ts {
Expand Down Expand Up @@ -1668,6 +1668,18 @@ namespace ts {
return getAssignmentTargetKind(node) !== AssignmentKind.None;
}

// a node is delete target iff. it is PropertyAccessExpression/ElementAccessExpression with parentheses skipped
export function isDeleteTarget(node: Node): boolean {
if (node.kind !== SyntaxKind.PropertyAccessExpression && node.kind !== SyntaxKind.ElementAccessExpression) {
return false;
}
node = node.parent;
while (node && node.kind === SyntaxKind.ParenthesizedExpression) {
node = node.parent;
}
return node && node.kind === SyntaxKind.DeleteExpression;
}

export function isNodeDescendantOf(node: Node, ancestor: Node): boolean {
while (node) {
if (node === ancestor) return true;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
tests/cases/conformance/async/es2017/await_unaryExpression_es2017_1.ts(7,12): error TS2703: The operand of a delete operator must be a property reference
tests/cases/conformance/async/es2017/await_unaryExpression_es2017_1.ts(11,12): error TS2703: The operand of a delete operator must be a property reference


==== tests/cases/conformance/async/es2017/await_unaryExpression_es2017_1.ts (2 errors) ====

async function bar() {
!await 42; // OK
}

async function bar1() {
delete await 42; // OK
~~~~~~~~
!!! error TS2703: The operand of a delete operator must be a property reference
}

async function bar2() {
delete await 42; // OK
~~~~~~~~
!!! error TS2703: The operand of a delete operator must be a property reference
}

async function bar3() {
void await 42;
}

async function bar4() {
+await 42;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
tests/cases/conformance/async/es2017/await_unaryExpression_es2017_2.ts(3,12): error TS2703: The operand of a delete operator must be a property reference
tests/cases/conformance/async/es2017/await_unaryExpression_es2017_2.ts(7,12): error TS2703: The operand of a delete operator must be a property reference


==== tests/cases/conformance/async/es2017/await_unaryExpression_es2017_2.ts (2 errors) ====

async function bar1() {
delete await 42;
~~~~~~~~
!!! error TS2703: The operand of a delete operator must be a property reference
}

async function bar2() {
delete await 42;
~~~~~~~~
!!! error TS2703: The operand of a delete operator must be a property reference
}

async function bar3() {
void await 42;
}
29 changes: 29 additions & 0 deletions tests/baselines/reference/await_unaryExpression_es6_1.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts(7,12): error TS2703: The operand of a delete operator must be a property reference
tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts(11,12): error TS2703: The operand of a delete operator must be a property reference


==== tests/cases/conformance/async/es6/await_unaryExpression_es6_1.ts (2 errors) ====

async function bar() {
!await 42; // OK
}

async function bar1() {
delete await 42; // OK
~~~~~~~~
!!! error TS2703: The operand of a delete operator must be a property reference
}

async function bar2() {
delete await 42; // OK
~~~~~~~~
!!! error TS2703: The operand of a delete operator must be a property reference
}

async function bar3() {
void await 42;
}

async function bar4() {
+await 42;
}
21 changes: 21 additions & 0 deletions tests/baselines/reference/await_unaryExpression_es6_2.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts(3,12): error TS2703: The operand of a delete operator must be a property reference
tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts(7,12): error TS2703: The operand of a delete operator must be a property reference


==== tests/cases/conformance/async/es6/await_unaryExpression_es6_2.ts (2 errors) ====

async function bar1() {
delete await 42;
~~~~~~~~
!!! error TS2703: The operand of a delete operator must be a property reference
}

async function bar2() {
delete await 42;
~~~~~~~~
!!! error TS2703: The operand of a delete operator must be a property reference
}

async function bar3() {
void await 42;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(4,1
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(5,9): error TS2378: A 'get' accessor must return a value.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(5,9): error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(5,17): error TS1102: 'delete' cannot be called on an identifier in strict mode.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(5,17): error TS2703: The operand of a delete operator must be a property reference
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(6,9): error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(7,16): error TS2378: A 'get' accessor must return a value.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(7,16): error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.


==== tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts (7 errors) ====
==== tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts (8 errors) ====
var id;
class C {
[0 + 1]() { }
Expand All @@ -21,6 +22,8 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES5.ts(7,1
!!! error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
~~
!!! error TS1102: 'delete' cannot be called on an identifier in strict mode.
~~
!!! error TS2703: The operand of a delete operator must be a property reference
set [[0, 1]](v) { }
~~~~~~~~
!!! error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(4,1
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(5,9): error TS2378: A 'get' accessor must return a value.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(5,9): error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(5,17): error TS1102: 'delete' cannot be called on an identifier in strict mode.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(5,17): error TS2703: The operand of a delete operator must be a property reference
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(6,9): error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(7,16): error TS2378: A 'get' accessor must return a value.
tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(7,16): error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.


==== tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts (7 errors) ====
==== tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts (8 errors) ====
var id;
class C {
[0 + 1]() { }
Expand All @@ -21,6 +22,8 @@ tests/cases/conformance/es6/computedProperties/computedPropertyNames3_ES6.ts(7,1
!!! error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
~~
!!! error TS1102: 'delete' cannot be called on an identifier in strict mode.
~~
!!! error TS2703: The operand of a delete operator must be a property reference
set [[0, 1]](v) { }
~~~~~~~~
!!! error TS2464: A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
Expand Down
23 changes: 23 additions & 0 deletions tests/baselines/reference/controlFlowDeleteOperator.errors.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts(15,12): error TS2703: The operand of a delete operator must be a property reference


==== tests/cases/conformance/controlFlow/controlFlowDeleteOperator.ts (1 errors) ====

function f() {
let x: { a?: number | string, b: number | string } = { b: 1 };
x.a;
x.b;
x.a = 1;
x.b = 1;
x.a;
x.b;
delete x.a;
delete x.b;
x.a;
x.b;
x;
delete x; // No effect
~
!!! error TS2703: The operand of a delete operator must be a property reference
x;
}
13 changes: 11 additions & 2 deletions tests/baselines/reference/deleteOperator1.errors.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,19 @@
tests/cases/compiler/deleteOperator1.ts(2,25): error TS2703: The operand of a delete operator must be a property reference
tests/cases/compiler/deleteOperator1.ts(3,21): error TS2703: The operand of a delete operator must be a property reference
tests/cases/compiler/deleteOperator1.ts(4,5): error TS2322: Type 'boolean' is not assignable to type 'number'.
tests/cases/compiler/deleteOperator1.ts(4,24): error TS2703: The operand of a delete operator must be a property reference


==== tests/cases/compiler/deleteOperator1.ts (1 errors) ====
==== tests/cases/compiler/deleteOperator1.ts (4 errors) ====
var a;
var x: boolean = delete a;
~
!!! error TS2703: The operand of a delete operator must be a property reference
var y: any = delete a;
~
!!! error TS2703: The operand of a delete operator must be a property reference
var z: number = delete a;
~
!!! error TS2322: Type 'boolean' is not assignable to type 'number'.
!!! error TS2322: Type 'boolean' is not assignable to type 'number'.
~
!!! error TS2703: The operand of a delete operator must be a property reference
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
tests/cases/compiler/deleteOperatorInStrictMode.ts(3,8): error TS1102: 'delete' cannot be called on an identifier in strict mode.
tests/cases/compiler/deleteOperatorInStrictMode.ts(3,8): error TS2703: The operand of a delete operator must be a property reference


==== tests/cases/compiler/deleteOperatorInStrictMode.ts (1 errors) ====
==== tests/cases/compiler/deleteOperatorInStrictMode.ts (2 errors) ====
"use strict"
var a;
delete a;
~
!!! error TS1102: 'delete' cannot be called on an identifier in strict mode.
!!! error TS1102: 'delete' cannot be called on an identifier in strict mode.
~
!!! error TS2703: The operand of a delete operator must be a property reference
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(5,20): error TS1005: ',' expected.
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(5,26): error TS2703: The operand of a delete operator must be a property reference
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(5,27): error TS1109: Expression expected.
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(8,22): error TS2703: The operand of a delete operator must be a property reference
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(8,23): error TS1109: Expression expected.
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(13,16): error TS1102: 'delete' cannot be called on an identifier in strict mode.
tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts(13,16): error TS2703: The operand of a delete operator must be a property reference


==== tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts (4 errors) ====
==== tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperatorInvalidOperations.ts (7 errors) ====
// Unary operator delete
var ANY;

// operand before delete operator
var BOOLEAN1 = ANY delete ; //expect error
~~~~~~
!!! error TS1005: ',' expected.

!!! error TS2703: The operand of a delete operator must be a property reference
~
!!! error TS1109: Expression expected.

// miss an operand
var BOOLEAN2 = delete ;

!!! error TS2703: The operand of a delete operator must be a property reference
~
!!! error TS1109: Expression expected.

Expand All @@ -26,5 +33,7 @@ tests/cases/conformance/expressions/unaryOperators/deleteOperator/deleteOperator
delete s; //expect error
~
!!! error TS1102: 'delete' cannot be called on an identifier in strict mode.
~
!!! error TS2703: The operand of a delete operator must be a property reference
}
}
Loading