Skip to content

Commit a453eff

Browse files
authored
Restrict parsing of literals and their expressions a _lot_ more (#17628)
1 parent 313c93c commit a453eff

File tree

4 files changed

+247
-7
lines changed

4 files changed

+247
-7
lines changed

src/compiler/parser.ts

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2061,7 +2061,7 @@ namespace ts {
20612061
return <TemplateMiddle | TemplateTail>fragment;
20622062
}
20632063

2064-
function parseLiteralLikeNode(kind: SyntaxKind): LiteralLikeNode {
2064+
function parseLiteralLikeNode(kind: SyntaxKind): LiteralExpression | LiteralLikeNode {
20652065
const node = <LiteralExpression>createNode(kind);
20662066
const text = scanner.getTokenValue();
20672067
node.text = text;
@@ -2611,11 +2611,31 @@ namespace ts {
26112611
return token() === SyntaxKind.DotToken ? undefined : node;
26122612
}
26132613

2614-
function parseLiteralTypeNode(): LiteralTypeNode {
2615-
const node = <LiteralTypeNode>createNode(SyntaxKind.LiteralType);
2616-
node.literal = parseSimpleUnaryExpression();
2617-
finishNode(node);
2618-
return node;
2614+
function parseLiteralTypeNode(negative?: boolean): LiteralTypeNode {
2615+
const node = createNode(SyntaxKind.LiteralType) as LiteralTypeNode;
2616+
let unaryMinusExpression: PrefixUnaryExpression;
2617+
if (negative) {
2618+
unaryMinusExpression = createNode(SyntaxKind.PrefixUnaryExpression) as PrefixUnaryExpression;
2619+
unaryMinusExpression.operator = SyntaxKind.MinusToken;
2620+
nextToken();
2621+
}
2622+
let expression: UnaryExpression;
2623+
switch (token()) {
2624+
case SyntaxKind.StringLiteral:
2625+
case SyntaxKind.NumericLiteral:
2626+
expression = parseLiteralLikeNode(token()) as LiteralExpression;
2627+
break;
2628+
case SyntaxKind.TrueKeyword:
2629+
case SyntaxKind.FalseKeyword:
2630+
expression = parseTokenNode();
2631+
}
2632+
if (negative) {
2633+
unaryMinusExpression.operand = expression;
2634+
finishNode(unaryMinusExpression);
2635+
expression = unaryMinusExpression;
2636+
}
2637+
node.literal = expression;
2638+
return finishNode(node);
26192639
}
26202640

26212641
function nextTokenIsNumericLiteral() {
@@ -2650,7 +2670,7 @@ namespace ts {
26502670
case SyntaxKind.FalseKeyword:
26512671
return parseLiteralTypeNode();
26522672
case SyntaxKind.MinusToken:
2653-
return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode() : parseTypeReference();
2673+
return lookAhead(nextTokenIsNumericLiteral) ? parseLiteralTypeNode(/*negative*/ true) : parseTypeReference();
26542674
case SyntaxKind.VoidKeyword:
26552675
case SyntaxKind.NullKeyword:
26562676
return parseTokenNode<TypeNode>();
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
tests/cases/compiler/base.d.ts(1,23): error TS1005: ',' expected.
2+
tests/cases/compiler/base.d.ts(1,34): error TS1005: '=' expected.
3+
tests/cases/compiler/boolean.ts(7,23): error TS1005: ',' expected.
4+
tests/cases/compiler/boolean.ts(7,24): error TS1134: Variable declaration expected.
5+
tests/cases/compiler/boolean.ts(11,16): error TS2304: Cannot find name 'document'.
6+
tests/cases/compiler/boolean.ts(12,22): error TS1005: ';' expected.
7+
tests/cases/compiler/number.ts(7,26): error TS1005: ',' expected.
8+
tests/cases/compiler/number.ts(7,27): error TS1134: Variable declaration expected.
9+
tests/cases/compiler/number.ts(11,16): error TS2304: Cannot find name 'document'.
10+
tests/cases/compiler/number.ts(12,20): error TS1005: ';' expected.
11+
tests/cases/compiler/string.ts(7,20): error TS1005: ',' expected.
12+
tests/cases/compiler/string.ts(7,21): error TS1134: Variable declaration expected.
13+
tests/cases/compiler/string.ts(11,15): error TS2304: Cannot find name 'document'.
14+
tests/cases/compiler/string.ts(12,19): error TS1005: ';' expected.
15+
16+
17+
==== tests/cases/compiler/base.d.ts (2 errors) ====
18+
declare const x: "foo".charCodeAt(0);
19+
~
20+
!!! error TS1005: ',' expected.
21+
~
22+
!!! error TS1005: '=' expected.
23+
24+
==== tests/cases/compiler/string.ts (4 errors) ====
25+
interface String {
26+
typeof<T>(x: T): T;
27+
}
28+
29+
class C {
30+
foo() {
31+
const x: "".typeof(this.foo);
32+
~
33+
!!! error TS1005: ',' expected.
34+
~~~~~~
35+
!!! error TS1134: Variable declaration expected.
36+
}
37+
}
38+
39+
const nodes = document.getElementsByTagName("li");
40+
~~~~~~~~
41+
!!! error TS2304: Cannot find name 'document'.
42+
type ItemType = "".typeof(nodes.item(0));
43+
~
44+
!!! error TS1005: ';' expected.
45+
46+
==== tests/cases/compiler/number.ts (4 errors) ====
47+
interface Number {
48+
typeof<T>(x: T): T;
49+
}
50+
51+
class C2 {
52+
foo() {
53+
const x: 3.141592.typeof(this.foo);
54+
~
55+
!!! error TS1005: ',' expected.
56+
~~~~~~
57+
!!! error TS1134: Variable declaration expected.
58+
}
59+
}
60+
61+
const nodes2 = document.getElementsByTagName("li");
62+
~~~~~~~~
63+
!!! error TS2304: Cannot find name 'document'.
64+
type ItemType2 = 4..typeof(nodes.item(0));
65+
~
66+
!!! error TS1005: ';' expected.
67+
68+
==== tests/cases/compiler/boolean.ts (4 errors) ====
69+
interface Boolean {
70+
typeof<T>(x: T): T;
71+
}
72+
73+
class C3 {
74+
foo() {
75+
const x: false.typeof(this.foo);
76+
~
77+
!!! error TS1005: ',' expected.
78+
~~~~~~
79+
!!! error TS1134: Variable declaration expected.
80+
}
81+
}
82+
83+
const nodes3 = document.getElementsByTagName("li");
84+
~~~~~~~~
85+
!!! error TS2304: Cannot find name 'document'.
86+
type ItemType3 = true.typeof(nodes.item(0));
87+
~
88+
!!! error TS1005: ';' expected.
89+
90+
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//// [tests/cases/compiler/expressionTypeNodeShouldError.ts] ////
2+
3+
//// [base.d.ts]
4+
declare const x: "foo".charCodeAt(0);
5+
6+
//// [string.ts]
7+
interface String {
8+
typeof<T>(x: T): T;
9+
}
10+
11+
class C {
12+
foo() {
13+
const x: "".typeof(this.foo);
14+
}
15+
}
16+
17+
const nodes = document.getElementsByTagName("li");
18+
type ItemType = "".typeof(nodes.item(0));
19+
20+
//// [number.ts]
21+
interface Number {
22+
typeof<T>(x: T): T;
23+
}
24+
25+
class C2 {
26+
foo() {
27+
const x: 3.141592.typeof(this.foo);
28+
}
29+
}
30+
31+
const nodes2 = document.getElementsByTagName("li");
32+
type ItemType2 = 4..typeof(nodes.item(0));
33+
34+
//// [boolean.ts]
35+
interface Boolean {
36+
typeof<T>(x: T): T;
37+
}
38+
39+
class C3 {
40+
foo() {
41+
const x: false.typeof(this.foo);
42+
}
43+
}
44+
45+
const nodes3 = document.getElementsByTagName("li");
46+
type ItemType3 = true.typeof(nodes.item(0));
47+
48+
49+
50+
//// [string.js]
51+
var C = (function () {
52+
function C() {
53+
}
54+
C.prototype.foo = function () {
55+
var x;
56+
typeof (this.foo);
57+
};
58+
return C;
59+
}());
60+
var nodes = document.getElementsByTagName("li");
61+
typeof (nodes.item(0));
62+
//// [number.js]
63+
var C2 = (function () {
64+
function C2() {
65+
}
66+
C2.prototype.foo = function () {
67+
var x;
68+
typeof (this.foo);
69+
};
70+
return C2;
71+
}());
72+
var nodes2 = document.getElementsByTagName("li");
73+
typeof (nodes.item(0));
74+
//// [boolean.js]
75+
var C3 = (function () {
76+
function C3() {
77+
}
78+
C3.prototype.foo = function () {
79+
var x;
80+
typeof (this.foo);
81+
};
82+
return C3;
83+
}());
84+
var nodes3 = document.getElementsByTagName("li");
85+
typeof (nodes.item(0));
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// @Filename: base.d.ts
2+
declare const x: "foo".charCodeAt(0);
3+
4+
// @filename: string.ts
5+
interface String {
6+
typeof<T>(x: T): T;
7+
}
8+
9+
class C {
10+
foo() {
11+
const x: "".typeof(this.foo);
12+
}
13+
}
14+
15+
const nodes = document.getElementsByTagName("li");
16+
type ItemType = "".typeof(nodes.item(0));
17+
18+
// @filename: number.ts
19+
interface Number {
20+
typeof<T>(x: T): T;
21+
}
22+
23+
class C2 {
24+
foo() {
25+
const x: 3.141592.typeof(this.foo);
26+
}
27+
}
28+
29+
const nodes2 = document.getElementsByTagName("li");
30+
type ItemType2 = 4..typeof(nodes.item(0));
31+
32+
// @filename: boolean.ts
33+
interface Boolean {
34+
typeof<T>(x: T): T;
35+
}
36+
37+
class C3 {
38+
foo() {
39+
const x: false.typeof(this.foo);
40+
}
41+
}
42+
43+
const nodes3 = document.getElementsByTagName("li");
44+
type ItemType3 = true.typeof(nodes.item(0));
45+

0 commit comments

Comments
 (0)