capture thisArg of optionalChaining in parens (#35494)

Fixes: #35476
This commit is contained in:
Klaus Meinhardt
2021-03-04 04:35:17 +01:00
committed by GitHub
parent 8a81a6722d
commit 15e69acc20
4 changed files with 52 additions and 3 deletions

View File

@@ -21,11 +21,15 @@ namespace ts {
return node;
}
switch (node.kind) {
case SyntaxKind.CallExpression: {
const updated = visitNonOptionalCallExpression(node as CallExpression, /*captureThisArg*/ false);
Debug.assertNotNode(updated, isSyntheticReference);
return updated;
}
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.CallExpression:
if (node.flags & NodeFlags.OptionalChain) {
const updated = visitOptionalExpression(node as OptionalChain, /*captureThisArg*/ false, /*isDelete*/ false);
if (isOptionalChain(node)) {
const updated = visitOptionalExpression(node, /*captureThisArg*/ false, /*isDelete*/ false);
Debug.assertNotNode(updated, isSyntheticReference);
return updated;
}
@@ -94,6 +98,15 @@ namespace ts {
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
return visitOptionalExpression(node, captureThisArg, /*isDelete*/ false);
}
if (isParenthesizedExpression(node.expression) && isOptionalChain(skipParentheses(node.expression))) {
// capture thisArg for calls of parenthesized optional chains like `(foo?.bar)()`
const expression = visitNonOptionalParenthesizedExpression(node.expression, /*captureThisArg*/ true, /*isDelete*/ false);
const args = visitNodes(node.arguments, visitor, isExpression);
if (isSyntheticReference(expression)) {
return setTextRange(factory.createFunctionCallCall(expression.expression, expression.thisArg, args), node);
}
return factory.updateCallExpression(node, expression, /*typeArguments*/ undefined, args);
}
return visitEachChild(node, visitor, context);
}

View File

@@ -188,4 +188,11 @@ describe("unittests:: evaluation:: optionalCall", () => {
assert.strictEqual(result.output[1], 2);
assert.strictEqual(result.output[2], result.o);
});
it("(o?.f)()", async () => {
const result = evaluator.evaluateTypeScript(`
export const foo = { bar() { return this } };
export const output = (foo?.bar)();
`);
assert.strictEqual(result.output, result.foo);
});
});