Skip to content

Commit

Permalink
Merge pull request #11990 from HerringtonDarkholme/delete-readonly
Browse files Browse the repository at this point in the history
fix #11480, disallow delete operator on readonly property or index  signature
  • Loading branch information
mhegazy authored Dec 26, 2016
2 parents 20097d7 + 634dff2 commit 0b125a3
Show file tree
Hide file tree
Showing 28 changed files with 774 additions and 16 deletions.
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

0 comments on commit 0b125a3

Please sign in to comment.