Skip to content

Commit 1679f44

Browse files
authored
More rigorous ASI prevention when emitting return/yield (#60304)
1 parent a62ac67 commit 1679f44

7 files changed

+789
-10
lines changed

src/compiler/emitter.ts

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,17 +3226,90 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
32263226
* Wraps an expression in parens if we would emit a leading comment that would introduce a line separator
32273227
* between the node and its parent.
32283228
*/
3229-
function parenthesizeExpressionForNoAsi(node: Expression) {
3230-
if (!commentsDisabled && isPartiallyEmittedExpression(node) && willEmitLeadingNewLine(node)) {
3231-
const parseNode = getParseTreeNode(node);
3232-
if (parseNode && isParenthesizedExpression(parseNode)) {
3233-
// If the original node was a parenthesized expression, restore it to preserve comment and source map emit
3234-
const parens = factory.createParenthesizedExpression(node.expression);
3235-
setOriginalNode(parens, node);
3236-
setTextRange(parens, parseNode);
3237-
return parens;
3229+
function parenthesizeExpressionForNoAsi(node: Expression): Expression {
3230+
if (!commentsDisabled) {
3231+
switch (node.kind) {
3232+
case SyntaxKind.PartiallyEmittedExpression:
3233+
if (willEmitLeadingNewLine(node)) {
3234+
const parseNode = getParseTreeNode(node);
3235+
if (parseNode && isParenthesizedExpression(parseNode)) {
3236+
// If the original node was a parenthesized expression, restore it to preserve comment and source map emit
3237+
const parens = factory.createParenthesizedExpression((node as PartiallyEmittedExpression).expression);
3238+
setOriginalNode(parens, node);
3239+
setTextRange(parens, parseNode);
3240+
return parens;
3241+
}
3242+
return factory.createParenthesizedExpression(node);
3243+
}
3244+
return factory.updatePartiallyEmittedExpression(
3245+
node as PartiallyEmittedExpression,
3246+
parenthesizeExpressionForNoAsi((node as PartiallyEmittedExpression).expression),
3247+
);
3248+
case SyntaxKind.PropertyAccessExpression:
3249+
return factory.updatePropertyAccessExpression(
3250+
node as PropertyAccessExpression,
3251+
parenthesizeExpressionForNoAsi((node as PropertyAccessExpression).expression),
3252+
(node as PropertyAccessExpression).name,
3253+
);
3254+
case SyntaxKind.ElementAccessExpression:
3255+
return factory.updateElementAccessExpression(
3256+
node as ElementAccessExpression,
3257+
parenthesizeExpressionForNoAsi((node as ElementAccessExpression).expression),
3258+
(node as ElementAccessExpression).argumentExpression,
3259+
);
3260+
case SyntaxKind.CallExpression:
3261+
return factory.updateCallExpression(
3262+
node as CallExpression,
3263+
parenthesizeExpressionForNoAsi((node as CallExpression).expression),
3264+
(node as CallExpression).typeArguments,
3265+
(node as CallExpression).arguments,
3266+
);
3267+
case SyntaxKind.TaggedTemplateExpression:
3268+
return factory.updateTaggedTemplateExpression(
3269+
node as TaggedTemplateExpression,
3270+
parenthesizeExpressionForNoAsi((node as TaggedTemplateExpression).tag),
3271+
(node as TaggedTemplateExpression).typeArguments,
3272+
(node as TaggedTemplateExpression).template,
3273+
);
3274+
case SyntaxKind.PostfixUnaryExpression:
3275+
return factory.updatePostfixUnaryExpression(
3276+
node as PostfixUnaryExpression,
3277+
parenthesizeExpressionForNoAsi((node as PostfixUnaryExpression).operand),
3278+
);
3279+
case SyntaxKind.BinaryExpression:
3280+
return factory.updateBinaryExpression(
3281+
node as BinaryExpression,
3282+
parenthesizeExpressionForNoAsi((node as BinaryExpression).left),
3283+
(node as BinaryExpression).operatorToken,
3284+
(node as BinaryExpression).right,
3285+
);
3286+
case SyntaxKind.ConditionalExpression:
3287+
return factory.updateConditionalExpression(
3288+
node as ConditionalExpression,
3289+
parenthesizeExpressionForNoAsi((node as ConditionalExpression).condition),
3290+
(node as ConditionalExpression).questionToken,
3291+
(node as ConditionalExpression).whenTrue,
3292+
(node as ConditionalExpression).colonToken,
3293+
(node as ConditionalExpression).whenFalse,
3294+
);
3295+
case SyntaxKind.AsExpression:
3296+
return factory.updateAsExpression(
3297+
node as AsExpression,
3298+
parenthesizeExpressionForNoAsi((node as AsExpression).expression),
3299+
(node as AsExpression).type,
3300+
);
3301+
case SyntaxKind.SatisfiesExpression:
3302+
return factory.updateSatisfiesExpression(
3303+
node as SatisfiesExpression,
3304+
parenthesizeExpressionForNoAsi((node as SatisfiesExpression).expression),
3305+
(node as SatisfiesExpression).type,
3306+
);
3307+
case SyntaxKind.NonNullExpression:
3308+
return factory.updateNonNullExpression(
3309+
node as NonNullExpression,
3310+
parenthesizeExpressionForNoAsi((node as NonNullExpression).expression),
3311+
);
32383312
}
3239-
return factory.createParenthesizedExpression(node);
32403313
}
32413314
return node;
32423315
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
//// [tests/cases/conformance/statements/returnStatements/returnStatementNoAsiAfterTransform.ts] ////
2+
3+
//// [returnStatementNoAsiAfterTransform.ts]
4+
declare var a: any;
5+
6+
function t1() {
7+
return (
8+
// comment
9+
a as any
10+
);
11+
}
12+
function t2() {
13+
return (
14+
// comment
15+
a as any
16+
) + 1;
17+
}
18+
function t3() {
19+
return (
20+
// comment
21+
a as any
22+
) ? 0 : 1;
23+
}
24+
function t4() {
25+
return (
26+
// comment
27+
a as any
28+
).b;
29+
}
30+
function t5() {
31+
return (
32+
// comment
33+
a as any
34+
)[a];
35+
}
36+
function t6() {
37+
return (
38+
// comment
39+
a as any
40+
)();
41+
}
42+
function t7() {
43+
return (
44+
// comment
45+
a as any
46+
)``;
47+
}
48+
function t8() {
49+
return (
50+
// comment
51+
a as any
52+
) as any;
53+
}
54+
function t9() {
55+
return (
56+
// comment
57+
a as any
58+
) satisfies any;
59+
}
60+
function t10() {
61+
return (
62+
// comment
63+
a as any
64+
)!;
65+
}
66+
67+
68+
//// [returnStatementNoAsiAfterTransform.js]
69+
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
70+
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
71+
return cooked;
72+
};
73+
function t1() {
74+
return (
75+
// comment
76+
a);
77+
}
78+
function t2() {
79+
return (
80+
// comment
81+
a) + 1;
82+
}
83+
function t3() {
84+
return (
85+
// comment
86+
a) ? 0 : 1;
87+
}
88+
function t4() {
89+
return (
90+
// comment
91+
a).b;
92+
}
93+
function t5() {
94+
return (
95+
// comment
96+
a)[a];
97+
}
98+
function t6() {
99+
return (
100+
// comment
101+
a)();
102+
}
103+
function t7() {
104+
return (
105+
// comment
106+
a)(__makeTemplateObject([""], [""]));
107+
}
108+
function t8() {
109+
return (
110+
// comment
111+
a);
112+
}
113+
function t9() {
114+
return (
115+
// comment
116+
a);
117+
}
118+
function t10() {
119+
return (
120+
// comment
121+
a);
122+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
//// [tests/cases/conformance/statements/returnStatements/returnStatementNoAsiAfterTransform.ts] ////
2+
3+
//// [returnStatementNoAsiAfterTransform.ts]
4+
declare var a: any;
5+
6+
function t1() {
7+
return (
8+
// comment
9+
a as any
10+
);
11+
}
12+
function t2() {
13+
return (
14+
// comment
15+
a as any
16+
) + 1;
17+
}
18+
function t3() {
19+
return (
20+
// comment
21+
a as any
22+
) ? 0 : 1;
23+
}
24+
function t4() {
25+
return (
26+
// comment
27+
a as any
28+
).b;
29+
}
30+
function t5() {
31+
return (
32+
// comment
33+
a as any
34+
)[a];
35+
}
36+
function t6() {
37+
return (
38+
// comment
39+
a as any
40+
)();
41+
}
42+
function t7() {
43+
return (
44+
// comment
45+
a as any
46+
)``;
47+
}
48+
function t8() {
49+
return (
50+
// comment
51+
a as any
52+
) as any;
53+
}
54+
function t9() {
55+
return (
56+
// comment
57+
a as any
58+
) satisfies any;
59+
}
60+
function t10() {
61+
return (
62+
// comment
63+
a as any
64+
)!;
65+
}
66+
67+
68+
//// [returnStatementNoAsiAfterTransform.js]
69+
function t1() {
70+
return (
71+
// comment
72+
a);
73+
}
74+
function t2() {
75+
return (
76+
// comment
77+
a) + 1;
78+
}
79+
function t3() {
80+
return (
81+
// comment
82+
a) ? 0 : 1;
83+
}
84+
function t4() {
85+
return (
86+
// comment
87+
a).b;
88+
}
89+
function t5() {
90+
return (
91+
// comment
92+
a)[a];
93+
}
94+
function t6() {
95+
return (
96+
// comment
97+
a)();
98+
}
99+
function t7() {
100+
return (
101+
// comment
102+
a) ``;
103+
}
104+
function t8() {
105+
return (
106+
// comment
107+
a);
108+
}
109+
function t9() {
110+
return (
111+
// comment
112+
a);
113+
}
114+
function t10() {
115+
return (
116+
// comment
117+
a);
118+
}

0 commit comments

Comments
 (0)