Skip to content

Commit

Permalink
More rigorous ASI prevention when emitting return/yield (#60304)
Browse files Browse the repository at this point in the history
  • Loading branch information
rbuckton authored Oct 22, 2024
1 parent a62ac67 commit 1679f44
Show file tree
Hide file tree
Showing 7 changed files with 789 additions and 10 deletions.
93 changes: 83 additions & 10 deletions src/compiler/emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3226,17 +3226,90 @@ export function createPrinter(printerOptions: PrinterOptions = {}, handlers: Pri
* Wraps an expression in parens if we would emit a leading comment that would introduce a line separator
* between the node and its parent.
*/
function parenthesizeExpressionForNoAsi(node: Expression) {
if (!commentsDisabled && isPartiallyEmittedExpression(node) && willEmitLeadingNewLine(node)) {
const parseNode = getParseTreeNode(node);
if (parseNode && isParenthesizedExpression(parseNode)) {
// If the original node was a parenthesized expression, restore it to preserve comment and source map emit
const parens = factory.createParenthesizedExpression(node.expression);
setOriginalNode(parens, node);
setTextRange(parens, parseNode);
return parens;
function parenthesizeExpressionForNoAsi(node: Expression): Expression {
if (!commentsDisabled) {
switch (node.kind) {
case SyntaxKind.PartiallyEmittedExpression:
if (willEmitLeadingNewLine(node)) {
const parseNode = getParseTreeNode(node);
if (parseNode && isParenthesizedExpression(parseNode)) {
// If the original node was a parenthesized expression, restore it to preserve comment and source map emit
const parens = factory.createParenthesizedExpression((node as PartiallyEmittedExpression).expression);
setOriginalNode(parens, node);
setTextRange(parens, parseNode);
return parens;
}
return factory.createParenthesizedExpression(node);
}
return factory.updatePartiallyEmittedExpression(
node as PartiallyEmittedExpression,
parenthesizeExpressionForNoAsi((node as PartiallyEmittedExpression).expression),
);
case SyntaxKind.PropertyAccessExpression:
return factory.updatePropertyAccessExpression(
node as PropertyAccessExpression,
parenthesizeExpressionForNoAsi((node as PropertyAccessExpression).expression),
(node as PropertyAccessExpression).name,
);
case SyntaxKind.ElementAccessExpression:
return factory.updateElementAccessExpression(
node as ElementAccessExpression,
parenthesizeExpressionForNoAsi((node as ElementAccessExpression).expression),
(node as ElementAccessExpression).argumentExpression,
);
case SyntaxKind.CallExpression:
return factory.updateCallExpression(
node as CallExpression,
parenthesizeExpressionForNoAsi((node as CallExpression).expression),
(node as CallExpression).typeArguments,
(node as CallExpression).arguments,
);
case SyntaxKind.TaggedTemplateExpression:
return factory.updateTaggedTemplateExpression(
node as TaggedTemplateExpression,
parenthesizeExpressionForNoAsi((node as TaggedTemplateExpression).tag),
(node as TaggedTemplateExpression).typeArguments,
(node as TaggedTemplateExpression).template,
);
case SyntaxKind.PostfixUnaryExpression:
return factory.updatePostfixUnaryExpression(
node as PostfixUnaryExpression,
parenthesizeExpressionForNoAsi((node as PostfixUnaryExpression).operand),
);
case SyntaxKind.BinaryExpression:
return factory.updateBinaryExpression(
node as BinaryExpression,
parenthesizeExpressionForNoAsi((node as BinaryExpression).left),
(node as BinaryExpression).operatorToken,
(node as BinaryExpression).right,
);
case SyntaxKind.ConditionalExpression:
return factory.updateConditionalExpression(
node as ConditionalExpression,
parenthesizeExpressionForNoAsi((node as ConditionalExpression).condition),
(node as ConditionalExpression).questionToken,
(node as ConditionalExpression).whenTrue,
(node as ConditionalExpression).colonToken,
(node as ConditionalExpression).whenFalse,
);
case SyntaxKind.AsExpression:
return factory.updateAsExpression(
node as AsExpression,
parenthesizeExpressionForNoAsi((node as AsExpression).expression),
(node as AsExpression).type,
);
case SyntaxKind.SatisfiesExpression:
return factory.updateSatisfiesExpression(
node as SatisfiesExpression,
parenthesizeExpressionForNoAsi((node as SatisfiesExpression).expression),
(node as SatisfiesExpression).type,
);
case SyntaxKind.NonNullExpression:
return factory.updateNonNullExpression(
node as NonNullExpression,
parenthesizeExpressionForNoAsi((node as NonNullExpression).expression),
);
}
return factory.createParenthesizedExpression(node);
}
return node;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//// [tests/cases/conformance/statements/returnStatements/returnStatementNoAsiAfterTransform.ts] ////

//// [returnStatementNoAsiAfterTransform.ts]
declare var a: any;

function t1() {
return (
// comment
a as any
);
}
function t2() {
return (
// comment
a as any
) + 1;
}
function t3() {
return (
// comment
a as any
) ? 0 : 1;
}
function t4() {
return (
// comment
a as any
).b;
}
function t5() {
return (
// comment
a as any
)[a];
}
function t6() {
return (
// comment
a as any
)();
}
function t7() {
return (
// comment
a as any
)``;
}
function t8() {
return (
// comment
a as any
) as any;
}
function t9() {
return (
// comment
a as any
) satisfies any;
}
function t10() {
return (
// comment
a as any
)!;
}


//// [returnStatementNoAsiAfterTransform.js]
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
return cooked;
};
function t1() {
return (
// comment
a);
}
function t2() {
return (
// comment
a) + 1;
}
function t3() {
return (
// comment
a) ? 0 : 1;
}
function t4() {
return (
// comment
a).b;
}
function t5() {
return (
// comment
a)[a];
}
function t6() {
return (
// comment
a)();
}
function t7() {
return (
// comment
a)(__makeTemplateObject([""], [""]));
}
function t8() {
return (
// comment
a);
}
function t9() {
return (
// comment
a);
}
function t10() {
return (
// comment
a);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
//// [tests/cases/conformance/statements/returnStatements/returnStatementNoAsiAfterTransform.ts] ////

//// [returnStatementNoAsiAfterTransform.ts]
declare var a: any;

function t1() {
return (
// comment
a as any
);
}
function t2() {
return (
// comment
a as any
) + 1;
}
function t3() {
return (
// comment
a as any
) ? 0 : 1;
}
function t4() {
return (
// comment
a as any
).b;
}
function t5() {
return (
// comment
a as any
)[a];
}
function t6() {
return (
// comment
a as any
)();
}
function t7() {
return (
// comment
a as any
)``;
}
function t8() {
return (
// comment
a as any
) as any;
}
function t9() {
return (
// comment
a as any
) satisfies any;
}
function t10() {
return (
// comment
a as any
)!;
}


//// [returnStatementNoAsiAfterTransform.js]
function t1() {
return (
// comment
a);
}
function t2() {
return (
// comment
a) + 1;
}
function t3() {
return (
// comment
a) ? 0 : 1;
}
function t4() {
return (
// comment
a).b;
}
function t5() {
return (
// comment
a)[a];
}
function t6() {
return (
// comment
a)();
}
function t7() {
return (
// comment
a) ``;
}
function t8() {
return (
// comment
a);
}
function t9() {
return (
// comment
a);
}
function t10() {
return (
// comment
a);
}
Loading

0 comments on commit 1679f44

Please sign in to comment.